diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000000..14da7f057c --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,817 @@ +version: 2.1 + +parameters: + compute_size_small: + type: string + default: "small" + compute_size_large: + type: string + default: "large" + compute_size_mac_medium: + type: string + default: "macos.m1.medium.gen1" + compute_size_windows_medium: + type: string + default: "windows.medium" + maven_version: + type: string + default: "3.9.9" + maven_dependency_plugin_version: + type: string + default: "3.8.1" + maven_dependency_check_plugin_version: + type: string + default: "12.1.1" + java_tool_options: + type: string + default: "-DtrimStackTrace=false -Djava.awt.headless=true -XX:+UseNUMA -XX:+UseG1GC -XX:+UseStringDeduplication" + # NOTE(AR) -XX:+UseZGC seems to exhibit a need for more memory and somehow causes the limits of the CI to be exhausted in Docker contains even though -XX:MaxRAMPercentage=75.0 is set below + # default: "-DtrimStackTrace=false -Djava.awt.headless=true -XX:+UseNUMA -XX:+UseZGC" + extra_java_tool_options_docker: + type: string + default: "-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0" + + +executors: + linux-docker-jdk21: + docker: + - image: "cimg/openjdk:21.0" + environment: + MAVEN_BIN: /opt/apache-maven/bin/mvn + macos-vm-xcode16: + macos: + xcode: 16.4.0 + environment: + MAVEN_BIN: /tmp/maven/bin/mvn + JAVA_HOME: /Library/Java/JavaVirtualMachines/liberica-jdk-21.jdk/Contents/Home + windows-vm: + machine: + image: "windows-server-2022-gui:current" + shell: bash.exe + environment: + JAVA_HOME: /c/progra~1/BellSoft/LibericaJDK-21 + MAVEN_BIN: /tmp/maven/bin/mvn + + +commands: + install_jdk: + parameters: + jdk_major_version: + description: "The major version of the JDK to install" + type: string + default: "21" + compute_size: + type: string + default: << pipeline.parameters.compute_size_small >> + steps: + - when: + condition: + and: + - matches: { pattern: "^macos.+$", value: << parameters.compute_size >> } + steps: + - run: + name: "Brew - Add BellSoft Libercia JDK Tap" + command: "brew tap bell-sw/liberica" + - run: + name: "Brew - Install BellSoft Libercia JDK" + command: "brew install --cask liberica-jdk<< parameters.jdk_major_version >>" + - when: + condition: + and: + - matches: { pattern: "^windows.+$", value: << parameters.compute_size >> } + steps: + - run: + name: "Choco - Install BellSoft Libercia JDK" + command: "choco install liberica<< parameters.jdk_major_version >>jdk" + shell: cmd.exe + - run: + name: "Java - Show Version" + command: | + echo JAVA_HOME="${JAVA_HOME}" + $JAVA_HOME/bin/java -version + + install_maven: + parameters: + maven_version: + description: "The version of Maven to install" + type: string + default: << pipeline.parameters.maven_version >> + directory: + description: "The directory in which to install Maven. Default: /tmp." + type: string + default: "/tmp" + symlink_target: + description: "The target to symlink the Maven folder to. Default: /tmp/maven." + type: string + default: "/tmp/maven" + compute_size: + type: string + default: << pipeline.parameters.compute_size_small >> + steps: + - when: + condition: + or: + - matches: { pattern: "^macos.+$", value: << parameters.compute_size >> } + - matches: { pattern: "^windows.+$", value: << parameters.compute_size >> } + steps: + - run: + name: "Install Maven" + environment: + MAVEN_VERSION: << parameters.maven_version >> + MAVEN_TARGET_DIR: << parameters.directory >> + MAVEN_SYMLINK_TARGET: << parameters.symlink_target >> + command: | + set -x + MAVEN_ARTIFACT=apache-maven-$MAVEN_VERSION + MAVEN_ARCHIVE=$MAVEN_ARTIFACT-bin.tar.gz + TMP_DOWNLOAD=/tmp/$MAVEN_ARCHIVE + if [ -z "$MAVEN_TARGET_DIR" ]; then + MAVEN_TARGET_DIR=$HOME + fi + if [ -z "$MAVEN_SYMLINK_TARGET" ]; then + MAVEN_SYMLINK_TARGET=$HOME/maven + fi + curl --fail --output $TMP_DOWNLOAD --location https://archive.apache.org/dist/maven/maven-3/$MAVEN_VERSION/binaries/$MAVEN_ARCHIVE + tar zxvf $TMP_DOWNLOAD -C $MAVEN_TARGET_DIR + ln -s $MAVEN_TARGET_DIR/$MAVEN_ARTIFACT $MAVEN_SYMLINK_TARGET + rm $TMP_DOWNLOAD + set +x + - run: + name: "Maven - Show Version" + command: | + echo MAVEN_BIN="${MAVEN_BIN}" + $MAVEN_BIN --version + + maven_with_cache: + # NOTE(AR) based on https://circleci.com/developer/orbs/orb/circleci/maven + parameters: + app_src_directory: + description: "The directory containing the pom.xml file for the project." + type: string + default: '' + cache_name_prefix: + description: "The cache's name prefix to allow for multiple caches and/or cache invalidation." + type: string + dependency_plugin_version: + description: "Specify the Maven Dependency Plugin" + type: string + default: << pipeline.parameters.maven_dependency_plugin_version >> + verify_dependencies: + description: "Verify dependencies are valid and available from public sources" + type: boolean + default: true + steps: + description: "The steps to execute with the cache" + type: steps + compute_size: + type: string + default: << pipeline.parameters.compute_size_small >> + steps: + - when: + condition: + and: + - not: + and: + - matches: { pattern: "^windows.+$", value: << parameters.compute_size >> } + steps: + - run: + name: Generate Cache Checksum (Linux/macOS) + working_directory: << parameters.app_src_directory >> + command: "/usr/bin/find . -name 'pom.xml' | /usr/bin/sort | xargs cat > /tmp/maven_cache_seed" + - restore_cache: + keys: + - << parameters.cache_name_prefix >>-{{ checksum "/tmp/maven_cache_seed" }} + - when: + condition: + and: + - matches: { pattern: "^windows.+$", value: << parameters.compute_size >> } + steps: + - run: + name: Generate Cache Checksum (Windows) + working_directory: << parameters.app_src_directory >> + command: "/usr/bin/find . -name 'pom.xml' | /usr/bin/sort | xargs cat > /c/Users/circleci/AppData/Local/Temp/maven_cache_seed" + - restore_cache: + keys: + - << parameters.cache_name_prefix >>-{{ checksum "C:\\Users\\circleci\\AppData\\Local\\Temp\\maven_cache_seed" }} + - when: + condition: << parameters.verify_dependencies >> + steps: + - run: + name: Maven - Collect and Verify Dependencies + environment: + PARAM_DEP_PLUGIN_VER: << parameters.dependency_plugin_version >> + working_directory: << parameters.app_src_directory >> + command: "$MAVEN_BIN -V -T2C org.apache.maven.plugins:maven-dependency-plugin:$PARAM_DEP_PLUGIN_VER:go-offline" + - steps: << parameters.steps >> + + - when: + condition: + and: + - not: + and: + - matches: { pattern: "^windows.+$", value: << parameters.compute_size >> } + steps: + - save_cache: + key: << parameters.cache_name_prefix >>-{{ checksum "/tmp/maven_cache_seed" }} + paths: + - ~/.m2/repository + - when: + condition: + and: + - matches: { pattern: "^windows.+$", value: << parameters.compute_size >> } + steps: + - save_cache: + key: << parameters.cache_name_prefix >>-{{ checksum "C:\\Users\\circleci\\AppData\\Local\\Temp\\maven_cache_seed" }} + paths: + - C:\Users\circleci\.m2\repository + + install_artifacts: + parameters: + compute_size: + type: string + default: << pipeline.parameters.compute_size_small >> + steps: + - run: + name: "Maven - Install Artifacts" + environment: + COMPUTE_SIZE: << parameters.compute_size >> + command: | + if [[ $COMPUTE_SIZE == "small" ]] || [[ $COMPUTE_SIZE == "large" ]]; then + export JAVA_TOOL_OPTIONS="<< pipeline.parameters.java_tool_options >> << pipeline.parameters.extra_java_tool_options_docker >>" + else + export JAVA_TOOL_OPTIONS="<< pipeline.parameters.java_tool_options >>" + fi + $MAVEN_BIN -V -T2C install -DskipTests -Ddependency-check.skip=true -Dmdep.analyze.skip=true -Dlicense.skip=true --projects '!exist-distribution,!exist-installer' --also-make + + persist_project: + parameters: + compute_size: + type: string + default: << pipeline.parameters.compute_size_small >> + steps: + - when: + condition: + or: + - equal: [ small, << parameters.compute_size >> ] + - equal: [ large, << parameters.compute_size >> ] + steps: + - persist_to_workspace: + root: /home/circleci/project + paths: + - "**" + - when: + condition: + and: + - matches: { pattern: "^macos.+$", value: << parameters.compute_size >> } + steps: + - persist_to_workspace: + root: /Users/distiller/project + paths: + - "**" + - when: + condition: + and: + - matches: { pattern: "^windows.+$", value: << parameters.compute_size >> } + steps: + - persist_to_workspace: + root: C:\Users\circleci\project + paths: + - "**" + + attach_project: + parameters: + compute_size: + type: string + default: << pipeline.parameters.compute_size_small >> + steps: + - when: + condition: + or: + - equal: [ small, << parameters.compute_size >> ] + - equal: [ large, << parameters.compute_size >> ] + steps: + - attach_workspace: + at: /home/circleci/project + - when: + condition: + and: + - matches: { pattern: "^macos.+$", value: << parameters.compute_size >> } + steps: + - attach_workspace: + at: /Users/distiller/project + - when: + condition: + and: + - matches: { pattern: "^windows.+$", value: << parameters.compute_size >> } + steps: + - attach_workspace: + at: C:\Users\circleci\project + + create_maven_settings: + steps: + - run: + name: Create Maven settings.xml + command: | + mkdir -p ~/.m2 + cat > ~/.m2/settings.xml \<< EOF + + + + ossindex + ${OSSINDEX_USERNAME} + ${OSSINDEX_TOKEN} + + + + EOF + +jobs: + license-check: + parameters: + os: + type: executor + compute_size: + type: string + default: << pipeline.parameters.compute_size_small >> + maven_cache_name_prefix: + type: string + executor: << parameters.os >> + resource_class: << parameters.compute_size >> + steps: + - checkout + - install_jdk: + compute_size: << parameters.compute_size >> + - install_maven: + compute_size: << parameters.compute_size >> + - maven_with_cache: + compute_size: << parameters.compute_size >> + cache_name_prefix: << parameters.maven_cache_name_prefix >> + verify_dependencies: false + steps: + - steps: + - run: + name: "Maven - License Check" + command: "$MAVEN_BIN -V -T2C license:check" + + + build: + parameters: + os: + type: executor + compute_size: + type: string + default: << pipeline.parameters.compute_size_small >> + maven_cache_name_prefix: + type: string + executor: << parameters.os >> + resource_class: << parameters.compute_size >> + environment: + COMPUTE_SIZE: << parameters.compute_size >> + steps: + - checkout + - install_jdk: + compute_size: << parameters.compute_size >> + - install_maven: + compute_size: << parameters.compute_size >> + - maven_with_cache: + compute_size: << parameters.compute_size >> + cache_name_prefix: << parameters.maven_cache_name_prefix >> + verify_dependencies: true + steps: + - steps: + - run: + name: "Maven - Build Package" + command: | + if [[ $COMPUTE_SIZE == "small" ]] || [[ $COMPUTE_SIZE == "large" ]]; then + export JAVA_TOOL_OPTIONS="<< pipeline.parameters.java_tool_options >> << pipeline.parameters.extra_java_tool_options_docker >>" + else + export JAVA_TOOL_OPTIONS="<< pipeline.parameters.java_tool_options >>" + fi + $MAVEN_BIN -V -T2C package -DskipTests -Dappbundler.skip=true -Ddocker=false -P !mac-dmg-on-mac,!codesign-mac-app,!codesign-mac-dmg,!mac-dmg-on-unix,!installer,!concurrency-stress-tests,!micro-benchmarks,skip-build-dist-archives + - persist_project: + compute_size: << parameters.compute_size >> + + dependency-analyze: + parameters: + os: + type: executor + compute_size: + type: string + default: << pipeline.parameters.compute_size_small >> + maven_cache_name_prefix: + type: string + executor: << parameters.os >> + resource_class: << parameters.compute_size >> + environment: + COMPUTE_SIZE: << parameters.compute_size >> + steps: + - attach_project: + compute_size: << parameters.compute_size >> + - install_jdk: + compute_size: << parameters.compute_size >> + - install_maven: + compute_size: << parameters.compute_size >> + - maven_with_cache: + compute_size: << parameters.compute_size >> + cache_name_prefix: << parameters.maven_cache_name_prefix >> + verify_dependencies: false + steps: + - steps: + - run: + name: "Maven - Run Dependency Analysis" + command: | + if [[ $COMPUTE_SIZE == "small" ]] || [[ $COMPUTE_SIZE == "large" ]]; then + export JAVA_TOOL_OPTIONS="<< pipeline.parameters.java_tool_options >> << pipeline.parameters.extra_java_tool_options_docker >>" + else + export JAVA_TOOL_OPTIONS="<< pipeline.parameters.java_tool_options >>" + fi + $MAVEN_BIN -V -T2C dependency:analyze + + owasp-dependency-check: + parameters: + os: + type: executor + compute_size: + type: string + default: << pipeline.parameters.compute_size_small >> + maven_cache_name_prefix: + type: string + executor: << parameters.os >> + resource_class: << parameters.compute_size >> + environment: + COMPUTE_SIZE: << parameters.compute_size >> + steps: + - attach_project: + compute_size: << parameters.compute_size >> + - install_jdk: + compute_size: << parameters.compute_size >> + - install_maven: + compute_size: << parameters.compute_size >> + - create_maven_settings + - restore_cache: + keys: + - << parameters.maven_cache_name_prefix >>-dependency-check-data-{{ checksum "/tmp/dependency-check-data/odc.mv.db" }} + - maven_with_cache: + compute_size: << parameters.compute_size >> + cache_name_prefix: << parameters.maven_cache_name_prefix >> + verify_dependencies: false + steps: + - steps: + - install_artifacts: + compute_size: << parameters.compute_size >> + - run: + name: "Maven - Run Dependency Check" + no_output_timeout: 30m + command: | + if [[ $COMPUTE_SIZE == "small" ]] || [[ $COMPUTE_SIZE == "large" ]]; then + export JAVA_TOOL_OPTIONS="<< pipeline.parameters.java_tool_options >> << pipeline.parameters.extra_java_tool_options_docker >>" + else + export JAVA_TOOL_OPTIONS="<< pipeline.parameters.java_tool_options >>" + fi + $MAVEN_BIN -V -T2C -DdataDirectory=/tmp/dependency-check-data dependency-check:<< pipeline.parameters.maven_dependency_check_plugin_version >>:check + - save_cache: + key: << parameters.maven_cache_name_prefix >>-dependency-check-data-{{ checksum "/tmp/dependency-check-data/odc.mv.db" }} + paths: + - /tmp/dependency-check-data + + javadoc: + parameters: + os: + type: executor + compute_size: + type: string + default: << pipeline.parameters.compute_size_small >> + maven_cache_name_prefix: + type: string + executor: << parameters.os >> + resource_class: << parameters.compute_size >> + environment: + COMPUTE_SIZE: << parameters.compute_size >> + steps: + - attach_project: + compute_size: << parameters.compute_size >> + - install_jdk: + compute_size: << parameters.compute_size >> + - install_maven: + compute_size: << parameters.compute_size >> + - maven_with_cache: + compute_size: << parameters.compute_size >> + cache_name_prefix: << parameters.maven_cache_name_prefix >> + verify_dependencies: false + steps: + - steps: + - install_artifacts: + compute_size: << parameters.compute_size >> + - run: + name: "Maven - Generate Javadoc" + command: | + if [[ $COMPUTE_SIZE == "small" ]] || [[ $COMPUTE_SIZE == "large" ]]; then + export JAVA_TOOL_OPTIONS="<< pipeline.parameters.java_tool_options >> << pipeline.parameters.extra_java_tool_options_docker >>" + else + export JAVA_TOOL_OPTIONS="<< pipeline.parameters.java_tool_options >>" + fi + $MAVEN_BIN -V -T2C -q javadoc:javadoc --projects '!exist-distribution,!exist-installer' --also-make + + test: + parameters: + os: + type: executor + compute_size: + type: string + default: << pipeline.parameters.compute_size_large >> + maven_cache_name_prefix: + type: string + executor: << parameters.os >> + resource_class: << parameters.compute_size >> + environment: + COMPUTE_SIZE: << parameters.compute_size >> + steps: + - attach_project: + compute_size: << parameters.compute_size >> + - install_jdk: + compute_size: << parameters.compute_size >> + - install_maven: + compute_size: << parameters.compute_size >> + - maven_with_cache: + compute_size: << parameters.compute_size >> + cache_name_prefix: << parameters.maven_cache_name_prefix >> + verify_dependencies: false + steps: + - steps: + - run: + name: "Maven - Run Tests" + command: | + if [[ $COMPUTE_SIZE == "small" ]] || [[ $COMPUTE_SIZE == "large" ]]; then + export JAVA_TOOL_OPTIONS="<< pipeline.parameters.java_tool_options >> << pipeline.parameters.extra_java_tool_options_docker >>" + else + export JAVA_TOOL_OPTIONS="<< pipeline.parameters.java_tool_options >>" + fi + $MAVEN_BIN test integration-test -Dappbundler.skip=true -Ddocker=false -P !mac-dmg-on-mac,!codesign-mac-app,!codesign-mac-dmg,!mac-dmg-on-unix,!installer,!concurrency-stress-tests,!micro-benchmarks,skip-build-dist-archives + - run: + name: Save test results + command: | + mkdir -p ~/test-results/junit/ + /usr/bin/find . -type f -regex ".*/target/surefire-reports/.*xml" -exec cp {} ~/test-results/junit/ \; + /usr/bin/find . -type f -regex ".*/target/failsafe-reports/.*xml" -exec cp {} ~/test-results/junit/ \; + when: always + - store_test_results: + path: ~/test-results + - when: + # NOTE(AR) only persist the workspace when we are on the `main` branch, and it has a `large` compute, as we then reuse it for the `code-coverage` and `sonar-analysis` jobs + condition: + and: + - equal: [ large, << parameters.compute_size >> ] + - equal: [ main, << pipeline.git.branch >> ] + steps: + - persist_project: + compute_size: << parameters.compute_size >> + + code-coverage: + parameters: + os: + type: executor + compute_size: + type: string + default: << pipeline.parameters.compute_size_small >> + maven_cache_name_prefix: + type: string + executor: << parameters.os >> + resource_class: << parameters.compute_size >> + environment: + COMPUTE_SIZE: << parameters.compute_size >> + steps: + - attach_project: + compute_size: << parameters.compute_size >> + - install_jdk: + compute_size: << parameters.compute_size >> + - install_maven: + compute_size: << parameters.compute_size >> + - maven_with_cache: + compute_size: << parameters.compute_size >> + cache_name_prefix: << parameters.maven_cache_name_prefix >> + verify_dependencies: false + steps: + - steps: + - run: + name: "Maven - Produce Coverage and Coveralls Reports" + command: | + if [[ $COMPUTE_SIZE == "small" ]] || [[ $COMPUTE_SIZE == "large" ]]; then + export JAVA_TOOL_OPTIONS="<< pipeline.parameters.java_tool_options >> << pipeline.parameters.extra_java_tool_options_docker >>" + else + export JAVA_TOOL_OPTIONS="<< pipeline.parameters.java_tool_options >>" + fi + $MAVEN_BIN -V -T1C jacoco:report coveralls:report + + sonar-analysis: + parameters: + os: + type: executor + compute_size: + type: string + default: << pipeline.parameters.compute_size_small >> + maven_cache_name_prefix: + type: string + executor: << parameters.os >> + resource_class: << parameters.compute_size >> + environment: + COMPUTE_SIZE: << parameters.compute_size >> + steps: + - attach_project: + compute_size: << parameters.compute_size >> + - install_jdk: + compute_size: << parameters.compute_size >> + - install_maven: + compute_size: << parameters.compute_size >> + - maven_with_cache: + compute_size: << parameters.compute_size >> + cache_name_prefix: << parameters.maven_cache_name_prefix >> + verify_dependencies: false + steps: + - steps: + - run: + name: "Maven - Analyze on SonarQube Cloud" + no_output_timeout: 30m + command: | + if [[ $COMPUTE_SIZE == "small" ]] || [[ $COMPUTE_SIZE == "large" ]]; then + export JAVA_TOOL_OPTIONS="<< pipeline.parameters.java_tool_options >> << pipeline.parameters.extra_java_tool_options_docker >>" + else + export JAVA_TOOL_OPTIONS="<< pipeline.parameters.java_tool_options >>" + fi + $MAVEN_BIN -V -T2C -P !installer,!concurrency-stress-tests,!micro-benchmarks sonar:sonar -Dsonar.projectKey=evolvedbinary_elemental + + build-elemental-w3c-xqts-runner: + parameters: + os: + type: executor + compute_size: + type: string + default: << pipeline.parameters.compute_size_small >> + maven_cache_name_prefix: + type: string + executor: << parameters.os >> + resource_class: << parameters.compute_size >> + steps: + - checkout + - maven_with_cache: + compute_size: << parameters.compute_size >> + cache_name_prefix: << parameters.maven_cache_name_prefix >> + verify_dependencies: true + steps: + - steps: + - run: + name: "Maven - Build Elemental's XQTS Runner" + command: "$MAVEN_BIN -V -T2C clean package -Dmdep.analyze.skip=true -DskipTests -Ddependency-check.skip=true -Dlicense.skip=true --projects exist-xqts --also-make" + - persist_project: + compute_size: << parameters.compute_size >> + + run-elemental-w3c-xqts-runner: + parameters: + os: + type: executor + compute_size: + type: string + default: << pipeline.parameters.compute_size_small >> + maven_cache_name_prefix: + type: string + executor: << parameters.os >> + resource_class: << parameters.compute_size >> + environment: + JAVA_OPTS: "<< pipeline.parameters.java_tool_options >> << pipeline.parameters.extra_java_tool_options_docker >> -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp -XX:+ExitOnOutOfMemoryError" + steps: + - attach_project: + compute_size: << parameters.compute_size >> + - run: + name: "Run Elemental's W3C XQTS Runner" + command: | + #!/usr/bin/env bash + DIR="$(find exist-xqts/target -type d -name exist-xqts-*)" + $DIR/bin/exist-xqts-runner.sh --xqts-version HEAD --output-dir /tmp/xqts-output --exclude-test-case RangeExpr-411d,RangeExpr-409d,RangeExpr-408d,RangeExpr-409c,RangeExpr-408c,GenCompEq-21 + - run: + name: "Compress (any) Heap Dump files" + command: | + #!/usr/bin/env bash + if [ -f /tmp/*.hprof ]; then + tar cvf /tmp/heap-dumps.tar -C /tmp *.hprof + zstd --rm -9 --progress -T0 /tmp/heap-dumps.tar + fi + when: on_fail + - store_artifacts: + name: "Store (any) Heap Dump files" + path: /tmp/heap-dumps.tar.zst + destination: heap-dumps + - store_artifacts: + name: "Archive XQTS Logs" + path: /tmp/xqts-output + destination: xqts-logs + + +workflows: + license-check: + jobs: + - license-check: + os: linux-docker-jdk21 + maven_cache_name_prefix: linux-docker-jdk21 + + build-and-test: + jobs: + - build: + name: build-<< matrix.os >> + matrix: + parameters: + os: [linux-docker-jdk21, macos-vm-xcode16, windows-vm] + compute_size: [<< pipeline.parameters.compute_size_small >>, << pipeline.parameters.compute_size_mac_medium >>, << pipeline.parameters.compute_size_windows_medium >>] + maven_cache_name_prefix: [ << matrix.os >> ] + exclude: + - os: linux-docker-jdk21 + compute_size: << pipeline.parameters.compute_size_mac_medium >> + maven_cache_name_prefix: << matrix.os >> + - os: linux-docker-jdk21 + compute_size: << pipeline.parameters.compute_size_windows_medium >> + maven_cache_name_prefix: << matrix.os >> + - os: macos-vm-xcode16 + compute_size: << pipeline.parameters.compute_size_small >> + maven_cache_name_prefix: << matrix.os >> + - os: macos-vm-xcode16 + compute_size: << pipeline.parameters.compute_size_windows_medium >> + maven_cache_name_prefix: << matrix.os >> + - os: windows-vm + compute_size: << pipeline.parameters.compute_size_small >> + maven_cache_name_prefix: << matrix.os >> + - os: windows-vm + compute_size: << pipeline.parameters.compute_size_mac_medium >> + maven_cache_name_prefix: << matrix.os >> + + - dependency-analyze: + os: linux-docker-jdk21 + maven_cache_name_prefix: linux-docker-jdk21 + requires: + - build-linux-docker-jdk21 + - owasp-dependency-check: + os: linux-docker-jdk21 + maven_cache_name_prefix: linux-docker-jdk21 + requires: + - build-linux-docker-jdk21 + - javadoc: + os: linux-docker-jdk21 + maven_cache_name_prefix: linux-docker-jdk21 + requires: + - build-linux-docker-jdk21 + - test: + name: test-<< matrix.os >> + matrix: + parameters: + os: [linux-docker-jdk21, macos-vm-xcode16, windows-vm] + compute_size: [<< pipeline.parameters.compute_size_large >>, << pipeline.parameters.compute_size_mac_medium >>, << pipeline.parameters.compute_size_windows_medium >>] + maven_cache_name_prefix: [<< matrix.os >>] + exclude: + - os: linux-docker-jdk21 + compute_size: << pipeline.parameters.compute_size_mac_medium >> + maven_cache_name_prefix: << matrix.os >> + - os: linux-docker-jdk21 + compute_size: << pipeline.parameters.compute_size_windows_medium >> + maven_cache_name_prefix: << matrix.os >> + - os: macos-vm-xcode16 + compute_size: << pipeline.parameters.compute_size_large >> + maven_cache_name_prefix: << matrix.os >> + - os: macos-vm-xcode16 + compute_size: << pipeline.parameters.compute_size_windows_medium >> + maven_cache_name_prefix: << matrix.os >> + - os: windows-vm + compute_size: << pipeline.parameters.compute_size_large >> + maven_cache_name_prefix: << matrix.os >> + - os: windows-vm + compute_size: << pipeline.parameters.compute_size_mac_medium >> + maven_cache_name_prefix: << matrix.os >> + requires: + - build-<< matrix.os >> + - code-coverage: + os: linux-docker-jdk21 + maven_cache_name_prefix: linux-docker-jdk21 + requires: + - test-linux-docker-jdk21 + filters: + branches: + only: + - main + - sonar-analysis: + os: linux-docker-jdk21 + compute_size: << pipeline.parameters.compute_size_large >> + maven_cache_name_prefix: linux-docker-jdk21 + requires: + - test-linux-docker-jdk21 + filters: + branches: + only: + - main + + w3c-xqts: + jobs: + - build-elemental-w3c-xqts-runner: + os: linux-docker-jdk21 + maven_cache_name_prefix: linux-docker-jdk21 + - run-elemental-w3c-xqts-runner: + os: linux-docker-jdk21 + compute_size: << pipeline.parameters.compute_size_large >> + maven_cache_name_prefix: linux-docker-jdk21 + requires: + - build-elemental-w3c-xqts-runner diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index a065fd8db1..0000000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -open_collective: existdb diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index b987330cfc..92752f787c 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -5,21 +5,20 @@ To be able to better understand you problem or suggestion, please add as much in Please fill in the following sections: ### What is the problem -> Describe exactly what you see (e.g. an output of an XQuery) +> Describe exactly what you see (e.g. the output of an XQuery) ### What did you expect -> Describe what you expected to happen. Add for example a reference to a [specification](https://www.w3.org/TR/xquery-3/). +> Describe what you expected to happen. Add for example a reference to a [specification](https://www.w3.org/TR/xquery-31/). ### Describe how to reproduce or add a test -> Describe how we can can reproduce the problem. +> Describe how we can reproduce the problem. -> The *best* way is to provide an [SSCCE (Short, Self Contained, Correct (Compilable), Example)](http://sscce.org/). One type of SSCCE could be a small test which reproduces the issue and can be run without dependencies. 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) (XQuery - Run as Test) +> The *best* way is to provide an [SSCCE (Short, Self Contained, Correct (Compilable), Example)](http://sscce.org/). One type of SSCCE could be a small test which reproduces the issue and can be run without dependencies. The [XQSuite - Annotation-based Test Framework for XQuery](http://exist-db.org/exist/apps/doc/xqsuite.xml) makes it 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`. ### Context information -Please always add the following information -- eXist-db version + Git Revision hash e.g. eXist-db 3.0 / acd0c14 -- Java version (e.g. Java8u121) -- Operating system (Windows 7, Linux, MacOs) -- 32 or 64 bit -- How is eXist-db installed? (JAR installer, DMG, .tar.gz/.zip distribution, clone from GitHub) -- Any custom changes in e.g. conf.xml +Please always add the following information: +- Elemental version + Git Revision hash e.g. Elemental 6.3.1 / 31fc2c1 +- Java version (e.g. Java 8u121) +- Operating system (Windows 11, Linux, macOS) +- How is Elemental installed? (JAR installer, DMG, .tar.gz/.zip distribution, clone from GitHub) +- Any custom config changes in e.g. conf.xml diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 1af912a732..934e3dc888 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,13 +1,13 @@ --- name: Bug report -about: Thank you for reporting your issue and helping us to improve! +about: Thank you for helping us to improve Elemental by reporting a bug. title: "[BUG]" labels: '' assignees: '' --- -> To be able to better understand you problem, please add as much information as possible to this ticket. Always test your bugs against the latest stable release of exist. We cannot provide support for older versions here on GitHub. If the version of eXist that is experiencing the issue is more than 1 major version behind the most recent release, please consider posting a question on our mailing list. +> To be able to better understand you problem, please add as much information as possible to this ticket. Please also test your bugs against the latest stable release of Elemental to check whether it has already been fixed. **Describe the bug** @@ -17,29 +17,30 @@ A clear and concise description of what the bug is. A clear and concise description of what you expected to happen. **To Reproduce** -> The *best* way is to provide an [SSCCE (Short, Self Contained, Correct (Compilable), Example)](http://sscce.org/). One type of SSCCE could be a small test which reproduces the issue and can be run without dependencies. 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) (XQuery - Run as Test) +> The *best* way is to provide an [SSCCE (Short, Self Contained, Correct (Compilable), Example)](http://sscce.org/). One type of SSCCE could be a small test which reproduces the issue and can be run without dependencies. 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) `XQuery` > `Run as Test`. -```Xquery +```xquery xquery version "3.1"; module namespace t="http://exist-db.org/xquery/test"; declare namespace test="http://exist-db.org/xquery/xqsuite"; - +(: Replace root with your data :) declare variable $t:XML := document { - + }; - -declare variable $t:xconf := +(: Replace index config if needed :) +declare variable $t:xconf := document { - - - -; + + + + +}; - +(: Collections and Indexes can be configured here :) declare %test:setUp function t:setup() { @@ -60,33 +61,33 @@ function t:tearDown() { xmldb:remove("/db/system/config/db/test") }; -<-- Adjust to your reported issue --> +(: Adjust to your reported issue :) declare - %test:assertTrue -function t:test() { + %test:assertEquals(1) +function t:test-1() { let $test-data := collection('/db/test') for $result in $test-data//root return - count($result) eq 1 + count($result) }; ``` -If the above isn't working, please tell us the exact steps you took when you encountered the problem: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error +If the above isn't working, please tell us the exact steps you took when you encountered the problem, e.g. +1. Go to ... +2. Click on ... +3. Scroll down to ... +4. Results in the error ... **Screenshots** If applicable, add screenshots to help explain your problem. **Context (please always complete the following information)** -One option is to use [xst](https://www.npmjs.com/package/@existdb/xst), and copy and paste the output produced by running `xst info` here:** - - Build: [eXist-6.1.0] - - Java: [1.8.0_352] - - OS: [Mac OS X 12.6.2] +* Version: [Elemental 6.3.1] +* Java: [1.8.0_352] +* OS: [macOS X 12.6.2] **Additional context** -- How is eXist-db installed? [e.g. JAR installer, DMG, … ] -- Any custom changes in e.g. `conf.xml`? + +* How is Elemental installed? [e.g. JAR installer, DMG, … ] +* Any custom changes in e.g. `conf.xml`? diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 0b55e198c6..f44f6da08b 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,14 +1,14 @@ -Thank you for your contribution to eXist-db! +Thank you for contributing to Elemental! -To help the community judge your pull request (PR), please include the following: +To help the community judge your PR (Pull Request), please include the following: -- A (short) description of the content of changes. -- 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. +- A (short) description of the content of your changes. +- A context reference to a [Github Issue](https://github.com/evolvedbinary/elemental/issues), a message in the [Elemental users mailing list](https://groups.google.com/u/1/a/elemental.xyz/g/users), 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 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 [GitHub Actions](https://github.com/eXist-db/exist/actions) against a number of operating systems and environments. The build status is visible in the PR. +Your PR will be tested using [CircleCI](https://github.com/evolvedbinary/elemental/actions) 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 `mvn -V clean verify`. +To detect errors in your PR before submitting it, please run Elemental's full test suite on your own system via `mvn -V clean site`. ------ @@ -16,4 +16,4 @@ To detect errors in your PR before submitting it, please run eXist's full test s ### Reference: -### Type of tests: +### Tests: diff --git a/.github/actions/install-mvnd/action.yml b/.github/actions/install-mvnd/action.yml deleted file mode 100644 index a0dc3bdf1f..0000000000 --- a/.github/actions/install-mvnd/action.yml +++ /dev/null @@ -1,89 +0,0 @@ -name: 'install-mvnd' -description: 'Install the Maven Daemon' -inputs: - version: - description: 'The version of the Maven Daemon to install' - required: true - default: '0.9.0' - file-version-suffix: - description: 'A suffix to append to the version of the download file of Maven Daemon to install' - required: false - default: '' - install-path: - description: 'The folder in which Maven Daemon will be installed as a sub-folder' - required: true - default: '/tmp' - cache: - description: 'Set to true to cache Maven Daemon artifacts per-platform-architecture' - required: true - default: 'true' - mvnd-connect-timeout: - description: 'The timeout (as a duration, e.g. `90 seconds`) for connecting to the Maven Daemon' - required: true - default: '90 seconds' -outputs: - mvnd-dir: - description: "The directory where the command mvnd is located" - value: ${{ steps.mvnd-location.outputs.mvnd-dir }} -runs: - using: "composite" - steps: - - name: Determine mvnd platform and architecture - shell: bash - run: | - if [ "$RUNNER_OS" == "Linux" ]; then - MVND_PLATFORM="linux" - elif [ "$RUNNER_OS" == "macOS" ]; then - MVND_PLATFORM="darwin" - elif [ "$RUNNER_OS" == "Windows" ]; then - MVND_PLATFORM="windows" - else - "echo Unknown platform: $RUNNER_OS" - exit 1 - fi - MVND_ARCHITECTURE="amd64" - echo "MVND_PLATFORM=${MVND_PLATFORM}" >> $GITHUB_ENV - echo "MVND_ARCHITECTURE=${MVND_ARCHITECTURE}" >> $GITHUB_ENV - echo "MVND_NAME=maven-mvnd-${{ inputs.version }}${{ inputs.file-version-suffix }}-${MVND_PLATFORM}-${MVND_ARCHITECTURE}" >> $GITHUB_ENV - - name: Cache mvnd - if: inputs.cache == 'true' - id: cache-mvnd - uses: actions/cache@v4 - with: - path: | - ${{ inputs.install-path }}/${{ env.MVND_NAME }}.zip - ${{ inputs.install-path }}/${{ env.MVND_NAME }}.zip.sha256 - ${{ inputs.install-path }}/${{ env.MVND_NAME }} - key: setup-${{ env.MVND_NAME }} - - name: Download mvnd - if: steps.cache-mvnd.outputs.cache-hit != 'true' - shell: bash - run: | - curl -fsSL -o ${{ inputs.install-path }}/${{ env.MVND_NAME }}.zip https://archive.apache.org/dist/maven/mvnd/${{ inputs.version }}/${{ env.MVND_NAME }}.zip - curl -fsSL -o ${{ inputs.install-path }}/${{ env.MVND_NAME }}.zip.sha256 https://archive.apache.org/dist/maven/mvnd/${{ inputs.version }}/${{ env.MVND_NAME }}.zip.sha256 - - name: Install sha256sum (macOS) - if: ${{ runner.os == 'macOS' }} - shell: bash - run: brew install coreutils - - name: Verify mvnd sha256 checksum - shell: bash - run: echo "$(cat ${{ inputs.install-path }}/${{ env.MVND_NAME }}.zip.sha256) ${{ inputs.install-path }}/${{ env.MVND_NAME }}.zip" | sha256sum --check - - name: Unzip mvnd - if: steps.cache-mvnd.outputs.cache-hit != 'true' - shell: bash - run: unzip ${{ inputs.install-path }}/${{ env.MVND_NAME }}.zip -d ${{ inputs.install-path }}/ - - name: Show Maven Daemon version - shell: bash - run: | - ${{ inputs.install-path }}/${{ env.MVND_NAME }}/bin/mvnd -D'mvnd.connectTimeout=${{ inputs.mvnd-connect-timeout }}' --version - ${{ inputs.install-path }}/${{ env.MVND_NAME }}/bin/mvnd -D'mvnd.connectTimeout=${{ inputs.mvnd-connect-timeout }}' --status - - name: Set mvnd-dir - id: mvnd-location - shell: bash - run: | - MVND_BIN_DIR="${{ inputs.install-path }}/${{ env.MVND_NAME }}/bin" - if [ "$RUNNER_OS" == "Windows" ]; then - MVND_BIN_DIR="$(cygpath --absolute --long-name --windows $MVND_BIN_DIR)" - fi - echo "MVND_BIN_DIR=${MVND_BIN_DIR}" >> $GITHUB_ENV - echo "mvnd-dir=${MVND_BIN_DIR}" >> $GITHUB_OUTPUT diff --git a/.github/move.yml b/.github/move.yml deleted file mode 100644 index e52b287683..0000000000 --- a/.github/move.yml +++ /dev/null @@ -1,12 +0,0 @@ -# Configuration for move-issues - https://github.com/dessant/move-issues - -# Delete the command comment. Ignored when the comment also contains other content -deleteCommand: true -# Close the source issue after moving -closeSourceIssue: true -# Lock the source issue after moving -lockSourceIssue: false -# Set custom aliases for targets -# aliases: -# r: repo -# or: owner/repo diff --git a/.github/opencollective.yml b/.github/opencollective.yml deleted file mode 100644 index f455e87a92..0000000000 --- a/.github/opencollective.yml +++ /dev/null @@ -1,17 +0,0 @@ -collective: eXist-db -tiers: - - tiers: '*' - labels: ['backer'] - message: 'Hey ' - - tiers: ['Sponsor'] - labels: ['sponsor'] - message: 'Hey sponsor ' -invitation: | - Hey :wave:, - - Thank you for opening an issue. We will get back to you as soon as we can. - - Also, check out our [Open Collective](https://opencollective.com/existdb) and consider backing us - every little helps! - - :gift_heart: We also offer bounties for some issues, please tell us if you want to boost this issue with one! - diff --git a/.github/workflows/ci-deploy.yml b/.github/workflows/ci-deploy.yml deleted file mode 100644 index 94b1ee46c4..0000000000 --- a/.github/workflows/ci-deploy.yml +++ /dev/null @@ -1,71 +0,0 @@ -name: Deploy -on: [push, pull_request] -jobs: - build: - name: Build and Test Images - runs-on: ubuntu-latest - # NOTE (DP): Publish on develop and master, test on PRs against these - if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || github.base_ref == 'develop' || github.base_ref == 'master' - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - distribution: liberica - java-version: '17' - - name: Make buildkit default - uses: docker/setup-buildx-action@v3 - id: buildx - with: - install: true - - name: Cache Maven packages - uses: actions/cache@v4 - with: - path: ~/.m2 - key: deploy-${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: deploy-${{ runner.os }}-maven - - name: Install bats - run: sudo apt-get install bats - - name: Build images - run: mvn -V -B -q -Pdocker -DskipTests -Ddependency-check.skip=true -P !mac-dmg-on-unix,!installer,!concurrency-stress-tests,!micro-benchmarks,skip-build-dist-archives clean package - - name: Check local images - run: docker image ls - - name: Check license headers - run: mvn license:check - working-directory: exist-docker - - name: Start exist-ci container - run: | - docker run -dit -p 8080:8080 --name exist-ci --rm existdb/existdb:latest - sleep 35s - - name: Run tests - run: bats --tap exist-docker/src/test/bats/*.bats - # NOTE (DP): When on master push release, when on develop push latest: Version is included automatically - # TODO (DP): Confirm that releases triggered from maven publish images with the non SNAPSHOT version - - name: Publish latest images - if: github.ref == 'refs/heads/develop' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} - DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} - run: mvn -q -Ddocker.tag=latest -Ddocker.username=$DOCKER_USERNAME -Ddocker.password=$DOCKER_PASSWORD docker:build docker:push - working-directory: ./exist-docker - - name: Publish release images - if: github.ref == 'refs/heads/master' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} - DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} - run: mvn -q -Ddocker.tag=release -Ddocker.username=$DOCKER_USERNAME -Ddocker.password=$DOCKER_PASSWORD docker:build docker:push - working-directory: ./exist-docker - # NOTE (DP): This is for debugging, publishes an experimental image from inside PRs against develop - # - name: Publish experimental images - # if: github.base_ref == 'develop' - # env: - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} - # DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} - # run: mvn -q -Ddocker.tag=experimental -Ddocker.username=$DOCKER_USERNAME -Ddocker.password=$DOCKER_PASSWORD docker:build docker:push - # working-directory: ./exist-docker - diff --git a/.github/workflows/ci-test.yml b/.github/workflows/ci-test.yml deleted file mode 100644 index 66a053a326..0000000000 --- a/.github/workflows/ci-test.yml +++ /dev/null @@ -1,86 +0,0 @@ -name: Test & documentation -on: [push, pull_request] -permissions: - contents: read -env: - MAVEN_OPTS: -DtrimStackTrace=false -D'maven.resolver.transport=wagon' - DEV_JDK: '17' -jobs: - license: - name: License check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 - with: - distribution: liberica - java-version: ${{ env.DEV_JDK }} - cache: 'maven' - - run: mvn -V -B license:check - timeout-minutes: 60 - dependencies: - name: Dependency checks - if: ${{ github.event_name != 'pull_request' && github.ref == 'refs/heads/develop' }} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 - with: - distribution: liberica - java-version: ${{ env.DEV_JDK }} - cache: 'maven' - - name: OWASP dependency check - env: - NVD_API_KEY: ${{ secrets.NVD_API_KEY }} - run: mvn -V -B dependency-check:check - timeout-minutes: 60 - test: - name: ${{ matrix.os }} Test - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macOS-latest] - jvm: ['17', '21'] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v4 - - name: Set up JDK - uses: actions/setup-java@v4 - with: - distribution: liberica - java-version: ${{ matrix.jvm }} - cache: 'maven' - - name: Install Maven Daemon - id: install-mvnd - uses: ./.github/actions/install-mvnd - with: - version: '1.0.2' - file-version-suffix: '' - cache: 'true' - - name: Maven Build - timeout-minutes: 10 - run: ${{ steps.install-mvnd.outputs.mvnd-dir }}/mvnd -V -B -T 1C compile test-compile -DtrimStackTrace=false -D'dependency-check.skip' -D'license.skip' - - name: Maven Test - timeout-minutes: 60 - run: ${{ steps.install-mvnd.outputs.mvnd-dir }}/mvnd -V -B verify -DtrimStackTrace=false -D'dependency-check.skip' -D'license.skip' -D'mvnd.maxLostKeepAlive=6000' - - name: Javadoc (Linux only) - if: ${{ matrix.os == 'ubuntu-latest' }} - run: ${{ steps.install-mvnd.outputs.mvnd-dir }}/mvnd -V -B -q -T 1C install javadoc:javadoc -DskipTests -D'dependency-check.skip' -D'license.skip' --projects '!exist-distribution,!exist-installer' --also-make - - name: Maven Code Coverage (Develop branch on Linux only) - if: ${{ github.event_name != 'pull_request' && github.ref == 'refs/heads/develop' && matrix.os == 'ubuntu-latest' }} - env: - CI_NAME: github - BRANCH_NAME_OR_REF: ${{ github.head_ref || github.ref }} - CI_BUILD_NUMBER: ${{ github.run_id }} - CI_BUILD_URL: https://github.com/${{ github.repository }}/commit/${{ github.event.after }}/checks - COVERALLS_TOKEN: ${{ secrets.COVERALLS_TOKEN }} - run: ${{ steps.install-mvnd.outputs.mvnd-dir }}/mvnd -V -B jacoco:report coveralls:report - - name: Archive build logs - if: always() - uses: actions/upload-artifact@v4 - with: - name: ${{ runner.os }}-${{ matrix.jvm }}-build-logs - retention-days: 5 - path: | - **/hs_err_pid*.log - **/target/surefire-reports/* diff --git a/.github/workflows/ci-xqts.yml b/.github/workflows/ci-xqts.yml deleted file mode 100644 index f326aec091..0000000000 --- a/.github/workflows/ci-xqts.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: XQTS -on: [push, pull_request] -permissions: - contents: read - -jobs: - xqts: - name: W3C XQuery Test Suite - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - distribution: liberica - java-version: '17' - - name: Cache Maven packages - uses: actions/cache@v4 - with: - path: ~/.m2 - key: xqts-${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: xqts-${{ runner.os }}-maven - - name: Maven XQTS Build - run: mvn -V -B clean package -DskipTests -Ddependency-check.skip=true --projects exist-xqts --also-make - - name: Run XQTS - timeout-minutes: 60 - env: - JAVA_OPTS: -XX:+UseZGC -Xmx6g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp -XX:+ExitOnOutOfMemoryError - run: find exist-xqts/target -name exist-xqts-runner.sh -exec {} --xqts-version HEAD --output-dir /tmp/xqts-output --exclude-test-case RangeExpr-411d,RangeExpr-409d,RangeExpr-408d,RangeExpr-409c,RangeExpr-408c,GenCompEq-21 \; - - name: Check for HeapDump - id: check_heapdump - uses: andstor/file-existence-action@v3 - with: - files: "/tmp/*.hprof" - - name: Compress HeapDump - if: steps.check_heapdump.outputs.files_exists == 'true' - run: zstd --rm -9 --progress -T0 /tmp/*.hprof - - name: Attach HeapDump artifact - if: steps.check_heapdump.outputs.files_exists == 'true' - uses: actions/upload-artifact@v4 - with: - name: exist-xqts-runner-hprof - retention-days: 1 - path: /tmp/*.hprof.zst - - name: Archive XQTS Logs - if: always() - uses: actions/upload-artifact@v4 - with: - name: xqts-logs - retention-days: 14 - path: /tmp/xqts-output - - name: Get Previous XQTS Logs Artifacts JSON - run: 'curl -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/repos/exist-db/exist/actions/artifacts?name=xqts-logs > /tmp/previous-xqts-logs-artifacts.json' - - name: Extract Previous XQTS Logs Artifact JSON - run: cat /tmp/previous-xqts-logs-artifacts.json | jq -r "[.artifacts[] | select(.workflow_run.head_branch == \"develop\")][1].archive_download_url" > /tmp/previous-xqts-logs-artifact.json - - name: Get Previous XQTS Logs Artifact - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: 'cat /tmp/previous-xqts-logs-artifact.json | xargs curl -H "Authorization: Bearer ${GITHUB_TOKEN}" --location --output /tmp/previous-xqts-output.zip' - - name: Extract Previous XQTS Logs Artifact - run: mkdir /tmp/previous-xqts-output && unzip /tmp/previous-xqts-output.zip -d /tmp/previous-xqts-output - - name: Compare Previous and Current XQTS Logs - run: java -jar ~/.m2/repository/net/sf/saxon/Saxon-HE/9.9.1-8/Saxon-HE-9.9.1-8.jar -xsl:exist-xqts/src/main/xslt/compare-results.xslt -it:compare-results -o:/tmp/comparison-results.xml xqts.previous.junit-data-path=/tmp/previous-xqts-output/junit/data xqts.current.junit-data-path=/tmp/xqts-output/junit/data - - name: Show Comparison Results - run: cat /tmp/comparison-results.xml diff --git a/.idea/runConfigurations/Java_Admin_Client.xml b/.idea/runConfigurations/Java_Admin_Client.xml index dd116638bf..229b57992a 100644 --- a/.idea/runConfigurations/Java_Admin_Client.xml +++ b/.idea/runConfigurations/Java_Admin_Client.xml @@ -1,11 +1,11 @@ - diff --git a/exist-core/project-suppression.xml b/exist-core/project-suppression.xml index 624a75b6e7..69582fff6b 100644 --- a/exist-core/project-suppression.xml +++ b/exist-core/project-suppression.xml @@ -1,15 +1,14 @@ - - - ^org\.apache\.xmlrpc:xmlrpc-common:.*$ - CVE-2016-5002 - \ No newline at end of file diff --git a/exist-core/src/main/antlr/org/exist/xquery/parser/XQuery.g b/exist-core/src/main/antlr/org/exist/xquery/parser/XQuery.g index bc59b416c8..d9c7a228fb 100644 --- a/exist-core/src/main/antlr/org/exist/xquery/parser/XQuery.g +++ b/exist-core/src/main/antlr/org/exist/xquery/parser/XQuery.g @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -150,6 +174,8 @@ imaginaryTokenDefinitions NAMESPACE_DECL DEF_NAMESPACE_DECL DEF_COLLATION_DECL + DECIMAL_FORMAT_DECL + DEFAULT_DECIMAL_FORMAT DEF_FUNCTION_NS_DECL CONTEXT_ITEM_DECL ANNOT_DECL @@ -256,7 +282,7 @@ prolog throws XPathException ( importDecl | - ( "declare" ( "default" | "boundary-space" | "ordering" | "construction" | "base-uri" | "copy-namespaces" | "namespace" ) ) => + ( "declare" ( "default" | "boundary-space" | "ordering" | "construction" | "base-uri" | "copy-namespaces" | "namespace" | "decimal-format" ) ) => s:setter { if(!inSetters) @@ -295,10 +321,44 @@ versionDecl throws XPathException { #versionDecl = #(#[VERSION_DECL, v.getText()], enc); } ; +dfPropertyName +: + "decimal-separator" + | "grouping-separator" + | "infinity" + | "minus-sign" + | "NaN" + | "percent" + | "per-mille" + | "zero-digit" + | "digit" + | "pattern-separator" + | "exponent-separator" + ; + +decimalFormatDecl +{ String dfName = null; } +: + "declare"! + ( + "default" "decimal-format" + ( dfPropertyName EQ! STRING_LITERAL )* + { + ## = #( #[DECIMAL_FORMAT_DECL, "DECIMAL_FORMAT_DECL"], #[DEFAULT_DECIMAL_FORMAT, "DEFAULT_DECIMAL_FORMAT"], ## ); + } + | + "decimal-format" eqName + ( dfPropertyName EQ! STRING_LITERAL )* + { + ## = #( #[DECIMAL_FORMAT_DECL, "DECIMAL_FORMAT_DECL"], ## ); + } + ) +; + setter : ( - ( "declare" "default" ) => + ( "declare" "default" ( "collation" | "element" | "function" | "order" ) ) => "declare"! "default"! ( "collation"! defc:STRING_LITERAL @@ -330,6 +390,8 @@ setter | ( "declare" "namespace" ) => namespaceDecl + | ( "declare" ( "default" )? "decimal-format" ) => + decimalFormatDecl ) ; diff --git a/exist-core/src/main/antlr/org/exist/xquery/parser/XQueryTree.g b/exist-core/src/main/antlr/org/exist/xquery/parser/XQueryTree.g index 048ee8e7e8..44119f869d 100644 --- a/exist-core/src/main/antlr/org/exist/xquery/parser/XQueryTree.g +++ b/exist-core/src/main/antlr/org/exist/xquery/parser/XQueryTree.g @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -56,8 +80,6 @@ header { import org.exist.storage.ElementValue; import org.exist.xquery.functions.map.MapExpr; import org.exist.xquery.functions.array.ArrayConstructor; - - import static org.apache.commons.lang3.ArrayUtils.isNotEmpty; } /** @@ -84,6 +106,7 @@ options { protected Set importedModules = new HashSet<>(); protected Set importedModuleFunctions = null; protected Set importedModuleVariables = null; + private boolean hasDefaultDecimalFormat = false; public XQueryTreeParser(XQueryContext context) { this(context, null); @@ -489,6 +512,76 @@ throws PermissionDeniedException, EXistException, XPathException } ) | + #( + DECIMAL_FORMAT_DECL + { + final XQueryAST root = (XQueryAST) _t; // points to DECIMAL_FORMAT_DECL + // first sibling is either DEFAULT_DECIMAL_FORMAT (default) or EQNAME (named) + final XQueryAST dfName = (XQueryAST) root.getNextSibling(); + + final QName qnDfName; + if ("default".equals(dfName.getText())) { + qnDfName = XQueryContext.UNNAMED_DECIMAL_FORMAT; + if (hasDefaultDecimalFormat) { + throw new XPathException(dfName.getLine(), dfName.getColumn(), ErrorCodes.W3CErrorCode.XQST0111.getErrorCode(), "Query prolog cannot contain two default decimal format declarations."); + } else { + hasDefaultDecimalFormat = true; + } + } else { + try { + qnDfName = QName.parse(staticContext, dfName.getText(), null); + } catch (final IllegalQNameException iqe) { + throw new XPathException(dfName.getLine(), dfName.getColumn(), ErrorCodes.XPST0081, "No namespace defined for prefix " + dfName.getText()); + } + + if (staticContext.getStaticDecimalFormat(qnDfName) != null) { + throw new XPathException(dfName.getLine(), dfName.getColumn(), ErrorCodes.W3CErrorCode.XQST0111.getErrorCode(), "Query prolog cannot contain two decimal format declarations with the same name: " + dfName.getText()); + } + } + + // position current at the first property name for the decimal format + XQueryAST current = (XQueryAST) dfName.getNextSibling(); + if ("default".equals(dfName.getText())) { + current = (XQueryAST) current.getNextSibling(); + } + + final Map dfProperties = new HashMap<>(); + + while (current != null) { + final XQueryAST pname = current; + final XQueryAST pval = (XQueryAST) current.getNextSibling(); + + if (pval == null) { + break; + } + + final String pn = pname.getText(); + String pv = pval.getText(); + if (pv.length() >= 2 && (pv.startsWith("\"") || pv.startsWith("'"))) { + pv = pv.substring(1, pv.length() - 1); + } + if (dfProperties.put(pn, pv) != null) { + throw new XPathException(dfName.getLine(), dfName.getColumn(), ErrorCodes.W3CErrorCode.XQST0114.getErrorCode(), "Decimal format: " + dfName.getText() + " defines the property: " + pn + " more than once."); + } + + current = (XQueryAST) pval.getNextSibling(); + } + + final DecimalFormat df; + try { + df = DecimalFormat.fromProperties(dfProperties); + } catch (final IllegalArgumentException ex) { + throw new XPathException(dfName.getLine(), dfName.getColumn(), ErrorCodes.W3CErrorCode.XQST0097.getErrorCode(), ex.getMessage() + " within the picture string of the decimal format: " + dfName.getText() + "."); + } + if (!df.checkDistinctCharacters()) { + throw new XPathException(dfName.getLine(), dfName.getColumn(), ErrorCodes.W3CErrorCode.XQST0098.getErrorCode(), "Characters within the picture string of the decimal format: " + dfName.getText() + " are not distinct."); + } + + staticContext.setStaticDecimalFormat(qnDfName, df); + context.setStaticDecimalFormat(qnDfName, df); + } + ) + | #( qname:GLOBAL_VAR { @@ -510,9 +603,8 @@ throws PermissionDeniedException, EXistException, XPathException } declaredGlobalVars.add(qn); } - { List annots = new ArrayList(); } - (annotations [annots] - )? + { List annots = new ArrayList(); } + (annotations [annots])? ( #( "as" @@ -542,22 +634,11 @@ throws PermissionDeniedException, EXistException, XPathException step=ext:expr [defaultValue] )? { - // variable may be declared in static context: retrieve and set its sequence type - Variable external = null; - try { - external = context.resolveVariable(qname.getText()); - if (external != null) { - external.setSequenceType(type); - } - } catch (XPathException ignoredException) { - } - final VariableDeclaration decl = new VariableDeclaration(context, qn, defaultValue); decl.setSequenceType(type); + decl.setExternal(true); decl.setASTNode(ext); - if (external == null) { - path.add(decl); - } + path.add(decl); if(myModule != null) { myModule.declareVariable(qn, decl); } @@ -675,12 +756,12 @@ throws PermissionDeniedException, EXistException, XPathException throw xpe; } - if (isNotEmpty(modules)) { + if (modules != null) { for (final org.exist.xquery.Module module : modules) { // check modules does not import any duplicate function definitions final FunctionSignature[] signatures = module.listFunctions(); - if (isNotEmpty(signatures)) { + if (signatures != null) { for (final FunctionSignature signature : signatures) { final String qualifiedNameArity = signature.getName().toURIQualifiedName() + '#' + signature.getArgumentCount(); if (importedModuleFunctions != null) { @@ -752,7 +833,7 @@ throws PermissionDeniedException, EXistException, XPathException throw xpe; } // We ought to do this for now until Dannes can say it works. /ljo - //throw new XPathException(s, ErrorCodes.XQST0009, "The eXist-db XQuery implementation does not support the Schema Import Feature quite yet."); + //throw new XPathException(s, ErrorCodes.XQST0009, "The XQuery implementation does not support the Schema Import Feature quite yet."); } ) ; @@ -2984,19 +3065,38 @@ throws PermissionDeniedException, EXistException, XPathException rs.setAxis(Constants.DESCENDANT_AXIS); } else if (rs.getAxis() == Constants.SELF_AXIS) { rs.setAxis(Constants.DESCENDANT_SELF_AXIS); - } else { + } else if (rs.getAxis() == Constants.CHILD_AXIS || rs.getAxis() == Constants.UNKNOWN_AXIS) { + // For CHILD_AXIS or UNKNOWN_AXIS, change to descendant-or-self rs.setAxis(Constants.DESCENDANT_SELF_AXIS); rs.setAbbreviated(true); + } else { + // For other explicit axes (following, preceding, ancestor, etc.) + // insert a separate descendant-or-self::node() step before this step + final LocationStep dsStep = new LocationStep(context, Constants.DESCENDANT_SELF_AXIS, new AnyNodeTest()); + path.insertBeforeLast(dsStep); } } else { - rightStep.setPrimaryAxis(Constants.DESCENDANT_SELF_AXIS); - if(rightStep instanceof VariableReference) { - rightStep = new SimpleStep(context, Constants.DESCENDANT_SELF_AXIS, rightStep); - path.replaceLastExpression(rightStep); - } else if (rightStep instanceof FilteredExpression) - ((FilteredExpression)rightStep).setAbbreviated(true); + if (rightStep instanceof Function) { + // For non-LocationStep expressions (function calls, etc.) + // insert a separate descendant-or-self::node() step before this step + final LocationStep dsStep = new LocationStep(context, Constants.DESCENDANT_SELF_AXIS, new AnyNodeTest()); + path.insertBeforeLast(dsStep); + } else { + if (rightStep.getPrimaryAxis() == Constants.ATTRIBUTE_AXIS) { + rightStep.setPrimaryAxis(Constants.DESCENDANT_ATTRIBUTE_AXIS); + } else { + rightStep.setPrimaryAxis(Constants.DESCENDANT_SELF_AXIS); + } + if(rightStep instanceof VariableReference) { + // VariableReference needs special handling + rightStep = new SimpleStep(context, Constants.DESCENDANT_SELF_AXIS, rightStep); + path.replaceLastExpression(rightStep); + } else if (rightStep instanceof FilteredExpression) { + ((FilteredExpression)rightStep).setAbbreviated(true); + } + } } } )? diff --git a/exist-core/src/main/java/org/exist/Indexer.java b/exist-core/src/main/java/org/exist/Indexer.java index ea69cbcb2f..a7b7a1c7d0 100644 --- a/exist-core/src/main/java/org/exist/Indexer.java +++ b/exist-core/src/main/java/org/exist/Indexer.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -600,7 +624,7 @@ public void startElement(final String namespace, final String name, final String setPrevious(null); node.setOwnerDocument(document); node.setAttributes((short) attrLength); - if (nsMappings != null && nsMappings.size() > 0) { + if (!nsMappings.isEmpty()) { node.setNamespaceMappings(nsMappings); nsMappings.clear(); } @@ -624,7 +648,7 @@ public void startElement(final String namespace, final String name, final String node.setOwnerDocument(document); node.setNodeId(broker.getBrokerPool().getNodeFactory().createInstance(nodeFactoryInstanceCnt++)); node.setAttributes((short) attrLength); - if (nsMappings != null && nsMappings.size() > 0) { + if (!nsMappings.isEmpty()) { node.setNamespaceMappings(nsMappings); nsMappings.clear(); } diff --git a/exist-core/src/main/java/org/exist/Namespaces.java b/exist-core/src/main/java/org/exist/Namespaces.java index 593ab89085..187f8d38cd 100644 --- a/exist-core/src/main/java/org/exist/Namespaces.java +++ b/exist-core/src/main/java/org/exist/Namespaces.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -41,7 +65,8 @@ public interface Namespaces { String SCHEMA_INSTANCE_NS = XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI; // Move this here from Function.BUILTIN_FUNCTION_NS? /ljo - String XPATH_FUNCTIONS_NS = "http://www.w3.org/2005/xpath-functions"; + String XPATH_FUNCTIONS_NS = "http://www.w3.org/2005/xpath-functions"; + String XPATH_FUNCTIONS_PREFIX = "fn"; String XQUERY_LOCAL_NS = "http://www.w3.org/2005/xquery-local-functions"; String XPATH_DATATYPES_NS = "http://www.w3.org/2003/05/xpath-datatypes"; diff --git a/exist-core/src/main/java/org/exist/backup/Backup.java b/exist-core/src/main/java/org/exist/backup/Backup.java index e000fa6d93..4ab112b1d3 100644 --- a/exist-core/src/main/java/org/exist/backup/Backup.java +++ b/exist-core/src/main/java/org/exist/backup/Backup.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -421,7 +445,7 @@ private void backup(final Set seenBlobIds, final Collection current, fin } attr.addAttribute(Namespaces.EXIST_NS, "filename", "filename", "CDATA", filename); - attr.addAttribute(Namespaces.EXIST_NS, "mimetype", "mimetype", "CDATA", encode(((EXistResource) resource).getMimeType())); + attr.addAttribute(Namespaces.EXIST_NS, "mimetype", "mimetype", "CDATA", encode(((EXistResource) resource).getMediaType())); if (XML_RESOURCE.equals(resourceType)) { diff --git a/exist-core/src/main/java/org/exist/backup/CreateBackupDialog.java b/exist-core/src/main/java/org/exist/backup/CreateBackupDialog.java index 189d06b3b9..5d2b92bef4 100644 --- a/exist-core/src/main/java/org/exist/backup/CreateBackupDialog.java +++ b/exist-core/src/main/java/org/exist/backup/CreateBackupDialog.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -22,12 +46,14 @@ package org.exist.backup; import org.exist.client.Messages; -import org.exist.client.MimeTypeFileFilter; +import org.exist.client.MediaTypeFileFilter; import org.exist.security.PermissionDeniedException; import org.exist.xmldb.XmldbURI; import org.xmldb.api.DatabaseManager; import org.xmldb.api.base.Collection; import org.xmldb.api.base.XMLDBException; +import xyz.elemental.mediatype.MediaType; +import xyz.elemental.mediatype.MediaTypeResolver; import javax.swing.*; import java.awt.*; @@ -49,12 +75,13 @@ public class CreateBackupDialog extends JPanel { final String passwd; Path backupDir; final String defaultSelectedCollection; + private final MediaTypeResolver mediaTypeResolver; - public CreateBackupDialog(final String uri, final String user, final String passwd, final Path backupDir) throws HeadlessException { - this(uri, user, passwd, backupDir, null); + public CreateBackupDialog(final String uri, final String user, final String passwd, final Path backupDir, final MediaTypeResolver mediaTypeResolver) throws HeadlessException { + this(uri, user, passwd, backupDir, null, mediaTypeResolver); } - public CreateBackupDialog(final String uri, final String user, final String passwd, final Path backupDir, final String defaultSelectedCollection) throws HeadlessException { + public CreateBackupDialog(final String uri, final String user, final String passwd, final Path backupDir, final String defaultSelectedCollection, final MediaTypeResolver mediaTypeResolver) throws HeadlessException { super(false); this.uri = uri; @@ -62,6 +89,7 @@ public CreateBackupDialog(final String uri, final String user, final String pass this.passwd = passwd; this.backupDir = backupDir; this.defaultSelectedCollection = defaultSelectedCollection; + this.mediaTypeResolver = mediaTypeResolver; setupComponents(); setSize(new Dimension(350, 200)); @@ -147,7 +175,8 @@ private void actionSelect() { final JFileChooser chooser = new JFileChooser(); chooser.setMultiSelectionEnabled(false); chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); - chooser.addChoosableFileFilter(new MimeTypeFileFilter("application/zip")); + final MediaType mediaType = mediaTypeResolver.fromString(MediaType.APPLICATION_ZIP); + chooser.addChoosableFileFilter(new MediaTypeFileFilter(mediaType)); chooser.setSelectedFile(Paths.get("eXist-backup.zip").toFile()); chooser.setCurrentDirectory(backupDir.toFile()); diff --git a/exist-core/src/main/java/org/exist/backup/ExportGUI.java b/exist-core/src/main/java/org/exist/backup/ExportGUI.java index 2ed389b54f..d50d380164 100644 --- a/exist-core/src/main/java/org/exist/backup/ExportGUI.java +++ b/exist-core/src/main/java/org/exist/backup/ExportGUI.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -29,14 +53,14 @@ import org.exist.storage.DBBroker; import org.exist.storage.txn.Txn; import org.exist.util.Configuration; -import org.exist.util.MimeTable; -import org.exist.util.MimeType; import org.exist.util.OSUtil; import org.exist.util.SystemExitCodes; import org.exist.xquery.TerminatedException; import se.softhouse.jargo.Argument; import se.softhouse.jargo.ArgumentException; import se.softhouse.jargo.CommandLineParser; +import xyz.elemental.mediatype.MediaType; +import xyz.elemental.mediatype.StorageType; import javax.swing.*; import javax.swing.filechooser.FileFilter; @@ -413,19 +437,20 @@ private void btnConfSelectActionPerformed(final java.awt.event.ActionEvent evt) .toFile()); chooser.setCurrentDirectory(dir.resolve("etc").toFile()); chooser.setFileFilter(new FileFilter() { + @Override public boolean accept(final File f) { if (f.isDirectory()) { return (true); } - final MimeType mime = MimeTable.getInstance().getContentTypeFor(f.getName()); + final MediaType mediaType = pool.getMediaTypeService().getMediaTypeResolver().fromFileName(f.toPath()); - if (mime == null) { + if (mediaType == null) { return false; } - return mime.isXMLType(); + return mediaType.getStorageType() == StorageType.XML; } - + @Override public String getDescription() { return ("Database XML configuration file"); } @@ -625,7 +650,7 @@ public static void main(final String[] args) { // parse command-line options CommandLineParser .withArguments(helpArg) - .programName("export-gui" + (OSUtil.isWindows() ? ".bat" : ".sh")) + .programName("export-gui" + (OSUtil.IS_WINDOWS ? ".bat" : ".sh")) .parse(args); } catch (final StartException e) { diff --git a/exist-core/src/main/java/org/exist/backup/ExportMain.java b/exist-core/src/main/java/org/exist/backup/ExportMain.java index 117eaa9163..f4bcef145a 100644 --- a/exist-core/src/main/java/org/exist/backup/ExportMain.java +++ b/exist-core/src/main/java/org/exist/backup/ExportMain.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -131,7 +155,7 @@ public static void main(final String[] args) { .withArguments(noCheckArg, checkDocsArg, directAccessArg, exportArg, noExportArg, incrementalArg, zipArg, noZipArg) .andArguments(configArg, outputDirArg) .andArguments(helpArg, verboseArg) - .programName("export" + (OSUtil.isWindows() ? ".bat" : ".sh")) + .programName("export" + (OSUtil.IS_WINDOWS ? ".bat" : ".sh")) .parse(args); process(arguments); diff --git a/exist-core/src/main/java/org/exist/backup/Main.java b/exist-core/src/main/java/org/exist/backup/Main.java index c5098db9bb..f63f98b6f2 100644 --- a/exist-core/src/main/java/org/exist/backup/Main.java +++ b/exist-core/src/main/java/org/exist/backup/Main.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -22,6 +46,7 @@ package org.exist.backup; import org.exist.client.ClientFrame; +import org.exist.mediatype.MediaTypeUtil; import org.exist.start.CompatibleJavaVersionCheck; import org.exist.start.StartException; import org.exist.util.ConfigurationHelper; @@ -34,7 +59,9 @@ import org.xmldb.api.base.Database; import org.xmldb.api.base.XMLDBException; import se.softhouse.jargo.*; +import xyz.elemental.mediatype.MediaTypeResolver; +import javax.annotation.Nullable; import javax.swing.*; import java.io.File; import java.io.IOException; @@ -199,12 +226,17 @@ public static void process(final ParsedArguments arguments) { return; } + // load MediaTypeResolver + final Optional existHome = ConfigurationHelper.getExistHome(); + @Nullable final Path applicationConfigDir = existHome.map(p -> p.resolve("etc")).filter(Files::exists).orElse(null); + @Nullable final MediaTypeResolver mediaTypeResolver = MediaTypeUtil.newMediaTypeResolver(applicationConfigDir); + // process if (backupCollection.isPresent()) { String collection = backupCollection.get(); if (collection.isEmpty()) { if (guiMode) { - final CreateBackupDialog dialog = new CreateBackupDialog(properties.getProperty(URI_PROP, DEFAULT_URI), properties.getProperty(USER_PROP, DEFAULT_USER), properties.getProperty(PASSWORD_PROP, DEFAULT_PASSWORD), Paths.get(preferences.get("directory.backup", System.getProperty("user.dir")))); + final CreateBackupDialog dialog = new CreateBackupDialog(properties.getProperty(URI_PROP, DEFAULT_URI), properties.getProperty(USER_PROP, DEFAULT_USER), properties.getProperty(PASSWORD_PROP, DEFAULT_PASSWORD), Paths.get(preferences.get("directory.backup", System.getProperty("user.dir"))), mediaTypeResolver); if (JOptionPane.showOptionDialog(null, dialog, "Create Backup", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null) == JOptionPane.YES_OPTION) { collection = dialog.getCollection(); @@ -462,7 +494,7 @@ public static void main(final String[] args) { .andArguments(backupCollectionArg, backupOutputDirArg, backupDeduplicateBlobs) .andArguments(restoreArg, rebuildExpathRepoArg, overwriteAppsArg) .andArguments(helpArg, guiArg, quietArg, optionArg) - .programName("backup" + (OSUtil.isWindows() ? ".bat" : ".sh")) + .programName("backup" + (OSUtil.IS_WINDOWS ? ".bat" : ".sh")) .parse(args); process(arguments); diff --git a/exist-core/src/main/java/org/exist/backup/Restore.java b/exist-core/src/main/java/org/exist/backup/Restore.java index 7b38622b11..b66debebf9 100644 --- a/exist-core/src/main/java/org/exist/backup/Restore.java +++ b/exist-core/src/main/java/org/exist/backup/Restore.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -36,6 +60,7 @@ import org.exist.util.XMLReaderPool; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; +import xyz.elemental.mediatype.MediaTypeResolver; import javax.annotation.Nullable; import java.io.IOException; @@ -57,7 +82,7 @@ public class Restore { private static final byte[] ZIP_FILE_MAGIC_NUMBER = {0x50, 0x4B, 0x03, 0x04}; public void restore(final DBBroker broker, @Nullable final Txn transaction, final String newAdminPass, final Path f, - final RestoreListener listener, final boolean overwriteApps) throws EXistException, IOException, SAXException, PermissionDeniedException { + final RestoreListener listener, final boolean overwriteApps, final MediaTypeResolver mediaTypeResolver) throws EXistException, IOException, SAXException, PermissionDeniedException { //set the admin password if (newAdminPass != null) { diff --git a/exist-core/src/main/java/org/exist/backup/SystemExport.java b/exist-core/src/main/java/org/exist/backup/SystemExport.java index 0a8b585746..d9eae3b9cb 100644 --- a/exist-core/src/main/java/org/exist/backup/SystemExport.java +++ b/exist-core/src/main/java/org/exist/backup/SystemExport.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -69,6 +93,7 @@ import org.xml.sax.helpers.AttributesImpl; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.NamespaceSupport; +import xyz.elemental.mediatype.MediaType; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; @@ -541,10 +566,10 @@ private void exportDocument(final BackupWriter output, final Date date, final Ba } attr.addAttribute(Namespaces.EXIST_NS, "filename", "filename", "CDATA", Backup.encode(URIUtils.urlDecodeUtf8(doc.getFileURI()))); - String mimeType = "application/xml"; + String mimeType = MediaType.APPLICATION_XML; - if (doc.getMimeType() != null) { - mimeType = Backup.encode(doc.getMimeType()); + if (doc.getMediaType() != null) { + mimeType = Backup.encode(doc.getMediaType()); } attr.addAttribute(Namespaces.EXIST_NS, "mimetype", "mimetype", "CDATA", mimeType); @@ -614,8 +639,9 @@ private void writeXML(final DocumentImpl doc, final Receiver receiver) { receiver.startPrefixMapping(reader.getNamespacePrefix(ni), reader.getNamespaceURI(ni)); } - final AttrList attribs = new AttrList(); - for (int j = 0; j < reader.getAttributeCount(); j++) { + final int attrCount = reader.getAttributeCount(); + final AttrList attribs = new AttrList(attrCount); + for (int j = 0; j < attrCount; j++) { final QName qn = new QName(reader.getAttributeLocalName(j), reader.getAttributeNamespace(j), reader.getAttributePrefix(j)); attribs.addAttribute(qn, reader.getAttributeValue(j)); } diff --git a/exist-core/src/main/java/org/exist/backup/ZipWriter.java b/exist-core/src/main/java/org/exist/backup/ZipWriter.java index 6e214f3703..dee39fa485 100644 --- a/exist-core/src/main/java/org/exist/backup/ZipWriter.java +++ b/exist-core/src/main/java/org/exist/backup/ZipWriter.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -21,6 +45,8 @@ */ package org.exist.backup; +import org.apache.commons.io.output.StringBuilderWriter; + import java.io.*; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -38,7 +64,7 @@ public class ZipWriter implements BackupWriter { private String currentPath; private final ZipOutputStream out; - private StringWriter contents; + private StringBuilderWriter contents; private boolean dataWritten = false; public ZipWriter(final String zipFile, final String collection) throws IOException @@ -53,9 +79,9 @@ public ZipWriter(final Path zipFile, final String collection) throws IOException currentPath = collection; } - public Writer newContents() throws IOException + public Writer newContents() { - contents = new StringWriter(); + contents = new StringBuilderWriter(); return( contents ); } diff --git a/exist-core/src/main/java/org/exist/backup/restore/AbstractRestoreHandler.java b/exist-core/src/main/java/org/exist/backup/restore/AbstractRestoreHandler.java index 218efd7237..34fe394668 100644 --- a/exist-core/src/main/java/org/exist/backup/restore/AbstractRestoreHandler.java +++ b/exist-core/src/main/java/org/exist/backup/restore/AbstractRestoreHandler.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -55,6 +79,10 @@ import org.xml.sax.SAXParseException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; +import xyz.elemental.mediatype.MediaType; +import xyz.elemental.mediatype.MediaTypeResolver; +import xyz.elemental.mediatype.StorageType; +import xyz.elemental.mediatype.impl.MediaTypeImpl; import javax.annotation.Nullable; import java.io.IOException; @@ -63,6 +91,7 @@ import static com.evolvedbinary.j8fu.tuple.Tuple.Tuple; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.exist.util.StringUtil.isNullOrEmpty; /** * SAX Content Handler that can act upon @@ -89,7 +118,6 @@ public abstract class AbstractRestoreHandler extends DefaultHandler { @Nullable private final Txn transaction; private final BackupDescriptor descriptor; private final RestoreListener listener; - @Nullable private final Set pathsToIgnore; //handler state @@ -312,7 +340,7 @@ private DeferredPermission restoreResourceEntry(final Attributes attributes) thr final boolean xmlType = Optional.ofNullable(attributes.getValue("type")).filter(s -> s.equals("XMLResource")).isPresent(); final String filename = getAttr(attributes, "filename", commonAttributes.name); - @Nullable final String mimeTypeStr = attributes.getValue("mimetype"); + @Nullable final String mediaTypeStr = attributes.getValue("mimetype"); @Nullable final String dateModifiedStr = attributes.getValue("modified"); @Nullable final String publicId = attributes.getValue("publicid"); @Nullable final String systemId = attributes.getValue("systemid"); @@ -343,12 +371,19 @@ private DeferredPermission restoreResourceEntry(final Attributes attributes) thr } } - final MimeType mimeType; - if (mimeTypeStr == null || mimeTypeStr.trim().isEmpty()) { - mimeType = xmlType ? MimeType.XML_TYPE : MimeType.BINARY_TYPE; - listener.warn("Missing mimetype attribute in the backup __contents__.xml file for: " + commonAttributes.name + ", assuming: " + mimeType); + final MediaTypeResolver mediaTypeResolver = broker.getBrokerPool().getMediaTypeService().getMediaTypeResolver(); + + MediaType mediaType; + if (isNullOrEmpty(mediaTypeStr)) { + mediaType = xmlType ? mediaTypeResolver.fromString(MediaType.APPLICATION_XML) : mediaTypeResolver.forUnknown(); + listener.warn("Missing mimetype attribute in the backup __contents__.xml file for: " + commonAttributes.name + ", assuming: " + mediaType); } else { - mimeType = new MimeType(mimeTypeStr.trim(), xmlType ? MimeType.XML : MimeType.BINARY); + mediaType = mediaTypeResolver.fromString(mediaTypeStr.trim()); + if (xmlType && mediaType.getStorageType() != StorageType.XML) { + mediaType = MediaTypeImpl.builder(mediaTypeStr.trim(), StorageType.XML).build(); + } else if ((!xmlType) && mediaType.getStorageType() != StorageType.BINARY) { + mediaType = MediaTypeImpl.builder(mediaTypeStr.trim(), StorageType.BINARY).build(); + } } Date dateCreated = null; @@ -385,7 +420,7 @@ private DeferredPermission restoreResourceEntry(final Attributes attributes) thr try (final Collection collection = broker.openCollection(currentCollectionUri, Lock.LockMode.WRITE_LOCK); final ManagedDocumentLock docLock = broker.getBrokerPool().getLockManager().acquireDocumentWriteLock(docUri)) { - broker.storeDocument(transaction, docName, is, mimeType, dateCreated, dateModified, null, docType, null, collection); + broker.storeDocument(transaction, docName, is, mediaType, dateCreated, dateModified, null, docType, null, collection); validated = true; notifyStartDocumentRestore(docUri, attributes); @@ -572,6 +607,7 @@ private static String getAttr(final Attributes atts, final String name, final St * @param descriptor the backup descriptor to start restoring from * @param listener the listener to report restore events to * @param pathsToIgnore database paths to ignore in the backup + * * @return a new restore handler */ protected abstract AbstractRestoreHandler newSelf(final DBBroker broker, @Nullable final Txn transaction, diff --git a/exist-core/src/main/java/org/exist/backup/restore/AppRestoreUtils.java b/exist-core/src/main/java/org/exist/backup/restore/AppRestoreUtils.java index 261bbad142..c19e67d71a 100644 --- a/exist-core/src/main/java/org/exist/backup/restore/AppRestoreUtils.java +++ b/exist-core/src/main/java/org/exist/backup/restore/AppRestoreUtils.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -21,7 +45,6 @@ */ package org.exist.backup.restore; -import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.exist.Namespaces; @@ -44,6 +67,8 @@ import java.io.IOException; import java.util.*; +import static org.exist.util.StringUtil.isNullOrEmpty; + /** * Utility to compare the applications contained in a backup with the already * installed applications in the package repo. @@ -141,7 +166,7 @@ public void startElement(String uri, String localName, String qName, Attributes if (PKG_NAMESPACE.equals(uri) && "package".equals(localName)) { final String version = attributes.getValue("version"); final String name = attributes.getValue("name"); - if (StringUtils.isEmpty(version) || StringUtils.isEmpty(name)) { + if (isNullOrEmpty(version) || isNullOrEmpty(name)) { LOG.warn("Invalid package descriptor for {}", app.getSymbolicPath()); return; } diff --git a/exist-core/src/main/java/org/exist/backup/xquery/RetrieveBackup.java b/exist-core/src/main/java/org/exist/backup/xquery/RetrieveBackup.java index 64a54d8746..c481831bb5 100644 --- a/exist-core/src/main/java/org/exist/backup/xquery/RetrieveBackup.java +++ b/exist-core/src/main/java/org/exist/backup/xquery/RetrieveBackup.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -31,6 +55,7 @@ import org.exist.xquery.value.Sequence; import org.exist.xquery.value.SequenceType; import org.exist.xquery.value.Type; +import xyz.elemental.mediatype.MediaType; import java.io.IOException; import java.io.OutputStream; @@ -101,7 +126,7 @@ public Sequence eval(final Sequence[] args, final Sequence contextSequence ) thr throw new XPathException(this, signature.toString() + " can only be used within the EXistServlet or XQueryServlet"); } - response.setContentType("application/zip"); + response.setContentType(MediaType.APPLICATION_ZIP); response.setHeader("Content-Length", String.valueOf(FileUtils.sizeQuietly(backupFile))); try { try(final OutputStream os = response.getOutputStream()) { diff --git a/exist-core/src/main/java/org/exist/client/ClientFrame.java b/exist-core/src/main/java/org/exist/client/ClientFrame.java index 479f48ad16..52547f6fbb 100644 --- a/exist-core/src/main/java/org/exist/client/ClientFrame.java +++ b/exist-core/src/main/java/org/exist/client/ClientFrame.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -21,6 +45,7 @@ */ package org.exist.client; +import org.apache.commons.io.output.StringBuilderWriter; import org.exist.SystemProperties; import org.exist.backup.Backup; import org.exist.backup.CreateBackupDialog; @@ -33,7 +58,6 @@ import org.exist.security.internal.aider.SimpleACLPermissionAider; import org.exist.storage.serializers.EXistOutputKeys; import org.exist.util.FileUtils; -import org.exist.util.MimeTable; import org.exist.util.SystemExitCodes; import org.exist.util.crypto.digest.DigestType; import org.exist.util.crypto.digest.MessageDigest; @@ -48,7 +72,11 @@ import org.xmldb.api.base.Resource; import org.xmldb.api.base.XMLDBException; import org.xmldb.api.modules.XMLResource; +import xyz.elemental.mediatype.MediaType; +import xyz.elemental.mediatype.MediaTypeResolver; +import xyz.elemental.mediatype.StorageType; +import javax.annotation.Nullable; import javax.swing.*; import javax.swing.border.BevelBorder; import javax.swing.filechooser.FileFilter; @@ -81,11 +109,14 @@ import java.util.stream.Collectors; import static java.nio.charset.StandardCharsets.UTF_8; +import static javax.swing.JOptionPane.INFORMATION_MESSAGE; import static org.exist.client.InteractiveClient.DATE_TIME_FORMATTER; import static org.exist.util.FileUtils.humanSize; /** - * Main frame of the eXist GUI + * @author Adam Retter + * + * Main frame of the Elemental Java Admin client GUI */ public class ClientFrame extends JFrame implements WindowFocusListener, KeyListener, ActionListener, MouseListener { @@ -108,7 +139,7 @@ public class ClientFrame extends JFrame implements WindowFocusListener, KeyListe public static final String MULTIPLE_INDICATOR = "[...]"; private static final String NON_APPLICABLE = "N/A"; - private static final String COLLECTION_MIME_TYPE = "exist/collection"; + private static final String COLLECTION_MIME_TYPE = "elemental/collection"; private int commandStart = 0; @@ -130,7 +161,7 @@ public class ClientFrame extends JFrame implements WindowFocusListener, KeyListe /** * Constructor. * - * @param client Existdb client + * @param client Elemental client * @param path Database connection URL. * @param properties Configuration items. * @throws java.awt.HeadlessException Environment does not support a keyboard, display, or mouse. @@ -143,7 +174,7 @@ public ClientFrame(final InteractiveClient client, final XmldbURI path, final Pr this.processRunnable = new ProcessRunnable(); this.processThread = client.newClientThread("process", processRunnable); - this.setIconImage(InteractiveClient.getExistIcon(getClass()).getImage()); + this.setIconImage(InteractiveClient.getElementalIcon(getClass()).getImage()); setupComponents(); addWindowListener(new WindowAdapter() { @@ -179,7 +210,7 @@ private void setupComponents() { try { client.reloadCollection(); } catch (final XMLDBException e1) { - //TODO report message + showErrorMessage(e1.getMessage(), e1); } }); toolbar.add(button); @@ -270,7 +301,7 @@ private void setupComponents() { // shell window doc = new DefaultStyledDocument(); shell = new JTextPane(doc); - shell.setContentType("text/plain; charset=UTF-8"); //$NON-NLS-1$ + shell.setContentType(MediaType.TEXT_PLAIN + "; charset=UTF-8"); //$NON-NLS-1$ shell.setFont(new Font("Monospaced", Font.PLAIN, 12)); //$NON-NLS-1$ shell.setMargin(new Insets(7, 5, 7, 5)); shell.addKeyListener(this); @@ -538,14 +569,15 @@ protected void displayPrompt() { final String pathString = path.getCollectionPath(); try { commandStart = doc.getLength(); - doc.insertString(commandStart, Messages.getString("ClientFrame.91"), promptAttrs); //$NON-NLS-1$ - commandStart += 6; + final String prompt = Messages.getString("ClientFrame.91"); + doc.insertString(commandStart, prompt, promptAttrs); //$NON-NLS-1$ + commandStart += prompt.length(); doc.insertString(commandStart, pathString + '>', promptAttrs); commandStart += pathString.length() + 1; doc.insertString(commandStart++, Messages.getString("ClientFrame.92"), defaultAttrs); //$NON-NLS-1$ shell.setCaretPosition(commandStart); } catch (final BadLocationException e) { - //TODO show error + showErrorMessage(e.getMessage(), e); } } @@ -561,7 +593,7 @@ protected void display(final String message) { shell.setCaretPosition(commandStart); } catch (final BadLocationException e) { - //TODO show error + showErrorMessage(e.getMessage(), e); } } @@ -740,6 +772,13 @@ private void removeAction(final ActionEvent ev) { } } + try { + removeRootCollection.close(); + client.reloadCollection(); + } catch (final XMLDBException e) { + showErrorMessage(e.getMessage(), e); + } + ClientAction.call(client::getResources, e -> showErrorMessage(e.getMessage(), e)); }; client.newClientThread("remove", removeTask).start(); @@ -962,8 +1001,8 @@ private void uploadAction(final ActionEvent ev) { final JFileChooser chooser = new JFileChooser(preferences.get("directory.last", System.getProperty("user.dir"))); chooser.setMultiSelectionEnabled(true); chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); - chooser.addChoosableFileFilter(new BinaryFileFilter()); - chooser.addChoosableFileFilter(new XMLFileFilter()); + chooser.addChoosableFileFilter(new BinaryFileFilter(client.getMediaTypeResolver())); + chooser.addChoosableFileFilter(new XMLFileFilter(client.getMediaTypeResolver())); if (chooser.showDialog(this, Messages.getString("ClientFrame.146")) == JFileChooser.APPROVE_OPTION) { //$NON-NLS-1$ // remember directory in preferences preferences.put("directory.last", chooser.getCurrentDirectory().getAbsolutePath()); @@ -1017,7 +1056,8 @@ private void backupAction(final ActionEvent ev) { properties.getProperty(InteractiveClient.USER, SecurityManager.DBA_USER), properties.getProperty(InteractiveClient.PASSWORD, null), Paths.get(preferences.get("directory.backup", System.getProperty("user.home"))), - defaultSelectedCollection + defaultSelectedCollection, + client.getMediaTypeResolver() ); if (JOptionPane.showOptionDialog(this, dialog, Messages.getString("ClientFrame.157"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null) == JOptionPane.YES_OPTION) { @@ -1284,7 +1324,7 @@ private void setPermAction(final ActionEvent ev) throws PermissionDeniedExceptio final Resource res = collection.getResource(thisName.toString()); thisCreated = DATE_TIME_FORMATTER.format(res.getCreationTime()); thisModified = DATE_TIME_FORMATTER.format(res.getLastModificationTime()); - thisMimeType = ((EXistResource) res).getMimeType(); + thisMimeType = ((EXistResource) res).getMediaType(); if (res instanceof EXistBinaryResource) { final MessageDigest messageDigest = ((EXistBinaryResource) res).getContentDigest(DigestType.BLAKE_256); thisMessageDigestType = messageDigest.getDigestType().getCommonNames()[0]; @@ -1482,7 +1522,8 @@ private void close() { } private void AboutAction() { - JOptionPane.showMessageDialog(this, client.getNotice()); + final Icon icon = InteractiveClient.getElementalIcon(getClass()); + JOptionPane.showMessageDialog(this, client.getNotice(), "About", INFORMATION_MESSAGE, icon); } class TableMouseListener extends MouseAdapter { @@ -1503,7 +1544,7 @@ public void mouseClicked(final MouseEvent e) { try { final Resource doc = client.retrieve(resource.getName(), properties.getProperty(OutputKeys.INDENT, "yes")); //$NON-NLS-1$ - if ("application/xquery".equals(((EXistResource) doc).getMimeType())) { + if (MediaType.APPLICATION_XQUERY.equals(((EXistResource) doc).getMediaType())) { final Collection collection = client.getCollection(); final QueryDialog dialog = new QueryDialog(client, collection, doc, properties); dialog.setVisible(true); @@ -1686,7 +1727,7 @@ protected static Properties getLoginData(final Properties props) { final ConnectionDialog connectionDialog = new ConnectionDialog(null, true, defaultConnectionSettings, Boolean.parseBoolean(props.getProperty(InteractiveClient.LOCAL_MODE, InteractiveClient.LOCAL_MODE_DEFAULT)), Boolean.parseBoolean(props.getProperty(InteractiveClient.NO_EMBED_MODE, InteractiveClient.NO_EMBED_MODE_DEFAULT))); - connectionDialog.setTitle(SystemProperties.getInstance().getSystemProperty("product-name", "eXist-db") + " " + SystemProperties.getInstance().getSystemProperty("product-version", "unknown") + " Database Login"); + connectionDialog.setTitle(SystemProperties.getInstance().getSystemProperty("product-name", "Elemental") + " " + SystemProperties.getInstance().getSystemProperty("product-version", "unknown") + " Database Login"); connectionDialog.addDialogCompleteWithResponseCallback(connection -> { properties.setProperty(InteractiveClient.USER, connection.getUsername()); @@ -1714,16 +1755,17 @@ public static void showErrorMessage(final String message, final Throwable t) { msgArea.setEditable(false); msgArea.setBackground(null); if (t != null) { - final StringWriter out = new StringWriter(); - final PrintWriter writer = new PrintWriter(out); - t.printStackTrace(writer); - final JTextArea stacktrace = new JTextArea(out.toString(), 20, 50); - stacktrace.setBackground(null); - stacktrace.setEditable(false); - scroll = new JScrollPane(stacktrace); - scroll.setPreferredSize(new Dimension(250, 300)); - scroll.setBorder(BorderFactory + try (final StringBuilderWriter out = new StringBuilderWriter(); + final PrintWriter writer = new PrintWriter(out)) { + t.printStackTrace(writer); + final JTextArea stacktrace = new JTextArea(out.toString(), 20, 50); + stacktrace.setBackground(null); + stacktrace.setEditable(false); + scroll = new JScrollPane(stacktrace); + scroll.setPreferredSize(new Dimension(250, 300)); + scroll.setBorder(BorderFactory .createTitledBorder(Messages.getString("ClientFrame.215"))); //$NON-NLS-1$ + } } final JOptionPane optionPane = new JOptionPane(); optionPane.setMessage(new Object[]{msgArea, scroll}); @@ -1747,7 +1789,7 @@ public static int showErrorMessageQuery(final String message, final Throwable t) JScrollPane scrollStacktrace = null; if (t != null) { - try (final StringWriter out = new StringWriter(); + try (final StringBuilderWriter out = new StringBuilderWriter(); final PrintWriter writer = new PrintWriter(out)) { t.printStackTrace(writer); final JTextArea stacktrace = new JTextArea(out.toString(), 20, 50); @@ -1759,8 +1801,6 @@ public static int showErrorMessageQuery(final String message, final Throwable t) scrollStacktrace.setPreferredSize(new Dimension(600, 300)); scrollStacktrace.setBorder(BorderFactory .createTitledBorder(Messages.getString("ClientFrame.218"))); //$NON-NLS-1$ - } catch (final IOException ioe) { - ioe.printStackTrace(); } } @@ -1851,46 +1891,46 @@ public void mouseReleased(final MouseEvent e) { } static class BinaryFileFilter extends FileFilter { + private final MediaTypeResolver mediaTypeResolver; + + public BinaryFileFilter(final MediaTypeResolver mediaTypeResolver) { + this.mediaTypeResolver = mediaTypeResolver; + } - /* (non-Javadoc) - * @see javax.swing.filechooser.FileFilter#getDescription() - */ @Override public String getDescription() { return Messages.getString("ClientFrame.220"); //$NON-NLS-1$ } - /* (non-Javadoc) - * @see javax.swing.filechooser.FileFilter#accept(java.io.File) - */ @Override public boolean accept(final File f) { if (f.isDirectory()) { return true; } - return !MimeTable.getInstance().isXMLContent(f.getName()); + @Nullable MediaType mediaType = mediaTypeResolver.fromFileName(f.toPath().getFileName()); + return mediaType == null || mediaType.getStorageType() != StorageType.XML; } } static class XMLFileFilter extends FileFilter { + private final MediaTypeResolver mediaTypeResolver; + + public XMLFileFilter(final MediaTypeResolver mediaTypeResolver) { + this.mediaTypeResolver = mediaTypeResolver; + } - /* (non-Javadoc) - * @see javax.swing.filechooser.FileFilter#getDescription() - */ @Override public String getDescription() { return Messages.getString("ClientFrame.221"); //$NON-NLS-1$ } - /* (non-Javadoc) - * @see javax.swing.filechooser.FileFilter#accept(java.io.File) - */ @Override public boolean accept(final File f) { if (f.isDirectory()) { return true; } - return MimeTable.getInstance().isXMLContent(f.getName()); + @Nullable MediaType mediaType = mediaTypeResolver.fromFileName(f.toPath().getFileName()); + return mediaType != null && mediaType.getStorageType() == StorageType.XML; } } @@ -1945,7 +1985,7 @@ private List getFilesWin32(final Transferable transferable) throws Unsuppo private List getFilesUnix(final Transferable transferable) throws ClassNotFoundException, UnsupportedFlavorException, IOException, URISyntaxException { List files = null; - final DataFlavor unixFileDataFlavour = new DataFlavor("text/uri-list;class=java.lang.String"); + final DataFlavor unixFileDataFlavour = new DataFlavor(MediaType.TEXT_URI_LIST + ";class=java.lang.String"); final String data = (String) transferable.getTransferData(unixFileDataFlavour); for (final StringTokenizer st = new StringTokenizer(data, "\r\n"); st.hasMoreTokens(); ) { final String token = st.nextToken().trim(); diff --git a/exist-core/src/main/java/org/exist/client/CommandlineOptions.java b/exist-core/src/main/java/org/exist/client/CommandlineOptions.java index 3c42d6577f..2e89c9dfe7 100644 --- a/exist-core/src/main/java/org/exist/client/CommandlineOptions.java +++ b/exist-core/src/main/java/org/exist/client/CommandlineOptions.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -177,7 +201,7 @@ public static CommandlineOptions parse(final String[] args) throws ArgumentExcep .andArguments(setDocArg, xupdateArg) .andArguments(reindexArg, reindexRecurseDirsArg) .andArguments(helpArg, quietArg, verboseArg, outputFileArg, optionArg) - .programName("client" + (OSUtil.isWindows() ? ".bat" : ".sh")) + .programName("client" + (OSUtil.IS_WINDOWS ? ".bat" : ".sh")) .parse(args); final boolean quiet = getBool(arguments, quietArg); diff --git a/exist-core/src/main/java/org/exist/client/Connection.java b/exist-core/src/main/java/org/exist/client/Connection.java index 19be3d17dc..7680b031e1 100644 --- a/exist-core/src/main/java/org/exist/client/Connection.java +++ b/exist-core/src/main/java/org/exist/client/Connection.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -18,12 +42,12 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + */ package org.exist.client; /** * Represents the Connection detail for - * connecting to either a local or remote eXist-db instance + * connecting to either a local or remote Elemental instance * * You can have either: * 1) Remote Connection, provide a uri and ssl flag. diff --git a/exist-core/src/main/java/org/exist/client/ConnectionDialog.java b/exist-core/src/main/java/org/exist/client/ConnectionDialog.java index 8fd6913950..c290d1415d 100644 --- a/exist-core/src/main/java/org/exist/client/ConnectionDialog.java +++ b/exist-core/src/main/java/org/exist/client/ConnectionDialog.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -72,7 +96,7 @@ public ConnectionDialog(final java.awt.Frame parent, final boolean modal, final this.defaultConnectionSettings = defaultConnectionSettings; this.config = Paths.get(defaultConnectionSettings.getConfiguration()); this.disableEmbeddedConnectionType = disableEmbeddedConnectionType; - this.setIconImage(InteractiveClient.getExistIcon(getClass()).getImage()); + this.setIconImage(InteractiveClient.getElementalIcon(getClass()).getImage()); initComponents(); if (disableEmbeddedConnectionType) { @@ -240,7 +264,7 @@ protected final void paintTabBorder(final java.awt.Graphics g, final int tabPlac setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); setTitle("Database Connection"); - lblExistLogo.setIcon(InteractiveClient.getExistIcon(getClass())); + lblExistLogo.setIcon(InteractiveClient.getElementalIcon(getClass())); lblUsername.setText(getLabelText("LoginPanel.2")); diff --git a/exist-core/src/main/java/org/exist/client/DocumentView.java b/exist-core/src/main/java/org/exist/client/DocumentView.java index 315c686830..bd752fee5a 100644 --- a/exist-core/src/main/java/org/exist/client/DocumentView.java +++ b/exist-core/src/main/java/org/exist/client/DocumentView.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -59,6 +83,7 @@ import javax.swing.border.BevelBorder; import javax.xml.transform.OutputKeys; +import org.apache.commons.io.output.StringBuilderWriter; import org.exist.security.Account; import org.exist.storage.ElementIndex; import org.exist.util.ProgressIndicator; @@ -75,6 +100,9 @@ import static org.xmldb.api.base.ResourceType.XML_RESOURCE; +/** + * @author Adam Retter + */ class DocumentView extends JFrame { private static final long serialVersionUID = 1L; @@ -99,7 +127,7 @@ public DocumentView(InteractiveClient client, XmldbURI resourceName, Resource re this.resourceName = resourceName; this.resource = resource; this.client = client; - this.setIconImage(InteractiveClient.getExistIcon(getClass()).getImage()); + this.setIconImage(InteractiveClient.getElementalIcon(getClass()).getImage()); this.collection = client.getCollection(); this.properties = properties; getContentPane().setLayout(new BorderLayout()); @@ -159,16 +187,17 @@ private static void showErrorMessage(String message, Throwable t) { msgArea.setEditable(false); msgArea.setBackground(null); if (t != null) { - final StringWriter out = new StringWriter(); - final PrintWriter writer = new PrintWriter(out); - t.printStackTrace(writer); - final JTextArea stacktrace = new JTextArea(out.toString(), 20, 50); - stacktrace.setBackground(null); - stacktrace.setEditable(false); - scroll = new JScrollPane(stacktrace); - scroll.setPreferredSize(new Dimension(250, 300)); - scroll.setBorder(BorderFactory + try (final StringBuilderWriter out = new StringBuilderWriter(); + final PrintWriter writer = new PrintWriter(out)) { + t.printStackTrace(writer); + final JTextArea stacktrace = new JTextArea(out.toString(), 20, 50); + stacktrace.setBackground(null); + stacktrace.setEditable(false); + scroll = new JScrollPane(stacktrace); + scroll.setPreferredSize(new Dimension(250, 300)); + scroll.setBorder(BorderFactory .createTitledBorder("Exception Stacktrace:")); //$NON-NLS-1$ + } } final JOptionPane optionPane = new JOptionPane(); optionPane.setMessage(new Object[]{msgArea, scroll}); diff --git a/exist-core/src/main/java/org/exist/client/IndexDialog.java b/exist-core/src/main/java/org/exist/client/IndexDialog.java index 6acf725ea0..9950cc6be0 100644 --- a/exist-core/src/main/java/org/exist/client/IndexDialog.java +++ b/exist-core/src/main/java/org/exist/client/IndexDialog.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -41,9 +65,7 @@ /** * Dialog for viewing and editing Indexes in the Admin Client * - * @author Adam Retter - * @serial 2006-03-12 - * @version 1.0 + * @author Adam Retter */ class IndexDialog extends JFrame { @@ -75,7 +97,7 @@ public IndexDialog(String title, InteractiveClient client) { super(title); this.client = client; - this.setIconImage(InteractiveClient.getExistIcon(getClass()).getImage()); + this.setIconImage(InteractiveClient.getElementalIcon(getClass()).getImage()); //capture the frame's close event final WindowListener windowListener = new WindowAdapter() { diff --git a/exist-core/src/main/java/org/exist/client/InteractiveClient.java b/exist-core/src/main/java/org/exist/client/InteractiveClient.java index 7511b01fe6..fbcfd5de0b 100644 --- a/exist-core/src/main/java/org/exist/client/InteractiveClient.java +++ b/exist-core/src/main/java/org/exist/client/InteractiveClient.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -41,6 +65,7 @@ import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; +import javax.annotation.Nullable; import javax.swing.ImageIcon; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; @@ -52,6 +77,7 @@ import org.apache.tools.ant.DirectoryScanner; import org.exist.SystemProperties; import org.exist.dom.persistent.XMLUtil; +import org.exist.mediatype.MediaTypeUtil; import org.exist.security.Account; import org.exist.security.Group; import org.exist.security.Permission; @@ -86,8 +112,12 @@ import org.xmldb.api.base.*; import org.xmldb.api.base.Collection; import org.xmldb.api.modules.BinaryResource; +import org.xmldb.api.modules.XMLResource; import org.xmldb.api.modules.XUpdateQueryService; import se.softhouse.jargo.ArgumentException; +import xyz.elemental.mediatype.MediaType; +import xyz.elemental.mediatype.MediaTypeResolver; +import xyz.elemental.mediatype.StorageType; import static java.nio.charset.StandardCharsets.UTF_8; import static java.time.ZoneOffset.UTC; @@ -99,6 +129,7 @@ /** * Command-line client based on the XML:DB API. * + * @author Adam Retter * @author wolf */ public class InteractiveClient { @@ -201,6 +232,8 @@ public InteractiveClient(CommandlineOptions options) { this.options = options; } + private MediaTypeResolver mediaTypeResolver = null; + /** * Display help on commands */ @@ -1040,7 +1073,7 @@ protected boolean process(final String line) { command.append(lastLine); } } catch (final UserInterruptException e) { - //TODO report error? + errorln("Interrupted by user: " + e.getMessage()); } final String xupdate = "" @@ -1157,16 +1190,18 @@ private ResourceSet find(String xpath) throws XMLDBException { } final String xpathCopy = xpath; - getTraceWriter().ifPresent(writer -> { + final Optional maybeWriter = getTraceWriter(); + if (maybeWriter.isPresent()) { + final Writer writer = maybeWriter.get(); try { writer.write(""); writer.write(xpathCopy); writer.write(""); writer.write(EOL); } catch (final IOException e) { - //TODO report error? + throw new XMLDBException(ErrorCodes.UNKNOWN_ERROR, e); } - }); + } String sortBy = null; final int p = xpath.indexOf(" sort by "); @@ -1284,21 +1319,25 @@ private void reindex() throws XMLDBException { private void storeBinary(final String fileName) throws XMLDBException { final Path file = Paths.get(fileName).normalize(); if (Files.isReadable(file)) { - final MimeType mime = MimeTable.getInstance().getContentTypeFor(FileUtils.fileName(file)); + @Nullable final MediaType mediaType = mediaTypeResolver.fromFileName(FileUtils.fileName(file)); try (final BinaryResource resource = current.createResource(FileUtils.fileName(file), BinaryResource.class)) { resource.setContent(file); - ((EXistResource) resource).setMimeType(mime == null ? "application/octet-stream" : mime.getName()); + ((EXistResource) resource).setMediaType(mediaType == null ? mediaTypeResolver.forUnknown().getIdentifier() : mediaType.getIdentifier()); current.storeResource(resource); } } } + MediaTypeResolver getMediaTypeResolver() { + return mediaTypeResolver; + } + private synchronized boolean findRecursive(final Collection collection, final Path dir, final XmldbURI base) throws XMLDBException { Collection c; EXistCollectionManagementService mgtService; //The XmldbURIs here aren't really used... XmldbURI next; - MimeType mimeType; + @Nullable MediaType mediaType = null; try { final List files = FileUtils.list(dir); @@ -1321,15 +1360,15 @@ private synchronized boolean findRecursive(final Collection collection, final Pa findRecursive(c, file, next); } else { final long start1 = System.currentTimeMillis(); - mimeType = MimeTable.getInstance().getContentTypeFor(FileUtils.fileName(file)); - if (mimeType == null) { + mediaType = mediaTypeResolver.fromFileName(FileUtils.fileName(file)); + if (mediaType == null) { messageln("File " + FileUtils.fileName(file) + " has an unknown suffix. Cannot determine file type."); - mimeType = MimeType.BINARY_TYPE; + mediaType = mediaTypeResolver.forUnknown(); } - try (final Resource document = collection.createResource(FileUtils.fileName(file), mimeType.getXMLDBType())) { + try (final Resource document = collection.createResource(FileUtils.fileName(file), toResourceTypeClass(mediaType))) { message("storing document " + FileUtils.fileName(file) + " (" + i + " of " + files.size() + ") " + "..."); document.setContent(file); - ((EXistResource) document).setMimeType(mimeType.getName()); + ((EXistResource) document).setMediaType(mediaType.getIdentifier()); collection.storeResource(document); ++filesCount; messageln(" " + FileUtils.sizeQuietly(file) + " bytes in " + (System.currentTimeMillis() - start1) + "ms."); @@ -1346,6 +1385,10 @@ private synchronized boolean findRecursive(final Collection collection, final Pa } } + private static Class toResourceTypeClass(final MediaType mediaType) { + return mediaType.getStorageType() == StorageType.XML ? XMLResource.class : BinaryResource.class; + } + /** * Stores given Resource * @@ -1391,20 +1434,20 @@ protected synchronized boolean parse(final Path file) throws XMLDBException { final long start0 = System.currentTimeMillis(); long bytes = 0; - MimeType mimeType; + @Nullable MediaType mediaType = null; for (int i = 0; i < files.size(); i++) { if (Files.isDirectory(files.get(i))) { continue; } final long start = System.currentTimeMillis(); - mimeType = MimeTable.getInstance().getContentTypeFor(FileUtils.fileName(files.get(i))); - if (mimeType == null) { - mimeType = MimeType.BINARY_TYPE; + mediaType = mediaTypeResolver.fromFileName(FileUtils.fileName(files.get(i))); + if (mediaType == null) { + mediaType = mediaTypeResolver.forUnknown(); } - try (final Resource document = current.createResource(FileUtils.fileName(files.get(i)), mimeType.getXMLDBType())) { + try (final Resource document = current.createResource(FileUtils.fileName(files.get(i)), toResourceTypeClass(mediaType))) { message("storing document " + FileUtils.fileName(files.get(i)) + " (" + (i + 1) + " of " + files.size() + ") ..."); document.setContent(files.get(i)); - ((EXistResource) document).setMimeType(mimeType.getName()); + ((EXistResource) document).setMediaType(mediaType.getIdentifier()); current.storeResource(document); messageln(DONE); messageln("parsing " + FileUtils.sizeQuietly(files.get(i)) + " bytes took " + (System.currentTimeMillis() - start) + "ms." + EOL); @@ -1426,7 +1469,7 @@ private synchronized boolean findGZipRecursive(final Collection collection, fina EXistCollectionManagementService mgtService; //The XmldbURIs here aren't really used... XmldbURI next; - MimeType mimeType; + @Nullable MediaType mediaType = null; int i = 0; for (final Path file : files) { i++; @@ -1458,15 +1501,15 @@ private synchronized boolean findGZipRecursive(final Collection collection, fina break; } } - mimeType = MimeTable.getInstance().getContentTypeFor(localName); - if (mimeType == null) { + mediaType = mediaTypeResolver.fromFileName(localName); + if (mediaType == null) { messageln("File " + compressedName + " has an unknown suffix. Cannot determine file type."); - mimeType = MimeType.BINARY_TYPE; + mediaType = mediaTypeResolver.forUnknown(); } - try (final Resource document = collection.createResource(compressedName, mimeType.getXMLDBType())) { + try (final Resource document = collection.createResource(compressedName, toResourceTypeClass(mediaType))) { message("storing document " + compressedName + " (" + i + " of " + files.size() + ") " + "..."); document.setContent(isCompressed ? new GZIPInputSource(file) : file); - ((EXistResource) document).setMimeType(mimeType.getName()); + ((EXistResource) document).setMediaType(mediaType.getIdentifier()); collection.storeResource(document); ++filesCount; messageln(" " + Files.size(file) + (isCompressed ? " compressed" : "") + " bytes in " @@ -1533,7 +1576,7 @@ protected synchronized boolean parseGZip(String fileName) throws XMLDBException, final long start0 = System.currentTimeMillis(); long bytes = 0; - MimeType mimeType; + @Nullable MediaType mediaType = null; int i = 0; for (final Path p : files) { i++; @@ -1553,15 +1596,15 @@ protected synchronized boolean parseGZip(String fileName) throws XMLDBException, break; } } - mimeType = MimeTable.getInstance().getContentTypeFor(localName); - if (mimeType == null) { - mimeType = MimeType.BINARY_TYPE; + mediaType = mediaTypeResolver.fromFileName(localName); + if (mediaType == null) { + mediaType = mediaTypeResolver.forUnknown(); } - try (final Resource document = current.createResource(compressedName, mimeType.getXMLDBType())) { + try (final Resource document = current.createResource(compressedName, toResourceTypeClass(mediaType))) { message("storing document " + compressedName + " (" + i + " of " + Files.size(p) + ") ..."); document.setContent(isCompressed ? new GZIPInputSource(p) : p); - ((EXistResource) document).setMimeType(mimeType.getName()); + ((EXistResource) document).setMediaType(mediaType.getIdentifier()); current.storeResource(document); messageln(DONE); messageln("parsing " + Files.size(p) + (isCompressed ? " compressed" : "") + " bytes took " @@ -1631,15 +1674,15 @@ protected synchronized boolean parseZip(final Path zipPath) throws XMLDBExceptio if (!ze.isDirectory()) { final String localName = pathSteps[pathSteps.length - 1]; final long start = System.currentTimeMillis(); - MimeType mimeType = MimeTable.getInstance().getContentTypeFor(localName); - if (mimeType == null) { - mimeType = MimeType.BINARY_TYPE; + @Nullable MediaType mediaType = mediaTypeResolver.fromFileName(localName); + if (mediaType == null) { + mediaType = mediaTypeResolver.forUnknown(); } - try (final Resource document = base.createResource(localName, mimeType.getXMLDBType())) { + try (final Resource document = base.createResource(localName, toResourceTypeClass(mediaType))) { message("storing Zip-entry document " + localName + " (" + (number) + " of " + zfile.size() + ") ..."); document.setContent(new ZipEntryInputSource(zfile, ze)); - ((EXistResource) document).setMimeType(mimeType.getName()); + ((EXistResource) document).setMediaType(mediaType.getIdentifier()); base.storeResource(document); messageln(DONE); messageln("parsing " + ze.getSize() + " bytes took " @@ -1756,19 +1799,17 @@ private void store(final Collection collection, final Path file, final UploadDia final long fileSize = FileUtils.sizeQuietly(file); upload.setCurrentSize(fileSize); - MimeType mimeType = MimeTable.getInstance().getContentTypeFor(FileUtils.fileName(file)); + MediaType mediaType = mediaTypeResolver.fromFileName(FileUtils.fileName(file)); // unknown mime type, here prefered is to do nothing - if (mimeType == null) { - upload.showMessage(file.toAbsolutePath() + - " - unknown suffix. No matching mime-type found in : " + - MimeTable.getInstance().getSrc()); + if (mediaType == null) { + upload.showMessage(file.toAbsolutePath() + " - unknown suffix. No matching mime-type found"); // if some one prefers to store it as binary by default, but dangerous - mimeType = MimeType.BINARY_TYPE; + mediaType = mediaTypeResolver.forUnknown(); } - try (final Resource res = collection.createResource(filenameUri.toString(), mimeType.getXMLDBType())) { - ((EXistResource) res).setMimeType(mimeType.getName()); + try (final Resource res = collection.createResource(filenameUri.toString(), toResourceTypeClass(mediaType))) { + ((EXistResource) res).setMediaType(mediaType.getIdentifier()); res.setContent(file); collection.storeResource(res); ++filesCount; @@ -2077,11 +2118,14 @@ private void connectToDatabase() { public boolean run() throws Exception { this.path = options.setCol.orElse(XmldbURI.ROOT_COLLECTION_URI); - // get eXist home + // get Elemental home final Optional home = ConfigurationHelper.getExistHome(); // get default configuration filename from the driver class and set it in properties - applyDefaultConfig(home); + final Optional configFile = applyDefaultConfig(home); + + @Nullable final Path applicationConfigDir = configFile.map(Path::getParent).filter(Files::exists).orElse(null); + this.mediaTypeResolver = MediaTypeUtil.newMediaTypeResolver(applicationConfigDir); properties.putAll(loadClientProperties()); @@ -2099,8 +2143,8 @@ public boolean run() throws Exception { return false; } - historyFile = home.map(h -> h.resolve(".exist_history")).orElse(Paths.get(".exist_history")); - queryHistoryFile = home.map(h -> h.resolve(".exist_query_history")).orElse(Paths.get(".exist_query_history")); + historyFile = home.map(h -> h.resolve(".elemental_jac_history")).orElse(Paths.get(".elemental_jac_history")); + queryHistoryFile = home.map(h -> h.resolve(".elemental_jac_query_history")).orElse(Paths.get(".elemental_jac_query_history")); readQueryHistory(); if (interactive) { @@ -2164,7 +2208,7 @@ private boolean checkLoginInfos(boolean interactive) { return false; } - private void applyDefaultConfig(Optional home) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { + private Optional applyDefaultConfig(Optional home) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { Optional configFile = ConfigurationHelper.getFromSystemProperty(); if (!configFile.isPresent()) { final Class cl = Class.forName(properties.getProperty(DRIVER)); @@ -2174,6 +2218,7 @@ private void applyDefaultConfig(Optional home) throws ClassNotFoundExcepti } } configFile.ifPresent(value -> properties.setProperty(CONFIGURATION, value.toString())); + return configFile; } final boolean isInteractive() { @@ -2382,10 +2427,10 @@ public void readlineInputLoop() { while (cont) { try { if ("true".equals(properties.getProperty(COLORS))) { - line = console.readLine(ANSI_CYAN + "exist:" + path + "> " + line = console.readLine(ANSI_CYAN + "elemental:" + path + "> " + ANSI_WHITE); } else { - line = console.readLine("exist:" + path + "> "); + line = console.readLine("elemental:" + path + "> "); } if (line != null) { cont = process(line); @@ -2456,22 +2501,16 @@ public String getNotice() { String getNotice(BinaryOperator propertyAction) { final StringBuilder builder = new StringBuilder(); - builder.append(propertyAction.apply("product-name", "eXist-db")); + builder.append(propertyAction.apply("product-name", "Elemental")); builder.append(" version "); builder.append(propertyAction.apply("product-version", "unknown")); final String gitCommitId = propertyAction.apply("git-commit", ""); if (!gitCommitId.isEmpty()) { builder.append(" (").append(gitCommitId).append(")"); } - builder.append(", Copyright (C) 2001-"); + builder.append(", Copyright (C) 2024-"); builder.append(Calendar.getInstance().get(Calendar.YEAR)); - builder.append(" The eXist-db Project"); - builder.append(EOL); - builder.append("eXist-db comes with ABSOLUTELY NO WARRANTY."); - builder.append(EOL); - builder.append("This is free software, and you are welcome to redistribute it"); - builder.append(EOL); - builder.append("under certain conditions; for details read the license file."); + builder.append(" Evolved Binary Ltd"); builder.append(EOL); return builder.toString(); } @@ -2628,7 +2667,7 @@ public static Properties getSystemProperties() { return sysProperties; } - public static ImageIcon getExistIcon(final Class clazz) { - return new javax.swing.ImageIcon(clazz.getResource("/org/exist/client/icons/x.png")); + public static ImageIcon getElementalIcon(final Class clazz) { + return new javax.swing.ImageIcon(clazz.getResource("/org/exist/client/icons/elemental-device.png")); } } diff --git a/exist-core/src/main/java/org/exist/client/MimeTypeFileFilter.java b/exist-core/src/main/java/org/exist/client/MediaTypeFileFilter.java similarity index 52% rename from exist-core/src/main/java/org/exist/client/MimeTypeFileFilter.java rename to exist-core/src/main/java/org/exist/client/MediaTypeFileFilter.java index 611aa6e537..aacdcd9ef5 100644 --- a/exist-core/src/main/java/org/exist/client/MimeTypeFileFilter.java +++ b/exist-core/src/main/java/org/exist/client/MediaTypeFileFilter.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -22,12 +46,10 @@ package org.exist.client; import java.io.File; -import java.util.Iterator; -import java.util.List; import javax.swing.filechooser.FileFilter; -import org.exist.util.MimeTable; +import xyz.elemental.mediatype.MediaType; /** @@ -36,18 +58,16 @@ * * Java 6 API has a similar FileNameExtensionFilter */ -public class MimeTypeFileFilter extends FileFilter { +public class MediaTypeFileFilter extends FileFilter { - private String description = null; - private List extensions = null; + private final MediaType mediaType; - public MimeTypeFileFilter(String mimeType) { - description = MimeTable.getInstance().getContentType(mimeType).getDescription(); - extensions = MimeTable.getInstance().getAllExtensions(mimeType); + public MediaTypeFileFilter(final MediaType mediaType) { + this.mediaType = mediaType; } @Override - public boolean accept(File file) { + public boolean accept(final File file) { if(file.isDirectory()){ //permit directories to be viewed return true; } @@ -60,8 +80,9 @@ public boolean accept(File file) { //check the extension is that of a file as defined in mime-types.xml final String fileExtension = file.getName().substring(extensionOffset).toLowerCase(); - for(final String extension : extensions) { - if(fileExtension.equals(extension)) { + final String[] extensions = mediaType.getKnownFileExtensions(); + for (final String extension : extensions) { + if (fileExtension.equals(extension)) { return true; } } @@ -71,15 +92,16 @@ public boolean accept(File file) { @Override public String getDescription() { - final StringBuilder description = new StringBuilder(this.description); + final StringBuilder description = new StringBuilder(mediaType.getIdentifier()); description.append(" ("); - for(final Iterator itExtensions = extensions.iterator(); itExtensions.hasNext();) { - description.append(itExtensions.next()); - if(itExtensions.hasNext()) { + final String[] extensions = mediaType.getKnownFileExtensions(); + for (int i = 0; i < extensions.length; i++) { + if (i > 0) { description.append(' '); } + description.append(extensions[i]); } description.append(")"); diff --git a/exist-core/src/main/java/org/exist/client/NewResourceDialog.java b/exist-core/src/main/java/org/exist/client/NewResourceDialog.java index 373e9831be..fc7dc739f2 100644 --- a/exist-core/src/main/java/org/exist/client/NewResourceDialog.java +++ b/exist-core/src/main/java/org/exist/client/NewResourceDialog.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -44,6 +68,9 @@ import org.xmldb.api.base.XMLDBException; import org.xmldb.api.modules.BinaryResource; import org.xmldb.api.modules.XMLResource; +import xyz.elemental.mediatype.MediaType; + +import static org.exist.util.StringUtil.isNullOrEmpty; /** * @@ -65,9 +92,9 @@ public NewResourceDialog(final InteractiveClient client) { } private enum ResourceType { - XML_DOCUMENT("XML Document", "xml", "application/xml", "xml-resource.tmpl"), - XQUERY_MAIN("XQuery Main Module", "xqy", "application/xquery", "xquery-resource.tmpl"), - XQUERY_LIBRARY("XQuery Library Module", "xqm", "application/xquery", "xquery-lib-resource.tmpl"); + XML_DOCUMENT("XML Document", "xml", MediaType.APPLICATION_XML, "xml-resource.tmpl"), + XQUERY_MAIN("XQuery Main Module", "xqy", MediaType.APPLICATION_XQUERY, "xquery-resource.tmpl"), + XQUERY_LIBRARY("XQuery Library Module", "xqm", MediaType.APPLICATION_XQUERY, "xquery-lib-resource.tmpl"); private final String label; private final String fileExtension; @@ -289,7 +316,7 @@ private void createResource(final ResourceType resourceType, final String filena try (final Collection collection = client.current; final Resource resource = collection.createResource(resName, resType)) { resource.setContent(resourceContent); - ((EXistResource) resource).setMimeType(resourceType.getMimeType()); + ((EXistResource) resource).setMediaType(resourceType.getMimeType()); collection.storeResource(resource); } client.reloadCollection(); @@ -297,8 +324,4 @@ private void createResource(final ResourceType resourceType, final String filena ClientFrame.showErrorMessage(xmldbe.getMessage(), xmldbe); } } - - private boolean isNullOrEmpty(String str) { - return str == null || str.isEmpty(); - } -} \ No newline at end of file +} diff --git a/exist-core/src/main/java/org/exist/client/QueryDialog.java b/exist-core/src/main/java/org/exist/client/QueryDialog.java index d5de7aec1f..1253ac6eaf 100644 --- a/exist-core/src/main/java/org/exist/client/QueryDialog.java +++ b/exist-core/src/main/java/org/exist/client/QueryDialog.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -62,6 +86,7 @@ import javax.swing.event.PopupMenuListener; import javax.xml.transform.OutputKeys; +import org.apache.commons.io.output.StringBuilderWriter; import org.exist.security.PermissionDeniedException; import org.exist.util.Holder; import org.exist.xmldb.EXistXQueryService; @@ -81,10 +106,14 @@ import org.xmldb.api.base.ResourceIterator; import org.xmldb.api.base.ResourceSet; import org.xmldb.api.base.XMLDBException; +import xyz.elemental.mediatype.MediaType; import static java.nio.charset.StandardCharsets.UTF_8; import static org.xmldb.api.base.ResourceType.XML_RESOURCE; +/** + * @author Adam Retter + */ public class QueryDialog extends JFrame { private static final long serialVersionUID = 1L; @@ -120,7 +149,7 @@ private QueryDialog(final InteractiveClient client, final Collection collection, this.collection = collection; this.properties = properties; this.client = client; - this.setIconImage(InteractiveClient.getExistIcon(getClass()).getImage()); + this.setIconImage(InteractiveClient.getElementalIcon(getClass()).getImage()); setupComponents(loadedFromDb); pack(); } @@ -413,7 +442,7 @@ private void open() { chooser.setCurrentDirectory(Paths.get(workDir).toFile()); chooser.setMultiSelectionEnabled(false); chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - chooser.addChoosableFileFilter(new MimeTypeFileFilter("application/xquery")); + chooser.addChoosableFileFilter(new MediaTypeFileFilter(client.getMediaTypeResolver().fromString(MediaType.APPLICATION_XQUERY))); if (chooser.showDialog(this, Messages.getString("QueryDialog.opendialog")) == JFileChooser.APPROVE_OPTION) { final Path selectedDir = chooser.getCurrentDirectory().toPath(); @@ -449,10 +478,10 @@ private void save(String stringToSave, String fileCategory) { chooser.setCurrentDirectory(Paths.get(workDir).toFile()); chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); if ("result".equals(fileCategory)) { - chooser.addChoosableFileFilter(new MimeTypeFileFilter("application/xhtml+xml")); - chooser.addChoosableFileFilter(new MimeTypeFileFilter("application/xml")); + chooser.addChoosableFileFilter(new MediaTypeFileFilter(client.getMediaTypeResolver().fromString(MediaType.APPLICATION_XHTML))); + chooser.addChoosableFileFilter(new MediaTypeFileFilter(client.getMediaTypeResolver().fromString(MediaType.APPLICATION_XML))); } else { - chooser.addChoosableFileFilter(new MimeTypeFileFilter("application/xquery")); + chooser.addChoosableFileFilter(new MediaTypeFileFilter(client.getMediaTypeResolver().fromString(MediaType.APPLICATION_XQUERY))); } if (chooser.showDialog(this, Messages.getString("QueryDialog.savedialogpre") + " " + fileCategory + " " + Messages.getString("QueryDialog.savedialogpost")) == JFileChooser.APPROVE_OPTION) { @@ -511,9 +540,10 @@ private void compileQuery() { tCompiled = t1 - t0; // In this way we can see the parsed structure meanwhile the query is - final StringWriter writer = new StringWriter(); - service.dump(compiled, writer); - exprDisplay.setText(writer.toString()); + try (final StringBuilderWriter writer = new StringBuilderWriter()) { + service.dump(compiled, writer); + exprDisplay.setText(writer.toString()); + } resultTabs.setSelectedComponent(exprDisplayScrollPane); statusMessage.setText(Messages.getString(QUERY_DIALOG_COMPILATION) + ": " + tCompiled + "ms"); @@ -583,9 +613,10 @@ public void run() { tCompiled = t1 - t0; // In this way we can see the parsed structure meanwhile the query is - StringWriter writer = new StringWriter(); - service.dump(compiled, writer); - exprDisplay.setText(writer.toString()); + try (final StringBuilderWriter writer = new StringBuilderWriter()) { + service.dump(compiled, writer); + exprDisplay.setText(writer.toString()); + } result = service.execute(compiled); tResult = System.currentTimeMillis() - t1; @@ -596,9 +627,10 @@ public void run() { } // jmfg: Is this still needed? I don't think so - writer = new StringWriter(); - service.dump(compiled, writer); - exprDisplay.setText(writer.toString()); + try (final StringBuilderWriter writer = new StringBuilderWriter()) { + service.dump(compiled, writer); + exprDisplay.setText(writer.toString()); + } statusMessage.setText(Messages.getString("QueryDialog.retrievingmessage")); final int howmany = count.getNumber().intValue(); diff --git a/exist-core/src/main/java/org/exist/client/TriggersDialog.java b/exist-core/src/main/java/org/exist/client/TriggersDialog.java index 832b2af858..f7a0241ed5 100644 --- a/exist-core/src/main/java/org/exist/client/TriggersDialog.java +++ b/exist-core/src/main/java/org/exist/client/TriggersDialog.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -51,10 +75,8 @@ /** * Dialog for viewing and editing Triggers in the Admin Client - * - * @author Adam Retter - * @serial 2012-11-24 - * @version 1.1 + * + * @author Adam Retter */ class TriggersDialog extends JFrame { @@ -72,7 +94,7 @@ class TriggersDialog extends JFrame { public TriggersDialog(final String title, final InteractiveClient client) { super(title); this.client = client; - this.setIconImage(InteractiveClient.getExistIcon(getClass()).getImage()); + this.setIconImage(InteractiveClient.getElementalIcon(getClass()).getImage()); //capture the frame's close event final WindowListener windowListener = new WindowAdapter() { @Override diff --git a/exist-core/src/main/java/org/exist/client/UploadDialog.java b/exist-core/src/main/java/org/exist/client/UploadDialog.java index 1246a18699..cadcc02b15 100644 --- a/exist-core/src/main/java/org/exist/client/UploadDialog.java +++ b/exist-core/src/main/java/org/exist/client/UploadDialog.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -39,6 +63,9 @@ import org.exist.storage.ElementIndex; import org.exist.util.ProgressIndicator; +/** + * @author Adam Retter + */ class UploadDialog extends JFrame { private static final long serialVersionUID = 1L; @@ -61,7 +88,7 @@ public UploadDialog() { c.insets = new Insets(5, 5, 5, 5); JLabel label = new JLabel(Messages.getString("UploadDialog.1")); //$NON-NLS-1$ - this.setIconImage(InteractiveClient.getExistIcon(getClass()).getImage()); + this.setIconImage(InteractiveClient.getElementalIcon(getClass()).getImage()); c.gridx = 0; c.gridy = 0; c.anchor = GridBagConstraints.WEST; diff --git a/exist-core/src/main/java/org/exist/client/security/AccessControlEntryDialog.java b/exist-core/src/main/java/org/exist/client/security/AccessControlEntryDialog.java index 5bf16b25f6..833b435031 100644 --- a/exist-core/src/main/java/org/exist/client/security/AccessControlEntryDialog.java +++ b/exist-core/src/main/java/org/exist/client/security/AccessControlEntryDialog.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -38,7 +62,7 @@ /** * - * @author Adam Retter + * @author Adam Retter */ public class AccessControlEntryDialog extends javax.swing.JFrame implements DialogWithResponse { @@ -53,7 +77,7 @@ public class AccessControlEntryDialog extends javax.swing.JFrame implements Dial public AccessControlEntryDialog(final UserManagementService userManagementService, final String title) throws XMLDBException { this.userManagementService = userManagementService; - this.setIconImage(InteractiveClient.getExistIcon(getClass()).getImage()); + this.setIconImage(InteractiveClient.getElementalIcon(getClass()).getImage()); allUsernames = new HashSet<>(); for(final Account account : userManagementService.getAccounts()) { allUsernames.add(account.getName()); diff --git a/exist-core/src/main/java/org/exist/client/security/EditPropertiesDialog.java b/exist-core/src/main/java/org/exist/client/security/EditPropertiesDialog.java index 5768b37cc1..daf85fe116 100644 --- a/exist-core/src/main/java/org/exist/client/security/EditPropertiesDialog.java +++ b/exist-core/src/main/java/org/exist/client/security/EditPropertiesDialog.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -50,7 +74,7 @@ /** * - * @author Adam Retter + * @author Adam Retter */ public class EditPropertiesDialog extends javax.swing.JFrame { private final UserManagementService userManagementService; @@ -90,7 +114,7 @@ public EditPropertiesDialog(final UserManagementService userManagementService, f this.mode = mode; this.acl = acl; this.applyTo = applyTo; - this.setIconImage(InteractiveClient.getExistIcon(getClass()).getImage()); + this.setIconImage(InteractiveClient.getElementalIcon(getClass()).getImage()); initComponents(); setFormProperties(); } diff --git a/exist-core/src/main/java/org/exist/client/security/UserDialog.java b/exist-core/src/main/java/org/exist/client/security/UserDialog.java index caeb8f904b..bee43c2b68 100644 --- a/exist-core/src/main/java/org/exist/client/security/UserDialog.java +++ b/exist-core/src/main/java/org/exist/client/security/UserDialog.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -37,7 +61,7 @@ /** * - * @author Adam Retter + * @author Adam Retter */ public class UserDialog extends javax.swing.JFrame { @@ -54,7 +78,7 @@ public class UserDialog extends javax.swing.JFrame { public UserDialog(final UserManagementService userManagementService) { this.userManagementService = userManagementService; - this.setIconImage(InteractiveClient.getExistIcon(getClass()).getImage()); + this.setIconImage(InteractiveClient.getElementalIcon(getClass()).getImage()); initComponents(); } diff --git a/exist-core/src/main/java/org/exist/client/security/UserManagerDialog.java b/exist-core/src/main/java/org/exist/client/security/UserManagerDialog.java index 6bfff3d75a..49b861bdb7 100644 --- a/exist-core/src/main/java/org/exist/client/security/UserManagerDialog.java +++ b/exist-core/src/main/java/org/exist/client/security/UserManagerDialog.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -43,7 +67,7 @@ /** * - * @author Adam Retter + * @author Adam Retter */ public class UserManagerDialog extends javax.swing.JFrame { @@ -60,7 +84,7 @@ public UserManagerDialog(final UserManagementService userManagementService, fina this.userManagementService = userManagementService; this.currentUser = currentUser; this.client = client; - this.setIconImage(InteractiveClient.getExistIcon(getClass()).getImage()); + this.setIconImage(InteractiveClient.getElementalIcon(getClass()).getImage()); initComponents(); tblUsers.setDefaultRenderer(Object.class, new HighlightedTableCellRenderer()); tblGroups.setDefaultRenderer(Object.class, new HighlightedTableCellRenderer()); diff --git a/exist-core/src/main/java/org/exist/collections/Collection.java b/exist-core/src/main/java/org/exist/collections/Collection.java index ed68afcf2c..c7bf145fad 100644 --- a/exist-core/src/main/java/org/exist/collections/Collection.java +++ b/exist-core/src/main/java/org/exist/collections/Collection.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -30,7 +54,7 @@ import org.exist.security.SecurityManager; import org.exist.storage.*; import org.exist.storage.io.VariableByteInput; -import org.exist.storage.io.VariableByteOutputStream; +import org.exist.storage.io.VariableByteOutput; import org.exist.storage.lock.*; import org.exist.storage.lock.Lock.LockMode; import org.exist.storage.txn.Txn; @@ -42,6 +66,7 @@ import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; +import xyz.elemental.mediatype.MediaType; import javax.annotation.Nullable; import java.io.IOException; @@ -590,7 +615,7 @@ DocumentSet getDocuments(DBBroker broker, MutableDocumentSet docs, LockedDocumen * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked * @throws IOException in case of I/O errors - * @throws TriggerException in case of eXist-db trigger error + * @throws TriggerException in case of trigger error */ void removeResource(Txn transaction, DBBroker broker, DocumentImpl doc) throws PermissionDeniedException, LockException, IOException, TriggerException; @@ -604,7 +629,7 @@ void removeResource(Txn transaction, DBBroker broker, DocumentImpl doc) * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked * @throws IOException in case of I/O errors - * @throws TriggerException in case of eXist-db trigger error + * @throws TriggerException in case of trigger error */ void removeXMLResource(Txn transaction, DBBroker broker, XmldbURI name) throws PermissionDeniedException, TriggerException, LockException, IOException; @@ -617,7 +642,7 @@ void removeXMLResource(Txn transaction, DBBroker broker, XmldbURI name) * @param name the name (without path) of the document * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked - * @throws TriggerException in case of eXist-db trigger error + * @throws TriggerException in case of trigger error */ void removeBinaryResource(Txn transaction, DBBroker broker, XmldbURI name) throws PermissionDeniedException, LockException, TriggerException; @@ -630,7 +655,7 @@ void removeBinaryResource(Txn transaction, DBBroker broker, XmldbURI name) * @param doc the document to remove * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked - * @throws TriggerException in case of eXist-db trigger error + * @throws TriggerException in case of trigger error */ void removeBinaryResource(Txn transaction, DBBroker broker, DocumentImpl doc) throws PermissionDeniedException, LockException, TriggerException; @@ -640,7 +665,7 @@ void removeBinaryResource(Txn transaction, DBBroker broker, DocumentImpl doc) * Since the process is dependent on the collection configuration, * the collection acquires a write lock during the process. * - * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} + * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} * * @param transaction The database transaction * @param broker The database broker @@ -651,10 +676,13 @@ void removeBinaryResource(Txn transaction, DBBroker broker, DocumentImpl doc) * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked * @throws IOException in case of I/O errors - * @throws TriggerException in case of eXist-db trigger error - * @throws EXistException general eXist-db exception + * @throws TriggerException in case of trigger error + * @throws EXistException general exception * @throws SAXException internal SAXException + * + * @deprecated Use {@link #storeDocument(Txn, DBBroker, XmldbURI, InputSource, MediaType)} instead. */ + @Deprecated void storeDocument(Txn transaction, DBBroker broker, XmldbURI name, InputSource source, @Nullable MimeType mimeType) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException; /** @@ -662,7 +690,29 @@ void removeBinaryResource(Txn transaction, DBBroker broker, DocumentImpl doc) * Since the process is dependent on the collection configuration, * the collection acquires a write lock during the process. * - * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} + * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} + * + * @param transaction The database transaction + * @param broker The database broker + * @param name The name (without path) of the document + * @param source The source of the content for the new document to store + * @param mediaType The Internet Media Type of the document to store, or null if unknown. + * + * @throws PermissionDeniedException if user has not sufficient rights + * @throws LockException if broker is locked + * @throws IOException in case of I/O errors + * @throws TriggerException in case of trigger error + * @throws EXistException general exception + * @throws SAXException internal SAXException + */ + void storeDocument(Txn transaction, DBBroker broker, XmldbURI name, InputSource source, @Nullable MediaType mediaType) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException; + + /** + * Stores a document. + * Since the process is dependent on the collection configuration, + * the collection acquires a write lock during the process. + * + * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} * * @param transaction The database transaction * @param broker The database broker @@ -679,10 +729,13 @@ void removeBinaryResource(Txn transaction, DBBroker broker, DocumentImpl doc) * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked * @throws IOException in case of I/O errors - * @throws TriggerException in case of eXist-db trigger error - * @throws EXistException general eXist-db exception + * @throws TriggerException in case of trigger error + * @throws EXistException general exception * @throws SAXException internal SAXException + * + * @deprecated Use {@link #storeDocument(Txn, DBBroker, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader)} instead. */ + @Deprecated void storeDocument(Txn transaction, DBBroker broker, XmldbURI name, InputSource source, @Nullable MimeType mimeType, @Nullable Date createdDate, @Nullable Date lastModifiedDate, @Nullable Permission permission, @Nullable DocumentType documentType, @Nullable XMLReader xmlReader) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException; /** @@ -690,7 +743,35 @@ void removeBinaryResource(Txn transaction, DBBroker broker, DocumentImpl doc) * Since the process is dependent on the collection configuration, * the collection acquires a write lock during the process. * - * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, Node, MimeType, Collection)} + * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} + * + * @param transaction The database transaction + * @param broker The database broker + * @param name The name (without path) of the document + * @param source The source of the content for the new document to store + * @param mediaType The Internet Media Type of the document to store, or null if unknown. + * If null, application/octet-stream will be used to store a binary document. + * @param createdDate The created date to set for the document, or if null the date is set to 'now' + * @param lastModifiedDate The lastModified date to set for the document, or if null the date is set to the {@code createdDate} + * @param permission A specific permission to set on the document, or null for the default permission + * @param documentType A document type declaration, or null if absent or a binary document is being stored + * @param xmlReader A custom XML Reader (e.g. a HTML to XHTML converting reader), or null to use the default XML reader or if a binary document is being stored + * + * @throws PermissionDeniedException if user has not sufficient rights + * @throws LockException if broker is locked + * @throws IOException in case of I/O errors + * @throws TriggerException in case of trigger error + * @throws EXistException general exception + * @throws SAXException internal SAXException + */ + void storeDocument(Txn transaction, DBBroker broker, XmldbURI name, InputSource source, @Nullable MediaType mediaType, @Nullable Date createdDate, @Nullable Date lastModifiedDate, @Nullable Permission permission, @Nullable DocumentType documentType, @Nullable XMLReader xmlReader) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException; + + /** + * Stores a document. + * Since the process is dependent on the collection configuration, + * the collection acquires a write lock during the process. + * + * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, Node, MediaType, Collection)} * * @param transaction The database transaction * @param broker The database broker @@ -701,10 +782,13 @@ void removeBinaryResource(Txn transaction, DBBroker broker, DocumentImpl doc) * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked * @throws IOException in case of I/O errors - * @throws TriggerException in case of eXist-db trigger error - * @throws EXistException general eXist-db exception + * @throws TriggerException in case of trigger error + * @throws EXistException general exception * @throws SAXException internal SAXException + * + * @deprecated Use {@link #storeDocument(Txn, DBBroker, XmldbURI, Node, MediaType)} instead. */ + @Deprecated void storeDocument(Txn transaction, DBBroker broker, XmldbURI name, Node node, @Nullable MimeType mimeType) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException; /** @@ -712,7 +796,29 @@ void removeBinaryResource(Txn transaction, DBBroker broker, DocumentImpl doc) * Since the process is dependent on the collection configuration, * the collection acquires a write lock during the process. * - * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, Node, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} + * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, Node, MediaType, Collection)} + * + * @param transaction The database transaction + * @param broker The database broker + * @param name The name (without path) of the document + * @param node The DOM Node to store as a new document + * @param mediaType The Internet Media Type of the document to store, or null if unknown. + * + * @throws PermissionDeniedException if user has not sufficient rights + * @throws LockException if broker is locked + * @throws IOException in case of I/O errors + * @throws TriggerException in case of trigger error + * @throws EXistException general exception + * @throws SAXException internal SAXException + */ + void storeDocument(Txn transaction, DBBroker broker, XmldbURI name, Node node, @Nullable MediaType mediaType) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException; + + /** + * Stores a document. + * Since the process is dependent on the collection configuration, + * the collection acquires a write lock during the process. + * + * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, Node, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} * * @param transaction The database transaction * @param broker The database broker @@ -729,12 +835,43 @@ void removeBinaryResource(Txn transaction, DBBroker broker, DocumentImpl doc) * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked * @throws IOException in case of I/O errors - * @throws TriggerException in case of eXist-db trigger error - * @throws EXistException general eXist-db exception + * @throws TriggerException in case of trigger error + * @throws EXistException general exception * @throws SAXException internal SAXException + * + * @deprecated Use {@link #storeDocument(Txn, DBBroker, XmldbURI, Node, MediaType, Date, Date, Permission, DocumentType, XMLReader)} instead. */ + @Deprecated void storeDocument(Txn transaction, DBBroker broker, XmldbURI name, Node node, @Nullable MimeType mimeType, @Nullable Date createdDate, @Nullable Date lastModifiedDate, @Nullable Permission permission, @Nullable DocumentType documentType, @Nullable XMLReader xmlReader) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException; + /** + * Stores a document. + * Since the process is dependent on the collection configuration, + * the collection acquires a write lock during the process. + * + * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, Node, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} + * + * @param transaction The database transaction + * @param broker The database broker + * @param name The name (without path) of the document + * @param node The DOM Node to store as a new document + * @param mediaType The Internet Media Type of the document to store, or null if unknown. + * If null, application/octet-stream will be used to store a binary document. + * @param createdDate The created date to set for the document, or if null the date is set to 'now' + * @param lastModifiedDate The lastModified date to set for the document, or if null the date is set to the {@code createdDate} + * @param permission A specific permission to set on the document, or null for the default permission + * @param documentType A document type declaration, or null if absent or a binary document is being stored + * @param xmlReader A custom XML Reader (e.g. a HTML to XHTML converting reader), or null to use the default XML reader or if a binary document is being stored + * + * @throws PermissionDeniedException if user has not sufficient rights + * @throws LockException if broker is locked + * @throws IOException in case of I/O errors + * @throws TriggerException in case of trigger error + * @throws EXistException general exception + * @throws SAXException internal SAXException + */ + void storeDocument(Txn transaction, DBBroker broker, XmldbURI name, Node node, @Nullable MediaType mediaType, @Nullable Date createdDate, @Nullable Date lastModifiedDate, @Nullable Permission permission, @Nullable DocumentType documentType, @Nullable XMLReader xmlReader) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException; + /** * Validates an XML document and prepares it for further storage. * Launches prepare and postValidate triggers. @@ -751,11 +888,11 @@ void removeBinaryResource(Txn transaction, DBBroker broker, DocumentImpl doc) * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked * @throws IOException in case of I/O errors - * @throws TriggerException in case of eXist-db trigger error - * @throws EXistException general eXist-db exception + * @throws TriggerException in case of trigger error + * @throws EXistException general exception * @throws SAXException internal SAXException * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated IndexInfo validateXMLResource(Txn transaction, DBBroker broker, XmldbURI name, InputSource source) @@ -779,11 +916,11 @@ IndexInfo validateXMLResource(Txn transaction, DBBroker broker, XmldbURI name, I * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked * @throws IOException in case of I/O errors - * @throws TriggerException in case of eXist-db trigger error - * @throws EXistException general eXist-db exception + * @throws TriggerException in case of trigger error + * @throws EXistException general exception * @throws SAXException internal SAXException * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated IndexInfo validateXMLResource(Txn transaction, DBBroker broker, XmldbURI name, InputSource source, XMLReader reader) @@ -805,11 +942,11 @@ IndexInfo validateXMLResource(Txn transaction, DBBroker broker, XmldbURI name, I * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked * @throws IOException in case of I/O errors - * @throws TriggerException in case of eXist-db trigger error - * @throws EXistException general eXist-db exception + * @throws TriggerException in case of trigger error + * @throws EXistException general exception * @throws SAXException internal SAXException * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated IndexInfo validateXMLResource(Txn transaction, DBBroker broker, XmldbURI name, String data) @@ -831,11 +968,11 @@ IndexInfo validateXMLResource(Txn transaction, DBBroker broker, XmldbURI name, S * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked * @throws IOException in case of I/O errors - * @throws TriggerException in case of eXist-db trigger error - * @throws EXistException general eXist-db exception + * @throws TriggerException in case of trigger error + * @throws EXistException general exception * @throws SAXException internal SAXException * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, Node, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, Node, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated IndexInfo validateXMLResource(Txn transaction, DBBroker broker, XmldbURI name, Node node) @@ -854,11 +991,11 @@ IndexInfo validateXMLResource(Txn transaction, DBBroker broker, XmldbURI name, N * * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked - * @throws TriggerException in case of eXist-db trigger error - * @throws EXistException general eXist-db exception + * @throws TriggerException in case of trigger error + * @throws EXistException general exception * @throws SAXException internal SAXException * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated void store(Txn transaction, DBBroker broker, IndexInfo info, InputSource source) @@ -878,11 +1015,11 @@ void store(Txn transaction, DBBroker broker, IndexInfo info, InputSource source) * * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked* - * @throws TriggerException in case of eXist-db trigger error - * @throws EXistException general eXist-db exception + * @throws TriggerException in case of trigger error + * @throws EXistException general exception * @throws SAXException internal SAXException * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated void store(final Txn transaction, final DBBroker broker, final IndexInfo info, final InputSource source, final XMLReader reader) @@ -901,11 +1038,11 @@ void store(final Txn transaction, final DBBroker broker, final IndexInfo info, f * * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked - * @throws TriggerException in case of eXist-db trigger error - * @throws EXistException general eXist-db exception + * @throws TriggerException in case of trigger error + * @throws EXistException general exception * @throws SAXException internal SAXException * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated void store(Txn transaction, DBBroker broker, IndexInfo info, String data) @@ -924,11 +1061,11 @@ void store(Txn transaction, DBBroker broker, IndexInfo info, String data) * * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked - * @throws TriggerException in case of eXist-db trigger error - * @throws EXistException general eXist-db exception + * @throws TriggerException in case of trigger error + * @throws EXistException general exception * @throws SAXException internal SAXException * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, Node, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, Node, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated void store(Txn transaction, DBBroker broker, IndexInfo info, Node node) @@ -946,9 +1083,9 @@ void store(Txn transaction, DBBroker broker, IndexInfo info, Node node) * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked * @throws IOException in case of I/O errors - * @throws TriggerException in case of eXist-db trigger error + * @throws TriggerException in case of trigger error * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated BinaryDocument validateBinaryResource(Txn transaction, DBBroker broker, XmldbURI name) @@ -966,7 +1103,7 @@ BinaryDocument validateBinaryResource(Txn transaction, DBBroker broker, XmldbURI * @param broker The database broker * @param name the name (without path) of the document * @param is The content for the document - * @param mimeType The Internet Media Type of the document + * @param mediaType The Internet Media Type of the document * @param size The size in bytes of the document (unused - size is calculated during storage) * @param created The created timestamp of the document * @param modified The modified timestamp of the document @@ -976,13 +1113,13 @@ BinaryDocument validateBinaryResource(Txn transaction, DBBroker broker, XmldbURI * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked * @throws IOException in case of I/O errors - * @throws TriggerException in case of eXist-db trigger error - * @throws EXistException general eXist-db exception* + * @throws TriggerException in case of trigger error + * @throws EXistException general exception* * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated - BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name, InputStream is, String mimeType, + BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name, InputStream is, String mediaType, @Deprecated long size, Date created, Date modified) throws EXistException, PermissionDeniedException, LockException, TriggerException, IOException; @@ -998,7 +1135,7 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name * @param broker The database broker * @param name the name (without path) of the document * @param is The content for the document - * @param mimeType The Internet Media Type of the document + * @param mediaType The Internet Media Type of the document * @param size The size in bytes of the document (unused - size is calculated during storage) * @param created The created timestamp of the document * @param modified The modified timestamp of the document @@ -1009,13 +1146,13 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked * @throws IOException in case of I/O errors - * @throws TriggerException in case of eXist-db trigger error - * @throws EXistException general eXist-db exception* + * @throws TriggerException in case of trigger error + * @throws EXistException general exception* * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated - BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name, InputStream is, String mimeType, + BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name, InputStream is, String mediaType, @Deprecated long size, Date created, Date modified, @Nullable Permission permission) throws EXistException, PermissionDeniedException, LockException, TriggerException, IOException; @@ -1031,20 +1168,20 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name * @param broker The database broker * @param name the name (without path) of the document * @param data The content for the document - * @param mimeType The Internet Media Type of the document + * @param mediaType The Internet Media Type of the document * * @return The stored Binary Document object * * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked * @throws IOException in case of I/O errors - * @throws TriggerException in case of eXist-db trigger error - * @throws EXistException general eXist-db exception + * @throws TriggerException in case of trigger error + * @throws EXistException general exception * * @deprecated Use {@link #addBinaryResource(Txn, DBBroker, XmldbURI, InputStream, String, long)} */ @Deprecated - BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name, byte[] data, String mimeType) + BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name, byte[] data, String mediaType) throws EXistException, PermissionDeniedException, LockException, TriggerException, IOException; /** @@ -1059,7 +1196,7 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name * @param broker The database broker * @param name the name (without path) of the document * @param data The content for the document - * @param mimeType The Internet Media Type of the document + * @param mediaType The Internet Media Type of the document * @param created The created timestamp of the document * @param modified The modified timestamp of the document * @@ -1068,13 +1205,13 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked * @throws IOException in case of I/O errors - * @throws TriggerException in case of eXist-db trigger error - * @throws EXistException general eXist-db exception + * @throws TriggerException in case of trigger error + * @throws EXistException general exception * * @deprecated Use {@link #addBinaryResource(Txn, DBBroker, BinaryDocument, InputStream, String, long, Date, Date)} */ @Deprecated - BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name, byte[] data, String mimeType, + BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name, byte[] data, String mediaType, Date created, Date modified) throws EXistException, PermissionDeniedException, LockException, TriggerException, IOException; @@ -1090,7 +1227,7 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name * @param broker The database broker * @param name the name (without path) of the document * @param is The content for the document - * @param mimeType The Internet Media Type of the document + * @param mediaType The Internet Media Type of the document * @param size The size in bytes of the document (unused - size is calculated during storage) * * @return The stored Binary Document object @@ -1098,14 +1235,14 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked * @throws IOException in case of I/O errors - * @throws TriggerException in case of eXist-db trigger error - * @throws EXistException general eXist-db exception + * @throws TriggerException in case of trigger error + * @throws EXistException general exception * * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name, InputStream is, - String mimeType, @Deprecated long size) throws EXistException, PermissionDeniedException, LockException, + String mediaType, @Deprecated long size) throws EXistException, PermissionDeniedException, LockException, TriggerException, IOException; /** @@ -1120,7 +1257,7 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name * @param broker The database broker * @param blob the binary resource to store the data into * @param is The content for the document - * @param mimeType The Internet Media Type of the document + * @param mediaType The Internet Media Type of the document * @param size The size in bytes of the document (unused - size is calculated during storage) * @param created The created timestamp of the document * @param modified The modified timestamp of the document @@ -1130,14 +1267,14 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked * @throws IOException in case of I/O errors - * @throws TriggerException in case of eXist-db trigger error - * @throws EXistException general eXist-db exception + * @throws TriggerException in case of trigger error + * @throws EXistException general exception * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, BinaryDocument blob, InputStream is, - String mimeType, @Deprecated long size, Date created, Date modified) throws EXistException, PermissionDeniedException, + String mediaType, @Deprecated long size, Date created, Date modified) throws EXistException, PermissionDeniedException, LockException, TriggerException, IOException; /** @@ -1152,7 +1289,7 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, BinaryDocumen * @param broker The database broker * @param blob the binary resource to store the data into * @param is The content for the document - * @param mimeType The Internet Media Type of the document + * @param mediaType The Internet Media Type of the document * @param size The size in bytes of the document (unused - size is calculated during storage) * @param created The created timestamp of the document * @param modified The modified timestamp of the document @@ -1165,14 +1302,14 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, BinaryDocumen * @throws PermissionDeniedException if user has not sufficient rights * @throws LockException if broker is locked * @throws IOException in case of I/O errors - * @throws TriggerException in case of eXist-db trigger error - * @throws EXistException general eXist-db exception + * @throws TriggerException in case of trigger error + * @throws EXistException general exception * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, BinaryDocument blob, InputStream is, - String mimeType, @Deprecated long size, Date created, Date modified, DBBroker.PreserveType preserve) + String mediaType, @Deprecated long size, Date created, Date modified, DBBroker.PreserveType preserve) throws EXistException, PermissionDeniedException, LockException, TriggerException, IOException; /** @@ -1183,7 +1320,7 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, BinaryDocumen * @throws IOException in case of I/O errors */ - @EnsureContainerLocked(mode=READ_LOCK) void serialize(final VariableByteOutputStream outputStream) throws IOException, LockException; + @EnsureContainerLocked(mode=READ_LOCK) void serialize(final VariableByteOutput outputStream) throws IOException, LockException; @Override void close(); diff --git a/exist-core/src/main/java/org/exist/collections/CollectionConfiguration.java b/exist-core/src/main/java/org/exist/collections/CollectionConfiguration.java index 1da819c20e..0ae78e2016 100644 --- a/exist-core/src/main/java/org/exist/collections/CollectionConfiguration.java +++ b/exist-core/src/main/java/org/exist/collections/CollectionConfiguration.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -160,7 +184,7 @@ protected void read(final DBBroker broker, final Document doc, final boolean che } else if (VALIDATION_ELEMENT.equals(node.getLocalName())) { final Element elem = (Element) node; final String mode = elem.getAttribute(VALIDATION_MODE_ATTR); - if (mode == null) { + if (mode.isEmpty()) { LOG.debug("Unable to determine validation mode in {}", srcCollectionURI); validationMode = XMLReaderObjectFactory.VALIDATION_SETTING.UNKNOWN; } else { diff --git a/exist-core/src/main/java/org/exist/collections/CollectionConfigurationManager.java b/exist-core/src/main/java/org/exist/collections/CollectionConfigurationManager.java index 824fbb5967..c6de4bf4b0 100644 --- a/exist-core/src/main/java/org/exist/collections/CollectionConfigurationManager.java +++ b/exist-core/src/main/java/org/exist/collections/CollectionConfigurationManager.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -36,7 +60,6 @@ import org.exist.storage.txn.TransactionManager; import org.exist.storage.txn.Txn; import org.exist.util.LockException; -import org.exist.util.MimeType; import org.exist.util.StringInputSource; import org.exist.util.XMLReaderPool; import org.exist.util.sanity.SanityCheck; @@ -45,6 +68,7 @@ import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; +import xyz.elemental.mediatype.MediaType; import java.io.IOException; import java.io.StringReader; @@ -102,7 +126,7 @@ public void startSystem(final DBBroker systemBroker, final Txn transaction) thro * * @param txn The transaction that will hold the WRITE locks until they are * released by commit()/abort() - * @param broker the eXist-db broker + * @param broker the broker * @param collection the collection to which the configuration applies. * @param config the xconf document as a String. * @throws CollectionConfigurationException if config is invalid @@ -131,7 +155,8 @@ public void addConfiguration(final Txn txn, final DBBroker broker, final Collect broker.saveCollection(txn, confCol); - broker.storeDocument(txn, configurationDocumentName, new StringInputSource(config), MimeType.XML_TYPE, confCol); + final MediaType xmlMediaType = broker.getBrokerPool().getMediaTypeService().getMediaTypeResolver().fromString(MediaType.APPLICATION_XML); + broker.storeDocument(txn, configurationDocumentName, new StringInputSource(config), xmlMediaType, confCol); // broker.sync(Sync.MAJOR_SYNC); } catch (final CollectionConfigurationException e) { @@ -366,7 +391,7 @@ public void invalidate(final XmldbURI collectionPath, final BrokerPool pool) { * Check if the collection exists below the system collection. If not, * create it. * - * @param broker eXist-db broker + * @param broker the broker * @param txn according transaction * @param uri to the collection to create * @throws EXistException if something goes wrong diff --git a/exist-core/src/main/java/org/exist/collections/LockedCollection.java b/exist-core/src/main/java/org/exist/collections/LockedCollection.java index 10138374e3..6ab9bf34ce 100644 --- a/exist-core/src/main/java/org/exist/collections/LockedCollection.java +++ b/exist-core/src/main/java/org/exist/collections/LockedCollection.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -29,7 +53,7 @@ import org.exist.security.PermissionDeniedException; import org.exist.security.Subject; import org.exist.storage.*; -import org.exist.storage.io.VariableByteOutputStream; +import org.exist.storage.io.VariableByteOutput; import org.exist.storage.lock.Lock; import org.exist.storage.lock.LockedDocumentMap; import org.exist.storage.lock.ManagedCollectionLock; @@ -42,6 +66,7 @@ import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; +import xyz.elemental.mediatype.MediaType; import javax.annotation.Nullable; import java.io.IOException; @@ -362,21 +387,41 @@ public void storeDocument(final Txn transaction, final DBBroker broker, final Xm broker.storeDocument(transaction, name, source, mimeType, collection); } + @Override + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final InputSource source, @Nullable final MediaType mediaType) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException { + broker.storeDocument(transaction, name, source, mediaType, collection); + } + @Override public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final InputSource source, @Nullable final MimeType mimeType, @Nullable final Date createdDate, @Nullable final Date lastModifiedDate, @Nullable final Permission permission, @Nullable final DocumentType documentType, @Nullable final XMLReader xmlReader) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException { collection.storeDocument(transaction, broker, name, source, mimeType, createdDate, lastModifiedDate, permission, documentType, xmlReader); } + @Override + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final InputSource source, @Nullable final MediaType mediaType, @Nullable final Date createdDate, @Nullable final Date lastModifiedDate, @Nullable final Permission permission, @Nullable final DocumentType documentType, @Nullable final XMLReader xmlReader) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException { + collection.storeDocument(transaction, broker, name, source, mediaType, createdDate, lastModifiedDate, permission, documentType, xmlReader); + } + @Override public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final Node node, @Nullable final MimeType mimeType) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException { broker.storeDocument(transaction, name, node, mimeType, collection); } + @Override + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final Node node, @Nullable final MediaType mediaType) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException { + broker.storeDocument(transaction, name, node, mediaType, collection); + } + @Override public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final Node node, @Nullable final MimeType mimeType, @Nullable final Date createdDate, @Nullable final Date lastModifiedDate, @Nullable final Permission permission, @Nullable final DocumentType documentType, @Nullable final XMLReader xmlReader) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException { collection.storeDocument(transaction, broker, name, node, mimeType, createdDate, lastModifiedDate, permission, documentType, xmlReader); } + @Override + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final Node node, @Nullable final MediaType mediaType, @Nullable final Date createdDate, @Nullable final Date lastModifiedDate, @Nullable final Permission permission, @Nullable final DocumentType documentType, @Nullable final XMLReader xmlReader) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException { + collection.storeDocument(transaction, broker, name, node, mediaType, createdDate, lastModifiedDate, permission, documentType, xmlReader); + } + @Deprecated @Override public IndexInfo validateXMLResource(final Txn transaction, final DBBroker broker, final XmldbURI name, final InputSource source) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException { @@ -473,7 +518,7 @@ public BinaryDocument addBinaryResource(final Txn transaction, final DBBroker br } @Override - public void serialize(final VariableByteOutputStream outputStream) throws IOException, LockException { + public void serialize(final VariableByteOutput outputStream) throws IOException, LockException { collection.serialize(outputStream); } diff --git a/exist-core/src/main/java/org/exist/collections/MutableCollection.java b/exist-core/src/main/java/org/exist/collections/MutableCollection.java index c8bbd757f5..03eb981dc0 100644 --- a/exist-core/src/main/java/org/exist/collections/MutableCollection.java +++ b/exist-core/src/main/java/org/exist/collections/MutableCollection.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -48,7 +72,7 @@ import org.exist.security.Subject; import org.exist.storage.*; import org.exist.storage.io.VariableByteInput; -import org.exist.storage.io.VariableByteOutputStream; +import org.exist.storage.io.VariableByteOutput; import org.exist.storage.lock.*; import org.exist.storage.lock.Lock.LockMode; import org.exist.storage.lock.Lock.LockType; @@ -68,6 +92,8 @@ import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; +import xyz.elemental.mediatype.MediaType; +import xyz.elemental.mediatype.StorageType; import javax.annotation.Nullable; @@ -171,7 +197,7 @@ private MutableCollection(final DBBroker broker, final int collectionId, /** * Deserializes a Collection object * - * Counterpart method to {@link #serialize(VariableByteOutputStream)} + * Counterpart method to {@link #serialize(VariableByteOutput)} * * @param broker The database broker * @param path The path of the Collection @@ -860,7 +886,7 @@ public Iterator iteratorNoLock(final DBBroker broker) throws Permi * @param outputStream The output stream to write the collection contents to */ @Override - public void serialize(final VariableByteOutputStream outputStream) throws IOException, LockException { + public void serialize(final VariableByteOutput outputStream) throws IOException, LockException { outputStream.writeInt(collectionId); final int size; @@ -890,7 +916,7 @@ public void close() { /** * Read collection contents from the stream * - * Counterpart method to {@link #serialize(VariableByteOutputStream)} + * Counterpart method to {@link #serialize(VariableByteOutput)} * * @param broker The database broker * @param path The path of the Collection @@ -1100,17 +1126,27 @@ public void removeBinaryResource(final Txn transaction, final DBBroker broker, f } @Override - public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final InputSource source, @Nullable MimeType mimeType) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final InputSource source, @Nullable final MimeType mimeType) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { storeDocument(transaction, broker, name, source, mimeType, null, null, null, null, null); } @Override - public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final InputSource source, @Nullable MimeType mimeType, final @Nullable Date createdDate, final @Nullable Date lastModifiedDate, final @Nullable Permission permission, final @Nullable DocumentType documentType, @Nullable final XMLReader xmlReader) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { - if (mimeType == null) { - mimeType = MimeType.BINARY_TYPE; + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final InputSource source, @Nullable final MediaType mediaType) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { + storeDocument(transaction, broker, name, source, mediaType, null, null, null, null, null); + } + + @Override + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final InputSource source, @Nullable final MimeType mimeType, final @Nullable Date createdDate, final @Nullable Date lastModifiedDate, final @Nullable Permission permission, final @Nullable DocumentType documentType, @Nullable final XMLReader xmlReader) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { + storeDocument(transaction, broker, name, source, mimeType.toMediaType(), createdDate, lastModifiedDate, permission, documentType, xmlReader); + } + + @Override + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final InputSource source, @Nullable MediaType mediaType, final @Nullable Date createdDate, final @Nullable Date lastModifiedDate, final @Nullable Permission permission, final @Nullable DocumentType documentType, @Nullable final XMLReader xmlReader) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { + if (mediaType == null) { + mediaType = broker.getBrokerPool().getMediaTypeService().getMediaTypeResolver().forUnknown(); } - if (mimeType.isXMLType()) { + if (mediaType.getStorageType() == StorageType.XML) { // Store XML Document final BiConsumer2E validatorFn = (xmlReader1, validateIndexInfo) -> { @@ -1133,7 +1169,7 @@ public void storeDocument(final Txn transaction, final DBBroker broker, final Xm } }; - storeXmlDocument(transaction, broker, name, mimeType, createdDate, lastModifiedDate, permission, documentType, xmlReader, validatorFn, parserFn); + storeXmlDocument(transaction, broker, name, mediaType, createdDate, lastModifiedDate, permission, documentType, xmlReader, validatorFn, parserFn); } else { // Store Binary Document @@ -1141,23 +1177,33 @@ public void storeDocument(final Txn transaction, final DBBroker broker, final Xm if (is == null) { throw new IOException("storeDocument received a null InputStream when trying to store a Binary Document"); } - addBinaryResource(transaction, broker, name, is, mimeType.getName(), -1, createdDate, lastModifiedDate, permission); + addBinaryResource(transaction, broker, name, is, mediaType.getIdentifier(), -1, createdDate, lastModifiedDate, permission); } } } @Override - public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final Node node, @Nullable MimeType mimeType) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { - storeDocument(transaction, broker, name, node, mimeType); + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final Node node, @Nullable final MimeType mimeType) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { + storeDocument(transaction, broker, name, node, mimeType, null, null, null, null, null); + } + + @Override + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final Node node, @Nullable final MediaType mediaType) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { + storeDocument(transaction, broker, name, node, mediaType, null, null, null, null, null); + } + + @Override + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final Node node, @Nullable final MimeType mimeType, final @Nullable Date createdDate, final @Nullable Date lastModifiedDate, final @Nullable Permission permission, final @Nullable DocumentType documentType, @Nullable final XMLReader xmlReader) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { + storeDocument(transaction, broker, name, node, mimeType.toMediaType(), createdDate, lastModifiedDate, permission, documentType, xmlReader); } @Override - public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final Node node, @Nullable MimeType mimeType, final @Nullable Date createdDate, final @Nullable Date lastModifiedDate, final @Nullable Permission permission, final @Nullable DocumentType documentType, @Nullable final XMLReader xmlReader) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { - if (mimeType == null) { - mimeType = MimeType.BINARY_TYPE; + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final Node node, @Nullable MediaType mediaType, final @Nullable Date createdDate, final @Nullable Date lastModifiedDate, final @Nullable Permission permission, final @Nullable DocumentType documentType, @Nullable final XMLReader xmlReader) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { + if (mediaType == null) { + mediaType = broker.getBrokerPool().getMediaTypeService().getMediaTypeResolver().forUnknown(); } - if (mimeType.isXMLType()) { + if (mediaType.getStorageType() == StorageType.XML) { // Store XML Document final BiConsumer2E validatorFn = (xmlReader1, validateIndexInfo) -> { validateIndexInfo.setReader(xmlReader1, null); @@ -1170,14 +1216,14 @@ public void storeDocument(final Txn transaction, final DBBroker broker, final Xm storeIndexInfo.getDOMStreamer().serialize(node, true); }; - storeXmlDocument(transaction, broker, name, mimeType, createdDate, lastModifiedDate, permission, documentType, xmlReader, validatorFn, parserFn); + storeXmlDocument(transaction, broker, name, mediaType, createdDate, lastModifiedDate, permission, documentType, xmlReader, validatorFn, parserFn); } else { throw new EXistException("Cannot store DOM Node as a Binary Document to URI: " + getURI().append(name)); } } - private void storeXmlDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final MimeType mimeType, final @Nullable Date createdDate, final @Nullable Date lastModifiedDate, final @Nullable Permission permission, final @Nullable DocumentType documentType, @Nullable final XMLReader xmlReader, final BiConsumer2E validatorFn, final BiConsumer2E parserFn) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { + private void storeXmlDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final MediaType mediaType, final @Nullable Date createdDate, final @Nullable Date lastModifiedDate, final @Nullable Permission permission, final @Nullable DocumentType documentType, @Nullable final XMLReader xmlReader, final BiConsumer2E validatorFn, final BiConsumer2E parserFn) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { final CollectionConfiguration colconf = getConfiguration(broker); // borrow a default XML Reader if needed @@ -1196,7 +1242,7 @@ private void storeXmlDocument(final Txn transaction, final DBBroker broker, fina // Phase 2 of 3 - Set the metadata for the document final DocumentImpl document = indexInfo.getDocument(); - document.setMimeType(mimeType.getName()); + document.setMediaType(mediaType.getIdentifier()); if (createdDate != null) { document.setCreated(createdDate.getTime()); if (lastModifiedDate == null) { @@ -1808,7 +1854,7 @@ public BinaryDocument addBinaryResource(final Txn transaction, final DBBroker br } private BinaryDocument addBinaryResource(final Database db, final Txn transaction, final DBBroker broker, - final BinaryDocument blob, final InputStream is, final String mimeType, @Deprecated final long size, final Date created, + final BinaryDocument blob, final InputStream is, final String mediaType, @Deprecated final long size, final Date created, final Date modified, @Nullable final Permission permission, final DBBroker.PreserveType preserve, final DocumentImpl oldDoc, final ManagedCollectionLock collectionLock) throws EXistException, PermissionDeniedException, LockException, TriggerException, IOException { @@ -1822,7 +1868,7 @@ private BinaryDocument addBinaryResource(final Database db, final Txn transactio if (!broker.preserveOnCopy(preserve)) { blob.copyOf(broker, blob, oldDoc); } - blob.setMimeType(mimeType == null ? MimeType.BINARY_TYPE.getName() : mimeType); + blob.setMediaType(mediaType != null ? mediaType : MediaType.APPLICATION_OCTET_STREAM); if (created != null) { blob.setCreated(created.getTime()); } diff --git a/exist-core/src/main/java/org/exist/collections/triggers/CollectionTrigger.java b/exist-core/src/main/java/org/exist/collections/triggers/CollectionTrigger.java index 97b6384a69..d8ee5d4160 100644 --- a/exist-core/src/main/java/org/exist/collections/triggers/CollectionTrigger.java +++ b/exist-core/src/main/java/org/exist/collections/triggers/CollectionTrigger.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -37,7 +61,7 @@ public interface CollectionTrigger extends Trigger { * This method is called once before the database will actually create, remove or rename a collection. You may * take any action here, using the supplied broker instance. * - * @param broker eXist-db broker + * @param broker the broker * @param txn the transaction * @param uri of the collection the trigger listens on * @throws TriggerException if an error in the trigger function is thrown @@ -47,7 +71,7 @@ public interface CollectionTrigger extends Trigger { /** * This method is called after the operation has completed. * - * @param broker eXist-db broker + * @param broker the broker * @param txn the transaction * @param collection the trigger listens on * @throws TriggerException if an error in the trigger function is thrown diff --git a/exist-core/src/main/java/org/exist/collections/triggers/CollectionTriggers.java b/exist-core/src/main/java/org/exist/collections/triggers/CollectionTriggers.java index 412b0e08aa..94ec596c30 100644 --- a/exist-core/src/main/java/org/exist/collections/triggers/CollectionTriggers.java +++ b/exist-core/src/main/java/org/exist/collections/triggers/CollectionTriggers.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -39,119 +63,146 @@ public class CollectionTriggers implements CollectionTrigger { private final List triggers; - public CollectionTriggers(DBBroker broker, Txn transaction) throws TriggerException { + public CollectionTriggers(final DBBroker broker, final Txn transaction) throws TriggerException { this(broker, transaction, null, null); } - public CollectionTriggers(DBBroker broker, Txn transaction, Collection collection) throws TriggerException { + public CollectionTriggers(final DBBroker broker, final Txn transaction, final Collection collection) throws TriggerException { this(broker, transaction, collection, collection.getConfiguration(broker)); } - public CollectionTriggers(DBBroker broker, Txn transaction, Collection collection, CollectionConfiguration config) throws TriggerException { - - List> colTriggers = null; - if (config != null) { - colTriggers = config.collectionTriggers(); - } - - java.util.Collection> masterTriggers = broker.getDatabase().getCollectionTriggers(); + public CollectionTriggers(final DBBroker broker, final Txn transaction, final Collection collection, final CollectionConfiguration config) throws TriggerException { + final List> colTriggers = config != null ? config.collectionTriggers() : null; + final java.util.Collection> masterTriggers = broker.getDatabase().getCollectionTriggers(); triggers = new ArrayList<>(masterTriggers.size() + (colTriggers == null ? 0 : colTriggers.size())); - for (TriggerProxy colTrigger : masterTriggers) { - - CollectionTrigger instance = colTrigger.newInstance(broker, transaction, collection); - + for (final TriggerProxy colTrigger : masterTriggers) { + final CollectionTrigger instance = colTrigger.newInstance(broker, transaction, collection); register(instance); } if (colTriggers != null) { - for (TriggerProxy colTrigger : colTriggers) { - - CollectionTrigger instance = colTrigger.newInstance(broker, transaction, collection); - + for (final TriggerProxy colTrigger : colTriggers) { + final CollectionTrigger instance = colTrigger.newInstance(broker, transaction, collection); register(instance); } } } - private void register(CollectionTrigger trigger) { + private void register(final CollectionTrigger trigger) { triggers.add(trigger); } @Override - public void configure(DBBroker broker, Txn transaction, Collection col, Map> parameters) throws TriggerException { + public void configure(final DBBroker broker, final Txn transaction, final Collection col, final Map> parameters) throws TriggerException { } @Override - public void beforeCreateCollection(DBBroker broker, Txn txn, XmldbURI uri) throws TriggerException { - for (CollectionTrigger trigger : triggers) { - trigger.beforeCreateCollection(broker, txn, uri); + public void beforeCreateCollection(final DBBroker broker, final Txn txn, final XmldbURI uri) throws TriggerException { + for (final CollectionTrigger trigger : triggers) { + try { + trigger.beforeCreateCollection(broker, txn, uri); + } catch (final Exception e) { + logAndThrowError("beforeCreateCollection", trigger, uri, e); + } } } @Override - public void afterCreateCollection(DBBroker broker, Txn txn, Collection collection) { - for (CollectionTrigger trigger : triggers) { + public void afterCreateCollection(final DBBroker broker, final Txn txn, final Collection collection) { + for (final CollectionTrigger trigger : triggers) { try { trigger.afterCreateCollection(broker, txn, collection); - } catch (Exception e) { - Trigger.LOG.error(e.getMessage(), e); + } catch (final Exception e) { + logError("afterCreateCollection", trigger, collection.getURI(), e); } } } @Override - public void beforeCopyCollection(DBBroker broker, Txn txn, Collection collection, XmldbURI newUri) throws TriggerException { - for (CollectionTrigger trigger : triggers) { - trigger.beforeCopyCollection(broker, txn, collection, newUri); + public void beforeCopyCollection(final DBBroker broker, final Txn txn, final Collection collection, final XmldbURI newUri) throws TriggerException { + for (final CollectionTrigger trigger : triggers) { + try { + trigger.beforeCopyCollection(broker, txn, collection, newUri); + } catch (final Exception e) { + logAndThrowError("beforeCopyCollection", trigger, collection.getURI(), e); + } } } @Override - public void afterCopyCollection(DBBroker broker, Txn txn, Collection collection, XmldbURI oldUri) { - for (CollectionTrigger trigger : triggers) { + public void afterCopyCollection(final DBBroker broker, final Txn txn, final Collection collection, final XmldbURI oldUri) { + for (final CollectionTrigger trigger : triggers) { try { trigger.afterCopyCollection(broker, txn, collection, oldUri); - } catch (Exception e) { - Trigger.LOG.error(e.getMessage(), e); + } catch (final Exception e) { + logError("afterCopyCollection", trigger, oldUri, e); } } } @Override - public void beforeMoveCollection(DBBroker broker, Txn txn, Collection collection, XmldbURI newUri) throws TriggerException { - for (CollectionTrigger trigger : triggers) { - trigger.beforeMoveCollection(broker, txn, collection, newUri); + public void beforeMoveCollection(final DBBroker broker, final Txn txn, final Collection collection, final XmldbURI newUri) throws TriggerException { + for (final CollectionTrigger trigger : triggers) { + try { + trigger.beforeMoveCollection(broker, txn, collection, newUri); + } catch (final Exception e) { + logAndThrowError("beforeMoveCollection", trigger, collection.getURI(), e); + } } } @Override - public void afterMoveCollection(DBBroker broker, Txn txn, Collection collection, XmldbURI oldUri) { - for (CollectionTrigger trigger : triggers) { + public void afterMoveCollection(final DBBroker broker, final Txn txn, final Collection collection, final XmldbURI oldUri) { + for (final CollectionTrigger trigger : triggers) { try { trigger.afterMoveCollection(broker, txn, collection, oldUri); - } catch (Exception e) { - Trigger.LOG.error(e.getMessage(), e); + } catch (final Exception e) { + logError("afterMoveCollection", trigger, oldUri, e); } } } @Override - public void beforeDeleteCollection(DBBroker broker, Txn txn, Collection collection) throws TriggerException { - for (CollectionTrigger trigger : triggers) { - trigger.beforeDeleteCollection(broker, txn, collection); + public void beforeDeleteCollection(final DBBroker broker, final Txn txn, final Collection collection) throws TriggerException { + for (final CollectionTrigger trigger : triggers) { + try { + trigger.beforeDeleteCollection(broker, txn, collection); + } catch (final Exception e) { + logAndThrowError("beforeDeleteCollection", trigger, collection.getURI(), e); + } } } @Override - public void afterDeleteCollection(DBBroker broker, Txn txn, XmldbURI uri) { - for (CollectionTrigger trigger : triggers) { + public void afterDeleteCollection(final DBBroker broker, final Txn txn, final XmldbURI uri) { + for (final CollectionTrigger trigger : triggers) { try { trigger.afterDeleteCollection(broker, txn, uri); - } catch (Exception e) { - Trigger.LOG.error(e.getMessage(), e); + } catch (final Exception e) { + logError("afterDeleteCollection", trigger, uri, e); } } } + + private void logAndThrowError(final String eventName, final CollectionTrigger collectionTrigger, final XmldbURI source, final Exception e) throws TriggerException { + logError(eventName, collectionTrigger, source, e); + throwError(e); + } + + private void logError(final String eventName, final CollectionTrigger collectionTrigger, final XmldbURI source, final Exception e) { + final String message = String.format("Error in %s#%s triggered by: %s, %s", collectionTrigger.getClass().getSimpleName(), eventName, source, e.getMessage()); + Trigger.LOG.error(message, e); + } + + private void throwError(final Exception e) throws TriggerException { + if (e instanceof TriggerException) { + throw (TriggerException) e; + } else if (e instanceof RuntimeException) { + throw (RuntimeException) e; + } else { + throw new TriggerException(e); + } + } } diff --git a/exist-core/src/main/java/org/exist/collections/triggers/DocumentTrigger.java b/exist-core/src/main/java/org/exist/collections/triggers/DocumentTrigger.java index 5177163ebf..3c4d4ca669 100644 --- a/exist-core/src/main/java/org/exist/collections/triggers/DocumentTrigger.java +++ b/exist-core/src/main/java/org/exist/collections/triggers/DocumentTrigger.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -79,7 +103,7 @@ public interface DocumentTrigger extends Trigger { * This method is called once before the database will actually parse the input data. You may take any action * here, using the supplied broker instance. * - * @param broker eXist-db DBBroker + * @param broker the DBBroker * @param txn transaction * @param uri the uri * @throws TriggerException in case of an error @@ -90,7 +114,7 @@ public interface DocumentTrigger extends Trigger { * This method is called after the operation completed. At this point, the document has already * been stored. * - * @param broker eXist-db DBBroker + * @param broker the DBBroker * @param txn transaction * @param document stored document * @throws TriggerException in case of an error diff --git a/exist-core/src/main/java/org/exist/collections/triggers/DocumentTriggers.java b/exist-core/src/main/java/org/exist/collections/triggers/DocumentTriggers.java index 6a9e3a9a77..c3da578b0c 100644 --- a/exist-core/src/main/java/org/exist/collections/triggers/DocumentTriggers.java +++ b/exist-core/src/main/java/org/exist/collections/triggers/DocumentTriggers.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -58,37 +82,28 @@ public class DocumentTriggers implements DocumentTrigger, ContentHandler, Lexica private final List triggers; - public DocumentTriggers(DBBroker broker, Txn transaction) throws TriggerException { + public DocumentTriggers(final DBBroker broker, final Txn transaction) throws TriggerException { this(broker, transaction, null, null, null); } - public DocumentTriggers(DBBroker broker, Txn transaction, Collection collection) throws TriggerException { + public DocumentTriggers(final DBBroker broker, final Txn transaction, final Collection collection) throws TriggerException { this(broker, transaction, null, collection, broker.isTriggersEnabled() ? collection.getConfiguration(broker) : null); } - public DocumentTriggers(DBBroker broker, Txn transaction, Indexer indexer, Collection collection, CollectionConfiguration config) throws TriggerException { - - List> docTriggers = null; - if (config != null) { - docTriggers = config.documentTriggers(); - } - - java.util.Collection> masterTriggers = broker.getDatabase().getDocumentTriggers(); + public DocumentTriggers(final DBBroker broker, final Txn transaction, final Indexer indexer, final Collection collection, final CollectionConfiguration config) throws TriggerException { + final List> docTriggers = config != null ? config.documentTriggers() : null; + final java.util.Collection> masterTriggers = broker.getDatabase().getDocumentTriggers(); triggers = new ArrayList<>(masterTriggers.size() + (docTriggers == null ? 0 : docTriggers.size())); - for (TriggerProxy docTrigger : masterTriggers) { - - DocumentTrigger instance = docTrigger.newInstance(broker, transaction, collection); - + for (final TriggerProxy docTrigger : masterTriggers) { + final DocumentTrigger instance = docTrigger.newInstance(broker, transaction, collection); register(instance); } if (docTriggers != null) { - for (TriggerProxy docTrigger : docTriggers) { - - DocumentTrigger instance = docTrigger.newInstance(broker, transaction, collection); - + for (final TriggerProxy docTrigger : docTriggers) { + final DocumentTrigger instance = docTrigger.newInstance(broker, transaction, collection); register(instance); } } @@ -100,7 +115,7 @@ public DocumentTriggers(DBBroker broker, Txn transaction, Indexer indexer, Colle last = null; } - private void finishPreparation(Indexer indexer) { + private void finishPreparation(final Indexer indexer) { if (last == null) { contentHandler = indexer; lexicalHandler = indexer; @@ -112,9 +127,8 @@ private void finishPreparation(Indexer indexer) { this.indexer = indexer; } - private void register(DocumentTrigger trigger) { + private void register(final DocumentTrigger trigger) { if (trigger instanceof SAXTrigger filteringTrigger) { - if (last == null) { contentHandler = filteringTrigger; lexicalHandler = filteringTrigger; @@ -131,11 +145,11 @@ private void register(DocumentTrigger trigger) { } @Override - public void configure(DBBroker broker, Txn txn, Collection parent, Map> parameters) throws TriggerException { + public void configure(final DBBroker broker, final Txn txn, final Collection parent, final Map> parameters) throws TriggerException { } @Override - public void setDocumentLocator(Locator locator) { + public void setDocumentLocator(final Locator locator) { contentHandler.setDocumentLocator(locator); } @@ -155,12 +169,12 @@ public void endDocument() throws SAXException { } @Override - public void startPrefixMapping(String prefix, String uri) throws SAXException { + public void startPrefixMapping(final String prefix, final String uri) throws SAXException { contentHandler.startPrefixMapping(prefix, uri); } @Override - public void endPrefixMapping(String prefix) throws SAXException { + public void endPrefixMapping(final String prefix) throws SAXException { contentHandler.endPrefixMapping(prefix); } @@ -170,32 +184,32 @@ public void startElement(String uri, String localName, String qName, Attributes } @Override - public void endElement(String uri, String localName, String qName) throws SAXException { + public void endElement(final String uri, final String localName, final String qName) throws SAXException { contentHandler.endElement(uri, localName, qName); } @Override - public void characters(char[] ch, int start, int length) throws SAXException { + public void characters(final char[] ch, final int start, final int length) throws SAXException { contentHandler.characters(ch, start, length); } @Override - public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { + public void ignorableWhitespace(final char[] ch, final int start, final int length) throws SAXException { contentHandler.ignorableWhitespace(ch, start, length); } @Override - public void processingInstruction(String target, String data) throws SAXException { + public void processingInstruction(final String target, final String data) throws SAXException { contentHandler.processingInstruction(target, data); } @Override - public void skippedEntity(String name) throws SAXException { + public void skippedEntity(final String name) throws SAXException { contentHandler.skippedEntity(name); } @Override - public void startDTD(String name, String publicId, String systemId) throws SAXException { + public void startDTD(final String name, final String publicId, final String systemId) throws SAXException { lexicalHandler.startDTD(name, publicId, systemId); } @@ -205,12 +219,12 @@ public void endDTD() throws SAXException { } @Override - public void startEntity(String name) throws SAXException { + public void startEntity(final String name) throws SAXException { lexicalHandler.startEntity(name); } @Override - public void endEntity(String name) throws SAXException { + public void endEntity(final String name) throws SAXException { lexicalHandler.endEntity(name); } @@ -225,114 +239,138 @@ public void endCDATA() throws SAXException { } @Override - public void comment(char[] ch, int start, int length) throws SAXException { + public void comment(final char[] ch, final int start, final int length) throws SAXException { lexicalHandler.comment(ch, start, length); } @Override - public void beforeCreateDocument(DBBroker broker, Txn txn, XmldbURI uri) throws TriggerException { - for (DocumentTrigger trigger : triggers) { - trigger.beforeCreateDocument(broker, txn, uri); + public void beforeCreateDocument(final DBBroker broker, final Txn txn, final XmldbURI uri) throws TriggerException { + for (final DocumentTrigger trigger : triggers) { + try { + trigger.beforeCreateDocument(broker, txn, uri); + } catch (final Exception e) { + logAndThrowError("beforeCreateDocument", trigger, uri, e); + } } } @Override - public void afterCreateDocument(DBBroker broker, Txn txn, DocumentImpl document) { - for (DocumentTrigger trigger : triggers) { + public void afterCreateDocument(final DBBroker broker, final Txn txn, final DocumentImpl document) { + for (final DocumentTrigger trigger : triggers) { try { trigger.afterCreateDocument(broker, txn, document); - } catch (Exception e) { - Trigger.LOG.error(e.getMessage(), e); + } catch (final Exception e) { + logError("afterCreateDocument", trigger, document.getURI(), e); } } } @Override - public void beforeUpdateDocument(DBBroker broker, Txn txn, DocumentImpl document) throws TriggerException { - for (DocumentTrigger trigger : triggers) { - trigger.beforeUpdateDocument(broker, txn, document); + public void beforeUpdateDocument(final DBBroker broker, final Txn txn, final DocumentImpl document) throws TriggerException { + for (final DocumentTrigger trigger : triggers) { + try { + trigger.beforeUpdateDocument(broker, txn, document); + } catch (final Exception e) { + logAndThrowError("beforeUpdateDocument", trigger, document.getURI(), e); + } } } @Override - public void afterUpdateDocument(DBBroker broker, Txn txn, DocumentImpl document) { - for (DocumentTrigger trigger : triggers) { + public void afterUpdateDocument(final DBBroker broker, final Txn txn, final DocumentImpl document) { + for (final DocumentTrigger trigger : triggers) { try { trigger.afterUpdateDocument(broker, txn, document); - } catch (Exception e) { - Trigger.LOG.error(e.getMessage(), e); + } catch (final Exception e) { + logError("afterUpdateDocument", trigger, document.getURI(), e); } } } @Override - public void beforeUpdateDocumentMetadata(DBBroker broker, Txn txn, DocumentImpl document) throws TriggerException { - for (DocumentTrigger trigger : triggers) { - trigger.beforeUpdateDocumentMetadata(broker, txn, document); + public void beforeUpdateDocumentMetadata(final DBBroker broker, final Txn txn, final DocumentImpl document) throws TriggerException { + for (final DocumentTrigger trigger : triggers) { + try { + trigger.beforeUpdateDocumentMetadata(broker, txn, document); + } catch (final Exception e) { + logAndThrowError("beforeUpdateDocumentMetadata", trigger, document.getURI(), e); + } } } @Override - public void afterUpdateDocumentMetadata(DBBroker broker, Txn txn, DocumentImpl document) { - for (DocumentTrigger trigger : triggers) { + public void afterUpdateDocumentMetadata(final DBBroker broker, final Txn txn, final DocumentImpl document) { + for (final DocumentTrigger trigger : triggers) { try { trigger.afterUpdateDocumentMetadata(broker, txn, document); - } catch (Exception e) { - Trigger.LOG.error(e.getMessage(), e); + } catch (final Exception e) { + logError("afterUpdateDocumentMetadata", trigger, document.getURI(), e); } } } @Override - public void beforeCopyDocument(DBBroker broker, Txn txn, DocumentImpl document, XmldbURI newUri) throws TriggerException { - for (DocumentTrigger trigger : triggers) { - trigger.beforeCopyDocument(broker, txn, document, newUri); + public void beforeCopyDocument(final DBBroker broker, final Txn txn, final DocumentImpl document, final XmldbURI newUri) throws TriggerException { + for (final DocumentTrigger trigger : triggers) { + try { + trigger.beforeCopyDocument(broker, txn, document, newUri); + } catch (final Exception e) { + logAndThrowError("beforeCopyDocument", trigger, document.getURI(), e); + } } } @Override - public void afterCopyDocument(DBBroker broker, Txn txn, DocumentImpl document, XmldbURI oldUri) { - for (DocumentTrigger trigger : triggers) { + public void afterCopyDocument(final DBBroker broker, final Txn txn, final DocumentImpl document, final XmldbURI oldUri) { + for (final DocumentTrigger trigger : triggers) { try { trigger.afterCopyDocument(broker, txn, document, oldUri); - } catch (Exception e) { - Trigger.LOG.error(e.getMessage(), e); + } catch (final Exception e) { + logError("afterCopyDocument", trigger, oldUri, e); } } } @Override - public void beforeMoveDocument(DBBroker broker, Txn txn, DocumentImpl document, XmldbURI newUri) throws TriggerException { - for (DocumentTrigger trigger : triggers) { - trigger.beforeMoveDocument(broker, txn, document, newUri); + public void beforeMoveDocument(final DBBroker broker, final Txn txn, final DocumentImpl document, final XmldbURI newUri) throws TriggerException { + for (final DocumentTrigger trigger : triggers) { + try { + trigger.beforeMoveDocument(broker, txn, document, newUri); + } catch (final Exception e) { + logAndThrowError("beforeMoveDocument", trigger, document.getURI(), e); + } } } @Override - public void afterMoveDocument(DBBroker broker, Txn txn, DocumentImpl document, XmldbURI oldUri) { - for (DocumentTrigger trigger : triggers) { + public void afterMoveDocument(final DBBroker broker, final Txn txn, final DocumentImpl document, final XmldbURI oldUri) { + for (final DocumentTrigger trigger : triggers) { try { trigger.afterMoveDocument(broker, txn, document, oldUri); - } catch (Exception e) { - Trigger.LOG.error(e.getMessage(), e); + } catch (final Exception e) { + logError("afterMoveDocument", trigger, oldUri, e); } } } @Override - public void beforeDeleteDocument(DBBroker broker, Txn txn, DocumentImpl document) throws TriggerException { - for (DocumentTrigger trigger : triggers) { - trigger.beforeDeleteDocument(broker, txn, document); + public void beforeDeleteDocument(final DBBroker broker, final Txn txn, final DocumentImpl document) throws TriggerException { + for (final DocumentTrigger trigger : triggers) { + try { + trigger.beforeDeleteDocument(broker, txn, document); + } catch (final Exception e) { + logAndThrowError("beforeDeleteDocument", trigger, document.getURI(), e); + } } } @Override - public void afterDeleteDocument(DBBroker broker, Txn txn, XmldbURI uri) { - for (DocumentTrigger trigger : triggers) { + public void afterDeleteDocument(final DBBroker broker, final Txn txn, final XmldbURI uri) { + for (final DocumentTrigger trigger : triggers) { try { trigger.afterDeleteDocument(broker, txn, uri); - } catch (Exception e) { - Trigger.LOG.error(e.getMessage(), e); + } catch (final Exception e) { + logError("afterDeleteDocument", trigger, uri, e); } } } @@ -343,8 +381,8 @@ public boolean isValidating() { } @Override - public void setValidating(boolean validating) { - for (DocumentTrigger trigger : triggers) { + public void setValidating(final boolean validating) { + for (final DocumentTrigger trigger : triggers) { trigger.setValidating(validating); } @@ -352,20 +390,43 @@ public void setValidating(boolean validating) { } @Override - public void warning(SAXParseException exception) throws SAXException { - if (errorHandler != null) + public void warning(final SAXParseException exception) throws SAXException { + if (errorHandler != null) { errorHandler.warning(exception); + } } @Override - public void error(SAXParseException exception) throws SAXException { - if (errorHandler != null) + public void error(final SAXParseException exception) throws SAXException { + if (errorHandler != null) { errorHandler.error(exception); + } } @Override - public void fatalError(SAXParseException exception) throws SAXException { - if (errorHandler != null) + public void fatalError(final SAXParseException exception) throws SAXException { + if (errorHandler != null) { errorHandler.fatalError(exception); + } + } + + private void logAndThrowError(final String eventName, final DocumentTrigger documentTrigger, final XmldbURI source, final Exception e) throws TriggerException { + logError(eventName, documentTrigger, source, e); + throwError(e); + } + + private void logError(final String eventName, final DocumentTrigger documentTrigger, final XmldbURI source, final Exception e) { + final String message = String.format("Error in %s#%s triggered by: %s, %s", documentTrigger.getClass().getSimpleName(), eventName, source, e.getMessage()); + Trigger.LOG.error(message, e); + } + + private void throwError(final Exception e) throws TriggerException { + if (e instanceof TriggerException) { + throw (TriggerException) e; + } else if (e instanceof RuntimeException) { + throw (RuntimeException) e; + } else { + throw new TriggerException(e); + } } } diff --git a/exist-core/src/main/java/org/exist/collections/triggers/XQueryStartupTrigger.java b/exist-core/src/main/java/org/exist/collections/triggers/XQueryStartupTrigger.java index 15e16e53d4..5c7d909028 100644 --- a/exist-core/src/main/java/org/exist/collections/triggers/XQueryStartupTrigger.java +++ b/exist-core/src/main/java/org/exist/collections/triggers/XQueryStartupTrigger.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -23,7 +47,6 @@ import java.util.*; -import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.exist.collections.Collection; @@ -44,6 +67,10 @@ import org.exist.xquery.XQuery; import org.exist.xquery.XQueryContext; import org.exist.xquery.value.Sequence; +import xyz.elemental.mediatype.MediaType; + +import static org.exist.util.StringUtil.endsWith; +import static org.exist.util.StringUtil.substringBeforeLast; /** * Startup Trigger to fire XQuery scripts during database startup. @@ -78,7 +105,7 @@ public class XQueryStartupTrigger implements StartupTrigger { private static final String XQUERY = "xquery"; private static final String AUTOSTART_COLLECTION = "/db/system/autostart"; private static final String[] XQUERY_EXTENSIONS = {".xq", ".xquery", ".xqy"}; - private static final String REQUIRED_MIMETYPE = "application/xquery"; + private static final String REQUIRED_MIMETYPE = MediaType.APPLICATION_XQUERY; @Override public void execute(DBBroker broker, final Txn transaction, Map> params) { @@ -124,7 +151,7 @@ private List getScriptsInStartupCollection(DBBroker broker) { if (isPermissionsOK(document)) { - if (StringUtils.endsWithAny(docPath, XQUERY_EXTENSIONS)) { + if (endsWith(docPath, XQUERY_EXTENSIONS)) { paths.add(XmldbURI.EMBEDDED_SERVER_URI_PREFIX + docPath); } else { @@ -182,7 +209,7 @@ private boolean isPermissionsOK(final DocumentImpl document) { return (perms.getOwner().hasDbaRole() && perms.getGroup().getName().equals(SecurityManager.DBA_GROUP) && perms.getMode() == Permission.DEFAULT_SYSTEM_SECURITY_COLLECTION_PERM - && document.getMimeType().equals(REQUIRED_MIMETYPE)); + && document.getMediaType().equals(REQUIRED_MIMETYPE)); } @@ -255,7 +282,7 @@ private void executeQuery(DBBroker broker, String path) { context = new XQueryContext(broker.getBrokerPool()); // Allow use of modules with relative paths - String moduleLoadPath = StringUtils.substringBeforeLast(path, "/"); + String moduleLoadPath = substringBeforeLast(path, "/"); context.setModuleLoadPath(moduleLoadPath); // Compile query diff --git a/exist-core/src/main/java/org/exist/collections/triggers/XQueryTrigger.java b/exist-core/src/main/java/org/exist/collections/triggers/XQueryTrigger.java index e05ae35d8f..4ca09b7e63 100644 --- a/exist-core/src/main/java/org/exist/collections/triggers/XQueryTrigger.java +++ b/exist-core/src/main/java/org/exist/collections/triggers/XQueryTrigger.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -49,6 +73,8 @@ import org.exist.xquery.value.Sequence; import org.exist.xquery.value.StringValue; +import javax.annotation.Nullable; + import static com.evolvedbinary.j8fu.tuple.Tuple.Tuple; /** @@ -232,33 +258,47 @@ private void prepare(final TriggerEvent event, final DBBroker broker, final Txn LOG.warn(e.getMessage()); return; } - - final XQueryContext context = new XQueryContext(broker.getBrokerPool()); - CompiledXQuery compiledQuery = null; - try { - //compile the XQuery - compiledQuery = service.compile(context, query); - declareExternalVariables(context, TriggerPhase.BEFORE, event, src, dst, isCollection); - - } catch (final XPathException | IOException | PermissionDeniedException e) { - TriggerStatePerThread.clear(); - throw new TriggerException(PREPARE_EXCEPTION_MESSAGE, e); - } - //execute the XQuery + @Nullable CompiledXQuery compiled = null; + @Nullable XQueryContext context = null; try { - //TODO : should we provide another contextSet ? - final NodeSet contextSet = NodeSet.EMPTY_SET; - service.execute(broker, compiledQuery, contextSet); - //TODO : should we have a special processing ? - if (LOG.isDebugEnabled()) { - LOG.debug("Trigger fired for prepare"); - } - } catch (final XPathException | PermissionDeniedException e) { - TriggerStatePerThread.clear(); - throw new TriggerException(PREPARE_EXCEPTION_MESSAGE, e); + + compiled = broker.getBrokerPool().getXQueryPool().borrowCompiledXQuery(broker, query); + if (compiled == null) { + context = new XQueryContext(broker.getBrokerPool()); + } else { + context = compiled.getContext(); + context.prepareForReuse(); + } + + if (compiled == null) { + compiled = service.compile(context, query); + } else { + compiled.getContext().updateContext(context); + context.getWatchDog().reset(); + } + + declareExternalVariables(context, TriggerPhase.BEFORE, event, src, dst, isCollection); + + //execute the XQuery + //TODO : should we provide another contextSet ? + final NodeSet contextSet = NodeSet.EMPTY_SET; + service.execute(broker, compiled, contextSet); + //TODO : should we have a special processing ? + if (LOG.isDebugEnabled()) { + LOG.debug("Trigger fired for prepare"); + } + + } catch (final XPathException | IOException | PermissionDeniedException e) { + TriggerStatePerThread.clear(); + throw new TriggerException(PREPARE_EXCEPTION_MESSAGE, e); } finally { - context.runCleanupTasks(); + if (context != null) { + context.runCleanupTasks(); + } + if (compiled != null) { + broker.getBrokerPool().getXQueryPool().returnCompiledXQuery(query, compiled); + } } } @@ -276,33 +316,42 @@ private void finish(final TriggerEvent event, final DBBroker broker, final Txn t LOG.warn(e.getMessage()); return; } - - final XQueryContext context = new XQueryContext(broker.getBrokerPool()); - CompiledXQuery compiledQuery = null; + + @Nullable CompiledXQuery compiled = null; + @Nullable XQueryContext context = null; try { - //compile the XQuery - compiledQuery = service.compile(context, query); - declareExternalVariables(context, TriggerPhase.AFTER, event, src, dst, isCollection); + compiled = broker.getBrokerPool().getXQueryPool().borrowCompiledXQuery(broker, query); + if (compiled == null) { + context = new XQueryContext(broker.getBrokerPool()); + } else { + context = compiled.getContext(); + context.prepareForReuse(); + } + + if (compiled == null) { + compiled = service.compile(context, query); + } else { + compiled.getContext().updateContext(context); + context.getWatchDog().reset(); + } + + declareExternalVariables(context, TriggerPhase.AFTER, event, src, dst, isCollection); + + //execute the XQuery + //TODO : should we provide another contextSet ? + final NodeSet contextSet = NodeSet.EMPTY_SET; + service.execute(broker, compiled, contextSet); + //TODO : should we have a special processing ? } catch (final XPathException | IOException | PermissionDeniedException e) { - //Should never be reached - LOG.error(e); - } - - //execute the XQuery - try { - //TODO : should we provide another contextSet ? - final NodeSet contextSet = NodeSet.EMPTY_SET; - service.execute(broker, compiledQuery, contextSet); - //TODO : should we have a special processing ? - } catch (final XPathException e) { - //Should never be reached - LOG.error("Error during trigger finish", e); - } catch (final PermissionDeniedException e) { - //Should never be reached - LOG.error(e); + LOG.error("Error during trigger finish", e); } finally { - context.runCleanupTasks(); + if (context != null) { + context.runCleanupTasks(); + } + if (compiled != null) { + broker.getBrokerPool().getXQueryPool().returnCompiledXQuery(query, compiled); + } } TriggerStatePerThread.clearIfFinished(TriggerPhase.AFTER); @@ -314,28 +363,28 @@ private void finish(final TriggerEvent event, final DBBroker broker, final Txn t private void declareExternalVariables(final XQueryContext context, final TriggerPhase phase, final TriggerEvent event, final XmldbURI src, final XmldbURI dst, final boolean isCollection) throws XPathException { //declare external variables - context.declareVariable(bindingPrefix + "type", new StringValue(phase.legacyPhaseName())); - context.declareVariable(bindingPrefix + "event", new StringValue(event.legacyEventName())); + context.declareVariable(bindingPrefix + "type", true, new StringValue(phase.legacyPhaseName())); + context.declareVariable(bindingPrefix + "event", true, new StringValue(event.legacyEventName())); if (isCollection) { - context.declareVariable(bindingPrefix + "collection", new AnyURIValue(src)); + context.declareVariable(bindingPrefix + "collection", true, new AnyURIValue(src)); } else { - context.declareVariable(bindingPrefix + "collection", new AnyURIValue(src.removeLastSegment())); + context.declareVariable(bindingPrefix + "collection", true, new AnyURIValue(src.removeLastSegment())); } - context.declareVariable(bindingPrefix + "uri", new AnyURIValue(src)); + context.declareVariable(bindingPrefix + "uri", true, new AnyURIValue(src)); if (dst == null) { - context.declareVariable(bindingPrefix + "new-uri", Sequence.EMPTY_SEQUENCE); + context.declareVariable(bindingPrefix + "new-uri", true, Sequence.EMPTY_SEQUENCE); } else { - context.declareVariable(bindingPrefix + "new-uri", new AnyURIValue(dst)); + context.declareVariable(bindingPrefix + "new-uri", true, new AnyURIValue(dst)); } // For backward compatibility - context.declareVariable(bindingPrefix + "eventType", new StringValue(phase.legacyPhaseName())); - context.declareVariable(bindingPrefix + "triggerEvent", new StringValue(event.legacyEventName())); + context.declareVariable(bindingPrefix + "eventType", true, new StringValue(phase.legacyPhaseName())); + context.declareVariable(bindingPrefix + "triggerEvent", true, new StringValue(event.legacyEventName())); if (isCollection) { - context.declareVariable(bindingPrefix + "collectionName", new AnyURIValue(src)); + context.declareVariable(bindingPrefix + "collectionName", true, new AnyURIValue(src)); } else { - context.declareVariable(bindingPrefix + "collectionName", new AnyURIValue(src.removeLastSegment())); - context.declareVariable(bindingPrefix + "documentName", new AnyURIValue(src)); + context.declareVariable(bindingPrefix + "collectionName", true, new AnyURIValue(src.removeLastSegment())); + context.declareVariable(bindingPrefix + "documentName", true, new AnyURIValue(src)); } //declare user defined parameters as external variables @@ -344,7 +393,7 @@ private void declareExternalVariables(final XQueryContext context, final Trigger final String varName = (String) o; final String varValue = userDefinedVariables.getProperty(varName); - context.declareVariable(bindingPrefix + varName, new StringValue(varValue)); + context.declareVariable(bindingPrefix + varName, true, new StringValue(varValue)); } } } @@ -356,16 +405,29 @@ private CompiledXQuery getScript(final DBBroker broker, final Txn transaction) t if(query == null) { return null; } - - final XQueryContext context = new XQueryContext(broker.getBrokerPool()); - if (query instanceof DBSource) { - context.setModuleLoadPath(XmldbURI.EMBEDDED_SERVER_URI_PREFIX + ((DBSource)query).getDocumentPath().removeLastSegment().toString()); - } - CompiledXQuery compiledQuery; + @Nullable CompiledXQuery compiled = null; + @Nullable XQueryContext context = null; try { + compiled = broker.getBrokerPool().getXQueryPool().borrowCompiledXQuery(broker, query); + if (compiled == null) { + context = new XQueryContext(broker.getBrokerPool()); + } else { + context = compiled.getContext(); + context.prepareForReuse(); + } + + if (query instanceof DBSource) { + context.setModuleLoadPath(XmldbURI.EMBEDDED_SERVER_URI_PREFIX + ((DBSource)query).getDocumentPath().removeLastSegment().toString()); + } + //compile the XQuery - compiledQuery = service.compile(context, query); + if (compiled == null) { + compiled = service.compile(context, query); + } else { + compiled.getContext().updateContext(context); + context.getWatchDog().reset(); + } //declare user defined parameters as external variables if (userDefinedVariables != null) { @@ -373,20 +435,18 @@ private CompiledXQuery getScript(final DBBroker broker, final Txn transaction) t final String varName = (String) o; final String varValue = userDefinedVariables.getProperty(varName); - context.declareVariable(bindingPrefix + varName, new StringValue(varValue)); + context.declareVariable(bindingPrefix + varName, true, new StringValue(varValue)); } } - - //reset & prepareForExecution for execution - compiledQuery.reset(); - context.getWatchDog().reset(); - - //do any preparation before execution - context.prepareForExecution(); - - return compiledQuery; + return compiled; } catch(final XPathException | IOException | PermissionDeniedException e) { + if (context != null) { + context.runCleanupTasks(); + } + if (compiled != null) { + broker.getBrokerPool().getXQueryPool().returnCompiledXQuery(query, compiled); + } LOG.warn(e.getMessage(), e); throw new TriggerException(PREPARE_EXCEPTION_MESSAGE, e); } @@ -406,23 +466,18 @@ private void execute(final TriggerPhase phase, final TriggerEvent event, final D LOG.debug("Execute: {} {}({}): {}", phase, event, src, getClass().getSimpleName()); } - final CompiledXQuery compiledQuery; + @Nullable CompiledXQuery compiled = null; + @Nullable XQueryContext context = null; try { - compiledQuery = getScript(broker, transaction); - if (compiledQuery == null) { + compiled = getScript(broker, transaction); + if (compiled == null) { // NOTE: can occur if there is no such XQueryTrigger library module available in the database TriggerStatePerThread.clearIfFinished(phase); return; } - } catch (final TriggerException e) { - TriggerStatePerThread.clear(); - throw e; - } - - final XQueryContext context = compiledQuery.getContext(); + context = compiled.getContext(); - //execute the XQuery - try { + //execute the XQuery final int nParams; if (dst != null) { nParams = 2; @@ -443,13 +498,18 @@ private void execute(final TriggerPhase phase, final TriggerEvent event, final D args.add(new LiteralValue(context, new AnyURIValue(src))); } - service.execute(broker, compiledQuery, Tuple(functionName, args, Optional.empty()), null, null, true); + service.execute(broker, compiled, Tuple(functionName, args, Optional.empty()), null, null, true); + + } catch (final TriggerException e) { + TriggerStatePerThread.clear(); + throw e; + } catch (final XPathException | PermissionDeniedException e) { // if the exception just indicates that there is no function in the trigger to call, then we can just log and return if (e instanceof XPathException xpe) { if (xpe.getErrorCode() == ErrorCodes.EXXQDY0005 || xpe.getErrorCode() == ErrorCodes.EXXQDY0006) { if (LOG.isDebugEnabled()) { - LOG.debug("No such function '" + functionName + "' in XQueryTrigger: " + compiledQuery.getSource()); + LOG.debug("No such function '" + functionName + "' in XQueryTrigger: " + compiled.getSource()); } TriggerStatePerThread.clearIfFinished(phase); return; @@ -459,8 +519,12 @@ private void execute(final TriggerPhase phase, final TriggerEvent event, final D TriggerStatePerThread.clear(); throw new TriggerException(PREPARE_EXCEPTION_MESSAGE, e); } finally { - compiledQuery.reset(); - context.runCleanupTasks(); + if (context != null) { + context.runCleanupTasks(); + } + if (compiled != null) { + broker.getBrokerPool().getXQueryPool().returnCompiledXQuery(compiled.getSource(), compiled); + } } TriggerStatePerThread.clearIfFinished(phase); diff --git a/exist-core/src/main/java/org/exist/config/Configuration.java b/exist-core/src/main/java/org/exist/config/Configuration.java index 372b2f52c9..e49ec56b6b 100644 --- a/exist-core/src/main/java/org/exist/config/Configuration.java +++ b/exist-core/src/main/java/org/exist/config/Configuration.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -167,7 +191,7 @@ public interface Configuration { /** * Save configuration. * - * @param broker eXist-db DBBroker + * @param broker the DBBroker * @throws PermissionDeniedException if permission to save the configuration is denied * @throws ConfigurationException if there is an error in the configuration */ diff --git a/exist-core/src/main/java/org/exist/config/ConfigurationImpl.java b/exist-core/src/main/java/org/exist/config/ConfigurationImpl.java index e577dbd3ee..99ce65eaaf 100644 --- a/exist-core/src/main/java/org/exist/config/ConfigurationImpl.java +++ b/exist-core/src/main/java/org/exist/config/ConfigurationImpl.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -122,20 +146,20 @@ private void cache() { Node child = element.getFirstChild(); while (child != null) { - if (child.getNodeType() == Node.ELEMENT_NODE) { + if (child instanceof Element) { + final Element childElement = (Element) child; - final String ns = child.getNamespaceURI(); - if (ns != null && NS.equals(ns)) { - - String name = child.getLocalName(); + final String ns = childElement.getNamespaceURI(); + if (NS.equals(ns)) { + final String name = childElement.getLocalName(); + if (names.contains(name)) { - - if (props.containsKey(name)) { - props.remove(name); - } + props.remove(name); } else { - props.put(name, child.getTextContent()); + if (!childElement.hasAttribute("key")) { // NOTE(AR) Skip Map entries + props.put(name, childElement.getTextContent()); + } names.add(name); } } @@ -342,7 +366,7 @@ public Long getPropertyLong(final String name, final Long defaultValue, final bo public Integer getPropertyMegabytes(String name, Integer defaultValue) { String cacheMem = element.getAttribute(name); - if (cacheMem != null) { + if (!cacheMem.isEmpty()) { if (cacheMem.endsWith("M") || cacheMem.endsWith("m")) { cacheMem = cacheMem.substring(0, cacheMem.length() - 1); } diff --git a/exist-core/src/main/java/org/exist/config/Configurator.java b/exist-core/src/main/java/org/exist/config/Configurator.java index 286523eb57..ada04750a9 100644 --- a/exist-core/src/main/java/org/exist/config/Configurator.java +++ b/exist-core/src/main/java/org/exist/config/Configurator.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -47,6 +71,7 @@ import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; +import org.apache.commons.io.output.StringBuilderWriter; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.exist.Database; @@ -68,7 +93,6 @@ import org.exist.storage.txn.Txn; import org.exist.util.ExistSAXParserFactory; import org.exist.util.LockException; -import org.exist.util.MimeType; import com.evolvedbinary.j8fu.function.ConsumerE; import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream; import org.exist.util.StringInputSource; @@ -80,6 +104,7 @@ import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; +import xyz.elemental.mediatype.MediaType; import static java.lang.invoke.MethodType.methodType; import static javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING; @@ -1267,24 +1292,22 @@ public static DocumentImpl save(final DBBroker broker, final Configurable instan protected static final Set saving = new ConcurrentSkipListSet<>(); public static DocumentImpl save(final Configurable instance, final DBBroker broker, final Collection collection, final XmldbURI uri) throws IOException, ConfigurationException { - - final StringWriter writer = new StringWriter(); - final SAXSerializer serializer = new SAXSerializer(writer, null); - - try { + final String data; + try (final StringBuilderWriter writer = new StringBuilderWriter()) { + final SAXSerializer serializer = new SAXSerializer(writer, null); + serializer.startDocument(); serialize(instance, serializer); serializer.endDocument(); - + + data = writer.toString(); + if (data == null || data.isEmpty()) { + return null; + } } catch (final SAXException saxe) { throw new ConfigurationException(saxe.getMessage(), saxe); } - final String data = writer.toString(); - if (data == null || data.length() == 0) { - return null; - } - FullXmldbURI fullURI = null; final BrokerPool pool = broker.getBrokerPool(); final TransactionManager transact = pool.getTransactionManager(); @@ -1311,7 +1334,8 @@ public static DocumentImpl save(final Configurable instance, final DBBroker brok systemResourcePermission.setGroup(systemSubject.getDefaultGroup()); systemResourcePermission.setMode(Permission.DEFAULT_SYSTEM_RESOURCE_PERM); - broker.storeDocument(txn, uri, new StringInputSource(data), MimeType.XML_TYPE, null, null, systemResourcePermission, null, null, collection); + final MediaType xmlMediaType = broker.getBrokerPool().getMediaTypeService().getMediaTypeResolver().fromString(MediaType.APPLICATION_XML); + broker.storeDocument(txn, uri, new StringInputSource(data), xmlMediaType, null, null, systemResourcePermission, null, null, collection); broker.saveCollection(txn, collection); if (!txnInProgress) { diff --git a/exist-core/src/main/java/org/exist/dom/NodeListImpl.java b/exist-core/src/main/java/org/exist/dom/NodeListImpl.java index 4bcf9aa664..33ebb60bb2 100644 --- a/exist-core/src/main/java/org/exist/dom/NodeListImpl.java +++ b/exist-core/src/main/java/org/exist/dom/NodeListImpl.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -46,6 +70,26 @@ public boolean add(final Node node) { return super.add(node); } + /** + * Add all elements of the other NodeListImpl to + * this NodeListImpl. + * + * @param other NodeListImpl to add. + * + * @return true if the list was modified, false otherwise. + */ + public boolean addAll(final NodeListImpl other) { + if (other == null) { + return false; + } + + if (other.isEmpty()) { + return false; + } + + return addAll((ArrayList) other); + } + /** * Add all elements of the other NodeList to * this NodeList @@ -54,18 +98,26 @@ public boolean add(final Node node) { * if none or only some were added. */ public boolean addAll(final NodeList other) { + if (other == null) { + return false; + } + + if (other instanceof NodeListImpl) { + return addAll((NodeListImpl) other); + } + if (other.getLength() == 0) { return false; - } else { - boolean result = true; - for(int i = 0; i < other.getLength(); i++) { - if(!add(other.item(i))) { - result = false; - break; - } + } + + boolean result = true; + for (int i = 0; i < other.getLength(); i++) { + if (!add(other.item(i))) { + result = false; + break; } - return result; } + return result; } @Override diff --git a/exist-core/src/main/java/org/exist/dom/QName.java b/exist-core/src/main/java/org/exist/dom/QName.java index 3ff7753c66..ef73420d91 100644 --- a/exist-core/src/main/java/org/exist/dom/QName.java +++ b/exist-core/src/main/java/org/exist/dom/QName.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -26,16 +50,19 @@ import org.exist.util.XMLNames; import org.exist.xquery.Constants; +import javax.annotation.Nullable; import javax.xml.XMLConstants; import java.util.regex.Matcher; import java.util.regex.Pattern; import static org.exist.dom.QName.Validity.*; +import static org.exist.util.StringUtil.isNullOrEmpty; /** * Represents a QName, consisting of a local name, a namespace URI and a prefix. * * @author Wolfgang + * @author Adam Retter */ public class QName implements Comparable { @@ -134,7 +161,18 @@ public byte getNameType() { * @return the string representation of this qualified name. * */ public String getStringValue() { - return getStringRepresentation(false); + return getStringRepresentation(false, false); + } + + /** + * Get an extended string representation of this qualified name. + * + * Will be of the format `local-name`, `{namespace}local-name`, or `{namespace}prefix:local-name`. + * + * @return the string representation of this qualified name. + */ + public String getExtendedStringValue() { + return getStringRepresentation(false, true); } /** @@ -146,23 +184,32 @@ public String getStringValue() { */ @Override public String toString() { - return getStringRepresentation(true); + return getStringRepresentation(true, false); } /** * Get a string representation of this qualified name. * * @param showNsWithoutPrefix true if the namespace should be shown even when there is no prefix, false otherwise. - * When shown, it will be output using Clark notation, e.g. `{http://namespace}local-name`. + * When shown, it will be output using Clark notation, e.g. `{namespace}local-name`. + * + * @param extended true if the namespace and prefix should be shown, requires showNsWithoutPrefix == false. * * @return the string representation of this qualified name. */ - private String getStringRepresentation(final boolean showNsWithoutPrefix) { + private String getStringRepresentation(final boolean showNsWithoutPrefix, final boolean extended) { if (prefix != null && !prefix.isEmpty()) { - return prefix + COLON + localPart; - } else if (showNsWithoutPrefix && namespaceURI != null && !XMLConstants.NULL_NS_URI.equals(namespaceURI)) { + if (extended) { + return LEFT_BRACE + namespaceURI + RIGHT_BRACE + prefix + COLON + localPart; + } else { + return prefix + COLON + localPart; + } + } + + if (showNsWithoutPrefix && namespaceURI != null && !XMLConstants.NULL_NS_URI.equals(namespaceURI)) { return LEFT_BRACE + namespaceURI + RIGHT_BRACE + localPart; } + return localPart; } @@ -330,6 +377,52 @@ public static QName parse(final String namespaceURI, final String qname) throws return new QName(qname.substring(p + 1), namespaceURI, qname.substring(0, p)); } + /** + * Extract a QName from a namespace and qualified name string. + * + * @param extendedStringValue a string representation as produced by {@link #getExtendedStringValue()}, i.e.: `local-name`, `{namespace}local-name`, or `{namespace}prefix:local-name`. + * @return The QName + * @throws IllegalQNameException if the qname component is invalid + */ + public static QName parse(String extendedStringValue) throws IllegalQNameException { + if (isNullOrEmpty(extendedStringValue)) { + throw new IllegalQNameException(ILLEGAL_FORMAT.val, "Illegal extended string QName is empty"); + } + + final String namespaceUri; + if (extendedStringValue.charAt(0) == LEFT_BRACE) { + final int idxNsEnd = extendedStringValue.indexOf(RIGHT_BRACE); + if (idxNsEnd == Constants.STRING_NOT_FOUND) { + throw new IllegalQNameException(ILLEGAL_FORMAT.val, "Illegal extended string QName, missing right brace: '" + extendedStringValue + "'"); + } + namespaceUri = extendedStringValue.substring(1, idxNsEnd); + extendedStringValue = extendedStringValue.substring(idxNsEnd + 1); + } else if (extendedStringValue.indexOf(RIGHT_BRACE) != Constants.STRING_NOT_FOUND) { + throw new IllegalQNameException(ILLEGAL_FORMAT.val, "Illegal extended string QName, missing left brace: '" + extendedStringValue + "'"); + } else { + namespaceUri = XMLConstants.NULL_NS_URI; + } + + @Nullable final String prefix; + final int idxColon = extendedStringValue.indexOf(COLON); + if (idxColon == Constants.STRING_NOT_FOUND) { + prefix = null; + } else { + prefix = extendedStringValue.substring(0, idxColon); + if (!XMLNames.isNCName(prefix)) { + throw new IllegalQNameException(INVALID_PREFIX.val, "Illegal extended string QName, invalid prefix: '" + extendedStringValue + "'"); + } + extendedStringValue = extendedStringValue.substring(idxColon + 1); + } + + final String localPart = extendedStringValue; + if (!XMLNames.isNCName(localPart)) { + throw new IllegalQNameException(INVALID_LOCAL_PART.val, "Illegal extended string QName, invalid prefix: '" + extendedStringValue + "'"); + } + + return new QName(localPart, namespaceUri, prefix); + } + /** * Parses the given string into a QName. The method uses context to look up * a namespace URI for an existing prefix. diff --git a/exist-core/src/main/java/org/exist/dom/memtree/AbstractCharacterData.java b/exist-core/src/main/java/org/exist/dom/memtree/AbstractCharacterData.java index ca40125edb..8d1e7be027 100644 --- a/exist-core/src/main/java/org/exist/dom/memtree/AbstractCharacterData.java +++ b/exist-core/src/main/java/org/exist/dom/memtree/AbstractCharacterData.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -280,11 +304,6 @@ public String getStringValue() { return getData(); } - @Override - public Node getFirstChild() { - return null; - } - @Override public void selectAttributes(final NodeTest test, final Sequence result) throws XPathException { diff --git a/exist-core/src/main/java/org/exist/dom/memtree/AttrImpl.java b/exist-core/src/main/java/org/exist/dom/memtree/AttrImpl.java index 019a03737f..ba9dcf0479 100644 --- a/exist-core/src/main/java/org/exist/dom/memtree/AttrImpl.java +++ b/exist-core/src/main/java/org/exist/dom/memtree/AttrImpl.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -52,7 +76,7 @@ public NodeId getNodeId() { @Override public String getName() { - return getQName().getStringValue(); + return getNodeName(); } @Override @@ -75,7 +99,7 @@ public String getBaseURI() { } @Override - public Node getFirstChild() { + public Node getPreviousSibling() { return null; } diff --git a/exist-core/src/main/java/org/exist/dom/memtree/DOMIndexer.java b/exist-core/src/main/java/org/exist/dom/memtree/DOMIndexer.java index 03fe4bfb11..dcad5549eb 100644 --- a/exist-core/src/main/java/org/exist/dom/memtree/DOMIndexer.java +++ b/exist-core/src/main/java/org/exist/dom/memtree/DOMIndexer.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -99,7 +123,7 @@ public DOMIndexer(final DBBroker broker, final Txn transaction, final DocumentIm */ public void scan() throws EXistException { //Creates a dummy DOCTYPE - final DocumentTypeImpl dt = new DocumentTypeImpl((doc != null) ? doc.getExpression() : null, "temp", null, ""); + final org.exist.dom.persistent.DocumentTypeImpl dt = new org.exist.dom.persistent.DocumentTypeImpl((doc != null) ? doc.getExpression() : null, "temp", null, ""); targetDoc.setDocumentType(dt); } diff --git a/exist-core/src/main/java/org/exist/dom/memtree/DocumentBuilderReceiver.java b/exist-core/src/main/java/org/exist/dom/memtree/DocumentBuilderReceiver.java index 31e9986e8b..7856237ea8 100644 --- a/exist-core/src/main/java/org/exist/dom/memtree/DocumentBuilderReceiver.java +++ b/exist-core/src/main/java/org/exist/dom/memtree/DocumentBuilderReceiver.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -56,8 +80,11 @@ public class DocumentBuilderReceiver implements ContentHandler, LexicalHandler, private boolean suppressWhitespace = true; + private StringBuilder cdataBuffer; + private final Expression expression; + public DocumentBuilderReceiver() { this((Expression) null); } @@ -195,12 +222,20 @@ public void addNamespaceNode(final QName qname) throws SAXException { @Override public void characters(final CharSequence seq) throws SAXException { - builder.characters(seq); + if (cdataBuffer != null) { + cdataBuffer.append(seq); + } else { + builder.characters(seq); + } } @Override public void characters(final char[] ch, final int start, final int len) throws SAXException { - builder.characters(ch, start, len); + if (cdataBuffer != null) { + cdataBuffer.append(ch, start, len); + } else { + builder.characters(ch, start, len); + } } @Override @@ -234,15 +269,14 @@ public void skippedEntity(final String name) throws SAXException { } @Override - public void endCDATA() throws SAXException { - } - - @Override - public void endDTD() throws SAXException { + public void startCDATA() throws SAXException { + this.cdataBuffer = new StringBuilder(); } @Override - public void startCDATA() throws SAXException { + public void endCDATA() throws SAXException { + builder.cdataSection(this.cdataBuffer); + this.cdataBuffer = null; } @Override @@ -256,17 +290,21 @@ public void comment(final char[] ch, final int start, final int length) throws S } @Override - public void endEntity(final String name) throws SAXException { + public void startEntity(final String name) throws SAXException { } @Override - public void startEntity(final String name) throws SAXException { + public void endEntity(final String name) throws SAXException { } @Override public void startDTD(final String name, final String publicId, final String systemId) throws SAXException { } + @Override + public void endDTD() throws SAXException { + } + @Override public void highlightText(final CharSequence seq) { // not supported with this receiver diff --git a/exist-core/src/main/java/org/exist/dom/memtree/DocumentImpl.java b/exist-core/src/main/java/org/exist/dom/memtree/DocumentImpl.java index 180fc01e96..9270b1652f 100644 --- a/exist-core/src/main/java/org/exist/dom/memtree/DocumentImpl.java +++ b/exist-core/src/main/java/org/exist/dom/memtree/DocumentImpl.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -27,6 +51,7 @@ import org.exist.dom.NodeListImpl; import org.exist.dom.QName; import org.exist.dom.QName.IllegalQNameException; +import org.exist.dom.memtree.reference.*; import org.exist.dom.persistent.NodeProxy; import org.exist.numbering.NodeId; import org.exist.numbering.NodeIdFactory; @@ -47,6 +72,7 @@ import org.w3c.dom.*; import org.xml.sax.SAXException; +import javax.annotation.Nullable; import javax.xml.XMLConstants; import java.util.Arrays; import java.util.Objects; @@ -71,19 +97,21 @@ * for example {@code int nextNodeNum = next[nodeNum]}. * * The following arrays hold the data of the nodes themselves: - * * {@link #namespaceParent} - * * {@link #namespaceCode} - * * {@link #nodeName} - * * {@link #alpha} - * * {@link #alphaLen} - * * {@link #characters} - * * {@link #nodeId} - * * {@link #attrName} - * * {@link #attrType} - * * {@link #attrNodeId} - * * {@link #attrParent} - * * {@link #attrValue} - * * {@link #references} + *
    + *
  • {@link #namespaceParent}
  • + *
  • {@link #namespaceCode}
  • + *
  • {@link #nodeName}
  • + *
  • {@link #alpha}
  • + *
  • {@link #alphaLen} For Element nodes, this is the ID of the first namespace for that Element. For Text, CData Section, Comment, and Processing Instruction nodes this is the lengh of their character data.
  • + *
  • {@link #characters}
  • + *
  • {@link #nodeId}
  • + *
  • {@link #attrName}
  • + *
  • {@link #attrType}
  • + *
  • {@link #attrNodeId}
  • + *
  • {@link #attrParent}
  • + *
  • {@link #attrValue}
  • + *
  • {@link #references}
  • + *
* * This implementation stores all node data in the document object. Nodes from another document, i.e. a persistent document in the database, can be * stored as reference nodes, i.e. the nodes are not copied into this document object. Instead a reference is inserted which will only be expanded @@ -98,6 +126,8 @@ public class DocumentImpl extends NodeImpl implements Document { private static final int CHAR_BUF_SIZE = 256; private static final int REF_SIZE = 8; + protected DocumentType docType = null; + // holds the node type of a node protected short[] nodeKind = null; @@ -222,11 +252,11 @@ public boolean isExplicitlyCreated() { return explicitlyCreated; } - public int addNode(final short kind, final short level, final QName qname) { - if(nodeKind == null) { + public int addNode(final short kind, final short level, @Nullable final QName qname) { + if (nodeKind == null) { init(); } - if(size == nodeKind.length) { + if (size == nodeKind.length) { grow(); } nodeKind[size] = kind; @@ -317,11 +347,11 @@ public void appendChars(final int nodeNum, final CharSequence s) { } } - public void addReferenceNode(final int nodeNum, final NodeProxy proxy) { - if(nodeKind == null) { + void addReferenceNode(final int nodeNum, final NodeProxy proxy) { + if (nodeKind == null) { init(); } - if((references == null) || (nextReferenceIdx == references.length)) { + if (references == null || nextReferenceIdx == references.length) { growReferences(); } references[nextReferenceIdx] = proxy; @@ -513,21 +543,71 @@ public NodeImpl getNamespaceNode(final int nodeNum) throws DOMException { } public NodeImpl getNode(final int nodeNum) throws DOMException { - if(nodeNum == 0) { + if (nodeNum == 0) { return this; } - if(nodeNum >= size) { + + if (nodeNum >= size) { throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, "node not found"); } - final NodeImpl node = switch (nodeKind[nodeNum]) { - case Node.ELEMENT_NODE -> new ElementImpl(getExpression(), this, nodeNum); - case Node.TEXT_NODE -> new TextImpl(getExpression(), this, nodeNum); - case Node.COMMENT_NODE -> new CommentImpl(getExpression(), this, nodeNum); - case Node.PROCESSING_INSTRUCTION_NODE -> new ProcessingInstructionImpl(getExpression(), this, nodeNum); - case Node.CDATA_SECTION_NODE -> new CDATASectionImpl(getExpression(), this, nodeNum); - case NodeImpl.REFERENCE_NODE -> new ReferenceNode(getExpression(), this, nodeNum); - default -> throw new DOMException(DOMException.NOT_FOUND_ERR, "node not found"); - }; + + final NodeImpl node; + switch (nodeKind[nodeNum]) { + case Node.ELEMENT_NODE: + node = new ElementImpl(getExpression(), this, nodeNum); + break; + + case Node.TEXT_NODE: + node = new TextImpl(getExpression(), this, nodeNum); + break; + + case Node.COMMENT_NODE: + node = new CommentImpl(getExpression(), this, nodeNum); + break; + + case Node.PROCESSING_INSTRUCTION_NODE: + node = new ProcessingInstructionImpl(getExpression(), this, nodeNum); + break; + + case Node.CDATA_SECTION_NODE: + node = new CDATASectionImpl(getExpression(), this, nodeNum); + break; + + case NodeImpl.REFERENCE_NODE: + final NodeProxy nodeProxy = references[alpha[nodeNum]]; + node = referenceFromNodeProxy(nodeNum, nodeProxy); + break; + + default: + throw new DOMException(DOMException.NOT_FOUND_ERR, "node not found"); + } + return node; + } + + private NodeImpl referenceFromNodeProxy(final int nodeNum, final NodeProxy nodeProxy) { + final NodeImpl node; + final int nodeType = nodeProxy.getNodeType(); + switch (nodeType) { + case Node.ELEMENT_NODE: + node = new ElementReferenceImpl(getExpression(), this, nodeNum, nodeProxy); + break; + + case Node.TEXT_NODE: + node = new TextReferenceImpl(getExpression(), this, nodeNum, nodeProxy); + break; + + case Node.PROCESSING_INSTRUCTION_NODE: + node = new ProcessingInstructionReferenceImpl(getExpression(), this, nodeNum, nodeProxy); + break; + + case Node.COMMENT_NODE: + node = new CommentReferenceImpl(getExpression(), this, nodeNum, nodeProxy); + break; + + default: + throw new DOMException(DOMException.NOT_FOUND_ERR, "reference node not found"); + } + return node; } @@ -545,7 +625,11 @@ public Node getParentNode() { @Override public DocumentType getDoctype() { - return null; + return docType; + } + + public void setDoctype(final DocumentType docType) { + this.docType = docType; } @Override @@ -570,7 +654,7 @@ public Element getDocumentElement() { @Override public Node getFirstChild() { - if(size > 1) { + if (size > 1) { return getNode(1); } return null; @@ -578,7 +662,17 @@ public Node getFirstChild() { @Override public Node getLastChild() { - return getFirstChild(); + if (size > 1) { + int nodeNum = 1; + for (; nodeNum < size; nodeNum++) { + if (treeLevel[nodeNum] > 1) { + nodeNum--; + break; + } + } + return getNode(nodeNum); + } + return null; } public int getAttributesCountFor(final int nodeNumber) { @@ -625,9 +719,10 @@ public int getFirstChildFor(final int nodeNumber) { final short level = treeLevel[nodeNumber]; final int nextNode = nodeNumber + 1; - if((nextNode < size) && (treeLevel[nextNode] > level)) { + if ((nextNode < size) && (treeLevel[nextNode] > level)) { return nextNode; } + return -1; } @@ -1083,33 +1178,41 @@ public DocumentImpl getOwnerDocument() { * @throws SAXException DOCUMENT ME! */ public void copyTo(final NodeImpl node, final DocumentBuilderReceiver receiver) throws SAXException { - copyTo(node, receiver, false); + copyTo(null, node, receiver); } - protected void copyTo(NodeImpl node, final DocumentBuilderReceiver receiver, final boolean expandRefs) - throws SAXException { + private void copyTo(@Nullable final Serializer serializer, NodeImpl node, final DocumentBuilderReceiver receiver) throws SAXException { final NodeImpl top = node; - while(node != null) { - copyStartNode(node, receiver, expandRefs); - NodeImpl nextNode; - if(node instanceof ReferenceNode) { - //Nothing more to stream ? - nextNode = null; + + @Nullable NodeImpl nextNode; + while (node != null) { + if (node instanceof AbstractReferenceNodeImpl) { + if (serializer != null) { + serializer.toReceiver(((AbstractReferenceNodeImpl) node).getNodeProxy(), false, false); + } else { + receiver.addReferenceNode(document.references[document.alpha[node.nodeNumber]]); + } + nextNode = (NodeImpl) node.getNextSibling(); + } else { + copyStartNode(node, receiver); nextNode = (NodeImpl) node.getFirstChild(); } - while(nextNode == null) { - if (node != null) { + + while (nextNode == null) { + if (!(node instanceof AbstractReferenceNodeImpl)) { copyEndNode(node, receiver); + + if (top.nodeNumber == node.nodeNumber) { + break; + } } - if((top != null) && (top.nodeNumber == node.nodeNumber)) { - break; - } + //No nextNode if the top node is a Document node nextNode = (NodeImpl) node.getNextSibling(); - if(nextNode == null) { + if (nextNode == null) { node = (NodeImpl) node.getParentNode(); - if((node == null) || ((top != null) && (top.nodeNumber == node.nodeNumber))) { + if (node == null || top.nodeNumber == node.nodeNumber) { if (node != null) { copyEndNode(node, receiver); } @@ -1117,14 +1220,14 @@ protected void copyTo(NodeImpl node, final DocumentBuilderReceiver receiver, fin } } } + node = nextNode; } } - private void copyStartNode(final NodeImpl node, final DocumentBuilderReceiver receiver, final boolean expandRefs) - throws SAXException { + private void copyStartNode(final NodeImpl node, final DocumentBuilderReceiver receiver) throws SAXException { final int nr = node.nodeNumber; - switch(node.getNodeType()) { + switch (node.getNodeType()) { case Node.ELEMENT_NODE: { final QName nodeName = document.nodeName[nr]; receiver.startElement(nodeName, null); @@ -1146,51 +1249,38 @@ private void copyStartNode(final NodeImpl node, final DocumentBuilderReceiver re } break; } + case Node.TEXT_NODE: receiver.characters(document.characters, document.alpha[nr], document.alphaLen[nr]); break; + case Node.CDATA_SECTION_NODE: receiver.cdataSection(document.characters, document.alpha[nr], document.alphaLen[nr]); break; + case Node.ATTRIBUTE_NODE: final QName attrQName = document.attrName[nr]; receiver.attribute(attrQName, attrValue[nr]); break; + case Node.COMMENT_NODE: receiver.comment(document.characters, document.alpha[nr], document.alphaLen[nr]); break; + case Node.PROCESSING_INSTRUCTION_NODE: final QName piQName = document.nodeName[nr]; final String data = new String(document.characters, document.alpha[nr], document.alphaLen[nr]); receiver.processingInstruction(piQName.getLocalPart(), data); break; + case NodeImpl.NAMESPACE_NODE: receiver.addNamespaceNode(document.namespaceCode[nr]); break; - case NodeImpl.REFERENCE_NODE: - if(expandRefs) { - try(final DBBroker broker = getDatabase().getBroker()) { - final Serializer serializer = broker.borrowSerializer(); - try { - serializer.setProperty(Serializer.GENERATE_DOC_EVENTS, "false"); - serializer.setReceiver(receiver); - serializer.toReceiver(document.references[document.alpha[nr]], false, false); - } finally { - broker.returnSerializer(serializer); - } - } catch(final EXistException e) { - throw new SAXException(e); - } - } else { - receiver.addReferenceNode(document.references[document.alpha[nr]]); - } - break; } } - private void copyEndNode(final NodeImpl node, final DocumentBuilderReceiver receiver) - throws SAXException { - if(node.getNodeType() == Node.ELEMENT_NODE) { + private void copyEndNode(final NodeImpl node, final DocumentBuilderReceiver receiver) throws SAXException { + if (node.getNodeType() == Node.ELEMENT_NODE) { receiver.endElement(node.getQName()); } } @@ -1205,6 +1295,7 @@ private void copyEndNode(final NodeImpl node, final DocumentBuilderReceiver rece */ @Override public void expand() throws DOMException { + // TODO(AR) see if we can get rid of expansion now we have org.exist.dom.memtree.reference.* classes if(size == 0) { return; } @@ -1212,31 +1303,36 @@ public void expand() throws DOMException { copyDocContents(newDoc); } + // TODO(AR) see if we can get rid of expansion now we have org.exist.dom.memtree.reference.* classes public DocumentImpl expandRefs(final NodeImpl rootNode) throws DOMException { - try { - if(nextReferenceIdx == 0) { - computeNodeIds(); - return this; - } - final MemTreeBuilder builder = new MemTreeBuilder(getExpression(), context); - final DocumentBuilderReceiver receiver = new DocumentBuilderReceiver(getExpression(), builder); + if(nextReferenceIdx == 0) { + computeNodeIds(); + return this; + } + final MemTreeBuilder builder = new MemTreeBuilder(getExpression(), context); + final DocumentBuilderReceiver receiver = new DocumentBuilderReceiver(getExpression(), builder); + try (final DBBroker broker = getDatabase().getBroker()) { + final Serializer serializer = broker.borrowSerializer(); try { + serializer.setProperty(Serializer.GENERATE_DOC_EVENTS, "false"); + serializer.setReceiver(receiver); + builder.startDocument(); NodeImpl node = (rootNode == null) ? (NodeImpl) getFirstChild() : rootNode; - while(node != null) { - copyTo(node, receiver, true); + while (node != null) { + copyTo(serializer, node, receiver); node = (NodeImpl) node.getNextSibling(); } receiver.endDocument(); - } catch(final SAXException e) { - throw new DOMException(DOMException.INVALID_STATE_ERR, e.getMessage()); + } finally { + broker.returnSerializer(serializer); } - final DocumentImpl newDoc = builder.getDocument(); - newDoc.computeNodeIds(); - return newDoc; - } catch(final EXistException e) { + } catch (final SAXException | EXistException e) { throw new DOMException(DOMException.INVALID_STATE_ERR, e.getMessage()); } + final DocumentImpl newDoc = builder.getDocument(); + newDoc.computeNodeIds(); + return newDoc; } public NodeImpl getNodeById(final NodeId id) { @@ -1249,7 +1345,7 @@ public NodeImpl getNodeById(final NodeId id) { return null; } - private void computeNodeIds() throws EXistException { + private void computeNodeIds() { if(nodeId[0] != null) { return; } @@ -1330,48 +1426,62 @@ private void copyDocContents(final DocumentImpl newDoc) { * @param receiver the receiveer * @throws SAXException DOCUMENT ME */ - public void streamTo(final Serializer serializer, NodeImpl node, final Receiver receiver) - throws SAXException { + public void streamTo(final Serializer serializer, NodeImpl node, final Receiver receiver) throws SAXException { final NodeImpl top = node; - while(node != null) { - startNode(serializer, node, receiver); - NodeImpl nextNode; - if(node instanceof ReferenceNode) { - //Nothing more to stream ? - nextNode = null; + + int level = node.getNodeType() == Node.DOCUMENT_NODE ? 0 : 1; + + while (node != null) { + + @Nullable NodeImpl nextNode; + if (node instanceof AbstractReferenceNodeImpl) { + serializer.toReceiver(((AbstractReferenceNodeImpl) node).getNodeProxy(), true, level == 1); + nextNode = (NodeImpl) node.getNextSibling(); + } else { + startNode(node, receiver); nextNode = (NodeImpl) node.getFirstChild(); + level++; } - while(nextNode == null) { - endNode(node, receiver); - if((top != null) && (top.nodeNumber == node.nodeNumber)) { - break; + + while (nextNode == null) { + if (!(node instanceof AbstractReferenceNodeImpl)) { + endNode(node, receiver); + level--; + + if (top.nodeNumber == node.nodeNumber) { + break; + } } + + //No nextNode if the top node is a Document node nextNode = (NodeImpl) node.getNextSibling(); - if(nextNode == null) { + if (nextNode == null) { node = (NodeImpl) node.getParentNode(); - if((node == null) || ((top != null) && (top.nodeNumber == node.nodeNumber))) { + if (node == null || top.nodeNumber == node.nodeNumber) { if (node != null) { endNode(node, receiver); + level--; } break; } } } + node = nextNode; } } - private void startNode(final Serializer serializer, final NodeImpl node, final Receiver receiver) - throws SAXException { - final int nr = node.nodeNumber; - switch(node.getNodeType()) { + private void startNode(final NodeImpl node, final Receiver receiver) throws SAXException { + final int nodeNumber = node.nodeNumber; + switch (node.getNodeType()) { case Node.ELEMENT_NODE: - final QName nodeName = document.nodeName[nr]; + final QName nodeName = node.getQName(); + //Output required namespace declarations - int ns = document.alphaLen[nr]; - if(ns > -1) { - while((ns < document.nextNamespace) && (document.namespaceParent[ns] == nr)) { + int ns = document.alphaLen[nodeNumber]; + if (ns > -1) { + while((ns < document.nextNamespace) && (document.namespaceParent[ns] == nodeNumber)) { final QName nsQName = document.namespaceCode[ns]; if(XMLConstants.XMLNS_ATTRIBUTE.equals(nsQName.getLocalPart())) { receiver.startPrefixMapping(XMLConstants.DEFAULT_NS_PREFIX, nsQName.getNamespaceURI()); @@ -1381,40 +1491,32 @@ private void startNode(final Serializer serializer, final NodeImpl node, final R ++ns; } } + //Create the attribute list - AttrList attribs = null; - int attr = document.alpha[nr]; - if(attr > -1) { - attribs = new AttrList(); - while((attr < document.nextAttr) && (document.attrParent[attr] == nr)) { - final QName attrQName = document.attrName[attr]; - attribs.addAttribute(attrQName, attrValue[attr]); - ++attr; - } - } + @Nullable final AttrList attribs = node.getAttrList(); receiver.startElement(nodeName, attribs); break; + case Node.TEXT_NODE: - receiver.characters(new String(document.characters, document.alpha[nr], - document.alphaLen[nr])); + receiver.characters(((TextImpl) node).getData()); break; + case Node.ATTRIBUTE_NODE: - final QName attrQName = document.attrName[nr]; - receiver.attribute(attrQName, attrValue[nr]); + receiver.attribute(node.getQName(), ((Attr) node).getValue()); break; + case Node.COMMENT_NODE: - receiver.comment(document.characters, document.alpha[nr], document.alphaLen[nr]); + final char[] commentData = ((Comment) node).getData().toCharArray(); + receiver.comment(commentData, 0, commentData.length); break; + case Node.PROCESSING_INSTRUCTION_NODE: - final QName qn = document.nodeName[nr]; - final String data = new String(document.characters, document.alpha[nr], document.alphaLen[nr]); - receiver.processingInstruction(qn.getLocalPart(), data); + receiver.processingInstruction(node.getQName().getLocalPart(), ((ProcessingInstruction) node).getData()); break; + case Node.CDATA_SECTION_NODE: - receiver.cdataSection(document.characters, document.alpha[nr], document.alphaLen[nr]); - break; - case NodeImpl.REFERENCE_NODE: - serializer.toReceiver(document.references[document.alpha[nr]], true, false); + final char[] cdataSectionData = ((CDATASection) node).getData().toCharArray(); + receiver.cdataSection(cdataSectionData, 0, cdataSectionData.length); break; } } @@ -1635,4 +1737,61 @@ public Node appendChild(final Node newChild) throws DOMException { throw unsupported(); } + + @Override + public String lookupNamespaceURI(final String prefix) { + if (prefix == null || prefix == XMLConstants.DEFAULT_NS_PREFIX) { + return XMLConstants.NULL_NS_URI; + } + + for (int i = nextNamespace - 1; i >= 0; i--) { + final QName namespaceMapping = namespaceCode[i]; + if (prefix.equals(namespaceMapping.getLocalPart())) { + return namespaceMapping.getNamespaceURI(); + } + } + + return null; + } + + /** + * Get the in-scope namespace URI for the namespace prefix. + * + * @param prefix the namespace prefix to lookup. + * @param nodeNumber the node to retrieve the in-scope namespace URI for. + * + * @return the namespace URI bound to the namespace prefix, or null if there is no such binding. + */ + public @Nullable String getInScopePrefix(String prefix, final int nodeNumber) { + if (prefix == null) { + prefix = XMLConstants.DEFAULT_NS_PREFIX; + } + + // First, look at the Namespaces on the current node + if (alphaLen != null) { + int ns = alphaLen[nodeNumber]; + if (ns != -1) { + while (ns < nextNamespace && namespaceParent[ns] == nodeNumber) { + final QName nsQName = namespaceCode[ns]; + if (prefix.equals(nsQName.getPrefix()) || (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX) && nsQName.getPrefix() == null && XMLConstants.XMLNS_ATTRIBUTE.equals(nsQName.getLocalPart()))) { + return nsQName.getNamespaceURI(); + } + ++ns; + } + } + } + + // Second, look at the parent, and so on... + if (next != null) { + int parent = next[nodeNumber]; + while (parent > nodeNumber) { + parent = next[parent]; + } + if (parent != -1 && !(nodeNumber == 0 && parent == 0)) { + return getInScopePrefix(prefix, parent); + } + } + + return null; + } } diff --git a/exist-core/src/main/java/org/exist/dom/memtree/DocumentTypeImpl.java b/exist-core/src/main/java/org/exist/dom/memtree/DocumentTypeImpl.java new file mode 100644 index 0000000000..0f55e3ddc6 --- /dev/null +++ b/exist-core/src/main/java/org/exist/dom/memtree/DocumentTypeImpl.java @@ -0,0 +1,148 @@ +/* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package org.exist.dom.memtree; + +import net.jcip.annotations.ThreadSafe; +import org.exist.xquery.Expression; +import org.exist.xquery.NodeTest; +import org.exist.xquery.XPathException; +import org.exist.xquery.value.Sequence; +import org.w3c.dom.DocumentType; +import org.w3c.dom.NamedNodeMap; + +import javax.annotation.Nullable; + +/** + * @author Adam Retter + */ +@ThreadSafe +public class DocumentTypeImpl extends NodeImpl implements DocumentType { + + private final String publicId; + private final String systemId; + private final String name; + + public DocumentTypeImpl(final DocumentImpl doc, final int nodeNumber, final String name, final String publicId, final String systemId) { + this(null, doc, nodeNumber, name, publicId, systemId); + } + + public DocumentTypeImpl(@Nullable final Expression expression, final DocumentImpl doc, final int nodeNumber, final String name, final String publicId, final String systemId) { + super(expression, doc, nodeNumber); + this.name = name; + this.publicId = publicId; + this.systemId = systemId; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getPublicId() { + return publicId; + } + + @Override + public String getSystemId() { + return systemId; + } + + @Override + public NamedNodeMap getEntities() { + return null; + } + + @Override + public NamedNodeMap getNotations() { + return null; + } + + @Override + public String getInternalSubset() { + return null; + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + + builder.append(""); + + return builder.toString(); + } + + @Override + public void selectAttributes(final NodeTest test, final Sequence result) throws XPathException { + } + + @Override + public void selectDescendantAttributes(final NodeTest test, final Sequence result) throws XPathException { + } + + @Override + public void selectChildren(final NodeTest test, final Sequence result) throws XPathException { + + } + + @Override + public int compareTo(final DocumentTypeImpl other) { + int comparison = name.compareTo(other.name); + if (comparison != 0) { + return comparison; + } + + if (publicId == null && other.publicId != null) { + return -1; + } else if (publicId != null && other.publicId == null) { + return 1; + } + comparison = publicId.compareTo(other.publicId); + if (comparison != 0) { + return comparison; + } + + if (systemId == null && other.systemId != null) { + return -1; + } else if (systemId != null && other.systemId == null) { + return 1; + } + comparison = systemId.compareTo(other.systemId); + if (comparison != 0) { + return comparison; + } + + return 0; + } +} diff --git a/exist-core/src/main/java/org/exist/dom/memtree/ElementImpl.java b/exist-core/src/main/java/org/exist/dom/memtree/ElementImpl.java index 892f4e9ff9..ab1b674080 100644 --- a/exist-core/src/main/java/org/exist/dom/memtree/ElementImpl.java +++ b/exist-core/src/main/java/org/exist/dom/memtree/ElementImpl.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -27,6 +51,7 @@ import org.exist.dom.QName; import org.exist.dom.QName.IllegalQNameException; import org.exist.storage.ElementValue; +import org.exist.util.serializer.AttrList; import org.exist.xmldb.XmldbURI; import org.exist.xquery.Expression; import org.exist.xquery.NodeTest; @@ -68,12 +93,12 @@ public boolean hasChildNodes() { @Override public Node getFirstChild() { - final short level = document.treeLevel[nodeNumber]; - final int nextNode = nodeNumber + 1; - if(nextNode < document.size && document.treeLevel[nextNode] > level) { - return document.getNode(nextNode); + final int firstChildNodeNumber = document.getFirstChildFor(nodeNumber); + if (firstChildNodeNumber == -1) { + return null; } - return null; + + return document.getNode(firstChildNodeNumber); } @Override @@ -102,28 +127,31 @@ public boolean hasAttributes() { @Override public String getAttribute(final String name) { int attr = document.alpha[nodeNumber]; + if(-1 < attr) { - while(attr < document.nextAttr && document.attrParent[attr] == nodeNumber) { + while (attr < document.nextAttr && document.attrParent[attr] == nodeNumber) { final QName attrQName = document.attrName[attr]; - if(attrQName.getStringValue().equals(name)) { + if (attrQName.getStringValue().equals(name)) { return document.attrValue[attr]; } ++attr; } } - if(name.startsWith(XMLConstants.XMLNS_ATTRIBUTE + ":")) { + + if (name.startsWith(XMLConstants.XMLNS_ATTRIBUTE + ":")) { int ns = document.alphaLen[nodeNumber]; - if(-1 < ns) { - while(ns < document.nextNamespace && document.namespaceParent[ns] == nodeNumber) { + if (-1 < ns) { + while (ns < document.nextNamespace && document.namespaceParent[ns] == nodeNumber) { final QName nsQName = document.namespaceCode[ns]; - if(nsQName.getStringValue().equals(name)) { + if (nsQName.getStringValue().equals(name)) { return nsQName.getNamespaceURI(); } ++ns; } } } - return null; + + return ""; } @Override @@ -220,6 +248,22 @@ public NamedNodeMap getAttributes() { return map; } + @Override + public AttrList getAttrList() { + //Create the attribute list + AttrList attrList = null; + int attr = document.alpha[nodeNumber]; + if (attr > -1) { + attrList = new AttrList(); + while((attr < document.nextAttr) && (document.attrParent[attr] == nodeNumber)) { + final QName attrQName = document.attrName[attr]; + attrList.addAttribute(attrQName, document.attrValue[attr]); + ++attr; + } + } + return attrList; + } + @Override public Attr getAttributeNode(final String name) { int attr = document.alpha[nodeNumber]; @@ -411,28 +455,31 @@ private NodeList getElementsByTagName(final QName qname) { @Override public String getAttributeNS(final String namespaceURI, final String localName) { int attr = document.alpha[nodeNumber]; - if(-1 < attr) { - while(attr < document.nextAttr && document.attrParent[attr] == nodeNumber) { + + if (-1 < attr) { + while (attr < document.nextAttr && document.attrParent[attr] == nodeNumber) { final QName name = document.attrName[attr]; - if(name.getLocalPart().equals(localName) && name.getNamespaceURI().equals(namespaceURI)) { + if (name.getLocalPart().equals(localName) && name.getNamespaceURI().equals(namespaceURI)) { return document.attrValue[attr]; } ++attr; } } - if(Namespaces.XMLNS_NS.equals(namespaceURI)) { + + if (Namespaces.XMLNS_NS.equals(namespaceURI)) { int ns = document.alphaLen[nodeNumber]; - if(-1 < ns) { - while(ns < document.nextNamespace && document.namespaceParent[ns] == nodeNumber) { + if (-1 < ns) { + while (ns < document.nextNamespace && document.namespaceParent[ns] == nodeNumber) { final QName nsQName = document.namespaceCode[ns]; - if(nsQName.getLocalPart().equals(localName)) { + if (nsQName.getLocalPart().equals(localName)) { return nsQName.getNamespaceURI(); } ++ns; } } } - return null; + + return ""; } @Override @@ -473,7 +520,32 @@ public Attr setAttributeNodeNS(final Attr newAttr) throws DOMException { @Override public boolean hasAttribute(final String name) { - return getAttribute(name) != null; + int attr = document.alpha[nodeNumber]; + + if (-1 < attr) { + while (attr < document.nextAttr && document.attrParent[attr] == nodeNumber) { + final QName attrQName = document.attrName[attr]; + if (attrQName.getStringValue().equals(name)) { + return true; + } + ++attr; + } + } + + if (name.startsWith(XMLConstants.XMLNS_ATTRIBUTE + ":")) { + int ns = document.alphaLen[nodeNumber]; + if (-1 < ns) { + while (ns < document.nextNamespace && document.namespaceParent[ns] == nodeNumber) { + final QName nsQName = document.namespaceCode[ns]; + if (nsQName.getStringValue().equals(name)) { + return true; + } + ++ns; + } + } + } + + return false; } @Override @@ -556,46 +628,43 @@ public String getBaseURI() { return "";//UNDERSTAND: is it ok? } - //TODO please, keep in sync with org.exist.dom.persistent.ElementImpl + // NOTE(AR) please keep in sync with org.exist.dom.persistent.ElementImpl private XmldbURI calculateBaseURI() { XmldbURI baseURI = null; final String nodeBaseURI = getAttributeNS(Namespaces.XML_NS, "base"); - if(nodeBaseURI != null) { + if (!nodeBaseURI.isEmpty()) { baseURI = XmldbURI.create(nodeBaseURI, false); - if(baseURI.isAbsolute()) { + if (baseURI.isAbsolute()) { return baseURI; } } int parent = -1; final int test = document.getParentNodeFor(nodeNumber); - if(document.nodeKind[test] != Node.DOCUMENT_NODE) { + if (document.nodeKind[test] != Node.DOCUMENT_NODE) { parent = test; } - if(parent != -1) { - if(nodeBaseURI == null) { + if (parent != -1) { + if (nodeBaseURI.isEmpty()) { baseURI = ((ElementImpl) document.getNode(parent)) .calculateBaseURI(); } else { - XmldbURI parentsBaseURI = ((ElementImpl) document.getNode(parent)) - .calculateBaseURI(); - - if(nodeBaseURI.isEmpty()) { - baseURI = parentsBaseURI; - } else { + final XmldbURI parentsBaseURI = ((ElementImpl) document.getNode(parent)).calculateBaseURI(); + if (parentsBaseURI.toString().endsWith("/") || !parentsBaseURI.toString().contains("/")) { baseURI = parentsBaseURI.append(baseURI); + } else { + // there is a filename, remove it + baseURI = parentsBaseURI.removeLastSegment().append(baseURI); } } } else { - if(nodeBaseURI == null) { + if (nodeBaseURI.isEmpty()) { return XmldbURI.create(getOwnerDocument().getBaseURI(), false); - } else if(nodeNumber == 1) { - //nothing to do - } else { + } else if (nodeNumber != 1) { final String docBaseURI = getOwnerDocument().getBaseURI(); - if(docBaseURI.endsWith("/")) { + if (docBaseURI.endsWith("/")) { baseURI = XmldbURI.create(getOwnerDocument().getBaseURI(), false); baseURI.append(baseURI); } else { @@ -605,6 +674,7 @@ private XmldbURI calculateBaseURI() { } } } + return baseURI; } diff --git a/exist-core/src/main/java/org/exist/dom/memtree/MemTreeBuilder.java b/exist-core/src/main/java/org/exist/dom/memtree/MemTreeBuilder.java index bf0424dc5d..10b18bbab7 100644 --- a/exist-core/src/main/java/org/exist/dom/memtree/MemTreeBuilder.java +++ b/exist-core/src/main/java/org/exist/dom/memtree/MemTreeBuilder.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -30,12 +54,15 @@ import org.exist.xquery.XQueryContext; import org.w3c.dom.DOMException; import org.w3c.dom.Node; +import org.w3c.dom.NodeList; import org.xml.sax.Attributes; import javax.annotation.Nullable; import javax.xml.XMLConstants; import java.util.Arrays; +import static org.exist.util.StringUtil.nullIfEmpty; + /** * Use this class to build a new in-memory DOM document. @@ -244,9 +271,9 @@ public void endElement() { public int addReferenceNode(final NodeProxy proxy) { final int lastNode = doc.getLastNode(); - if((lastNode > 0) && (level == doc.getTreeLevel(lastNode))) { + if (lastNode > 0 && level == doc.getTreeLevel(lastNode)) { - if((doc.getNodeType(lastNode) == Node.TEXT_NODE) && (proxy.getNodeType() == Node.TEXT_NODE)) { + if (doc.getNodeType(lastNode) == Node.TEXT_NODE && proxy.getNodeType() == Node.TEXT_NODE) { // if the last node is a text node, we have to append the // characters to this node. XML does not allow adjacent text nodes. @@ -254,12 +281,12 @@ public int addReferenceNode(final NodeProxy proxy) { return lastNode; } - if(doc.getNodeType(lastNode) == NodeImpl.REFERENCE_NODE) { + if (doc.getNodeType(lastNode) == NodeImpl.REFERENCE_NODE) { // check if the previous node is a reference node. if yes, check if it is a text node final int p = doc.alpha[lastNode]; - if((doc.references[p].getNodeType() == Node.TEXT_NODE) && (proxy.getNodeType() == Node.TEXT_NODE)) { + if (doc.references[p].getNodeType() == Node.TEXT_NODE && proxy.getNodeType() == Node.TEXT_NODE) { // found a text node reference. create a new char sequence containing // the concatenated text of both nodes @@ -269,10 +296,40 @@ public int addReferenceNode(final NodeProxy proxy) { } } } - final int nodeNr = doc.addNode(NodeImpl.REFERENCE_NODE, level, null); - doc.addReferenceNode(nodeNr, proxy); - linkNode(nodeNr); - return nodeNr; + + // check if the node is a Document Node, if so we don't add the document, but instead we add all of its children + final NodeProxy[] proxies; + if (proxy.getNodeType() == Node.DOCUMENT_NODE) { + final org.exist.dom.persistent.DocumentImpl document = (org.exist.dom.persistent.DocumentImpl) proxy.getNode(); + final NodeList documentChildren = document.getChildNodes(); + proxies = new NodeProxy[documentChildren.getLength()]; + for (int i = 0; i < documentChildren.getLength(); i++) { + final org.exist.dom.persistent.NodeImpl child = (org.exist.dom.persistent.NodeImpl) documentChildren.item(i); + proxies[i] = NodeProxy.wrap(proxy.getExpression(), child); + } + + // if we are at the top of the in-memory doc, copy over any doctype decl + if (level == 1 && document.getDoctype() != null) { + final DocumentTypeImpl documentType = new DocumentTypeImpl(document.getExpression(), doc, -1, document.getDoctype().getName(), document.getDoctype().getPublicId(), document.getDoctype().getSystemId()); + doc.setDoctype(documentType); + } + } else { + proxies = new NodeProxy[1]; + proxies[0] = proxy; + } + + // add the node proxy(s) as reference node(s) + int firstProxyNodeNr = -1; + for (int i = 0; i < proxies.length; i++) { + final int nodeNr = doc.addNode(NodeImpl.REFERENCE_NODE, level, null); + doc.addReferenceNode(nodeNr, proxies[i]); + linkNode(nodeNr); + + if (firstProxyNodeNr == -1) { + firstProxyNodeNr = nodeNr; + } + } + return firstProxyNodeNr; } @@ -305,22 +362,22 @@ public int addAttribute(final QName qname, final String value) { public int characters(final char[] ch, final int start, final int len) { final int lastNode = doc.getLastNode(); - if((lastNode > 0) && (level == doc.getTreeLevel(lastNode))) { + if (lastNode > 0 && level == doc.getTreeLevel(lastNode)) { - if(doc.getNodeType(lastNode) == Node.TEXT_NODE) { + if (doc.getNodeType(lastNode) == Node.TEXT_NODE || doc.getNodeType(lastNode) == Node.CDATA_SECTION_NODE) { - // if the last node is a text node, we have to append the + // if the last node is a Text or CDATA node, we have to append the // characters to this node. XML does not allow adjacent text nodes. doc.appendChars(lastNode, ch, start, len); return lastNode; } - if(doc.getNodeType(lastNode) == NodeImpl.REFERENCE_NODE) { + if (doc.getNodeType(lastNode) == NodeImpl.REFERENCE_NODE) { - // check if the previous node is a reference node. if yes, check if it is a text node + // check if the previous node is a reference node. if yes, check if it is a Text or CDATA node final int p = doc.alpha[lastNode]; - if(doc.references[p].getNodeType() == Node.TEXT_NODE) { + if (doc.references[p].getNodeType() == Node.TEXT_NODE || doc.references[p].getNodeType() == Node.CDATA_SECTION_NODE) { // found a text node reference. create a new char sequence containing // the concatenated text of both nodes @@ -346,28 +403,28 @@ public int characters(final char[] ch, final int start, final int len) { * @return the node number of the created node, -1 if no node was created */ public int characters(final CharSequence s) { - if(s == null) { + if (s == null) { return -1; } final int lastNode = doc.getLastNode(); - if((lastNode > 0) && (level == doc.getTreeLevel(lastNode))) { + if (lastNode > 0 && level == doc.getTreeLevel(lastNode)) { - if((doc.getNodeType(lastNode) == Node.TEXT_NODE) || (doc.getNodeType(lastNode) == Node.CDATA_SECTION_NODE)) { + if (doc.getNodeType(lastNode) == Node.TEXT_NODE || doc.getNodeType(lastNode) == Node.CDATA_SECTION_NODE) { - // if the last node is a text node, we have to append the + // if the last node is a Text or CDATA node, we have to append the // characters to this node. XML does not allow adjacent text nodes. doc.appendChars(lastNode, s); return lastNode; } - if(doc.getNodeType(lastNode) == NodeImpl.REFERENCE_NODE) { + if (doc.getNodeType(lastNode) == NodeImpl.REFERENCE_NODE) { - // check if the previous node is a reference node. if yes, check if it is a text node final int p = doc.alpha[lastNode]; + // check if the previous node is a reference node. if yes, check if it is a Text or CDATA node - if((doc.references[p].getNodeType() == Node.TEXT_NODE) || (doc.references[p].getNodeType() == Node.CDATA_SECTION_NODE)) { + if (doc.references[p].getNodeType() == Node.TEXT_NODE || doc.references[p].getNodeType() == Node.CDATA_SECTION_NODE) { // found a text node reference. create a new char sequence containing // the concatenated text of both nodes @@ -403,9 +460,9 @@ public int comment(final char[] ch, final int start, final int len) { public int cdataSection(final CharSequence data) { final int lastNode = doc.getLastNode(); - if((lastNode > 0) && (level == doc.getTreeLevel(lastNode))) { + if (lastNode > 0 && level == doc.getTreeLevel(lastNode)) { - if((doc.getNodeType(lastNode) == Node.TEXT_NODE) || (doc.getNodeType(lastNode) == Node.CDATA_SECTION_NODE)) { + if (doc.getNodeType(lastNode) == Node.TEXT_NODE || doc.getNodeType(lastNode) == Node.CDATA_SECTION_NODE) { // if the last node is a text node, we have to append the // characters to this node. XML does not allow adjacent text nodes. @@ -413,12 +470,12 @@ public int cdataSection(final CharSequence data) { return lastNode; } - if(doc.getNodeType(lastNode) == NodeImpl.REFERENCE_NODE) { + if (doc.getNodeType(lastNode) == NodeImpl.REFERENCE_NODE) { // check if the previous node is a reference node. if yes, check if it is a text node final int p = doc.alpha[lastNode]; - if((doc.references[p].getNodeType() == Node.TEXT_NODE) || (doc.references[p].getNodeType() == Node.CDATA_SECTION_NODE)) { + if (doc.references[p].getNodeType() == Node.TEXT_NODE || doc.references[p].getNodeType() == Node.CDATA_SECTION_NODE) { // found a text node reference. create a new char sequence containing // the concatenated text of both nodes @@ -458,14 +515,16 @@ public int namespaceNode(final QName qname) { } public int namespaceNode(final QName qname, final boolean checkNS) { + final String qnPrefix = qname.getPrefix() == null ? XMLConstants.DEFAULT_NS_PREFIX : qname.getPrefix(); + final String qnNs = qname.getNamespaceURI() == null ? XMLConstants.NULL_NS_URI : qname.getNamespaceURI(); + @Nullable final String qnLocalPart = nullIfEmpty(qname.getLocalPart()); + final int lastNode = doc.getLastNode(); - boolean addNode = true; if(doc.nodeName != null) { final QName elemQN = doc.nodeName[lastNode]; if(elemQN != null) { - final String elemPrefix = (elemQN.getPrefix() == null) ? XMLConstants.DEFAULT_NS_PREFIX : elemQN.getPrefix(); - final String elemNs = (elemQN.getNamespaceURI() == null) ? XMLConstants.NULL_NS_URI : elemQN.getNamespaceURI(); - final String qnPrefix = (qname.getPrefix() == null) ? XMLConstants.DEFAULT_NS_PREFIX : qname.getPrefix(); + final String elemPrefix = elemQN.getPrefix() == null ? XMLConstants.DEFAULT_NS_PREFIX : elemQN.getPrefix(); + final String elemNs = elemQN.getNamespaceURI() == null ? XMLConstants.NULL_NS_URI : elemQN.getNamespaceURI(); if (checkNS && XMLConstants.DEFAULT_NS_PREFIX.equals(elemPrefix) && XMLConstants.NULL_NS_URI.equals(elemNs) @@ -477,12 +536,23 @@ public int namespaceNode(final QName qname, final boolean checkNS) { "Cannot output a namespace node for the default namespace when the element is in no namespace." ); } - if(elemPrefix.equals(qname.getLocalPart()) && (elemQN.getNamespaceURI() != null)) { - addNode = false; - } } } - return (addNode ? doc.addNamespace(lastNode, qname) : -1); + + final String prefix; + if (XMLConstants.XMLNS_ATTRIBUTE.equals(qnPrefix) && qnLocalPart != null) { + prefix = qnLocalPart; + } else { + prefix = XMLConstants.DEFAULT_NS_PREFIX; + } + + @Nullable final String existingNs = doc.getInScopePrefix(prefix, lastNode); + if (!qnNs.equals(existingNs)) { + return doc.addNamespace(lastNode, qname); + + } else { + return -1; + } } diff --git a/exist-core/src/main/java/org/exist/dom/memtree/NamespaceNode.java b/exist-core/src/main/java/org/exist/dom/memtree/NamespaceNode.java index 55402f9a0e..feffedf9c7 100644 --- a/exist-core/src/main/java/org/exist/dom/memtree/NamespaceNode.java +++ b/exist-core/src/main/java/org/exist/dom/memtree/NamespaceNode.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -66,7 +90,7 @@ public boolean getSpecified() { @Override public String getName() { - return getQName().getStringValue(); + return getNodeName(); } @Override @@ -78,11 +102,6 @@ public String getValue() { public void setValue(final String value) throws DOMException { } - @Override - public Node getFirstChild() { - return null; - } - @Override public Node getLastChild() { return null; diff --git a/exist-core/src/main/java/org/exist/dom/memtree/NodeImpl.java b/exist-core/src/main/java/org/exist/dom/memtree/NodeImpl.java index 40754e5e81..0f5cbfa870 100644 --- a/exist-core/src/main/java/org/exist/dom/memtree/NodeImpl.java +++ b/exist-core/src/main/java/org/exist/dom/memtree/NodeImpl.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -34,6 +58,7 @@ import org.exist.numbering.NodeId; import org.exist.storage.DBBroker; import org.exist.storage.serializers.Serializer; +import org.exist.util.serializer.AttrList; import org.exist.util.serializer.Receiver; import org.exist.xquery.*; import org.exist.xquery.value.*; @@ -55,13 +80,13 @@ public abstract class NodeImpl> implements INode document.attrName[nodeNumber]; - case Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE -> document.nodeName[nodeNumber]; - case NodeImpl.NAMESPACE_NODE -> document.namespaceCode[nodeNumber]; - case Node.DOCUMENT_NODE, Node.COMMENT_NODE, Node.TEXT_NODE, Node.CDATA_SECTION_NODE -> QName.EMPTY_QNAME; - default -> QName.EMPTY_QNAME; - }; + public QName getQName() { + switch(getNodeType()) { + case Node.ATTRIBUTE_NODE: + return document.attrName[nodeNumber]; + + case Node.ELEMENT_NODE: + case Node.PROCESSING_INSTRUCTION_NODE: + return document.nodeName[nodeNumber]; + + case NodeImpl.NAMESPACE_NODE: + return document.namespaceCode[nodeNumber]; + + case Node.DOCUMENT_NODE: + return QName.EMPTY_QNAME; + + case Node.COMMENT_NODE: + return QName.EMPTY_QNAME; + + case Node.TEXT_NODE: + return QName.EMPTY_QNAME; + + case Node.CDATA_SECTION_NODE: + return QName.EMPTY_QNAME; + + default: + return null; + } } @Override @@ -117,24 +161,57 @@ public final void setQName(final QName qname) { @Override public final String getNodeName() { - return switch (getNodeType()) { - case Node.DOCUMENT_NODE -> "#document"; - case Node.DOCUMENT_FRAGMENT_NODE -> "#document-fragment"; - case Node.ELEMENT_NODE, Node.ATTRIBUTE_NODE, NAMESPACE_NODE -> getQName().getStringValue(); - case Node.PROCESSING_INSTRUCTION_NODE -> ((ProcessingInstructionImpl) this).getTarget(); - case Node.TEXT_NODE -> "#text"; - case Node.COMMENT_NODE -> "#comment"; - case Node.CDATA_SECTION_NODE -> "#cdata-section"; - default -> "#unknown"; - }; + switch(getNodeType()) { + case Node.DOCUMENT_NODE: + return "#document"; + + case Node.DOCUMENT_FRAGMENT_NODE: + return "#document-fragment"; + + case Node.ELEMENT_NODE: + case Node.ATTRIBUTE_NODE: + return getQName().getStringValue(); + + case NAMESPACE_NODE: + if (XMLConstants.XMLNS_ATTRIBUTE.equals(getQName().getPrefix()) && XMLConstants.DEFAULT_NS_PREFIX.equals(getQName().getLocalPart())) { + return XMLConstants.XMLNS_ATTRIBUTE; + } else { + return getQName().getStringValue(); + } + + case Node.PROCESSING_INSTRUCTION_NODE: + return ((ProcessingInstructionImpl)this).getTarget(); + + case Node.TEXT_NODE: + return "#text"; + + case Node.COMMENT_NODE: + return "#comment"; + + case Node.CDATA_SECTION_NODE: + return "#cdata-section"; + + default: + return "#unknown"; + } } @Override public String getLocalName() { - return switch (getNodeType()) { - case Node.ELEMENT_NODE, Node.ATTRIBUTE_NODE, NAMESPACE_NODE -> getQName().getLocalPart(); - default -> null; - }; + switch(getNodeType()) { + case Node.ELEMENT_NODE: + case Node.ATTRIBUTE_NODE: + return getQName().getLocalPart(); + case NAMESPACE_NODE: + if (XMLConstants.XMLNS_ATTRIBUTE.equals(getQName().getPrefix()) && XMLConstants.DEFAULT_NS_PREFIX.equals(getQName().getLocalPart())) { + return null; + } else { + return getQName().getLocalPart(); + } + + default: + return null; + } } @Override @@ -187,6 +264,7 @@ public NodeId getNodeId() { return document.nodeId[nodeNumber]; } + // TODO(AR) see if we can get rid of expansion now we have org.exist.dom.memtree.reference.* classes public void expand() throws DOMException { document.expand(); } @@ -364,6 +442,15 @@ public NamedNodeMap getAttributes() { return null; } + /** + * Get a list of attributes. + * + * @return the attribute list, or null if there are no attributes. + */ + public @Nullable AttrList getAttrList() { + return null; + } + @Override public DocumentImpl getOwnerDocument() { return document; @@ -867,7 +954,7 @@ public boolean isDefaultNamespace(final String namespaceURI) { @Override public String lookupNamespaceURI(final String prefix) { - throw unsupported(); + return document.lookupNamespaceURI(prefix); } @Override diff --git a/exist-core/src/main/java/org/exist/dom/memtree/ProcessingInstructionImpl.java b/exist-core/src/main/java/org/exist/dom/memtree/ProcessingInstructionImpl.java index ad2c3a79ec..913682b992 100644 --- a/exist-core/src/main/java/org/exist/dom/memtree/ProcessingInstructionImpl.java +++ b/exist-core/src/main/java/org/exist/dom/memtree/ProcessingInstructionImpl.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -111,12 +135,6 @@ public String getBaseURI() { return (baseURI); } - @Override - public Node getFirstChild() { - //No child - return null; - } - @Override public int getItemType() { return Type.PROCESSING_INSTRUCTION; diff --git a/exist-core/src/main/java/org/exist/dom/memtree/ReferenceNode.java b/exist-core/src/main/java/org/exist/dom/memtree/ReferenceNode.java deleted file mode 100644 index 5f80f8a007..0000000000 --- a/exist-core/src/main/java/org/exist/dom/memtree/ReferenceNode.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * eXist-db Open Source Native XML Database - * Copyright (C) 2001 The eXist-db Authors - * - * info@exist-db.org - * http://www.exist-db.org - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package org.exist.dom.memtree; - -import org.exist.dom.persistent.NodeProxy; -import org.exist.xquery.Expression; -import org.exist.xquery.NodeTest; -import org.exist.xquery.XPathException; -import org.exist.xquery.value.Sequence; -import org.w3c.dom.DOMException; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; - - -/** - * DOCUMENT ME! - * - * @author wolf - */ -public class ReferenceNode extends NodeImpl { - - public ReferenceNode(final DocumentImpl doc, final int nodeNumber) { - this(null, doc, nodeNumber); - } - - public ReferenceNode(final Expression expression, final DocumentImpl doc, final int nodeNumber) { - super(expression, doc, nodeNumber); - } - - public NodeProxy getReference() { - final int p = document.alpha[nodeNumber]; - return document.references[p]; - } - - @Override - public String toString() { - return "reference[ " + getReference().getNode().toString() + " ]"; - } - - @Override - public String getNamespaceURI() { - return getReference().getNode().getNamespaceURI(); - } - - @Override - public String getLocalName() { - return getReference().getNode().getLocalName(); - } - - @Override - public NamedNodeMap getAttributes() { - return getReference().getNode().getAttributes(); - } - - @Override - public Node getFirstChild() { - //TODO : how to make this node a reference as well ? - return getReference().getNode().getFirstChild(); - } - - @Override - public void selectAttributes(final NodeTest test, final Sequence result) - throws XPathException { - } - - @Override - public void selectChildren(final NodeTest test, final Sequence result) - throws XPathException { - } - - @Override - public void selectDescendantAttributes(final NodeTest test, final Sequence result) - throws XPathException { - } - - @Override - public String getNodeValue() throws DOMException { - return getReference().getNode().getNodeValue(); - } -} \ No newline at end of file diff --git a/exist-core/src/main/java/org/exist/dom/memtree/reference/AbstractReferenceCharacterData.java b/exist-core/src/main/java/org/exist/dom/memtree/reference/AbstractReferenceCharacterData.java new file mode 100644 index 0000000000..94ce237fb1 --- /dev/null +++ b/exist-core/src/main/java/org/exist/dom/memtree/reference/AbstractReferenceCharacterData.java @@ -0,0 +1,81 @@ +/* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package org.exist.dom.memtree.reference; + +import org.exist.dom.memtree.DocumentImpl; +import org.exist.dom.persistent.NodeProxy; +import org.exist.xquery.Expression; +import org.w3c.dom.CharacterData; +import org.w3c.dom.DOMException; + +import javax.annotation.Nullable; + +public class AbstractReferenceCharacterData, P extends org.exist.dom.persistent.AbstractCharacterData

> extends AbstractReferenceNodeImpl implements CharacterData { + + public AbstractReferenceCharacterData(@Nullable final Expression expression, final DocumentImpl doc, final int nodeNumber, final NodeProxy nodeProxy) { + super(expression, doc, nodeNumber, nodeProxy); + } + + @Override + public int compareTo(final T other) { + return getProxiedNode().compareTo(other.getProxiedNode()); + } + + @Override + public String getData() throws DOMException { + return getProxiedNode().getData(); + } + + @Override + public void setData(final String data) throws DOMException { + getProxiedNode().setData(data); + } + + @Override + public int getLength() { + return getProxiedNode().getLength(); + } + + @Override + public String substringData(final int offset, final int count) throws DOMException { + return getProxiedNode().substringData(offset, count); + } + + @Override + public void appendData(final String arg) throws DOMException { + getProxiedNode().appendData(arg); + } + + @Override + public void insertData(final int offset, final String arg) throws DOMException { + getProxiedNode().insertData(offset, arg); + } + + @Override + public void deleteData(int offset, int count) throws DOMException { + + } + + @Override + public void replaceData(int offset, int count, String arg) throws DOMException { + + } +} diff --git a/exist-core/src/main/java/org/exist/dom/memtree/reference/AbstractReferenceNodeImpl.java b/exist-core/src/main/java/org/exist/dom/memtree/reference/AbstractReferenceNodeImpl.java new file mode 100644 index 0000000000..80109afdab --- /dev/null +++ b/exist-core/src/main/java/org/exist/dom/memtree/reference/AbstractReferenceNodeImpl.java @@ -0,0 +1,176 @@ +/* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package org.exist.dom.memtree.reference; + +import org.exist.dom.QName; +import org.exist.dom.memtree.DocumentImpl; +import org.exist.dom.memtree.NodeImpl; +import org.exist.dom.persistent.AttrImpl; +import org.exist.dom.persistent.NodeProxy; +import org.exist.xquery.Expression; +import org.exist.xquery.NodeTest; +import org.exist.xquery.XPathException; +import org.exist.xquery.value.Sequence; +import org.w3c.dom.DOMException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import javax.annotation.Nullable; + +/** + * DOM Wrapper around a NodeProxy for use in the in-memory DOM. + * + * @author Adam Retter + */ +public abstract class AbstractReferenceNodeImpl, P extends org.exist.dom.persistent.NodeImpl

> extends NodeImpl { + + protected final NodeProxy nodeProxy; + + public AbstractReferenceNodeImpl(@Nullable final Expression expression, final DocumentImpl doc, final int nodeNumber, final NodeProxy nodeProxy) { + super(expression, doc, nodeNumber); + this.nodeProxy = nodeProxy; + } + + /** + * Get the node proxy. + * + * @return the node proxy. + */ + public NodeProxy getNodeProxy() { + return nodeProxy; + } + + @SuppressWarnings("unchchecked") + protected P getProxiedNode() { + return (P) nodeProxy.getNode(); + } + + @Override + public String toString() { + return "reference[ " + getProxiedNode().toString() + " ]"; + } + + @Override + public String getNamespaceURI() { + final QName qname = getNodeProxy().getQName(); + if (qname == null) { + return null; + } + return qname.getNamespaceURI(); + } + + @Override + public String getLocalName() { + final QName qname = getNodeProxy().getQName(); + if (qname == null) { + return null; + } + return qname.getLocalPart(); + } + + @Override + public NamedNodeMap getAttributes() { + return getProxiedNode().getAttributes(); + } + + @Override + public NodeList getChildNodes() { + return getProxiedNode().getChildNodes(); + } + + @Override + public Node getFirstChild() { + return getProxiedNode().getFirstChild(); + } + + @Override + public Node getLastChild() { + return getProxiedNode().getLastChild(); + } + + @Override + public boolean hasAttributes() { + return getProxiedNode().hasAttributes(); + } + + @Override + public void selectAttributes(final NodeTest test, final Sequence result) throws XPathException { + selectAttributes(getProxiedNode(), test, result); + } + + @Override + public boolean hasChildNodes() { + return getProxiedNode().hasChildNodes(); + } + + private void selectAttributes(final Node node, final NodeTest test, final Sequence result) throws XPathException { + @Nullable final NamedNodeMap attrs = node.getAttributes(); + if (attrs != null) { + for (int i = 0; i < attrs.getLength(); i++) { + final Node attr = attrs.item(i); + if (test.matches(attr)) { + result.add(new NodeProxy((org.exist.dom.persistent.AttrImpl) attr)); + } + } + } + } + + @Override + public void selectChildren(final NodeTest test, final Sequence result) throws XPathException { + @Nullable final NodeList children = getProxiedNode().getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + final Node child = children.item(i); + if (test.matches(child)) { + result.add(new NodeProxy((org.exist.dom.persistent.NodeHandle) child)); + } + } + } + + @Override + public void selectDescendantAttributes(final NodeTest test, final Sequence result) throws XPathException { + selectDescendantAttributes(getProxiedNode(), test, result); + } + + private void selectDescendantAttributes(final Node node, final NodeTest test, final Sequence result) throws XPathException { + final NodeList children = node.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + final Node child = children.item(i); + selectAttributes(child, test, result); + selectDescendantAttributes(child, test, result); + } + } + + @Override + public String getNodeValue() throws DOMException { + return getProxiedNode().getNodeValue(); + } + + @Override + public short getNodeType() { + return getNodeProxy().getNodeType(); + } + + @Override + public QName getQName() { + return getNodeProxy().getQName(); + } +} \ No newline at end of file diff --git a/exist-core/src/main/java/org/exist/dom/memtree/reference/CommentReferenceImpl.java b/exist-core/src/main/java/org/exist/dom/memtree/reference/CommentReferenceImpl.java new file mode 100644 index 0000000000..073ebea62e --- /dev/null +++ b/exist-core/src/main/java/org/exist/dom/memtree/reference/CommentReferenceImpl.java @@ -0,0 +1,40 @@ +/* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package org.exist.dom.memtree.reference; + +import org.exist.dom.memtree.DocumentImpl; +import org.exist.dom.persistent.NodeProxy; +import org.exist.xquery.Expression; +import org.w3c.dom.Comment; + +import javax.annotation.Nullable; + +/** + * Comment wrapper around a NodeProxy for use in the in-memory DOM. + * + * @author Adam Retter + */ +public class CommentReferenceImpl extends AbstractReferenceCharacterData implements Comment { + + public CommentReferenceImpl(@Nullable final Expression expression, final DocumentImpl doc, final int nodeNumber, final NodeProxy nodeProxy) { + super(expression, doc, nodeNumber, nodeProxy); + } +} diff --git a/exist-core/src/main/java/org/exist/dom/memtree/reference/ElementReferenceImpl.java b/exist-core/src/main/java/org/exist/dom/memtree/reference/ElementReferenceImpl.java new file mode 100644 index 0000000000..850d00e5f7 --- /dev/null +++ b/exist-core/src/main/java/org/exist/dom/memtree/reference/ElementReferenceImpl.java @@ -0,0 +1,174 @@ +/* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package org.exist.dom.memtree.reference; + +import org.exist.dom.QName; +import org.exist.dom.memtree.DocumentImpl; +import org.exist.dom.persistent.AttrImpl; +import org.exist.dom.persistent.NodeProxy; +import org.exist.dom.persistent.StoredNode; +import org.exist.numbering.NodeId; +import org.exist.storage.ElementValue; +import org.exist.util.serializer.AttrList; +import org.exist.xquery.Expression; +import org.w3c.dom.*; + +import javax.annotation.Nullable; + +/** + * Element wrapper around a NodeProxy for use in the in-memory DOM. + * + * @author Adam Retter + */ +public class ElementReferenceImpl extends AbstractReferenceNodeImpl implements Element { + + public ElementReferenceImpl(@Nullable final Expression expression, final DocumentImpl doc, final int nodeNumber, final NodeProxy nodeProxy) { + super(expression, doc, nodeNumber, nodeProxy); + } + + @Override + public int compareTo(final ElementReferenceImpl other) { + return 0; + } + + @Override + public String getTagName() { + final QName qname = getNodeProxy().getQName(); + if (qname == null) { + return null; + } + return qname.getStringValue(); + } + + @Override + public @Nullable AttrList getAttrList() { + @Nullable AttrList attrList = null; + @Nullable final NamedNodeMap attributes = getProxiedNode().getAttributes(); + if (attributes != null) { + final int attrsLength = attributes.getLength(); + for (int i = 0; i > attrsLength; i++) { + if (attrList == null) { + attrList = new AttrList(attrsLength); + } + final Attr attr = (Attr) attributes.item(i); + final QName attrQname = new QName(attr.getLocalName(), attr.getNamespaceURI(), attr.getPrefix(), ElementValue.ATTRIBUTE); + final NodeId attrNodeId = attr instanceof StoredNode ? ((StoredNode) attr).getNodeId() : null; + attrList.addAttribute(attrQname, attr.getValue(), AttrImpl.CDATA, attrNodeId); + } + } + return attrList; + } + + @Override + public String getAttribute(final String name) { + return getProxiedNode().getAttribute(name); + } + + @Override + public void setAttribute(final String name, final String value) throws DOMException { + getProxiedNode().setAttribute(name, value); + } + + @Override + public void removeAttribute(final String name) throws DOMException { + getProxiedNode().removeAttribute(name); + } + + @Override + public Attr getAttributeNode(final String name) { + return getProxiedNode().getAttributeNode(name); + } + + @Override + public Attr setAttributeNode(final Attr attr) throws DOMException { + return getProxiedNode().setAttributeNode(attr); + } + + @Override + public Attr removeAttributeNode(final Attr attr) throws DOMException { + return getProxiedNode().removeAttributeNode(attr); + } + + @Override + public NodeList getElementsByTagName(final String name) { + return getProxiedNode().getElementsByTagName(name); + } + + @Override + public String getAttributeNS(final String namespaceUri, final String localName) throws DOMException { + return getProxiedNode().getAttributeNS(namespaceUri, localName); + } + + @Override + public void setAttributeNS(final String namespaceUri, final String qualifiedName, final String value) throws DOMException { + getProxiedNode().setAttributeNS(namespaceUri, qualifiedName, value); + } + + @Override + public void removeAttributeNS(final String namespaceUri, final String localName) throws DOMException { + getProxiedNode().removeAttributeNS(namespaceUri, localName); + } + + @Override + public Attr getAttributeNodeNS(final String namespaceUri, final String localName) throws DOMException { + return getProxiedNode().getAttributeNodeNS(namespaceUri, localName); + } + + @Override + public Attr setAttributeNodeNS(final Attr attr) throws DOMException { + return getProxiedNode().setAttributeNodeNS(attr); + } + + @Override + public NodeList getElementsByTagNameNS(final String namespaceUri, final String localName) throws DOMException { + return getProxiedNode().getElementsByTagNameNS(namespaceUri, localName); + } + + @Override + public boolean hasAttribute(final String name) { + return getProxiedNode().hasAttribute(name); + } + + @Override + public boolean hasAttributeNS(final String namespaceUri, final String localName) throws DOMException { + return getProxiedNode().hasAttributeNS(namespaceUri, localName); + } + + @Override + public TypeInfo getSchemaTypeInfo() { + return getProxiedNode().getSchemaTypeInfo(); + } + + @Override + public void setIdAttribute(final String name, final boolean isId) throws DOMException { + getProxiedNode().setIdAttribute(name, isId); + } + + @Override + public void setIdAttributeNS(final String namespaceUri, final String localName, final boolean isId) throws DOMException { + getProxiedNode().setIdAttributeNS(namespaceUri, localName, isId); + } + + @Override + public void setIdAttributeNode(final Attr attr, final boolean isId) throws DOMException { + getProxiedNode().setIdAttributeNode(attr, isId); + } +} diff --git a/exist-core/src/main/java/org/exist/dom/memtree/reference/ProcessingInstructionReferenceImpl.java b/exist-core/src/main/java/org/exist/dom/memtree/reference/ProcessingInstructionReferenceImpl.java new file mode 100644 index 0000000000..cc4982ad56 --- /dev/null +++ b/exist-core/src/main/java/org/exist/dom/memtree/reference/ProcessingInstructionReferenceImpl.java @@ -0,0 +1,61 @@ +/* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package org.exist.dom.memtree.reference; + +import org.exist.dom.memtree.DocumentImpl; +import org.exist.dom.persistent.NodeProxy; +import org.exist.xquery.Expression; +import org.w3c.dom.DOMException; +import org.w3c.dom.ProcessingInstruction; + +import javax.annotation.Nullable; + +/** + * Processing Instruction wrapper around a NodeProxy for use in the in-memory DOM. + * + * @author Adam Retter + */ +public class ProcessingInstructionReferenceImpl extends AbstractReferenceNodeImpl implements ProcessingInstruction { + + public ProcessingInstructionReferenceImpl(@Nullable final Expression expression, final DocumentImpl doc, final int nodeNumber, final NodeProxy nodeProxy) { + super(expression, doc, nodeNumber, nodeProxy); + } + + @Override + public int compareTo(final ProcessingInstructionReferenceImpl other) { + return 0; + } + + @Override + public String getTarget() { + return getProxiedNode().getTarget(); + } + + @Override + public String getData() { + return getProxiedNode().getData(); + } + + @Override + public void setData(final String data) throws DOMException { + getProxiedNode().setData(data); + } +} diff --git a/exist-core/src/main/java/org/exist/dom/memtree/reference/TextReferenceImpl.java b/exist-core/src/main/java/org/exist/dom/memtree/reference/TextReferenceImpl.java new file mode 100644 index 0000000000..730e3d470e --- /dev/null +++ b/exist-core/src/main/java/org/exist/dom/memtree/reference/TextReferenceImpl.java @@ -0,0 +1,61 @@ +/* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package org.exist.dom.memtree.reference; + +import org.exist.dom.memtree.DocumentImpl; +import org.exist.dom.persistent.NodeProxy; +import org.exist.xquery.Expression; +import org.w3c.dom.DOMException; +import org.w3c.dom.Text; + +import javax.annotation.Nullable; + +/** + * Text wrapper around a NodeProxy for use in the in-memory DOM. + * + * @author Adam Retter + */ +public class TextReferenceImpl extends AbstractReferenceCharacterData implements Text { + + public TextReferenceImpl(@Nullable final Expression expression, final DocumentImpl doc, final int nodeNumber, final NodeProxy nodeProxy) { + super(expression, doc, nodeNumber, nodeProxy); + } + + @Override + public Text splitText(final int offset) throws DOMException { + return getProxiedNode().splitText(offset); + } + + @Override + public boolean isElementContentWhitespace() { + return getProxiedNode().isElementContentWhitespace(); + } + + @Override + public String getWholeText() { + return getProxiedNode().getWholeText(); + } + + @Override + public Text replaceWholeText(final String content) throws DOMException { + return getProxiedNode().replaceWholeText(content); + } +} diff --git a/exist-core/src/main/java/org/exist/dom/persistent/AbstractArrayNodeSet.java b/exist-core/src/main/java/org/exist/dom/persistent/AbstractArrayNodeSet.java index 634edb1c70..9b85afccae 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/AbstractArrayNodeSet.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/AbstractArrayNodeSet.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * diff --git a/exist-core/src/main/java/org/exist/dom/persistent/AbstractCharacterData.java b/exist-core/src/main/java/org/exist/dom/persistent/AbstractCharacterData.java index b23d6f2c8d..9ad53845d3 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/AbstractCharacterData.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/AbstractCharacterData.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -30,7 +54,7 @@ import org.w3c.dom.DOMException; import org.w3c.dom.Node; -public abstract class AbstractCharacterData extends StoredNode implements CharacterData { +public abstract class AbstractCharacterData> extends StoredNode implements CharacterData { protected XMLString cdata = null; diff --git a/exist-core/src/main/java/org/exist/dom/persistent/AbstractNodeSet.java b/exist-core/src/main/java/org/exist/dom/persistent/AbstractNodeSet.java index 250070ecfc..c600b75b5e 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/AbstractNodeSet.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/AbstractNodeSet.java @@ -547,7 +547,7 @@ public NodeSet getContextNodes(final int contextId) { if (Expression.NO_CONTEXT_ID != contextId) { context.addContextNode(contextId, context); } - if (lastDoc != null && lastDoc.getDocId() != context.getOwnerDocument().getDocId()) { + if (lastDoc == null || lastDoc.getDocId() != context.getOwnerDocument().getDocId()) { lastDoc = context.getOwnerDocument(); result.add(context, getSizeHint(lastDoc)); } else { diff --git a/exist-core/src/main/java/org/exist/dom/persistent/AttrImpl.java b/exist-core/src/main/java/org/exist/dom/persistent/AttrImpl.java index f46530fe92..a829fb5639 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/AttrImpl.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/AttrImpl.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -376,6 +400,11 @@ public Node getFirstChild() { return null; } + @Override + public Node getPreviousSibling() { + return null; + } + @Override public Node getNextSibling() { return null; diff --git a/exist-core/src/main/java/org/exist/dom/persistent/BinaryDocument.java b/exist-core/src/main/java/org/exist/dom/persistent/BinaryDocument.java index f9c12b3666..36583072a0 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/BinaryDocument.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/BinaryDocument.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -27,7 +51,7 @@ import org.exist.storage.BrokerPool; import org.exist.storage.blob.BlobId; import org.exist.storage.io.VariableByteInput; -import org.exist.storage.io.VariableByteOutputStream; +import org.exist.storage.io.VariableByteOutput; import org.exist.xmldb.XmldbURI; import org.exist.xquery.Expression; import org.w3c.dom.DocumentType; @@ -167,7 +191,7 @@ public void setBlobId(final BlobId blobId) { } @Override - public void write(final VariableByteOutputStream ostream) throws IOException { + public void write(final VariableByteOutput ostream) throws IOException { ostream.writeInt(getDocId()); ostream.writeUTF(getFileURI().toString()); @@ -181,7 +205,7 @@ public void write(final VariableByteOutputStream ostream) throws IOException { // document attributes ostream.writeLong(created); ostream.writeLong(lastModified); - ostream.writeInt(pool.getSymbols().getMimeTypeId(mimeType)); + ostream.writeInt(pool.getSymbols().getMimeTypeId(mediaType)); ostream.writeInt(pageCount); ostream.writeInt(userLock); if (docType != null) { diff --git a/exist-core/src/main/java/org/exist/dom/persistent/CommentImpl.java b/exist-core/src/main/java/org/exist/dom/persistent/CommentImpl.java index 91af39abf2..99d7ec3c7a 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/CommentImpl.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/CommentImpl.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -31,7 +55,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; -public class CommentImpl extends AbstractCharacterData implements Comment { +public class CommentImpl extends AbstractCharacterData implements Comment { public CommentImpl() { this((Expression) null); diff --git a/exist-core/src/main/java/org/exist/dom/persistent/DocumentImpl.java b/exist-core/src/main/java/org/exist/dom/persistent/DocumentImpl.java index be75909778..e5a0f919b8 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/DocumentImpl.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/DocumentImpl.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -35,11 +59,10 @@ import org.exist.security.*; import org.exist.storage.*; import org.exist.storage.io.VariableByteInput; -import org.exist.storage.io.VariableByteOutputStream; +import org.exist.storage.io.VariableByteOutput; import org.exist.storage.lock.EnsureContainerLocked; import org.exist.storage.lock.EnsureLocked; import org.exist.storage.txn.Txn; -import org.exist.util.MimeType; import org.exist.util.XMLString; import org.exist.xmldb.XmldbURI; import org.exist.xquery.Constants; @@ -47,6 +70,7 @@ import org.exist.xquery.NameTest; import org.exist.xquery.value.Type; import org.w3c.dom.*; +import xyz.elemental.mediatype.MediaType; import javax.annotation.Nullable; import javax.xml.XMLConstants; @@ -121,7 +145,7 @@ public class DocumentImpl extends NodeImpl implements Resource, Do /** * The mimeType of the document */ - protected String mimeType = MimeType.XML_TYPE.getName(); + protected String mediaType = MediaType.APPLICATION_XML; /** * The creation time of this document @@ -248,7 +272,7 @@ public DocumentImpl(final Expression expression, final int docId, final Document * @param childAddress the addresses of the child nodes * @param created the created time of the document * @param lastModified the last modified time of the document, or null to use the {@code created} time - * @param mimeType the media type of the document, or null for application/xml + * @param mediaType the media type of the document, or null for application/xml * @param docType the document type, or null * * @deprecated Use {@link DocumentImpl(BrokerPool, Collection, int, XmldbURI, Permission, int, long[], long, Long, String, XMLDeclarationImpl, DocumentType)} @@ -257,9 +281,9 @@ public DocumentImpl(final Expression expression, final int docId, final Document public DocumentImpl(final BrokerPool pool, @Nullable final Collection collection, final int docId, final XmldbURI fileURI, final Permission permissions, final int children, @Nullable final long[] childAddress, - final long created, @Nullable final Long lastModified, @Nullable final String mimeType, + final long created, @Nullable final Long lastModified, @Nullable final String mediaType, @Nullable final DocumentType docType) { - this(null, pool, collection, docId, fileURI, permissions, children, childAddress, created, lastModified, mimeType, null, docType); + this(null, pool, collection, docId, fileURI, permissions, children, childAddress, created, lastModified, mediaType, null, docType); } /** @@ -274,16 +298,16 @@ public DocumentImpl(final BrokerPool pool, @Nullable final Collection collection * @param childAddress the addresses of the child nodes * @param created the created time of the document * @param lastModified the last modified time of the document, or null to use the {@code created} time - * @param mimeType the media type of the document, or null for application/xml + * @param mediaType the media type of the document, or null for application/xml * @param xmlDecl the XML Declaration, or null * @param docType the document type, or null */ public DocumentImpl(final BrokerPool pool, @Nullable final Collection collection, final int docId, final XmldbURI fileURI, final Permission permissions, final int children, @Nullable final long[] childAddress, - final long created, @Nullable final Long lastModified, @Nullable final String mimeType, + final long created, @Nullable final Long lastModified, @Nullable final String mediaType, @Nullable final XMLDeclarationImpl xmlDecl, @Nullable final DocumentType docType) { - this(null, pool, collection, docId, fileURI, permissions, children, childAddress, created, lastModified, mimeType, xmlDecl, docType); + this(null, pool, collection, docId, fileURI, permissions, children, childAddress, created, lastModified, mediaType, xmlDecl, docType); } /** @@ -299,7 +323,7 @@ public DocumentImpl(final BrokerPool pool, @Nullable final Collection collection * @param childAddress the addresses of the child nodes * @param created the created time of the document * @param lastModified the last modified time of the document, or null to use the {@code created} time - * @param mimeType the media type of the document, or null for application/xml + * @param mediaType the media type of the document, or null for application/xml * @param docType the document type, or null * * @deprecated Use {@link DocumentImpl(Expression, BrokerPool, Collection, int ,XmldbURI, Permission, int, long[], long, Long, String, XMLDeclarationImpl, DocumentType)} @@ -308,9 +332,9 @@ public DocumentImpl(final BrokerPool pool, @Nullable final Collection collection public DocumentImpl(final Expression expression, final BrokerPool pool, @Nullable final Collection collection, final int docId, final XmldbURI fileURI, final Permission permissions, final int children, @Nullable final long[] childAddress, - final long created, @Nullable final Long lastModified, @Nullable final String mimeType, + final long created, @Nullable final Long lastModified, @Nullable final String mediaType, @Nullable final DocumentType docType) { - this(expression, pool, collection, docId, fileURI, permissions, children, childAddress, created, lastModified, mimeType, null, docType); + this(expression, pool, collection, docId, fileURI, permissions, children, childAddress, created, lastModified, mediaType, null, docType); } /** @@ -326,14 +350,14 @@ public DocumentImpl(final Expression expression, final BrokerPool pool, @Nullabl * @param childAddress the addresses of the child nodes * @param created the created time of the document * @param lastModified the last modified time of the document, or null to use the {@code created} time - * @param mimeType the media type of the document, or null for application/xml + * @param mediaType the media type of the document, or null for application/xml * @param xmlDecl the XML Declaration, or null * @param docType the document type, or null */ public DocumentImpl(final Expression expression, final BrokerPool pool, @Nullable final Collection collection, final int docId, final XmldbURI fileURI, final Permission permissions, final int children, @Nullable final long[] childAddress, - final long created, @Nullable final Long lastModified, @Nullable final String mimeType, + final long created, @Nullable final Long lastModified, @Nullable final String mediaType, @Nullable final XMLDeclarationImpl xmlDecl, @Nullable final DocumentType docType) { super(expression); this.pool = pool; @@ -348,7 +372,7 @@ public DocumentImpl(final Expression expression, final BrokerPool pool, @Nullabl this.childAddress = childAddress; this.created = created; this.lastModified = lastModified == null ? created : lastModified; - this.mimeType = mimeType == null ? MimeType.XML_TYPE.getName() : mimeType; + this.mediaType = mediaType != null ? mediaType : MediaType.APPLICATION_XML; this.xmlDecl = xmlDecl; this.docType = docType; @@ -465,12 +489,42 @@ public void setLastModified(final long lastModified) { this.lastModified = lastModified; } + /** + * Get the Internet Media Type of the document. + * + * @return the Internet Media Type of the document. + * + * @deprecated Use {@link #getMediaType()} instead. + */ + @Deprecated public String getMimeType() { - return mimeType; + return mediaType; } + /** + * Set the Internet Media Type of the document. + * + * @deprecated Use {@link #setMediaType(String)} instead. + */ + @Deprecated public void setMimeType(final String mimeType) { - this.mimeType = mimeType; + this.mediaType = mimeType; + } + + /** + * Get the Internet Media Type of the document. + * + * @return the Internet Media Type of the document. + */ + public String getMediaType() { + return mediaType; + } + + /** + * Set the Internet Media Type of the document. + */ + public void setMediaType(final String mediaType) { + this.mediaType = mediaType; } /** @@ -521,6 +575,14 @@ public void setLockToken(final LockToken token) { lockToken = token; } + /** + * Get the Document Type. + * + * @return the document type. + * + * @deprecated use {@link #getDoctype()}. + */ + @Deprecated public DocumentType getDocType() { return docType; } @@ -612,7 +674,7 @@ public DocumentMetadata getMetadata() { * Copy the relevant internal fields from the specified document object. * This is called by {@link Collection} when replacing a document. * - * @param broker eXist-db DBBroker + * @param broker the DBBroker * @param other a DocumentImpl value * @param prev if there was an existing document which we are replacing, * we will copy the mode, ACL, and birth time from the existing document. @@ -625,7 +687,7 @@ public void copyOf(final DBBroker broker, final DocumentImpl other, @EnsureLocke /** * Copy the relevant internal fields from the specified document object. * This is called by {@link Collection} when replacing a document. - * @param broker eXist-db DBBroker + * @param broker the DBBroker * @param other a DocumentImpl value * @param prev if there was an existing document which we are replacing, * we will copy the mode, ACL, and birth time from the existing document. @@ -651,7 +713,7 @@ private void copyOf(final DBBroker broker, @EnsureLocked(mode=READ_LOCK) final D this.created = other.created; this.lastModified = other.lastModified; - this.mimeType = other.mimeType; + this.mediaType = other.mediaType; this.docType = other.docType; final long timestamp = System.currentTimeMillis(); @@ -689,7 +751,7 @@ private void copyModeAcl(final DBBroker broker, final Permission srcPermissions, PermissionFactory.chmod(broker, destPermissions, Optional.of(srcPermissions.getMode()), Optional.empty()); if (srcPermissions instanceof SimpleACLPermission srcAclPermissions && destPermissions instanceof SimpleACLPermission destAclPermissions) { - if (!destAclPermissions.equalsAcl(srcAclPermissions)) { + if (!destAclPermissions.aclEquals(srcAclPermissions)) { PermissionFactory.chacl(destAclPermissions, newAcl -> ((SimpleACLPermission)newAcl).copyAclOf(srcAclPermissions) ); @@ -761,12 +823,14 @@ public void triggerDefrag() { } /** - * The method getNode + * Retrieve a node from the document + * by its nodeId * - * @param nodeId a NodeId value - * @return a Node value + * @param nodeId the nodeId of the node to find. + * + * @return the node, or null if it does not exist. */ - public Node getNode(final NodeId nodeId) { + @Nullable Node getNode(final NodeId nodeId) { try(final DBBroker broker = pool.getBroker()) { return broker.objectWith(this, nodeId); } catch(final EXistException e) { @@ -776,16 +840,21 @@ public Node getNode(final NodeId nodeId) { } /** - * The method getNode + * Retrieve a node from the document + * by its nodeProxy * - * @param p a NodeProxy value - * @return a Node value + * This should only be called from {@link NodeProxy#getNode()}. + * + * @param p the proxy of the node to find. + * + * @return the node, or null if it does not exist. */ - public Node getNode(final NodeProxy p) { - if(p.getNodeId().getTreeLevel() == 1) { - return getDocumentElement(); + Node getNode(final NodeProxy p) { + if (p.getNodeId() == NodeId.DOCUMENT_NODE || p.getNodeId().equals(NodeId.DOCUMENT_NODE)) { + return this; } - try(final DBBroker broker = pool.getBroker()) { + + try (final DBBroker broker = pool.getBroker()) { return broker.objectWith(p); } catch(final Exception e) { LOG.warn("Error occurred while retrieving node: {}", e.getMessage(), e); @@ -820,11 +889,11 @@ public void appendChild(final NodeHandle child) throws DOMException { /** * The method write * - * @param ostream a VariableByteOutputStream value + * @param ostream a VariableByteOutput value * @throws IOException if an error occurs */ @EnsureContainerLocked(mode=READ_LOCK) - public void write(final VariableByteOutputStream ostream) throws IOException { + public void write(final VariableByteOutput ostream) throws IOException { try { ostream.writeInt(docId); ostream.writeUTF(fileURI.toString()); @@ -846,10 +915,10 @@ public void write(final VariableByteOutputStream ostream) throws IOException { } } - void writeDocumentAttributes(final SymbolTable symbolTable, final VariableByteOutputStream ostream) throws IOException { + void writeDocumentAttributes(final SymbolTable symbolTable, final VariableByteOutput ostream) throws IOException { ostream.writeLong(created); ostream.writeLong(lastModified); - ostream.writeInt(symbolTable.getMimeTypeId(mimeType)); + ostream.writeInt(symbolTable.getMimeTypeId(mediaType)); ostream.writeInt(pageCount); ostream.writeInt(userLock); if (xmlDecl != null) { @@ -990,14 +1059,13 @@ public IStoredNode updateChild(final Txn transaction, final Node oldChild, final @Override @EnsureContainerLocked(mode=READ_LOCK) public Node getFirstChild() { - if(children == 0) { + if (children == 0) { return null; } - try(final DBBroker broker = pool.getBroker()) { - return broker.objectWith(new NodeProxy(getExpression(), this, NodeId.DOCUMENT_NODE, childAddress[0])); - } catch(final EXistException e) { + try (final DBBroker broker = pool.getBroker()) { + return broker.objectWith(getFirstChildProxy()); + } catch (final EXistException e) { LOG.warn("Exception while inserting node: {}", e.getMessage(), e); - //TODO : throw exception ? } return null; } @@ -1008,9 +1076,9 @@ protected NodeProxy getFirstChildProxy() { } /** - * The method getFirstChildAddress + * Get the address of the first child. * - * @return a long value + * @return the address of the first child. */ @EnsureContainerLocked(mode=READ_LOCK) public long getFirstChildAddress() { @@ -1020,6 +1088,37 @@ public long getFirstChildAddress() { return childAddress[0]; } + @Override + @EnsureContainerLocked(mode=READ_LOCK) + public Node getLastChild() { + if (children == 0) { + return null; + } + try (final DBBroker broker = pool.getBroker()) { + return broker.objectWith(getLastChildProxy()); + } catch (final EXistException e) { + LOG.warn("Exception while inserting node: {}", e.getMessage(), e); + } + return null; + } + + @EnsureContainerLocked(mode=READ_LOCK) + protected NodeProxy getLastChildProxy() { + return new NodeProxy(getExpression(), this, NodeId.ROOT_NODE, Node.ELEMENT_NODE, childAddress[children - 1]); + } + + /** + * Get the address of the last child. + * + * @return the address of the last child. + */ + @EnsureContainerLocked(mode=READ_LOCK) + public long getLastChildAddress() { + if (children == 0) { + return StoredNode.UNKNOWN_NODE_IMPL_ADDRESS; + } + return childAddress[children - 1]; + } @Override public boolean hasChildNodes() { @@ -1030,14 +1129,18 @@ public boolean hasChildNodes() { @EnsureContainerLocked(mode=READ_LOCK) public NodeList getChildNodes() { final org.exist.dom.NodeListImpl list = new org.exist.dom.NodeListImpl(); - try(final DBBroker broker = pool.getBroker()) { - for(int i = 0; i < children; i++) { - final Node child = broker.objectWith(new NodeProxy(getExpression(), this, NodeId.DOCUMENT_NODE, childAddress[i])); + + @Nullable final NodeProxy nodeProxy = children > 0 ? new NodeProxy(getExpression(), this, NodeId.DOCUMENT_NODE) : null; + try (final DBBroker broker = pool.getBroker()) { + for (int i = 0; i < children; i++) { + nodeProxy.setInternalAddress(childAddress[i]); + final Node child = broker.objectWith(nodeProxy); list.add(child); } - } catch(final EXistException e) { + } catch (final EXistException e) { LOG.warn("Exception while retrieving child nodes: {}", e.getMessage(), e); } + return list; } @@ -1357,12 +1460,19 @@ public Text createTextNode(final String data) { */ @Override public Element getDocumentElement() { - final NodeList cl = getChildNodes(); - for(int i = 0; i < cl.getLength(); i++) { - if(cl.item(i).getNodeType() == Node.ELEMENT_NODE) { - return (Element) cl.item(i); + try (final DBBroker broker = pool.getBroker()) { + @Nullable final NodeProxy childNodeProxy = children > 0 ? new NodeProxy(getExpression(), this, NodeId.DOCUMENT_NODE) : null; + for (int i = 0; i < children; i++) { + childNodeProxy.setInternalAddress(childAddress[i]); + final Node child = broker.objectWith(childNodeProxy); + if (child.getNodeType() == Node.ELEMENT_NODE) { + return (Element) child; + } } + } catch(final EXistException e) { + LOG.warn("Exception while retrieving document element: {}", e.getMessage(), e); } + return null; } @@ -1572,8 +1682,9 @@ public String getBaseURI() { @Override public String toString() { + @Nullable final Element documentElement = getDocumentElement(); return getURI() + " - <" + - (getDocumentElement() != null ? getDocumentElement().getNodeName() : null) + ">"; + (documentElement != null ? documentElement.getNodeName() : null) + ">"; } @Override diff --git a/exist-core/src/main/java/org/exist/dom/persistent/DocumentMetadata.java b/exist-core/src/main/java/org/exist/dom/persistent/DocumentMetadata.java index 77bdb4bd2c..6b6252f1b3 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/DocumentMetadata.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/DocumentMetadata.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -23,7 +47,7 @@ import org.exist.ResourceMetadata; import org.exist.storage.io.VariableByteInput; -import org.exist.storage.io.VariableByteOutputStream; +import org.exist.storage.io.VariableByteOutput; import org.w3c.dom.DocumentType; import java.io.IOException; @@ -71,12 +95,12 @@ public void setLastModified(final long lastModified) { @Deprecated public String getMimeType() { - return doc.getMimeType(); + return doc.getMediaType(); } @Deprecated public void setMimeType(final String mimeType) { - doc.setMimeType(mimeType); + doc.setMediaType(mimeType); } @Deprecated @@ -100,7 +124,7 @@ public void decPageCount() { } @Deprecated - public void write(final SymbolTable symbolTable, final VariableByteOutputStream ostream) throws IOException { + public void write(final SymbolTable symbolTable, final VariableByteOutput ostream) throws IOException { doc.writeDocumentAttributes(symbolTable, ostream); } @@ -109,7 +133,7 @@ public void read(final SymbolTable symbolTable, final VariableByteInput istream) final long created = istream.readLong(); final long lastModified = istream.readLong(); final int mimeTypeSymbolsIndex = istream.readInt(); - final String mimeType = symbolTable.getMimeType(mimeTypeSymbolsIndex); + final String mediaType = symbolTable.getMimeType(mimeTypeSymbolsIndex); final int pageCount = istream.readInt(); final int userLock = istream.readInt(); final DocumentTypeImpl docType; @@ -127,7 +151,7 @@ public void read(final SymbolTable symbolTable, final VariableByteInput istream) doc.setCreated(created); doc.setLastModified(lastModified); - doc.setMimeType(mimeType); + doc.setMediaType(mediaType); doc.setPageCount(pageCount); doc.setUserLock(userLock); doc.setDocType(docType); diff --git a/exist-core/src/main/java/org/exist/dom/persistent/DocumentSet.java b/exist-core/src/main/java/org/exist/dom/persistent/DocumentSet.java index 520e5ce238..05c1d1fb27 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/DocumentSet.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/DocumentSet.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -55,7 +79,7 @@ public interface DocumentSet { /** * Locks all of the documents currently in the document set. * - * @param broker the eXist-db DBBroker + * @param broker the DBBroker * @param exclusive true if a WRITE_LOCK is required, false if a READ_LOCK is required * @return The locks * @throws LockException if locking any document fails, when thrown no locks will be held on any documents in the set diff --git a/exist-core/src/main/java/org/exist/dom/persistent/DocumentTypeImpl.java b/exist-core/src/main/java/org/exist/dom/persistent/DocumentTypeImpl.java index 4fb48d3f7e..e1bfb1d470 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/DocumentTypeImpl.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/DocumentTypeImpl.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -23,7 +47,7 @@ import net.jcip.annotations.ThreadSafe; import org.exist.storage.io.VariableByteInput; -import org.exist.storage.io.VariableByteOutputStream; +import org.exist.storage.io.VariableByteOutput; import org.exist.xquery.Expression; import org.w3c.dom.DocumentType; import org.w3c.dom.NamedNodeMap; @@ -79,7 +103,7 @@ public String getInternalSubset() { return null; } - protected void write(final VariableByteOutputStream ostream) throws IOException { + protected void write(final VariableByteOutput ostream) throws IOException { ostream.writeUTF(name); ostream.writeUTF(systemId != null ? systemId : ""); ostream.writeUTF(publicId != null ? publicId : ""); diff --git a/exist-core/src/main/java/org/exist/dom/persistent/ElementImpl.java b/exist-core/src/main/java/org/exist/dom/persistent/ElementImpl.java index a0fb05c65b..c58e77d777 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/ElementImpl.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/ElementImpl.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -51,6 +75,7 @@ import org.exist.xquery.value.StringValue; import org.w3c.dom.*; +import javax.annotation.Nullable; import javax.xml.XMLConstants; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamException; @@ -171,10 +196,7 @@ public int getPosition() { } public boolean declaresNamespacePrefixes() { - if(namespaceMappings == null) { - return false; - } - return namespaceMappings.size() > 0; + return namespaceMappings != null && !namespaceMappings.isEmpty(); } /** @@ -450,13 +472,13 @@ public static void readNamespaceDecls(final List namespaces, final Val } public void addNamespaceMapping(final String prefix, final String ns) { - if(prefix == null) { + if (prefix == null) { return; } - if(namespaceMappings == null) { + if (namespaceMappings == null) { namespaceMappings = new HashMap<>(1); - } else if(namespaceMappings.containsKey(prefix)) { + } else if (namespaceMappings.containsKey(prefix)) { return; } @@ -803,8 +825,7 @@ public String getAttribute(final String name) { @Override public String getAttributeNS(final String namespaceURI, final String localName) { final Attr attr = findAttribute(new QName(localName, namespaceURI)); - return attr != null ? attr.getValue() : XMLConstants.NULL_NS_URI; - //XXX: if not present must return null + return attr != null ? attr.getValue() : ""; } @Deprecated //move as soon as getAttributeNS null issue resolved @@ -1088,7 +1109,7 @@ private Node getLastChild(final boolean attributesAreChildren) { Node node = null; if (!isDirty) { final NodeId child = nodeId.getChild(children); - node = ownerDocument.getNode(new NodeProxy(getExpression(), ownerDocument, child)); + node = new NodeProxy(getExpression(), ownerDocument, child).getNode(); } if (node == null) { final NodeList cl; @@ -1338,8 +1359,13 @@ public void setChildCount(final int count) { } public void setNamespaceMappings(final Map map) { - this.namespaceMappings = new HashMap<>(map); - for(final String ns : namespaceMappings.values()) { + if (this.namespaceMappings == null) { + this.namespaceMappings = new HashMap<>(map); + } else { + this.namespaceMappings.clear(); + this.namespaceMappings.putAll(map); + } + for (final String ns : namespaceMappings.values()) { ownerDocument.getBrokerPool().getSymbols().getNSSymbol(ns); } } @@ -1359,6 +1385,10 @@ public String getNamespaceForPrefix(final String prefix) { return namespaceMappings.get(prefix); } + public @Nullable Map getNamespaceMappings() { + return namespaceMappings; + } + /** * @see java.lang.Object#toString() */ @@ -1518,7 +1548,7 @@ public void insertBefore(final Txn transaction, final NodeList nodes, final Node } final IStoredNode following = (IStoredNode) refChild; - final IStoredNode previous = (IStoredNode) following.getPreviousSibling(); + final IStoredNode previous = (IStoredNode) ((StoredNode) following).getPreviousSibling(true); if(previous == null) { // there's no sibling node before the new node final NodeId newId = following.getNodeId().insertBefore(); @@ -1650,8 +1680,11 @@ public void update(final Txn transaction, final NodeList newContent) throws DOME * Update a child node. This method will only update the child node * but not its potential descendant nodes. * - * @param oldChild to be replace + * @param oldChild to be replaced * @param newChild to be added + * + * @return the new node + * * @throws DOMException in case of a DOM error */ @Override @@ -1671,7 +1704,7 @@ public IStoredNode updateChild(final Txn transaction, final Node oldChild, final attr.setValue(StringValue.trimWhitespace(StringValue.collapseWhitespace(attr.getValue()))); attr.setType(AttrImpl.ID); } - IStoredNode previousNode = (IStoredNode) oldNode.getPreviousSibling(); + IStoredNode previousNode = (IStoredNode) ((StoredNode) oldNode).getPreviousSibling(true); if(previousNode == null) { previousNode = this; } else { @@ -1842,13 +1875,16 @@ public boolean visit(final IStoredNode node) { } /** - * Replaces the oldNode with the newChild + * Replaces the oldChild with the newChild * * @param transaction the transaction * @param newChild to replace oldChild - * @param oldChild to be replace by newChild + * @param oldChild to be replaced by newChild + * * @return The new node (this differs from the {@link org.w3c.dom.Node#replaceChild(Node, Node)} specification) + * * @throws DOMException in case of a DOM error + * * @see org.w3c.dom.Node#replaceChild(org.w3c.dom.Node, org.w3c.dom.Node) */ @Override @@ -1862,7 +1898,7 @@ public Node replaceChild(final Txn transaction, final Node newChild, final Node } final NodePath thisPath = getPath(); - IStoredNode previous = (IStoredNode) oldNode.getPreviousSibling(); + IStoredNode previous = (IStoredNode) ((StoredNode) oldNode).getPreviousSibling(true); if(previous == null) { previous = this; } else { @@ -1973,41 +2009,37 @@ public String getBaseURI() { return ""; //UNDERSTAND: is it ok? } - //TODO Please, keep in sync with org.exist.dom.memtree.ElementImpl + // NOTE(AR) please keep in sync with org.exist.dom.memtree.ElementImpl private XmldbURI calculateBaseURI() { XmldbURI baseURI = null; - final String nodeBaseURI = _getAttributeNS(Namespaces.XML_NS, "base"); - if(nodeBaseURI != null) { + final String nodeBaseURI = getAttributeNS(Namespaces.XML_NS, "base"); + if (!nodeBaseURI.isEmpty()) { baseURI = XmldbURI.create(nodeBaseURI, false); - if(baseURI.isAbsolute()) { + if (baseURI.isAbsolute()) { return baseURI; } } - final IStoredNode parent = getParentStoredNode(); - if(parent != null) { - if(nodeBaseURI == null) { + final IStoredNode parent = getParentStoredNode(); + if (parent != null) { + if (nodeBaseURI.isEmpty()) { baseURI = ((ElementImpl) parent).calculateBaseURI(); } else { - XmldbURI parentsBaseURI = ((ElementImpl) parent).calculateBaseURI(); - if(nodeBaseURI.isEmpty()) { - baseURI = parentsBaseURI; + final XmldbURI parentsBaseURI = ((ElementImpl) parent).calculateBaseURI(); + if (parentsBaseURI.toString().endsWith("/") || !parentsBaseURI.toString().contains("/")) { + baseURI = parentsBaseURI.append(baseURI); } else { - if(parentsBaseURI.toString().endsWith("/") || !parentsBaseURI.toString().contains("/")){ - baseURI = parentsBaseURI.append(baseURI); - } else { - // there is a filename, remove it - baseURI = parentsBaseURI.removeLastSegment().append(baseURI); - } + // there is a filename, remove it + baseURI = parentsBaseURI.removeLastSegment().append(baseURI); } } } else { - if(nodeBaseURI == null) { + if (nodeBaseURI.isEmpty()) { return XmldbURI.create(getOwnerDocument().getBaseURI(), false); } else { final String docBaseURI = getOwnerDocument().getBaseURI(); - if(docBaseURI.endsWith("/")) { + if (docBaseURI.endsWith("/")) { baseURI = XmldbURI.create(getOwnerDocument().getBaseURI(), false); baseURI.append(baseURI); } else { @@ -2017,6 +2049,7 @@ private XmldbURI calculateBaseURI() { } } } + return baseURI; } diff --git a/exist-core/src/main/java/org/exist/dom/persistent/EmptyNodeSet.java b/exist-core/src/main/java/org/exist/dom/persistent/EmptyNodeSet.java index 8fe090e118..451ae11896 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/EmptyNodeSet.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/EmptyNodeSet.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -67,10 +91,12 @@ public boolean hasOne() { @Override public void add(final NodeProxy proxy) { + throw new IllegalStateException("Cannot add a NodeProxy to an EmptyNodeSet because it is immutable"); } @Override public void addAll(final NodeSet other) { + throw new IllegalStateException("Cannot add a NodeSet to an EmptyNodeSet because it is immutable"); } @Override diff --git a/exist-core/src/main/java/org/exist/dom/persistent/LockToken.java b/exist-core/src/main/java/org/exist/dom/persistent/LockToken.java index 7b9d60f926..57f5bd413d 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/LockToken.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/LockToken.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -22,7 +46,7 @@ package org.exist.dom.persistent; import org.exist.storage.io.VariableByteInput; -import org.exist.storage.io.VariableByteOutputStream; +import org.exist.storage.io.VariableByteOutput; import org.exist.util.UUIDGenerator; import javax.annotation.Nullable; @@ -123,7 +147,8 @@ public static String generateUUID() { return UUIDGenerator.getUUID(); } - public void write(final VariableByteOutputStream ostream) throws IOException { + public void write(final VariableByteOutput + ostream) throws IOException { // TODO(AR) these 3 bytes could be encoded into 1 ostream.writeByte(type.getValue()); ostream.writeByte(depth.getValue()); diff --git a/exist-core/src/main/java/org/exist/dom/persistent/NewArrayNodeSet.java b/exist-core/src/main/java/org/exist/dom/persistent/NewArrayNodeSet.java index ed5f630028..2bd6097478 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/NewArrayNodeSet.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/NewArrayNodeSet.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -41,7 +65,12 @@ import org.w3c.dom.Node; import javax.annotation.Nullable; -import java.util.*; +import java.lang.ref.WeakReference; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Set; /** * A fast node set implementation, based on arrays to store nodes and documents. @@ -67,7 +96,7 @@ */ public class NewArrayNodeSet extends AbstractArrayNodeSet implements ExtNodeSet, DocumentSet { - private Set cachedCollections = null; + @Nullable private WeakReference> cachedCollectionsRef = null; private int documentCount = 0; @@ -935,10 +964,10 @@ public NodeSet getContextNodes(final int contextId) { if(contextNode.getContextId() == contextId) { final NodeProxy context = contextNode.getNode(); context.addMatches(current); - if(Expression.NO_CONTEXT_ID != contextId) { + if (Expression.NO_CONTEXT_ID != contextId) { context.addContextNode(contextId, context); } - if(lastDoc != null && lastDoc.getDocId() != context.getOwnerDocument().getDocId()) { + if (lastDoc == null || lastDoc.getDocId() != context.getOwnerDocument().getDocId()) { lastDoc = context.getOwnerDocument(); result.add(context, getSizeHint(lastDoc)); } else { @@ -1014,16 +1043,27 @@ public boolean equalDocs(final DocumentSet other) { @Override public Iterator getCollectionIterator() { - sort(); - if(cachedCollections == null) { - cachedCollections = new HashSet<>(); - for(int i = 0; i < documentCount; i++) { - final DocumentImpl doc = nodes[documentNodesOffset[i]].getOwnerDocument(); - if(!cachedCollections.contains(doc.getCollection())) { - cachedCollections.add(doc.getCollection()); - } + // First, try and retrieve from Cache + Set cachedCollections; + if (this.cachedCollectionsRef != null) { + cachedCollections = this.cachedCollectionsRef.get(); + if (cachedCollections != null) { + return cachedCollections.iterator(); } } + + sort(); + + // Second, Cache is empty, so create a Cache and return + cachedCollections = new HashSet<>(); + for (int i = 0; i < documentCount; i++) { + final DocumentImpl doc = nodes[documentNodesOffset[i]].getOwnerDocument(); + final Collection collection = doc.getCollection(); + cachedCollections.add(collection); + } + + this.cachedCollectionsRef = new WeakReference<>(cachedCollections); + return cachedCollections.iterator(); } diff --git a/exist-core/src/main/java/org/exist/dom/persistent/NodeProxy.java b/exist-core/src/main/java/org/exist/dom/persistent/NodeProxy.java index 16dd1bb34f..93a0832368 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/NodeProxy.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/NodeProxy.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -49,6 +73,7 @@ import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import java.io.IOException; +import java.lang.ref.WeakReference; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Properties; @@ -58,17 +83,18 @@ * * NodeProxy is an internal proxy class, acting as a placeholder for all types of persistent XML nodes * during query processing. NodeProxy just stores the node's unique id and the document it belongs to. - * Query processing deals with these proxys most of the time. Using a NodeProxy is much cheaper + * Query processing deals with these proxy most of the time. Using a NodeProxy is much cheaper * than loading the actual node from the database. The real DOM node is only loaded, * if further information is required for the evaluation of an XPath expression. To obtain * the real node for a proxy, simply call {@link #getNode()}. * - * All sets of type NodeSet operate on NodeProxys. A node set is a special type of - * sequence, so NodeProxy does also implement {@link org.exist.xquery.value.Item} and - * can thus be an item in a sequence. Since, according to XPath 2, a single node is also - * a sequence, NodeProxy does itself extend NodeSet. It thus represents a node set containing - * just one, single node. + * All sets of type NodeSet operate on NodeProxy objects. A node set is a special type of + * sequence, so NodeProxy also implements {@link org.exist.xquery.value.Item}, and + * can thus be an item in a sequence. Since according to XPath 2, a single node is also + * a sequence, NodeProxy itself extends NodeSet. It thus represents a node set containing + * just one single node. * + * @author Adam Retter * @author Wolfgang Meier */ public class NodeProxy implements NodeSet, NodeValue, NodeHandle, DocumentSet, Comparable { @@ -79,8 +105,7 @@ public class NodeProxy implements NodeSet, NodeValue, NodeHandle, DocumentSet, C /** * The owner document of this node. */ - private DocumentImpl doc = null; - + private DocumentImpl doc; private NodeId nodeId; /** @@ -112,6 +137,8 @@ public class NodeProxy implements NodeSet, NodeValue, NodeHandle, DocumentSet, C private final Expression expression; + private @Nullable WeakReference cachedNode = null; + /** * Creates a new NodeProxy instance. * @@ -208,13 +235,19 @@ public NodeProxy(final Expression expression, final DocumentImpl doc, final Node this.nodeId = nodeId; } + private void invalidateCachedNode() { + this.cachedNode = null; + } + public void update(final ElementImpl element) { + invalidateCachedNode(); this.doc = element.getOwnerDocument(); - this.nodeType = UNKNOWN_NODE_TYPE; - this.internalAddress = StoredNode.UNKNOWN_NODE_IMPL_ADDRESS; + this.nodeType = Node.ELEMENT_NODE; + this.internalAddress = element.getInternalAddress(); this.nodeId = element.getNodeId(); this.match = null; this.context = null; + this.cachedNode = new WeakReference<>(element); } /** @@ -259,12 +292,31 @@ public NodeProxy(final Expression expression, final DocumentImpl doc) { this(expression, doc, NodeId.DOCUMENT_NODE, Node.DOCUMENT_NODE, StoredNode.UNKNOWN_NODE_IMPL_ADDRESS); } + public static NodeProxy wrap(@Nullable Expression expression, final NodeImpl node) { + final DocumentImpl doc = node instanceof DocumentImpl ? (DocumentImpl) node : (DocumentImpl) node.getOwnerDocument(); + expression = expression != null ? expression : doc.getExpression(); + + final long address; + if (node instanceof StoredNode) { + address = ((StoredNode) node).getInternalAddress(); + } else { + address = StoredNode.UNKNOWN_NODE_IMPL_ADDRESS; + } + + final NodeProxy wrapper = new NodeProxy(expression, doc, node.getNodeId(), node.getNodeType(), address); + wrapper.cachedNode = new WeakReference<>(node); + wrapper.qname = node.getQName(); + + return wrapper; + } + public Expression getExpression() { return expression; } @Override public void setNodeId(final NodeId id) { + invalidateCachedNode(); this.nodeId = id; } @@ -276,12 +328,13 @@ public NodeId getNodeId() { @Override public QName getQName() { if (qname == null) { + // NOTE(AR) get the node from the database, which will also update the `qname` getNode(); } return qname; } - public void setQName(QName qname) { + public void setQName(final QName qname) { this.qname = qname; } @@ -400,7 +453,7 @@ public DocumentImpl getOwnerDocument() { * @return a boolean value */ public boolean isDocument() { - return nodeType == Node.DOCUMENT_NODE; + return getNodeType() == Node.DOCUMENT_NODE; } /** @@ -410,20 +463,37 @@ public boolean isDocument() { */ @Override public Node getNode() { - if(isDocument()) { + // NOTE(AR) we don't call isDocument() or getNodeType() here as it would call back to getNode() and cause a StackOverflowError + if (nodeType == Node.DOCUMENT_NODE) { return doc; - } else { + } + + // try and get cached node + @Nullable Node node = null; + if (cachedNode != null) { + node = cachedNode.get(); + } + + if (node == null) { + // no cached node, get the node from the database final NodeImpl realNode = (NodeImpl) doc.getNode(this); - if(realNode != null) { + if (realNode != null) { this.nodeType = realNode.getNodeType(); this.qname = realNode.getQName(); } - return realNode; + this.cachedNode = new WeakReference<>(realNode); + node = realNode; } + + return node; } @Override public short getNodeType() { + if (nodeType == UNKNOWN_NODE_TYPE) { + // NOTE(AR) get the node from the database, which will also update the `nodeType` + getNode(); + } return nodeType; } @@ -443,10 +513,12 @@ public long getInternalAddress() { @Override public void setInternalAddress(final long internalAddress) { + invalidateCachedNode(); this.internalAddress = internalAddress; } - public void setIndexType(int type) { + public void setIndexType(final int type) { + invalidateCachedNode(); this.internalAddress = StorageAddress.setIndexType(internalAddress, (short) type); } @@ -671,6 +743,7 @@ public String debugContext() { // methods of interface Item @Override public int getType() { + final short nodeType = getNodeType(); if (nodeType == UNKNOWN_NODE_TYPE) { return Type.NODE; } @@ -684,10 +757,11 @@ public boolean isPersistentSet() { @Override public void nodeMoved(final NodeId oldNodeId, final NodeHandle newNode) { - if(nodeId.equals(oldNodeId)) { + if (nodeId.equals(oldNodeId)) { // update myself - nodeId = newNode.getNodeId(); - internalAddress = newNode.getInternalAddress(); + invalidateCachedNode(); + this.nodeId = newNode.getNodeId(); + this.internalAddress = newNode.getInternalAddress(); } } @@ -767,12 +841,9 @@ public void toSAX(final DBBroker broker, final ContentHandler handler, final Pro @Override public void copyTo(final DBBroker broker, final DocumentBuilderReceiver receiver) throws SAXException { - NodeImpl node = null; - if(nodeType < 0) { - node = (NodeImpl) getNode(); - } - if(nodeType == Node.ATTRIBUTE_NODE) { - final AttrImpl attr = (node == null ? (AttrImpl) getNode() : (AttrImpl) node); + final Node node = getNode(); + if (node.getNodeType() == Node.ATTRIBUTE_NODE) { + final AttrImpl attr = (AttrImpl) node; receiver.attribute(attr.getQName(), attr.getValue()); } else { receiver.addReferenceNode(this); @@ -1260,6 +1331,7 @@ public NodeSet selectFollowing(final NodeSet following, final int position, fina @Override public NodeSet directSelectAttribute(final DBBroker broker, final NodeTest test, final int contextId) { + final short nodeType = getNodeType(); if(nodeType != UNKNOWN_NODE_TYPE && nodeType != Node.ELEMENT_NODE) { return NodeSet.EMPTY_SET; } @@ -1303,6 +1375,7 @@ public NodeSet directSelectAttribute(final DBBroker broker, final NodeTest test, } public NodeSet directSelectChild(final QName qname, final int contextId) { + final short nodeType = getNodeType(); if(nodeType != UNKNOWN_NODE_TYPE && nodeType != Node.ELEMENT_NODE) { return NodeSet.EMPTY_SET; } @@ -1525,6 +1598,7 @@ public boolean equalDocs(final DocumentSet other) { @Override public boolean directMatchAttribute(final DBBroker broker, final NodeTest test, final int contextId) { + final short nodeType = getNodeType(); if(nodeType != UNKNOWN_NODE_TYPE && nodeType != Node.ELEMENT_NODE) { return false; } @@ -1554,6 +1628,7 @@ public boolean directMatchAttribute(final DBBroker broker, final NodeTest test, } public boolean directMatchChild(final QName qname, final int contextId) { + final short nodeType = getNodeType(); if(nodeType != UNKNOWN_NODE_TYPE && nodeType != Node.ELEMENT_NODE) { return false; } diff --git a/exist-core/src/main/java/org/exist/dom/persistent/NodeSet.java b/exist-core/src/main/java/org/exist/dom/persistent/NodeSet.java index 5f4ca084e8..de3056d31e 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/NodeSet.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/NodeSet.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -377,7 +401,7 @@ boolean matchAncestorDescendant(NodeSet al, int mode, boolean includeSelf, * * @param contextId used to track context nodes when evaluating predicate * expressions. If contextId != {@link org.exist.xquery.Expression#NO_CONTEXT_ID}, the current context - * will be added to each result of the of the selection. + * will be added to each result of the selection. * @return all context nodes associated with the nodes in this node set. */ NodeSet getContextNodes(int contextId); diff --git a/exist-core/src/main/java/org/exist/dom/persistent/ProcessingInstructionImpl.java b/exist-core/src/main/java/org/exist/dom/persistent/ProcessingInstructionImpl.java index eae1cbeb51..1f16448e98 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/ProcessingInstructionImpl.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/ProcessingInstructionImpl.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -21,6 +45,7 @@ */ package org.exist.dom.persistent; +import org.exist.dom.QName; import org.exist.numbering.NodeId; import org.exist.storage.Signatures; import org.exist.util.ByteConversion; @@ -37,7 +62,7 @@ * * @author wolf */ -public class ProcessingInstructionImpl extends StoredNode implements ProcessingInstruction { +public class ProcessingInstructionImpl extends NamedNode implements ProcessingInstruction { public static final int LENGTH_TARGET_DATA = 4; //Sizeof int; @@ -57,7 +82,7 @@ public ProcessingInstructionImpl(final NodeId nodeId, final String target, final } public ProcessingInstructionImpl(final Expression expression, final NodeId nodeId, final String target, final String data) { - super(expression, Node.PROCESSING_INSTRUCTION_NODE, nodeId); + super(expression, Node.PROCESSING_INSTRUCTION_NODE, nodeId, new QName(target, null)); this.target = target; this.data = data; } @@ -74,6 +99,7 @@ public ProcessingInstructionImpl(final Expression expression, final String targe public void clear() { super.clear(); target = null; + setQName(null); data = null; } @@ -94,6 +120,7 @@ public String getTarget() { */ public void setTarget(final String target) { this.target = target; + setQName(new QName(target, null)); } @Override diff --git a/exist-core/src/main/java/org/exist/dom/persistent/SortedNodeSet.java b/exist-core/src/main/java/org/exist/dom/persistent/SortedNodeSet.java index 88ecfb3864..cac8bcc27e 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/SortedNodeSet.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/SortedNodeSet.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -24,12 +48,13 @@ import antlr.RecognitionException; import antlr.TokenStreamException; import antlr.collections.AST; +import com.evolvedbinary.j8cu.list.linked.BoundedDoublyLinkedList; +import com.evolvedbinary.j8cu.list.linked.OrderedDoublyLinkedList; import org.exist.EXistException; import org.exist.numbering.NodeId; import org.exist.security.Subject; import org.exist.storage.BrokerPool; import org.exist.storage.DBBroker; -import org.exist.util.OrderedLinkedList; import org.exist.xquery.*; import org.exist.xquery.parser.XQueryLexer; import org.exist.xquery.parser.XQueryParser; @@ -40,15 +65,16 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; +import javax.annotation.Nullable; import java.io.StringReader; -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.Optional; +import java.util.*; + +import static com.evolvedbinary.j8cu.list.linked.Bounded.bound; public class SortedNodeSet extends AbstractNodeSet { - private final OrderedLinkedList list = new OrderedLinkedList(); + private final BoundedDoublyLinkedList list = bound(new OrderedDoublyLinkedList(), Long.MAX_VALUE); private final String sortExpr; private final BrokerPool pool; @@ -62,7 +88,7 @@ public SortedNodeSet(final BrokerPool pool, final Subject user, final String sor @Override public boolean isEmpty() { - return list.size() == 0; + return list.isEmpty(); } @Override @@ -96,27 +122,54 @@ public void addAll(final NodeSet other) { } final AST ast = parser.getAST(); LOG.debug("generated AST: {}", ast.toStringTree()); - final PathExpr expr = new PathExpr(context); - treeParser.xpath(ast, expr); - if(treeParser.foundErrors()) { - LOG.debug(treeParser.getErrorMessage()); - } - expr.analyze(new AnalyzeContextInfo()); - for(final SequenceIterator i = other.iterate(); i.hasNext(); ) { - final NodeProxy p = (NodeProxy) i.nextItem(); - final IteratorItem item = new IteratorItem(p, expr); - list.add(item); + final PathExpr sortExpression = new PathExpr(context); + try { + treeParser.xpath(ast, sortExpression); + if (treeParser.foundErrors()) { + LOG.debug(treeParser.getErrorMessage()); + } + sortExpression.analyze(new AnalyzeContextInfo()); + for (final SequenceIterator i = other.iterate(); i.hasNext(); ) { + final NodeProxy p = (NodeProxy) i.nextItem(); + final IteratorItem item = createIteratorItem(sortExpression, p); + list.add(item); + } + } finally { + sortExpression.getContext().runCleanupTasks(); + sortExpression.getContext().reset(); } } catch(final RecognitionException | TokenStreamException re) { LOG.debug(re); //TODO : throw exception ! -pb } catch(final EXistException | XPathException e) { - LOG.debug("Exception during sort", e); //TODO : throw exception ! -pb + LOG.debug("Exception during sort: " + e.getMessage(), e); //TODO : throw exception ! -pb } LOG.debug("sort-expression found {} in {}ms.", list.size(), System.currentTimeMillis() - start); } + private IteratorItem createIteratorItem(final Expression sortExpression, final NodeProxy nodeProxy) throws XPathException { + final Sequence seq = sortExpression.eval(nodeProxy, null); + + // copy string values of items into an array + int sbCapacity = 0; + final String[] strings = new String[seq.getItemCount()]; + for (int i = 0; i < strings.length; i++) { + final String strItem = seq.itemAt(i).getStringValue().toUpperCase(); + sbCapacity += strItem.length(); + strings[i] = strItem; + } + + // sort and then concatenate strings + Arrays.sort(strings); + final StringBuilder buf = new StringBuilder(sbCapacity); + for (int i = 0; i < strings.length; i++) { + buf.append(strings[i]); + } + + return new IteratorItem(nodeProxy, buf.toString()); + } + public void addAll(final NodeList other) { - if(!(other instanceof NodeSet)) { + if (!(other instanceof NodeSet)) { throw new RuntimeException("not implemented!"); } addAll((NodeSet) other); @@ -124,9 +177,9 @@ public void addAll(final NodeList other) { @Override public boolean contains(final NodeProxy proxy) { - for(final Iterator i = list.iterator(); i.hasNext(); ) { - final NodeProxy p = (i.next()).proxy; - if(p.compareTo(proxy) == 0) { + for (final IteratorItem iteratorItem : list) { + final NodeProxy p = iteratorItem.proxy; + if (p.compareTo(proxy) == 0) { return true; } } @@ -135,8 +188,8 @@ public boolean contains(final NodeProxy proxy) { @Override public boolean containsReference(final Item item) { - for (final Iterator i = list.iterator(); i.hasNext();) { - final NodeProxy p = (i.next()).proxy; + for (final IteratorItem iteratorItem : list) { + final NodeProxy p = iteratorItem.proxy; if (p == item) { return true; } @@ -146,8 +199,8 @@ public boolean containsReference(final Item item) { @Override public boolean contains(final Item item) { - for (final Iterator i = list.iterator(); i.hasNext();) { - final NodeProxy p = (i.next()).proxy; + for (final IteratorItem iteratorItem : list) { + final NodeProxy p = iteratorItem.proxy; if (p.equals(item)) { return true; } @@ -157,15 +210,15 @@ public boolean contains(final Item item) { @Override public NodeProxy get(final int pos) { - final IteratorItem item = (IteratorItem) list.get(pos); + final IteratorItem item = list.get(pos); return item == null ? null : item.proxy; } public NodeProxy get(final DocumentImpl doc, final NodeId nodeId) { final NodeProxy proxy = new NodeProxy(null, doc, nodeId); - for(final Iterator i = list.iterator(); i.hasNext(); ) { - final NodeProxy p = (i.next()).proxy; - if(p.compareTo(proxy) == 0) { + for (final IteratorItem iteratorItem : list) { + final NodeProxy p = iteratorItem.proxy; + if (p.compareTo(proxy) == 0) { return p; } } @@ -174,9 +227,9 @@ public NodeProxy get(final DocumentImpl doc, final NodeId nodeId) { @Override public NodeProxy get(final NodeProxy proxy) { - for(final Iterator i = list.iterator(); i.hasNext(); ) { - final NodeProxy p = (i.next()).proxy; - if(p.compareTo(proxy) == 0) { + for (final IteratorItem iteratorItem : list) { + final NodeProxy p = iteratorItem.proxy; + if (p.compareTo(proxy) == 0) { return p; } } @@ -185,7 +238,7 @@ public NodeProxy get(final NodeProxy proxy) { @Override public int getLength() { - return list.size(); + return (int) list.size(); } @Override @@ -195,15 +248,21 @@ public long getItemCountLong() { @Override public Node item(final int pos) { - final NodeProxy p = ((IteratorItem) list.get(pos)).proxy; - return p == null ? null : p.getOwnerDocument().getNode(p); + final IteratorItem iteratorItem = list.get(pos); + if (iteratorItem != null) { + final NodeProxy p = iteratorItem.proxy; + if (p != null) { + return p.getOwnerDocument().getNode(p); + } + } + return null; } //TODO : evaluate both semantics (item/itemAt) @Override public Item itemAt(final int pos) { - final NodeProxy p = ((IteratorItem) list.get(pos)).proxy; - return p == null ? null : p; + final IteratorItem iteratorItem = list.get(pos); + return iteratorItem == null ? null : iteratorItem.proxy; } @Override @@ -221,21 +280,20 @@ public SequenceIterator unorderedIterator() { return new SortedNodeSetIterator(list.iterator()); } - private static final class SortedNodeSetIterator implements NodeSetIterator, SequenceIterator { - + private static class SortedNodeSetIterator implements NodeSetIterator, SequenceIterator { private final Iterator ii; public SortedNodeSetIterator(final Iterator i) { ii = i; } - public final boolean hasNext() { + public boolean hasNext() { return ii.hasNext(); } @Override - public final NodeProxy next() { - if(!ii.hasNext()) { + public NodeProxy next() { + if (!ii.hasNext()) { throw new NoSuchElementException(); } else { return ii.next().proxy; @@ -243,18 +301,18 @@ public final NodeProxy next() { } @Override - public final void remove() { + public void remove() { throw new UnsupportedOperationException(); } @Override - public final NodeProxy peekNode() { + public NodeProxy peekNode() { return null; } @Override - public final Item nextItem() { - if(!ii.hasNext()) { + public Item nextItem() { + if (!ii.hasNext()) { return null; } else { return ii.next().proxy; @@ -262,54 +320,44 @@ public final Item nextItem() { } @Override - public final void setPosition(final NodeProxy proxy) { + public void setPosition(final NodeProxy proxy) { throw new UnsupportedOperationException("NodeSetIterator.setPosition() is not supported by SortedNodeSetIterator"); } } - private static final class IteratorItem extends OrderedLinkedList.Node { + private static class IteratorItem implements Comparable { private final NodeProxy proxy; - private String value = null; + private @Nullable final String value; - public IteratorItem(final NodeProxy proxy, final PathExpr expr) { + public IteratorItem(final NodeProxy proxy, final String value) { this.proxy = proxy; - try { - final Sequence seq = expr.eval(proxy, null); - final StringBuilder buf = new StringBuilder(); - final OrderedLinkedList strings = new OrderedLinkedList(); - Item item; - for(final SequenceIterator i = seq.iterate(); i.hasNext(); ) { - item = i.nextItem(); - strings.add(new OrderedLinkedList.SimpleNode(item.getStringValue().toUpperCase())); - } - for(final Iterator j = strings.iterator(); j.hasNext(); ) { - buf.append((j.next()).getData()); - } - value = buf.toString(); - } catch(final XPathException e) { - LOG.warn(e.getMessage(), e); //TODO : throw exception ! -pb - } finally { - expr.getContext().runCleanupTasks(); - expr.getContext().reset(); - } + this.value = value; } @Override - public int compareTo(final OrderedLinkedList.Node other) { - final IteratorItem o = (IteratorItem) other; - if(value == null) { - return o.value == null ? Constants.EQUAL : Constants.SUPERIOR; - } else if(o.value == null) { + public int compareTo(final IteratorItem other) { + if (value == null) { + return other.value == null ? Constants.EQUAL : Constants.SUPERIOR; + } else if (other.value == null) { return Constants.INFERIOR; } else { - return value.compareTo(o.value); + return value.compareTo(other.value); } } @Override - public boolean equals(final OrderedLinkedList.Node other) { - final IteratorItem o = (IteratorItem) other; - return value.equals(o.value); + public boolean equals(final Object other) { + if (!(other instanceof IteratorItem)) { + return false; + } + + final IteratorItem otherIteratorItem = (IteratorItem) other; + return Objects.equals(value, otherIteratorItem.value); + } + + @Override + public int hashCode() { + return Objects.hashCode(value); } } @@ -317,5 +365,4 @@ public boolean equals(final OrderedLinkedList.Node other) { public void add(final NodeProxy proxy) { LOG.info("Called SortedNodeSet.add()"); } - } diff --git a/exist-core/src/main/java/org/exist/dom/persistent/StoredNode.java b/exist-core/src/main/java/org/exist/dom/persistent/StoredNode.java index e70641b224..19e480f699 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/StoredNode.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/StoredNode.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -301,6 +325,10 @@ public StoredNode getParentStoredNode() { @Override public Node getPreviousSibling() { + return getPreviousSibling(false); + } + + Node getPreviousSibling(final boolean includeAttributes) { // if we are the root node, there is no sibling if(nodeId.equals(NodeId.ROOT_NODE)) { return null; @@ -351,12 +379,17 @@ public Node getPreviousSibling() { } final NodeId firstChild = parent.getNodeId().newChild(); - if(nodeId.equals(firstChild)) { + if (nodeId.equals(firstChild)) { return null; } final NodeId siblingId = nodeId.precedingSibling(); - return ownerDocument.getNode(siblingId); + final Node precedingSibling = ownerDocument.getNode(siblingId); + if (!includeAttributes && precedingSibling.getNodeType() == Node.ATTRIBUTE_NODE) { + // NOTE(AR) guard against returning attributes + return null; + } + return precedingSibling; } @Override diff --git a/exist-core/src/main/java/org/exist/dom/persistent/SymbolTable.java b/exist-core/src/main/java/org/exist/dom/persistent/SymbolTable.java index b9845861be..5e536a0781 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/SymbolTable.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/SymbolTable.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -28,10 +52,16 @@ import org.exist.EXistException; import org.exist.backup.RawDataBackup; import org.exist.dom.QName; -import org.exist.storage.*; + +import org.exist.storage.BrokerPool; +import org.exist.storage.BrokerPoolService; +import org.exist.storage.BrokerPoolServiceException; +import org.exist.storage.DBBroker; +import org.exist.storage.ElementValue; +import org.exist.storage.io.VariableByteFilterInputStream; +import org.exist.storage.io.VariableByteFilterOutputStream; import org.exist.storage.io.VariableByteInput; -import org.exist.storage.io.VariableByteInputStream; -import org.exist.storage.io.VariableByteOutputStream; +import org.exist.storage.io.VariableByteOutput; import org.exist.util.Configuration; import org.exist.util.FileUtils; import org.w3c.dom.Attr; @@ -111,8 +141,7 @@ public static SymbolType valueOf(final byte typeId) { * the underlying symbols.dbx file */ private Path file; - private final VariableByteOutputStream outBuffer = new VariableByteOutputStream(256); - private OutputStream os = null; + private VariableByteFilterOutputStream os = null; @Override public void configure(final Configuration configuration) { @@ -263,7 +292,7 @@ public synchronized String getNamespace(final short id) { * @param os outputstream * @throws IOException in response to an IO error */ - private synchronized void writeAll(final VariableByteOutputStream os) throws IOException { + private synchronized void writeAll(final VariableByteOutput os) throws IOException { os.writeFixedInt(FILE_FORMAT_VERSION_ID); localNameSymbols.write(os); namespaceSymbols.write(os); @@ -356,13 +385,11 @@ public final Path getFile() { * Save the entire symbol table. Will only be called when initializing an * empty database or when upgrading an older dbx file. * - * @throws EXistException in response to eXist-db error + * @throws EXistException in response to the error */ private void saveSymbols() throws EXistException { - try(final VariableByteOutputStream os = new VariableByteOutputStream(8192); - final OutputStream fos = new BufferedOutputStream(Files.newOutputStream(getFile()))) { + try (final VariableByteFilterOutputStream os = new VariableByteFilterOutputStream(new BufferedOutputStream(Files.newOutputStream(getFile())))) { writeAll(os); - fos.write(os.toByteArray()); } catch(final FileNotFoundException e) { throw new EXistException("File not found: " + this.getFile().toAbsolutePath().toString(), e); } catch(final IOException e) { @@ -375,12 +402,11 @@ private void saveSymbols() throws EXistException { * Read the global symbol table. The global symbol table stores QNames and * namespace/prefix mappings. * - * @throws EXistException in response to eXist-db error + * @throws EXistException in response to the error */ private synchronized void loadSymbols() throws EXistException { - try(final InputStream fis = new BufferedInputStream(Files.newInputStream(getFile()))) { + try (final VariableByteFilterInputStream is = new VariableByteFilterInputStream(new BufferedInputStream(Files.newInputStream(getFile())))) { - final VariableByteInput is = new VariableByteInputStream(fis); final int magic = is.readFixedInt(); if(magic == LEGACY_FILE_FORMAT_VERSION_ID) { LOG.info("Converting legacy symbols.dbx to new format..."); @@ -420,16 +446,15 @@ public void flush() throws EXistException { //Noting to do ? -pb } - private OutputStream getOutputStream() throws IOException { - if(os == null) { - os = new BufferedOutputStream(Files.newOutputStream(getFile(), StandardOpenOption.APPEND)); + private VariableByteFilterOutputStream getOutputStream() throws IOException { + if (os == null) { + os = new VariableByteFilterOutputStream(new BufferedOutputStream(Files.newOutputStream(getFile(), StandardOpenOption.APPEND))); } return os; } @Override public void close() throws IOException { - outBuffer.close(); if(os != null) { os.close(); } @@ -527,7 +552,7 @@ public synchronized int getId(final String name) { return id; } - protected final void write(final VariableByteOutputStream os) throws IOException { + protected final void write(final VariableByteOutput os) throws IOException { for (final String symbol : symbolsByName.keySet()) { final int id = symbolsByName.getInt(symbol); if (id < 0) { @@ -540,10 +565,8 @@ protected final void write(final VariableByteOutputStream os) throws IOException // Append a new entry to the .dbx file private void write(final int id, final String key) { - outBuffer.clear(); try { - writeEntry(id, key, outBuffer); - getOutputStream().write(outBuffer.toByteArray()); + writeEntry(id, key, getOutputStream()); getOutputStream().flush(); } catch(final FileNotFoundException e) { LOG.error("Symbol table: file not found!", e); @@ -554,7 +577,7 @@ private void write(final int id, final String key) { } } - private void writeEntry(final int id, final String key, final VariableByteOutputStream os) throws IOException { + private void writeEntry(final int id, final String key, final VariableByteOutput os) throws IOException { os.writeByte(getSymbolType().getTypeId()); os.writeInt(id); os.writeUTF(key); diff --git a/exist-core/src/main/java/org/exist/dom/persistent/TextImpl.java b/exist-core/src/main/java/org/exist/dom/persistent/TextImpl.java index e66f5f900d..7887e0b0ce 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/TextImpl.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/TextImpl.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -39,7 +63,7 @@ * * @author wolf */ -public class TextImpl extends AbstractCharacterData implements Text { +public class TextImpl extends AbstractCharacterData implements Text { public TextImpl() { this((Expression) null); diff --git a/exist-core/src/main/java/org/exist/dom/persistent/VirtualNodeSet.java b/exist-core/src/main/java/org/exist/dom/persistent/VirtualNodeSet.java index 2103c68efe..1b9faacf12 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/VirtualNodeSet.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/VirtualNodeSet.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -86,7 +110,7 @@ public class VirtualNodeSet extends AbstractNodeSet { /** * Creates a new VirtualNodeSet instance. * - * @param broker eXist-db DBBroker + * @param broker the DBBroker * @param axis an int value * @param test a NodeTest value * @param contextId an int value diff --git a/exist-core/src/main/java/org/exist/dom/persistent/XMLDeclarationImpl.java b/exist-core/src/main/java/org/exist/dom/persistent/XMLDeclarationImpl.java index 9f84d6f821..3ba9a1e27b 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/XMLDeclarationImpl.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/XMLDeclarationImpl.java @@ -13,7 +13,7 @@ * * The GNU Lesser General Public License v2.1 only license follows. * - * --------------------------------------------------------------------- + * ===================================================================== * * Copyright (C) 2014, Evolved Binary Ltd * @@ -33,7 +33,7 @@ package org.exist.dom.persistent; import org.exist.storage.io.VariableByteInput; -import org.exist.storage.io.VariableByteOutputStream; +import org.exist.storage.io.VariableByteOutput; import javax.annotation.Nullable; import java.io.IOException; @@ -93,7 +93,7 @@ public String getStandalone() { * * @throws IOException if an error occurs whilst writing to the output stream. */ - public void write(final VariableByteOutputStream ostream) throws IOException { + public void write(final VariableByteOutput ostream) throws IOException { ostream.writeUTF(version != null ? version : ""); ostream.writeUTF(encoding != null ? encoding : ""); ostream.writeUTF(standalone != null ? standalone : ""); diff --git a/exist-core/src/main/java/org/exist/dom/persistent/XMLUtil.java b/exist-core/src/main/java/org/exist/dom/persistent/XMLUtil.java index f6cfa5a8d3..eb946079af 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/XMLUtil.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/XMLUtil.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -21,6 +45,7 @@ */ package org.exist.dom.persistent; +import org.apache.commons.io.output.StringBuilderWriter; import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -32,7 +57,6 @@ import javax.xml.transform.TransformerException; import java.io.IOException; import java.io.InputStream; -import java.io.StringWriter; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; @@ -52,14 +76,14 @@ private XMLUtil() { } public static final String dump(final DocumentFragment fragment) { - final StringWriter writer = new StringWriter(); - final DOMSerializer serializer = new DOMSerializer(writer, null); - try { + try (final StringBuilderWriter writer = new StringBuilderWriter()) { + final DOMSerializer serializer = new DOMSerializer(writer, null); serializer.serialize(fragment); + return writer.toString(); } catch(final TransformerException e) { //Nothing to do ? } - return writer.toString(); + return null; } public static final String encodeAttrMarkup(final String str) { diff --git a/exist-core/src/main/java/org/exist/http/AuditTrailSessionListener.java b/exist-core/src/main/java/org/exist/http/AuditTrailSessionListener.java index 8aa8b54959..a518377901 100644 --- a/exist-core/src/main/java/org/exist/http/AuditTrailSessionListener.java +++ b/exist-core/src/main/java/org/exist/http/AuditTrailSessionListener.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -42,6 +66,8 @@ import jakarta.servlet.http.HttpSession; import jakarta.servlet.http.HttpSessionEvent; import jakarta.servlet.http.HttpSessionListener; + +import javax.annotation.Nullable; import java.util.Optional; import java.util.Properties; @@ -90,8 +116,14 @@ private void executeXQuery(String xqueryResourcePath) { if (xqueryResourcePath != null && xqueryResourcePath.length() > 0) { xqueryResourcePath = xqueryResourcePath.trim(); + @Nullable CompiledXQuery compiled = null; + @Nullable XQueryContext context = null; + @Nullable Source source = null; + try { final BrokerPool pool = BrokerPool.getInstance(); + final XQueryPool xqpool = pool.getXQueryPool(); + final Subject sysSubject = pool.getSecurityManager().getSystemSubject(); try (final DBBroker broker = pool.get(Optional.of(sysSubject))) { @@ -102,10 +134,8 @@ private void executeXQuery(String xqueryResourcePath) { final XmldbURI pathUri = XmldbURI.create(xqueryResourcePath); + try (final LockedDocument lockedResource = broker.getXMLResource(pathUri, LockMode.READ_LOCK)) { - try(final LockedDocument lockedResource = broker.getXMLResource(pathUri, LockMode.READ_LOCK)) { - - final Source source; if (lockedResource != null) { if (LOG.isTraceEnabled()) { LOG.trace("Resource [{}] exists.", xqueryResourcePath); @@ -116,16 +146,13 @@ private void executeXQuery(String xqueryResourcePath) { return; } - final XQuery xquery = pool.getXQueryService(); if (xquery == null) { LOG.error("broker unable to retrieve XQueryService"); return; } - final XQueryPool xqpool = pool.getXQueryPool(); - CompiledXQuery compiled = xqpool.borrowCompiledXQuery(broker, source); - final XQueryContext context; + compiled = xqpool.borrowCompiledXQuery(broker, source); if (compiled == null) { context = new XQueryContext(broker.getBrokerPool()); } else { @@ -144,18 +171,20 @@ private void executeXQuery(String xqueryResourcePath) { final Properties outputProperties = new Properties(); - try { - final long startTime = System.currentTimeMillis(); - final Sequence result = xquery.execute(broker, compiled, null, outputProperties); - final long queryTime = System.currentTimeMillis() - startTime; - if (LOG.isTraceEnabled()) { - LOG.trace("XQuery execution results: {} in {}ms.", result.toString(), queryTime); - } - } finally { - context.runCleanupTasks(); - xqpool.returnCompiledXQuery(source, compiled); + final long startTime = System.currentTimeMillis(); + final Sequence result = xquery.execute(broker, compiled, null, outputProperties); + final long queryTime = System.currentTimeMillis() - startTime; + if (LOG.isTraceEnabled()) { + LOG.trace("XQuery execution results: {} in {}ms.", result.toString(), queryTime); } } + } finally { + if (context != null) { + context.runCleanupTasks(); + } + if (compiled != null && source != null) { + xqpool.returnCompiledXQuery(source, compiled); + } } } catch (final Exception e) { diff --git a/exist-core/src/main/java/org/exist/http/Descriptor.java b/exist-core/src/main/java/org/exist/http/Descriptor.java index 2156835fbc..f4847c7f8b 100644 --- a/exist-core/src/main/java/org/exist/http/Descriptor.java +++ b/exist-core/src/main/java/org/exist/http/Descriptor.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -19,7 +43,6 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - package org.exist.http; import org.apache.logging.log4j.LogManager; @@ -78,7 +101,7 @@ public class Descriptor implements ErrorHandler { //Data private BufferedWriter bufWriteReplayLog = null; //Should a replay log of requests be created - private boolean requestsFiltered = false; + private boolean requestsFiltered; private String allowSourceList[] = null; //Array of xql files to allow source to be viewed private String mapList[][] = null; //Array of Mappings @@ -144,8 +167,9 @@ private Descriptor() { final Path logFile = Paths.get("request-replay-log.txt"); bufWriteReplayLog = Files.newBufferedWriter(logFile); final String attr = doc.getDocumentElement().getAttribute("filtered"); - if (attr != null) + if (!attr.isEmpty()) { requestsFiltered = "true".equals(attr); + } } //load settings @@ -206,7 +230,7 @@ private void configureAllowSourceXQuery(Element allowsourcexqueries) { String path = elem.getAttribute("path"); //@path //must be a path to allow source for - if (path == null) { + if (path.isEmpty()) { LOG.warn("Error element 'xquery' requires an attribute 'path'"); return; } @@ -242,7 +266,7 @@ private void configureMaps(Element maps) { String view = elem.getAttribute("view"); //@view //must be a path or a pattern to map from - if (path == null /*&& pattern == null*/) { + if (path.isEmpty() /*&& pattern == null*/) { LOG.warn("Error element 'map' requires an attribute 'path' or an attribute 'pattern'"); return; } @@ -250,7 +274,7 @@ private void configureMaps(Element maps) { SingleInstanceConfiguration.getWebappHome().orElse(Paths.get(".")).toAbsolutePath().toString().replace('\\', '/')); //must be a view to map to - if (view == null) { + if (view.isEmpty()) { LOG.warn("Error element 'map' requires an attribute 'view'"); return; } diff --git a/exist-core/src/main/java/org/exist/http/RESTServer.java b/exist-core/src/main/java/org/exist/http/RESTServer.java index 03f7e290ca..8254b7743d 100644 --- a/exist-core/src/main/java/org/exist/http/RESTServer.java +++ b/exist-core/src/main/java/org/exist/http/RESTServer.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -21,6 +45,7 @@ */ package org.exist.http; +import org.apache.commons.io.output.StringBuilderWriter; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.exist.EXistException; @@ -83,9 +108,13 @@ import org.xml.sax.XMLReader; import org.xml.sax.helpers.AttributesImpl; import org.xml.sax.helpers.XMLFilterImpl; +import xyz.elemental.mediatype.MediaType; +import xyz.elemental.mediatype.MediaTypeResolver; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; + +import javax.annotation.Nullable; import javax.xml.XMLConstants; import javax.xml.parsers.ParserConfigurationException; import javax.xml.stream.XMLStreamException; @@ -120,7 +149,7 @@ public class RESTServer { static { defaultProperties.setProperty(OutputKeys.INDENT, "yes"); - defaultProperties.setProperty(OutputKeys.MEDIA_TYPE, MimeType.XML_TYPE.getName()); + defaultProperties.setProperty(OutputKeys.MEDIA_TYPE, MediaType.APPLICATION_XML); defaultProperties.setProperty(EXistOutputKeys.EXPAND_XINCLUDES, "yes"); defaultProperties.setProperty(EXistOutputKeys.HIGHLIGHT_MATCHES, "elements"); defaultProperties.setProperty(EXistOutputKeys.PROCESS_XSL_PI, "yes"); @@ -131,8 +160,7 @@ public class RESTServer { defaultOutputKeysProperties.setProperty(EXistOutputKeys.OMIT_ORIGINAL_XML_DECLARATION, "no"); defaultOutputKeysProperties.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); defaultOutputKeysProperties.setProperty(OutputKeys.INDENT, "yes"); - defaultOutputKeysProperties.setProperty(OutputKeys.MEDIA_TYPE, - MimeType.XML_TYPE.getName()); + defaultOutputKeysProperties.setProperty(OutputKeys.MEDIA_TYPE, MediaType.APPLICATION_XML); } private final static String QUERY_ERROR_HEAD = "" + "" + "Query Error" + " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/exist-distribution/src/dmg/App_DS_Store b/exist-distribution/src/dmg/App_DS_Store deleted file mode 100644 index f6735206d8..0000000000 Binary files a/exist-distribution/src/dmg/App_DS_Store and /dev/null differ diff --git a/exist-distribution/src/dmg/VolumeIcon.icns b/exist-distribution/src/dmg/VolumeIcon.icns index 2c1ae0477b..1bc20c02c4 100644 Binary files a/exist-distribution/src/dmg/VolumeIcon.icns and b/exist-distribution/src/dmg/VolumeIcon.icns differ diff --git a/exist-distribution/src/dmg/background.png b/exist-distribution/src/dmg/background.png index 37327bcaba..452cf8b236 100644 Binary files a/exist-distribution/src/dmg/background.png and b/exist-distribution/src/dmg/background.png differ diff --git a/exist-distribution/src/dmgbuild/README.md b/exist-distribution/src/dmgbuild/README.md new file mode 100644 index 0000000000..87e5080804 --- /dev/null +++ b/exist-distribution/src/dmgbuild/README.md @@ -0,0 +1,19 @@ +The App_DS_Store file was created using https://github.com/al45tair/dmgbuild + +```bash +$ git clone https://github.com/al45tair/dmgbuild +$ cd dmgbuild +$ python setup.py install +``` + +Then with these settings: + +```bash +$ dmgbuild -s settings.py "Elemental" elemental-${project.version}.dmg +``` + +The .DS_Store file can then be found in: +```bash +$ open elemental-${project.version}.dmg +$ file /Volumes/Elemental/.DS_Store +``` diff --git a/exist-distribution/src/dmgbuild/settings.py b/exist-distribution/src/dmgbuild/settings.py new file mode 100644 index 0000000000..13d29b2d62 --- /dev/null +++ b/exist-distribution/src/dmgbuild/settings.py @@ -0,0 +1,47 @@ +# +# Elemental +# Copyright (C) 2024, Evolved Binary Ltd +# +# admin@evolvedbinary.com +# https://www.evolvedbinary.com | https://www.elemental.xyz +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; version 2.1. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + +format = 'UDZO' +filesystem = 'HFS+' +files = [ + ('${project.build.directory}/elemental-${project.version}.app', 'Elemental.app'), +] +symlinks = { 'Applications': '/Applications' } + +icon = '${project.basedir}/src/dmg/VolumeIcon.icns' + +icon_locations = { + 'Elemental.app': (100, 140), + 'Applications': (500, 140) +} +background = '${project.basedir}/src/dmg/background.png' + +# Window position in ((x, y), (w, h)) format +window_rect = ((100, 100), (640, 300)) + +default_view = 'icon-view' +icon_size = 128 +license = { + 'default-language': 'en_US', + 'licenses': { + 'en_US': '${project.basedir}/../LICENSE' + } +} diff --git a/exist-distribution/src/main/config/conf.xml b/exist-distribution/src/main/config/conf.xml index c266900c2e..86a46ae998 100644 --- a/exist-distribution/src/main/config/conf.xml +++ b/exist-distribution/src/main/config/conf.xml @@ -126,7 +126,7 @@ - minDiskSpace: The amount of disk space (in megabytes) which should be available for the database to continue operations. If free disk space goes below - the configured limit, eXist-db will flush all buffers to disk and + the configured limit, Elemental will flush all buffers to disk and switch to read-only mode in order to prevent potential data loss. Set the limit large enough to allow all pending operations to complete. Set to -1 to disable. The default is 1 gigabyte. diff --git a/exist-distribution/src/main/config/log4j2.xml b/exist-distribution/src/main/config/log4j2.xml index c415025404..147d8c9d43 100644 --- a/exist-distribution/src/main/config/log4j2.xml +++ b/exist-distribution/src/main/config/log4j2.xml @@ -3,9 +3,12 @@ ${log4j:configParentLocation}/../logs 10MB + 0 0 0 * * ? 14 %d{yyyyMMddHHmmss} - %d [%t] %-5p (%F [%M]:%L) - %m %n + %d{yyyy-MM-dd} + %d [%t] %-5p (%F [%M]:%L) - %m%n + %m%n @@ -14,15 +17,15 @@ - + - + - + @@ -30,7 +33,7 @@ - + @@ -38,84 +41,84 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - - + + - + - + - + @@ -123,15 +126,15 @@ - + - + - + @@ -139,95 +142,88 @@ - + - + - + - - - - - - + - + - + - - - + + - - + + - + - + - + - + - + + + + + - + - + - + - + - + - + - - - - - - + @@ -238,11 +234,11 @@ - + - + diff --git a/exist-distribution/src/main/scripts/codesign-jansi-mac.sh b/exist-distribution/src/main/scripts/codesign-jline-mac.sh similarity index 50% rename from exist-distribution/src/main/scripts/codesign-jansi-mac.sh rename to exist-distribution/src/main/scripts/codesign-jline-mac.sh index 42508dc08b..ec73ea8581 100755 --- a/exist-distribution/src/main/scripts/codesign-jansi-mac.sh +++ b/exist-distribution/src/main/scripts/codesign-jline-mac.sh @@ -1,22 +1,10 @@ #!/usr/bin/env bash # -# Copyright (C) 2014, Evolved Binary Ltd +# Elemental +# Copyright (C) 2024, Evolved Binary Ltd # -# This file was originally ported from FusionDB to eXist-db by -# Evolved Binary, for the benefit of the eXist-db Open Source community. -# Only the ported code as it appears in this file, at the time that -# it was contributed to eXist-db, was re-licensed under The GNU -# Lesser General Public License v2.1 only for use in eXist-db. -# -# This license grant applies only to a snapshot of the code as it -# appeared when ported, it does not offer or infer any rights to either -# updates of this source code or access to the original source code. -# -# The GNU Lesser General Public License v2.1 only license follows. -# -# --------------------------------------------------------------------- -# -# Copyright (C) 2014, Evolved Binary Ltd +# admin@evolvedbinary.com +# https://www.evolvedbinary.com | https://www.elemental.xyz # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -34,7 +22,7 @@ # $1 is .app/Contents/Java dir -# $2 is the jansi version +# $2 is the jline version # $3 is temp work directory # $4 the mac codesign identity @@ -53,21 +41,22 @@ archs=('arm64' 'x86' 'x86_64') for arch in ${archs[@]} do # create the temp output dirs - mkdir -p "${3}/org/fusesource/jansi/internal/native/Mac/${arch}" + mkdir -p "${3}/org/jline/nativ/Mac/${arch}" # switch to temp output dir pushd "${3}" # extract the native files - jar -xf "${1}/jansi-${2}.jar" "org/fusesource/jansi/internal/native/Mac/${arch}/libjansi.jnilib" + jar -xf "${1}/jline-${2}.jar" "org/jline/nativ/Mac/${arch}/libjlinenative.jnilib" # test if the file is unsigned, and sign if needed - /usr/bin/codesign --verbose --test-requirement="=anchor trusted" --verify "org/fusesource/jansi/internal/native/Mac/${arch}/libjansi.jnilib" || /usr/bin/codesign --verbose --force --timestamp --sign "${4}" "org/fusesource/jansi/internal/native/Mac/${arch}/libjansi.jnilib" + /usr/bin/codesign --verbose --test-requirement="=anchor trusted" --verify "org/jline/nativ/Mac/${arch}/libjlinenative.jnilib" || /usr/bin/codesign --verbose --force --timestamp --sign "${4}" "org/jline/nativ/Mac/${arch}/libjlinenative.jnilib" # overwrite the file in the jar - jar -uf "${1}/jansi-${2}.jar" "org/fusesource/jansi/internal/native/Mac/${arch}/libjansi.jnilib" + jar -uf "${1}/jline-${2}.jar" "org/jline/nativ/Mac/${arch}/libjlinenative.jnilib" # switch back from temp output dir popd done + diff --git a/exist-distribution/src/main/scripts/codesign-lz4-java-mac.sh b/exist-distribution/src/main/scripts/codesign-lz4-java-mac.sh new file mode 100755 index 0000000000..ab039c42c9 --- /dev/null +++ b/exist-distribution/src/main/scripts/codesign-lz4-java-mac.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +# +# Elemental +# Copyright (C) 2024, Evolved Binary Ltd +# +# admin@evolvedbinary.com +# https://www.evolvedbinary.com | https://www.elemental.xyz +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; version 2.1. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + + +# $1 is .app/Contents/Java dir +# $2 is the lz4-java version +# $3 is temp work directory +# $4 the mac codesign identity + + +set -e +#set -x ## enable to help debug + +# ensure a clean temp work directory +if [ -d "${3}/net" ] +then + rm -rf "${3}/net" +fi + +# for each native arch +archs=('aarch64' 'x86_64') +for arch in ${archs[@]} +do + # create the temp output dirs + mkdir -p "${3}/net/jpountz/util/darwin/${arch}" + + # switch to temp output dir + pushd "${3}" + + # extract the native files + jar -xf "${1}/lz4-java-${2}.jar" "net/jpountz/util/darwin/${arch}/liblz4-java.dylib" + + # test if the file is unsigned, and sign if needed + /usr/bin/codesign --verbose --test-requirement="=anchor trusted" --verify "net/jpountz/util/darwin/${arch}/liblz4-java.dylib" || /usr/bin/codesign --verbose --force --timestamp --sign "${4}" "net/jpountz/util/darwin/${arch}/liblz4-java.dylib" + + # overwrite the file in the jar + jar -uf "${1}/lz4-java-${2}.jar" "net/jpountz/util/darwin/${arch}/liblz4-java.dylib" + + # switch back from temp output dir + popd + +done + diff --git a/exist-distribution/src/main/scripts/create-dmg-mac.sh b/exist-distribution/src/main/scripts/create-dmg-mac.sh index fe4b7fe7da..9dec26efda 100755 --- a/exist-distribution/src/main/scripts/create-dmg-mac.sh +++ b/exist-distribution/src/main/scripts/create-dmg-mac.sh @@ -1,15 +1,14 @@ #!/usr/bin/env bash # -# eXist-db Open Source Native XML Database -# Copyright (C) 2001 The eXist-db Authors +# Elemental +# Copyright (C) 2024, Evolved Binary Ltd # -# info@exist-db.org -# http://www.exist-db.org +# admin@evolvedbinary.com +# https://www.evolvedbinary.com | https://www.elemental.xyz # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. +# License as published by the Free Software Foundation; version 2.1. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -21,64 +20,29 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # +## Uses dmgbuild (https://github.com/al45tair/dmgbuild) to build a DMG file -# $1 is .app dir +# $1 is the path to settings.py for dmgbuild # $2 is app name e.g. VolName -# $3 is background image -# $4 is Volume icons -# $5 is DS_Store -# $6 is the output DMG file path and name +# $3 is the output DMG file path and name +dmgbuild_settings_py=$1 +volname=$2 +output_dmg=$3 -set -e set -x -# cleanup any previous DMG before creating a new DMG -if [[ -f "${6}" ]]; then +# cleanup any previous DMG file before creating a new DMG image +if [[ -f "${output_dmg}" ]]; then echo "Removing previous DMG" - rm -v "${6}" + rm -v "${output_dmg}" fi -tmp_dmg=/tmp/$2-dmg-tmp -tmp_dmg_mount=$tmp_dmg-mount - -final_app_dir="$(dirname "$1")/$2.app" - -# Copy the produced .app to `volname`.app -cp -r $1 $final_app_dir - -# Create a temporary Disk Image -/usr/bin/hdiutil create -fs HFS+ -srcfolder $final_app_dir -volname $2 -ov $tmp_dmg -format UDRW - -# Attach the temporary image -/usr/bin/hdiutil attach $tmp_dmg.dmg -mountroot $tmp_dmg_mount - -# Copy the background, the volume icon and DS_Store files -mkdir -p $tmp_dmg_mount/$2/.DropDMGBackground -cp $3 $tmp_dmg_mount/$2/.DropDMGBackground/ -cp $4 $tmp_dmg_mount/$2/.VolumeIcon.icns -cp $5 $tmp_dmg_mount/$2/.DS_Store - -# Indicate that we want a custom icon -if [[ -f "/Applications/Xcode.app/Contents/Developer/Tools/SetFile" ]]; then - /Applications/Xcode.app/Contents/Developer/Tools/SetFile -a -c $tmp_dmg_mount/$2 -else - /usr/bin/SetFile -a -c $tmp_dmg_mount/$2 +# Make sure that dmgbuild is installed +if ! pip show dmgbuild > /dev/null 2>&1; then + yes | pip install dmgbuild fi -# Add a symbolic link to the Applications directory -ln -s /Applications $tmp_dmg_mount/$2/Applications - -# Detach the temporary image -/usr/bin/hdiutil detach $tmp_dmg_mount/$2 - -# Compress it to a new image -/usr/bin/hdiutil convert $tmp_dmg.dmg -format UDZO -o $6 - -# Delete the temporary image -rm $tmp_dmg.dmg - -# Delete the mount point -rm -r $tmp_dmg_mount +set -e -# Delete the copied `volname`.app used for the DMG -rm -r $final_app_dir +# Build a new DMG image +dmgbuild -s ${dmgbuild_settings_py} "${volname}" "${output_dmg}" diff --git a/exist-distribution/src/main/scripts/create-dmg-unix.sh b/exist-distribution/src/main/scripts/create-dmg-unix.sh index 572afe18b7..8305bf782c 100755 --- a/exist-distribution/src/main/scripts/create-dmg-unix.sh +++ b/exist-distribution/src/main/scripts/create-dmg-unix.sh @@ -1,5 +1,29 @@ #!/usr/bin/env bash # +# Elemental +# Copyright (C) 2024, Evolved Binary Ltd +# +# admin@evolvedbinary.com +# https://www.evolvedbinary.com | https://www.elemental.xyz +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; version 2.1. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +# NOTE: Parts of this file contain code from 'The eXist-db Authors'. +# The original license header is included below. +# +# ===================================================================== +# # eXist-db Open Source Native XML Database # Copyright (C) 2001 The eXist-db Authors # @@ -72,10 +96,9 @@ sudo mount -o loop,uid=$username $tmp_dmg.dmg $tmp_dmg_mount cp -r $final_app_dir $tmp_dmg_mount # Copy the background, the volume icon and DS_Store files -mkdir -p $tmp_dmg_mount/$2/.DropDMGBackground -cp $3 $tmp_dmg_mount/$2/.DropDMGBackground/ -cp $4 $tmp_dmg_mount/$2/.VolumeIcon.icns -cp $5 $tmp_dmg_mount/$2/.DS_Store +cp "${3}" "${tmp_dmg_mount}/${2}/.$(basename $3)" +cp "${4}" "${tmp_dmg_mount}/${2}/.VolumeIcon.icns" +cp "${5}" "${tmp_dmg_mount}/${2}/.DS_Store" # Add a symbolic link to the Applications directory ln -s /Applications $tmp_dmg_mount/$2/Applications diff --git a/exist-distribution/src/main/xslt/catalog.xml b/exist-distribution/src/main/xslt/catalog.xml index e1cf3c6b15..b8855f3ebc 100644 --- a/exist-distribution/src/main/xslt/catalog.xml +++ b/exist-distribution/src/main/xslt/catalog.xml @@ -1,5 +1,29 @@ +
${project.parent.relativePath}/../elemental-parent/elemental-LGPL-21-ONLY-license.template.txt
+ + **.md + pom.xml + src/assembly/** + src/test/** + src/main/xslt/** + + + + + + +
${project.parent.relativePath}/../elemental-parent/elemental-LGPL-21-ONLY-license.template.txt
+ +
${project.parent.relativePath}/../exist-parent/existdb-LGPL-21-license.template.txt
+
+ + pom.xml + +
+ + + +
${project.parent.relativePath}/../exist-parent/existdb-LGPL-21-license.template.txt
+ + pom.xml + src/main/resources-filtered/** + +
+ @@ -124,7 +189,7 @@ single - ${project.basedir}/../exist-distribution/target/exist-distribution-${project.version}-dir + ${project.basedir}/../exist-distribution/target/elemental-${project.version}-dir false src/assembly/dist-assembly-docker.xml @@ -170,7 +235,7 @@ shade - ${assemble.dir}/lib/${exist.uber.jar.filename} + ${assemble.dir}/lib/${elemental.uber.jar.filename} true @@ -208,44 +273,60 @@ io.fabric8 docker-maven-plugin - 0.45.1 + 0.46.0 true - existdb/existdb:%v - exist + evolvedbinary/elemental:%v + elemental + docker.io ${docker.tag} ${project.build.outputDirectory}/Dockerfile ${assemble.dir} + + + linux/amd64 + linux/arm64 + + + - existdb/existdb:%v-DEBUG - exist-debug + evolvedbinary/elemental:%v-DEBUG + elemental-debug + docker.io ${docker.debug.tag} ${project.build.outputDirectory}/Dockerfile-DEBUG ${assemble.dir} + + + linux/amd64 + linux/arm64 + + + - build image + build-image package build - push image to registry + push-image deploy push @@ -256,4 +337,4 @@ - + \ No newline at end of file diff --git a/exist-docker/src/main/resources-filtered/Dockerfile b/exist-docker/src/main/resources-filtered/Dockerfile index 1688729100..2839142a28 100644 --- a/exist-docker/src/main/resources-filtered/Dockerfile +++ b/exist-docker/src/main/resources-filtered/Dockerfile @@ -1,14 +1,13 @@ # -# eXist-db Open Source Native XML Database -# Copyright (C) 2001 The eXist-db Authors +# Elemental +# Copyright (C) 2024, Evolved Binary Ltd # -# info@exist-db.org -# http://www.exist-db.org +# admin@evolvedbinary.com +# https://www.evolvedbinary.com | https://www.elemental.xyz # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. +# License as published by the Free Software Foundation; version 2.1. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -20,72 +19,133 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # -# Use Debian Bullseye (which is the base of gcr.io/distroless/java:17) for additional library dependencies that we need -# FROM debian:bullseye-slim as debian-slim -# RUN apt-get update && apt-get -y dist-upgrade -# RUN apt-get install -y openjdk-17-jre-headless -# RUN apt-get install -y expat fontconfig # Install tools required by FOP +### START: Container build time args for Elemental Server +## +# Names of the Linux user account and group to run the Elemental Server service under +ARG ELEMENTAL_SERVER_SERVICE_ACCOUNT="edb01" +ARG ELEMENTAL_SERVER_SERVICE_GROUP="edb01" -FROM gcr.io/distroless/java17:latest +# Elemental data cache size +ARG ELEMENTAL_SERVER_CACHE_MEM="256" +# Elemental maximum number of database brokers +ARG ELEMENTAL_SERVER_MAX_BROKER="20" +## +### END: Container build time args for Elemental Server -# Copy over dependencies for Apache FOP, missing from GCR's JRE -# COPY --from=debian-slim /usr/lib/x86_64-linux-gnu/libfreetype.so.6 /usr/lib/x86_64-linux-gnu/libfreetype.so.6 -# COPY --from=debian-slim /usr/lib/x86_64-linux-gnu/liblcms2.so.2 /usr/lib/x86_64-linux-gnu/liblcms2.so.2 -# COPY --from=debian-slim /usr/lib/x86_64-linux-gnu/libpng16.so.16 /usr/lib/x86_64-linux-gnu/libpng16.so.16 -# COPY --from=debian-slim /usr/lib/x86_64-linux-gnu/libfontconfig.so.1 /usr/lib/x86_64-linux-gnu/libfontconfig.so.1 +### START: Container build time args for JVM (Java Virtual Machine) +## +# JVM maximum RAM use (as a percentage of RAM available to the Docker Container) +ARG JVM_MAX_RAM_PERCENTAGE="75.0" +# JVM Garbage Collector +ARG JVM_GC="Z" -# Copy dependencies for Apache Batik (used by Apache FOP to handle SVG rendering) -# COPY --from=debian-slim /etc/fonts /etc/fonts -# COPY --from=debian-slim /lib/x86_64-linux-gnu/libexpat.so.1 /lib/x86_64-linux-gnu/libexpat.so.1 -# COPY --from=debian-slim /usr/share/fontconfig /usr/share/fontconfig -# COPY --from=debian-slim /usr/share/fonts/truetype/dejavu /usr/share/fonts/truetype/dejavu +# Any additional options to be added to the JAVA_TOOL_OPTIONS Environment Variable for the JVM +ARG ADDITIONAL_JAVA_TOOL_OPTIONS +## +### END: Container build time args for JVM (Java Virtual Machine) -# Copy eXist-db -COPY LICENSE /exist/LICENSE -COPY autodeploy /exist/autodeploy -COPY etc /exist/etc -COPY lib /exist/lib -COPY logs /exist/logs +# Install latest JRE 21 in Chainguard Wolfi temporary builder image +FROM cgr.dev/chainguard/wolfi-base AS builder +# Inherit global args to this build stage +ARG ELEMENTAL_SERVER_SERVICE_ACCOUNT +ARG ELEMENTAL_SERVER_SERVICE_GROUP + +RUN apk update && apk upgrade +# Install dependencies needed for JRE +RUN apk add tzdata zlib libjpeg-turbo libpng lcms2 freetype ttf-dejavu fontconfig-config libfontconfig1 expat libuuid libbrotlicommon1 libbrotlidec1 libbrotlienc1 libcrypt1 +# Install latest CA certificates +RUN apk add ca-certificates java-cacerts +# Install latest JRE +RUN apk add openjdk-21-jre + +# Add Elemental Server service group and account +RUN addgroup -S ${ELEMENTAL_SERVER_SERVICE_GROUP} \ + && adduser -S -G ${ELEMENTAL_SERVER_SERVICE_GROUP} -H -h /nonexistent -s /sbin/nologin -g "Elemental Database Server - Instance 01" ${ELEMENTAL_SERVER_SERVICE_ACCOUNT} + + +# Use Chainguard distroless glibc base for dynamically linked libraries +FROM cgr.dev/chainguard/glibc-dynamic:latest + +# Inherit global args to this build stage +ARG ELEMENTAL_SERVER_SERVICE_ACCOUNT +ARG ELEMENTAL_SERVER_SERVICE_GROUP +ARG ELEMENTAL_SERVER_CACHE_MEM +ARG ELEMENTAL_SERVER_MAX_BROKER +ARG JVM_MAX_RAM_PERCENTAGE +ARG JVM_GC +ARG ADDITIONAL_JAVA_TOOL_OPTIONS + +# Copy over dependencies for updated JRE from Wolfi +COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo +COPY --from=builder /lib/libz.so.1 /lib/libz.so.1 +COPY --from=builder /usr/lib/libjpeg.so.8 /usr/lib/libjpeg.so.8 +COPY --from=builder /usr/lib/libturbojpeg.so.0 /usr/lib/libturbojpeg.so.0 +COPY --from=builder /usr/lib/libpng16.so.16 /usr/lib/libpng16.so.16 +COPY --from=builder /usr/lib/liblcms2.so.2 /usr/lib/liblcms2.so.2 +COPY --from=builder /usr/lib/libfreetype.so.6 /usr/lib/libfreetype.so.6 +COPY --from=builder /usr/share/fonts /usr/share/fonts +COPY --from=builder /etc/fonts /etc/fonts +COPY --from=builder /usr/share/fontconfig /usr/share/fontconfig +COPY --from=builder /usr/share/gettext /usr/share/gettext +COPY --from=builder /usr/share/xml /usr/share/xml +COPY --from=builder /usr/lib/libfontconfig.so.1 /usr/lib/libfontconfig.so.1 +COPY --from=builder /usr/lib/libexpat.so.1 /usr/lib/libexpat.so.1 +COPY --from=builder /usr/lib/libuuid.so.1 /usr/lib/libuuid.so.1 +COPY --from=builder /usr/lib/libbrotlicommon.so.1 /usr/lib/libbrotlicommon.so.1 +COPY --from=builder /usr/lib/libbrotlidec.so.1 /usr/lib/libbrotlidec.so.1 +COPY --from=builder /usr/lib/libbrotlienc.so.1 /usr/lib/libbrotlienc.so.1 + +# Copy over certificates for updated JRE from Wolfi +COPY --from=builder /etc/ca-certificates /etc/ca-certificates +COPY --from=builder /etc/ca-certificates.conf /etc/ca-certificates.conf +COPY --from=builder /etc/apk/protected_paths.d/ca-certificates.list /etc/apk/protected_paths.d/ca-certificates.list +COPY --from=builder /etc/ssl /etc/ssl +COPY --from=builder /etc/pki /etc/pki +COPY --from=builder /usr/share/ca-certificates /usr/share/ca-certificates + +# Copy over updated JRE from Wolfi +COPY --from=builder /usr/lib/jvm/java-21-openjdk /usr/lib/jvm/java-21-openjdk + +# Copy Elemental Server service group and account +COPY --from=builder --chown=root:root --chmod=0644 /etc/passwd /etc/passwd +COPY --from=builder --chown=root:root --chmod=0644 /etc/group /etc/group +COPY --from=builder --chown=root:root --chmod=0600 /etc/shadow /etc/shadow + +# Switch to Elemental Server service account +USER ${ELEMENTAL_SERVER_SERVICE_ACCOUNT} + +# Copy Elemental +COPY --chown=${ELEMENTAL_SERVER_SERVICE_ACCOUNT}:${ELEMENTAL_SERVER_SERVICE_GROUP} --chmod=0555 logs /elemental +COPY --chown=${ELEMENTAL_SERVER_SERVICE_ACCOUNT}:${ELEMENTAL_SERVER_SERVICE_GROUP} --chmod=0444 LICENSE /elemental/LICENSE +COPY --chown=${ELEMENTAL_SERVER_SERVICE_ACCOUNT}:${ELEMENTAL_SERVER_SERVICE_GROUP} --chmod=0570 autodeploy /elemental/autodeploy +COPY --chown=${ELEMENTAL_SERVER_SERVICE_ACCOUNT}:${ELEMENTAL_SERVER_SERVICE_GROUP} --chmod=0570 etc /elemental/etc +COPY --chown=${ELEMENTAL_SERVER_SERVICE_ACCOUNT}:${ELEMENTAL_SERVER_SERVICE_GROUP} --chmod=0550 lib /elemental/lib +COPY --chown=${ELEMENTAL_SERVER_SERVICE_ACCOUNT}:${ELEMENTAL_SERVER_SERVICE_GROUP} --chmod=0750 logs /elemental/logs +COPY --chown=${ELEMENTAL_SERVER_SERVICE_ACCOUNT}:${ELEMENTAL_SERVER_SERVICE_GROUP} --chmod=0750 logs /elemental/data # Build-time metadata as defined at http://label-schema.org # and used by autobuilder @hooks/build LABEL org.label-schema.build-date=${maven.build.timestamp} \ - org.label-schema.description="${project.description}" \ - org.label-schema.name="existdb" \ + org.label-schema.description="Elemental - NoSQL Database" \ + org.label-schema.name="elemental" \ org.label-schema.schema-version="1.0" \ org.label-schema.url="${project.url}" \ org.label-schema.vcs-ref=${build-commit-abbrev} \ org.label-schema.vcs-url="${project.scm.url}" \ - org.label-schema.vendor="existdb" + org.label-schema.vendor="${project.organization.name}" EXPOSE 8080 8443 -# make CACHE_MEM, MAX_BROKER, and JVM_MAX_RAM_PERCENTAGE available to users -ARG CACHE_MEM -ARG MAX_BROKER -ARG JVM_MAX_RAM_PERCENTAGE +ENV ELEMENTAL_HOME="/elemental" +ENV EXIST_HOME="/elemental" +ENV CLASSPATH="/elemental/lib/${elemental.uber.jar.filename}" + +ENV JAVA_HOME="/usr/lib/jvm/java-21-openjdk" + +ENV JAVA_TOOL_OPTIONS="-Dfile.encoding=UTF8 -Dsun.jnu.encoding=UTF-8 -Djava.awt.headless=true -Dorg.exist.db-connection.cacheSize=${ELEMENTAL_SERVER_CACHE_MEM}M -Dorg.exist.db-connection.pool.max=${ELEMENTAL_SERVER_MAX_BROKER} -Dlog4j.configurationFile=/elemental/etc/log4j2.xml -Dexist.home=/elemental -Dexist.configurationFile=/elemental/etc/conf.xml -Djetty.home=/elemental -Dexist.jetty.config=/elemental/etc/jetty/standard.enabled-jetty-configs -XX:+UseNUMA -XX:+Use${JVM_GC}GC -XX:+UseContainerSupport -XX:MaxRAMPercentage=${JVM_MAX_RAM_PERCENTAGE} -XX:+ExitOnOutOfMemoryError ${ADDITIONAL_JAVA_TOOL_OPTIONS}" -ENV EXIST_HOME "/exist" -ENV CLASSPATH=/exist/lib/${exist.uber.jar.filename} - -ENV JAVA_TOOL_OPTIONS \ - -Dfile.encoding=UTF8 \ - -Dsun.jnu.encoding=UTF-8 \ - -Djava.awt.headless=true \ - -Dorg.exist.db-connection.cacheSize=${CACHE_MEM:-256}M \ - -Dorg.exist.db-connection.pool.max=${MAX_BROKER:-20} \ - -Dlog4j.configurationFile=/exist/etc/log4j2.xml \ - -Dexist.home=/exist \ - -Dexist.configurationFile=/exist/etc/conf.xml \ - -Djetty.home=/exist \ - -Dexist.jetty.config=/exist/etc/jetty/standard.enabled-jetty-configs \ - -XX:+UseNUMA \ - -XX:+UseZGC \ - -XX:+UseStringDeduplication \ - -XX:+UseContainerSupport \ - -XX:MaxRAMPercentage=${JVM_MAX_RAM_PERCENTAGE:-75.0} \ - -XX:+ExitOnOutOfMemoryError +ENV PATH="/usr/lib/jvm/java-21-openjdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" HEALTHCHECK CMD [ "java", \ "org.exist.start.Main", "client", \ diff --git a/exist-docker/src/main/resources-filtered/Dockerfile-DEBUG b/exist-docker/src/main/resources-filtered/Dockerfile-DEBUG index 17bf023976..18f861f571 100644 --- a/exist-docker/src/main/resources-filtered/Dockerfile-DEBUG +++ b/exist-docker/src/main/resources-filtered/Dockerfile-DEBUG @@ -1,14 +1,13 @@ # -# eXist-db Open Source Native XML Database -# Copyright (C) 2001 The eXist-db Authors +# Elemental +# Copyright (C) 2024, Evolved Binary Ltd # -# info@exist-db.org -# http://www.exist-db.org +# admin@evolvedbinary.com +# https://www.evolvedbinary.com | https://www.elemental.xyz # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. +# License as published by the Free Software Foundation; version 2.1. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -20,59 +19,111 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # -# Use JDK 17 in Debian Bullseye (as our production image gcr.io/distroless/java:17 is based on Debian Bullseye with just a JRE) -FROM debian:bullseye-slim -RUN apt-get update && apt-get -y dist-upgrade -RUN apt-get install -y openjdk-17-jdk-headless -RUN apt-get install -y expat fontconfig # Install tools required by FOP +### START: Container build time args for Elemental Server +## +# Names of the Linux user account and group to run the Elemental Server service under +ARG ELEMENTAL_SERVER_SERVICE_ACCOUNT="edb01" +ARG ELEMENTAL_SERVER_SERVICE_GROUP="edb01" -# Copy eXist-db -COPY LICENSE /exist/LICENSE -COPY autodeploy /exist/autodeploy -COPY etc /exist/etc -COPY lib /exist/lib -COPY logs /exist/logs +# Name of the Linux user account to use for the interactive container user when needing to debug +ARG ELEMENTAL_CONTAINER_DEBUG_USER_ACCOUNT="debug" + +# Elemental data cache size +ARG ELEMENTAL_SERVER_CACHE_MEM="256" +# Elemental maximum number of database brokers +ARG ELEMENTAL_SERVER_MAX_BROKER="20" +## +### END: Container build time args for Elemental Server + +### START: Container build time args for JVM (Java Virtual Machine) +## +# JVM maximum RAM use (as a percentage of RAM available to the Docker Container) +ARG JVM_MAX_RAM_PERCENTAGE="75.0" +# JVM Garbage Collector +ARG JVM_GC="Z" + +# JVM debugging protocol, suspend process on startup (y = Yes, n = No) +ARG JVM_JDWP_SUSPEND="n" +# JVM debugging protocol address and/or port +ARG JVM_JDWP_ADDRESS="5005" + +# Any additional options to be added to the JAVA_TOOL_OPTIONS Environment Variable for the JVM +ARG ADDITIONAL_JAVA_TOOL_OPTIONS +## +### END: Container build time args for JVM (Java Virtual Machine) + + +# Use Chainguard Wolfi +FROM cgr.dev/chainguard/wolfi-base + +# Inherit global args to this build stage +ARG ELEMENTAL_SERVER_SERVICE_ACCOUNT +ARG ELEMENTAL_SERVER_SERVICE_GROUP +ARG ELEMENTAL_CONTAINER_DEBUG_USER_ACCOUNT +ARG ELEMENTAL_SERVER_CACHE_MEM +ARG ELEMENTAL_SERVER_MAX_BROKER +ARG JVM_MAX_RAM_PERCENTAGE +ARG JVM_GC +ARG JVM_JDWP_SUSPEND +ARG JVM_JDWP_ADDRESS +ARG ADDITIONAL_JAVA_TOOL_OPTIONS + +RUN apk update && apk upgrade +# Install dependencies needed for JDK +RUN apk add tzdata zlib libjpeg-turbo libpng lcms2 freetype ttf-dejavu fontconfig-config libfontconfig1 expat libuuid libbrotlicommon1 libbrotlidec1 libbrotlienc1 libcrypt1 +# Install latest CA certificates +RUN apk add ca-certificates java-cacerts +# Install latest JDK +RUN apk add openjdk-21 + +# Add Elemental Server service group and account +RUN addgroup -S ${ELEMENTAL_SERVER_SERVICE_GROUP} \ + && adduser -S -G ${ELEMENTAL_SERVER_SERVICE_GROUP} -H -h /nonexistent -s /sbin/nologin -g "Elemental Database Server - Instance 01" ${ELEMENTAL_SERVER_SERVICE_ACCOUNT} + +# Add 'debug' user for interactive use, and add then to the Elemental Server service group +RUN adduser -D -g "Elemental Docker Container - debug user" ${ELEMENTAL_CONTAINER_DEBUG_USER_ACCOUNT} \ + && addgroup ${ELEMENTAL_CONTAINER_DEBUG_USER_ACCOUNT} ${ELEMENTAL_SERVER_SERVICE_GROUP} + +# Install sudo +RUN apk add sudo-rs +COPY --chmod=0440 < 3f4dbbce9afa -Step 2/2 : COPY build/*.xar /exist/autodeploy - ---> ace38b0809de -``` - -The result is a new image of your app installed into eXist-db. -Since you didn't provide further instructions it will simply reuse the `EXPOSE`, `CMD`, `HEALTHCHECK`, etc instructions defined by the base image. -You can now publish this image to a docker registry and share it with others. - -### A slightly more complex single stage image -The following example will install your app, but also modify the underlying eXist-db instance in which your app is running. -Instead of a local build directory, we'll download the `.xar` from the web, and copy a modified `conf.xml` from a `src/` directory along side your `Dockerfile`. -To execute any of the `docker exec …` style commands from this readme, we need to use `RUN`. - -```docker -FROM existdb/existdb - -# NOTE: this is for syntax demo purposes only -RUN [ "java", "org.exist.start.Main", "client", "--no-gui", "-l", "-u", "admin", "-P", "", "-x", "sm:passwd('admin','123')" ] - -# use a modified conf.xml -COPY src/conf.xml /exist/etc - -ADD https://github.com/eXist-db/documentation/releases/download/4.0.4/exist-documentation-4.0.4.xar /exist/autodeploy -``` - -The above is intended to demonstrate the kind of operations available to you in a single stage build. -For security reasons [more elaborate techniques](https://docs.docker.com/engine/swarm/secrets/) for not sharing your password in the clear are highly recommended, -such as the use of secure variables inside your CI environment. -However, the above shows you how to execute the [Java Admin Client](http://www.exist-db.org/exist/apps/doc/java-admin-client.xml) from inside a `Dockerfile`, -which in turn allows you to run any XQuery code you want when modifying the eXist-db instance that will ship with your images. You can also chain multiple `RUN` commands. - -As for the sequence of the commands, those with the most frequent changes should come last to avoid cache busting. -Chances are, you wouldn't change the admin password very often, but the `.xar` might change more frequently. - -### Multi-stage build with ant -Lastly, you can eliminate external dependencies even further by using a multi-stage build. -To ensure compatibility between different Java engines we recommend sticking with debian based images for the builder stage. - -The following 2-stage build will download and install `ant` and `nodeJS` into a builder stage which then downloads frontend dependencies before building the `.xar` file. -The second stage (each `FROM` begins a stage) is just the simple example from above. -Such a setup ensures that non of your collaborators has to have `java` or `nodeJS` installed, and is great for fully automated builds and deployment. - -```docker -# START STAGE 1 -FROM openjdk:8-jdk-slim as builder - -USER root - -ENV ANT_VERSION 1.10.5 -ENV ANT_HOME /etc/ant-${ANT_VERSION} - -WORKDIR /tmp - -RUN wget http://www-us.apache.org/dist/ant/binaries/apache-ant-${ANT_VERSION}-bin.tar.gz \ - && mkdir ant-${ANT_VERSION} \ - && tar -zxvf apache-ant-${ANT_VERSION}-bin.tar.gz \ - && mv apache-ant-${ANT_VERSION} ${ANT_HOME} \ - && rm apache-ant-${ANT_VERSION}-bin.tar.gz \ - && rm -rf ant-${ANT_VERSION} \ - && rm -rf ${ANT_HOME}/manual \ - && unset ANT_VERSION - -ENV PATH ${PATH}:${ANT_HOME}/bin - -WORKDIR /home/my-app -COPY . . -RUN apk add --no-cache --virtual .build-deps \ - nodejs \ - nodejs-npm \ - git \ - && npm i npm@latest -g \ - && ant - - -# START STAGE 2 -FROM existdb/existdb:release - -COPY --from=builder /home/my-app/build/*.xar /exist/autodeploy - -EXPOSE 8080 8443 - -CMD [ "java", "org.exist.start.Main", "jetty" ] -``` - -The basic idea of the multi-staging is that everything you need for building your software should be managed by docker, -so that all collaborators can rely on one stable environment. In the end, and after how ever many stages you need, -only the files necessary to run your app should go into the final stage. The possibilities are virtually endless, -but with this example and the `Dockerfile` in this repo you should get a pretty good idea of how you might apply this idea to your own projects. - -## Development use via `docker-compose` -We highly recommend use of a `docker-compose.yml` for use with [docker-compose](https://docs.docker.com/compose/). -docker-compose for local development or integration into multi-container environments. -For options on how to configure your own compose file, follow the link at the beginning of this paragraph. - -To start exist using a compose file, type: -```bash -# starting eXist-db -docker-compose up -d -# stop eXist-db -docker-compose down -``` - -[Volumes](https://docs.docker.com/storage/volumes/) let you ensure data persistence between reboots, -in particular: - -* `exist/data` so that any database changes persist through reboots and updates. -* `exist/etc` so you can configure eXist startup options. - -can be declared as mount volumes. - -You can configure additional volumes e.g. for backups, -or additional services such as an nginx reverse proxy via a `docker-compose.yml`, to suite your needs. - -To update the exist-docker image from a newer version -```bash -docker-compose pull -``` - -### Caveat -As with normal installations, the password for the default dba user `admin` is empty. -Change it via the [usermanager](http://localhost:8080/exist/apps/usermanager/index.html) or from CLI \(s.a.\). - ## Building the Image -Building is integrated into maven via the [fabric8 plugin](https://dmp.fabric8.io): -To build a docker image from a local clone of exist: +Building is integrated into Maven via the [fabric8 plugin](https://dmp.fabric8.io): +To build a docker image from a local clone of Elemental: ```bash mvn -Pdocker -DskipTests -Ddependency-check.skip=true clean package ``` - -`-P` activates the docker profile. The maven plugin provides for a number of usefull commands to work with containers, e.g.: - -```bash -cd exist-docker -mvn docker:push -``` - -For a full list see the plugin documentation. - -### Testing -There are unit tests for our images that run on CI using the [bats](https://github.com/bats-core/bats-core) framework. The test are located in `exist-docker/src/test/bats`. - -To execute them run: -```bash -bats exist-docker/src/test/bats/*.bats -``` -The tests use fixtures and are creating a modified image call `ex-mod`. By default they expect a name container `exist-ci` to be up and running. When running test locally you must ensure that no previous image `ex-mod` exists, and that `exist-ci` is running before starting the testsuite. - -### Available Arguments and Defaults -eXist-db's cache size and maximum brokers can be configured at build time using the following syntax. -```bash -mvn -DskipTests clean package docker:build --build-arg MAX_CACHE=312 MAX_BROKER=15 . -``` - -NOTE: Due to the fact that the final images does not provide a shell, setting ENV variables via docker does not work. -```bash -# !This has no effect! -docker run -dit -p8080:8080 -e MAX_BROKER=10 ae4d6d653d30 -``` - -If you wish to permanently adopt a customized cache or broker configuration, -you can either make a local copy of the `Dockerfile` and edit the default values there. - -```bash -ARG MAX_BROKER=10 -``` - -Or modify eXist-db's configuration files via xslt scripts located at `exist-docker/src/main/xslt/`. -For multi-stage builds e.g. [xmlstarlet](http://xmlstar.sourceforge.net) let's you modify the default config files from within the builder stage, -e.g.: -```docker -# Config files are modified here -RUN echo 'modifying conf files'\ -&& cd $EXIST_HOME/etc \ -&& xmlstarlet ed -L -s '/Configuration/Loggers/Root' -t elem -n 'AppenderRefTMP' -v '' \ - -i //AppenderRefTMP -t attr -n 'ref' -v 'STDOUT'\ - -r //AppenderRefTMP -v AppenderRef \ - log4j2.xml -``` - - -#### JVM configuration -This image uses an advanced JVM configuration, via the `JAVA_TOOL_OPTIONS` env variable inside the Dockerfile. -You should avoid the traditional way of setting the heap size via `-Xmx` arguments, -this can lead to frequent crashes since Java8 and Docker are (literally) not on the same page concerning available memory. - -Instead, use the `-XX:MaxRAMFraction=1` argument to modify the memory available to the JVM *inside* the container. -For production use we recommend to increase the value to `2` or even `4`. -This value expresses a ratio, so setting it to `2` means half the container's memory will be available to the JVM, '4' means ¼, etc. - -To allocate e.g. 600mb to the container *around* the JVM use: -```bash -docker run -m 600m … -``` - -Lastly, this image uses a new garbage collection mechanism -[The Z Garbage Collector](https://docs.oracle.com/en/java/javase/11/gctuning/z-garbage-collector1.html) `-XX:+UseZGC` -and [string deduplication](http://openjdk.java.net/jeps/192) `-XX:+UseStringDeduplication` to improve performance. - -To disable or further tweak these features edit the relevant parts of the `Dockerfile`, or when running the image. -As always when using the latest and greatest, YMMV. -Feedback about real world experiences with these features in connection with eXist-db is very much welcome. diff --git a/exist-docker/src/test/bats/01-connect-spec.bats b/exist-docker/src/test/bats/01-connect-spec.bats index 0a2ba88278..fb72825cf0 100644 --- a/exist-docker/src/test/bats/01-connect-spec.bats +++ b/exist-docker/src/test/bats/01-connect-spec.bats @@ -1,4 +1,26 @@ #!/usr/bin/env bats +# +# eXist-db Open Source Native XML Database +# Copyright (C) 2001 The eXist-db Authors +# +# info@exist-db.org +# http://www.exist-db.org +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + # Basic start-up and connection tests @test "container jvm responds from client" { diff --git a/exist-docker/src/test/bats/02-config-spec.bats b/exist-docker/src/test/bats/02-config-spec.bats index 44abbf8368..49e832d9d9 100644 --- a/exist-docker/src/test/bats/02-config-spec.bats +++ b/exist-docker/src/test/bats/02-config-spec.bats @@ -1,4 +1,26 @@ #!/usr/bin/env bats +# +# eXist-db Open Source Native XML Database +# Copyright (C) 2001 The eXist-db Authors +# +# info@exist-db.org +# http://www.exist-db.org +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + # Tests for modifying eXist's configuration files @test "copy configuration file from container to disk" { diff --git a/exist-docker/src/test/bats/03-xquery-spec.bats b/exist-docker/src/test/bats/03-xquery-spec.bats index 3007b5e25e..673916d5d1 100644 --- a/exist-docker/src/test/bats/03-xquery-spec.bats +++ b/exist-docker/src/test/bats/03-xquery-spec.bats @@ -1,4 +1,26 @@ #!/usr/bin/env bats +# +# eXist-db Open Source Native XML Database +# Copyright (C) 2001 The eXist-db Authors +# +# info@exist-db.org +# http://www.exist-db.org +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + # Tests that execute xquery via Java entrypoint @test "Change admin password" { diff --git a/exist-installer/pom.xml b/exist-installer/pom.xml index 5d0163c9f8..4a53c6bff5 100644 --- a/exist-installer/pom.xml +++ b/exist-installer/pom.xml @@ -1,6 +1,30 @@ +
${project.parent.relativePath}/../elemental-parent/elemental-LGPL-21-ONLY-license.template.txt
+ + pom.xml + src/** + + + + + + +
${project.parent.relativePath}/../elemental-parent/elemental-LGPL-21-ONLY-license.template.txt
+ +
${project.parent.relativePath}/../exist-parent/existdb-LGPL-21-license.template.txt
+
+ + pom.xml + src/main/izpack/custom.eng.xml + src/main/izpack/install.xml + src/main/izpack/jobs.xml + src/main/izpack/readme.html + src/main/izpack/shortcutSpec.xml + src/main/izpack/start.html + src/main/izpack/UnixShortcutSpec.xml + src/main/izpack/userInput.xml + +
+ + + +
${project.parent.relativePath}/../exist-parent/existdb-LGPL-21-license.template.txt
+ + pom.xml + src/main/izpack/custom.eng.xml + src/main/izpack/install.xml + src/main/izpack/jobs.xml + src/main/izpack/readme.html + src/main/izpack/shortcutSpec.xml + src/main/izpack/start.html + src/main/izpack/UnixShortcutSpec.xml + src/main/izpack/userInput.xml + +
+ +
+ + org.apache.maven.plugins maven-dependency-plugin @@ -115,9 +203,28 @@ ${izpack.version} true + elemental-installer-${project.version} ${izpack.resources.target}/install.xml - ${basedir}/../exist-distribution/target/exist-distribution-${project.version}-dir + ${basedir}/../exist-distribution/target/elemental-${project.version}-dir + true + true + izpack.resources.target,izpack.installation.info.url,izpack.installation.info.appversion,izpack.installation.info.author.name,izpack.installation.info.author.email,saxon.version,project.build.target,build-commit-abbrev,build-commit,build-tag-delta,build-tag,build-tstamp,build-version,contact.email,copyright.string + + + + net.sf.saxon + Saxon-HE + ${saxon.version} + + + + com.evolvedbinary.thirdparty.xerces + xercesImpl + ${xerces.version} + jdk14-xml-schema-1.1 + + @@ -159,10 +266,10 @@ sign - ${existdb.release.keystore} - ${existdb.release.keystore.pass} - ${existdb.release.keystore.key.alias} - ${existdb.release.keystore.key.pass} + ${elemental.release.keystore} + ${elemental.release.keystore.pass} + ${elemental.release.keystore.key.alias} + ${elemental.release.keystore.key.pass} @@ -173,7 +280,7 @@ - exist-release + elemental-release @@ -190,12 +297,14 @@ true - Release Notes: https://exist-db.org/exist/apps/wiki/blogs/eXist/exist${project.version} + Elemental version ${project.version} - Maven Central: https://search.maven.org/search?q=g:org.exist-db + Docker Image: evolvedbinary/elemental:${project.version} + Maven Central: https://search.maven.org/search?q=g:xyz.elemental + Website: ${project.url} - eXist-db ${project.version} - eXist-${project.version} + Elemental ${project.version} + elemental-${project.version} ${project.build.directory} @@ -213,4 +322,4 @@ - + \ No newline at end of file diff --git a/exist-installer/src/main/izpack/UnixShortcutSpec.xml b/exist-installer/src/main/izpack/UnixShortcutSpec.xml index 72eaeea3dc..04745a69c6 100644 --- a/exist-installer/src/main/izpack/UnixShortcutSpec.xml +++ b/exist-installer/src/main/izpack/UnixShortcutSpec.xml @@ -1,6 +1,30 @@ - - + + + + + - + - + + + @@ -95,13 +128,13 @@ - + - + diff --git a/exist-installer/src/main/izpack/icon.ico b/exist-installer/src/main/izpack/icon.ico index a41ba28fb6..fcede135d9 100644 Binary files a/exist-installer/src/main/izpack/icon.ico and b/exist-installer/src/main/izpack/icon.ico differ diff --git a/exist-installer/src/main/izpack/icon.png b/exist-installer/src/main/izpack/icon.png index 48f753271c..5d92b55578 100644 Binary files a/exist-installer/src/main/izpack/icon.png and b/exist-installer/src/main/izpack/icon.png differ diff --git a/exist-installer/src/main/izpack/install.xml b/exist-installer/src/main/izpack/install.xml index f781da1cc6..b665addb90 100644 --- a/exist-installer/src/main/izpack/install.xml +++ b/exist-installer/src/main/izpack/install.xml @@ -1,6 +1,30 @@ - + + + - eXist-db + Elemental @{izpack.installation.info.appversion} @{izpack.installation.info.url} @@ -41,7 +74,8 @@ @{project.build.target} no - xz + + bzip2 @@ -61,7 +95,7 @@ - + @@ -69,7 +103,7 @@ - @@ -129,7 +163,7 @@ - Everything needed for the eXist-db database + Everything needed for Elemental diff --git a/exist-installer/src/main/izpack/installer-device-logo.png b/exist-installer/src/main/izpack/installer-device-logo.png new file mode 100644 index 0000000000..f5160d423a Binary files /dev/null and b/exist-installer/src/main/izpack/installer-device-logo.png differ diff --git a/exist-installer/src/main/izpack/installer-logo-vertical.png b/exist-installer/src/main/izpack/installer-logo-vertical.png new file mode 100644 index 0000000000..567e99914c Binary files /dev/null and b/exist-installer/src/main/izpack/installer-logo-vertical.png differ diff --git a/exist-installer/src/main/izpack/installer-logo.png b/exist-installer/src/main/izpack/installer-logo.png deleted file mode 100644 index 0a593b72aa..0000000000 Binary files a/exist-installer/src/main/izpack/installer-logo.png and /dev/null differ diff --git a/exist-installer/src/main/izpack/jobs.xml b/exist-installer/src/main/izpack/jobs.xml index 69f2549865..7549e6649c 100644 --- a/exist-installer/src/main/izpack/jobs.xml +++ b/exist-installer/src/main/izpack/jobs.xml @@ -1,6 +1,30 @@ - + + + $INSTALL_PATH${FILE_SEPARATOR}logs diff --git a/exist-installer/src/main/izpack/readme.html b/exist-installer/src/main/izpack/readme.html index 5306d6bf1b..15955abb1b 100644 --- a/exist-installer/src/main/izpack/readme.html +++ b/exist-installer/src/main/izpack/readme.html @@ -1,5 +1,29 @@ - - + + + + + + - - -
-
-

Welcome to the ${APP_NAME} ${APP_VER} Installer!

-

For more information about ${APP_NAME}, visit ${APP_URL}!

+
+
+
+
+

Welcome to the ${APP_NAME} ${APP_VER} Installer!

+

For more information about ${APP_NAME}, visit: www.elemental.xyz

+
diff --git a/exist-installer/src/main/izpack/userInput.xml b/exist-installer/src/main/izpack/userInput.xml index fe1397e2e5..e09c9bc8eb 100644 --- a/exist-installer/src/main/izpack/userInput.xml +++ b/exist-installer/src/main/izpack/userInput.xml @@ -1,6 +1,30 @@ - + + + + + + diff --git a/exist-jetty-config/pom.xml b/exist-jetty-config/pom.xml index 379d7a5d9f..9afbc753ab 100644 --- a/exist-jetty-config/pom.xml +++ b/exist-jetty-config/pom.xml @@ -1,6 +1,30 @@ +
${project.parent.relativePath}/../elemental-parent/elemental-LGPL-21-ONLY-license.template.txt
+ + pom.xml + src/** + + + + + + +
${project.parent.relativePath}/../elemental-parent/elemental-LGPL-21-ONLY-license.template.txt
+ +
${project.parent.relativePath}/../exist-parent/existdb-LGPL-21-license.template.txt
+
+ + pom.xml + src/main/resources/webapp/404.html + src/main/resources/webapp/controller.xq + src/main/resources/org/exist/jetty/etc/webapps/portal/index.html + +
+ + + +
${project.parent.relativePath}/../exist-parent/existdb-LGPL-21-license.template.txt
+ + pom.xml + src/** + +
+ - + \ No newline at end of file diff --git a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/jetty-logging.xml b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/jetty-logging.xml deleted file mode 100644 index 620f17ea09..0000000000 --- a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/jetty-logging.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - jetty.logging.dir - jetty.logs - /yyyy_mm_dd.stderrout.log - - - - - - - - - - - - - Redirecting stderr/stdout to - - - - - - - - diff --git a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/jetty-ssl-context.xml b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/jetty-ssl-context.xml index f3861787ef..3c508f636f 100644 --- a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/jetty-ssl-context.xml +++ b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/jetty-ssl-context.xml @@ -16,7 +16,7 @@ - + / diff --git a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/keystore.p12 b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/keystore.p12 index 4c299eb21e..f94a8e513a 100644 Binary files a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/keystore.p12 and b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/keystore.p12 differ diff --git a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/standalone-webapps/exist-webapp-context.xml b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/standalone-webapps/elemental-webapp-context.xml similarity index 93% rename from exist-jetty-config/src/main/resources/org/exist/jetty/etc/standalone-webapps/exist-webapp-context.xml rename to exist-jetty-config/src/main/resources/org/exist/jetty/etc/standalone-webapps/elemental-webapp-context.xml index 05ef5bcda5..4afaac937a 100644 --- a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/standalone-webapps/exist-webapp-context.xml +++ b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/standalone-webapps/elemental-webapp-context.xml @@ -1,7 +1,7 @@ - + / /../../../standalone-webapp/ diff --git a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/standalone.enabled-jetty-configs b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/standalone.enabled-jetty-configs index bd2a4da7c7..6a60798c0f 100644 --- a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/standalone.enabled-jetty-configs +++ b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/standalone.enabled-jetty-configs @@ -1,17 +1,13 @@ -### This file controls which jetty config files will be loaded by eXist +### This file controls which jetty config files will be loaded by Elemental # Note that the order of the configurations listen in this file is important, # dependency load order between the config files must be respected. # -# Dependency load order can be determined from interogating a clean jetty +# Dependency load order can be determined from interrogating a clean jetty # base with the desired modules enabled... # see: http://stackoverflow.com/questions/37846079/nullpointerexception-in-requestlogcollection-jetty-9-3-9#37932579 -### Jetty log redirection -# jetty-logging.xml # enable to redirect stdout and stderr to jetty.home/logs - - ### Main Server Config jetty-bytebufferpool.xml jetty-threadpool.xml diff --git a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/standard.enabled-jetty-configs b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/standard.enabled-jetty-configs index 4a64fb0402..b974de19a2 100644 --- a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/standard.enabled-jetty-configs +++ b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/standard.enabled-jetty-configs @@ -1,17 +1,13 @@ -### This file controls which jetty config files will be loaded by eXist +### This file controls which jetty config files will be loaded by Elemental # Note that the order of the configurations listen in this file is important, # dependency load order between the config files must be respected. # -# Dependency load order can be determined from interogating a clean jetty +# Dependency load order can be determined from interrogating a clean jetty # base with the desired modules enabled... # see: http://stackoverflow.com/questions/37846079/nullpointerexception-in-requestlogcollection-jetty-9-3-9#37932579 -### Jetty log redirection -# jetty-logging.xml # enable to redirect stdout and stderr to jetty.home/logs - - ### Main Server Config jetty-bytebufferpool.xml jetty-threadpool.xml diff --git a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/exist-webapp-context.xml b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/elemental-webapp-context.xml similarity index 93% rename from exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/exist-webapp-context.xml rename to exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/elemental-webapp-context.xml index 73c5b7e633..ba5f06796e 100644 --- a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/exist-webapp-context.xml +++ b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/elemental-webapp-context.xml @@ -1,7 +1,7 @@ - + /exist /../../../webapp/ diff --git a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/WEB-INF/jetty-web.xml b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/WEB-INF/jetty-web.xml index cdb3382bbb..0444ea725c 100755 --- a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/WEB-INF/jetty-web.xml +++ b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/WEB-INF/jetty-web.xml @@ -1,6 +1,6 @@ - + / /etc/webdefault.xml diff --git a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/WEB-INF/web.xml b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/WEB-INF/web.xml index aee0c88368..1fec0c92fd 100755 --- a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/WEB-INF/web.xml +++ b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/WEB-INF/web.xml @@ -6,6 +6,6 @@ metadata-complete="false" version="5.0"> - eXist-db portal + Elemental portal Provides an entry point for the / root context diff --git a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/index.html b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/index.html index 58bb0a07dd..bb66f7a856 100755 --- a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/index.html +++ b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/index.html @@ -1,17 +1,67 @@ + - eXist-db - Open Source Native XML Database - - + Elemental - NoSQL Database + + + + + \ No newline at end of file diff --git a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/resources/logo.jpg b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/resources/logo.jpg deleted file mode 100755 index e67139f2e8..0000000000 Binary files a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/resources/logo.jpg and /dev/null differ diff --git a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/resources/logo.png b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/resources/logo.png new file mode 100644 index 0000000000..93c9053608 Binary files /dev/null and b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/resources/logo.png differ diff --git a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/resources/site.webmanifest b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/resources/site.webmanifest new file mode 100644 index 0000000000..5ffb9a2c1e --- /dev/null +++ b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/resources/site.webmanifest @@ -0,0 +1,21 @@ +{ + "name": "Elemental Server", + "short_name": "Elemental Server", + "icons": [ + { + "src": "/resources/web-app-manifest-192x192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "/resources/web-app-manifest-512x512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} \ No newline at end of file diff --git a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/resources/web-app-manifest-192x192.png b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/resources/web-app-manifest-192x192.png new file mode 100644 index 0000000000..6568679a08 Binary files /dev/null and b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/resources/web-app-manifest-192x192.png differ diff --git a/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/resources/web-app-manifest-512x512.png b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/resources/web-app-manifest-512x512.png new file mode 100644 index 0000000000..4fd823699e Binary files /dev/null and b/exist-jetty-config/src/main/resources/org/exist/jetty/etc/webapps/portal/resources/web-app-manifest-512x512.png differ diff --git a/exist-jetty-config/src/main/resources/standalone-webapp/WEB-INF/controller-config.xml b/exist-jetty-config/src/main/resources/standalone-webapp/WEB-INF/controller-config.xml index cffb8bf1e8..622b986ea5 100644 --- a/exist-jetty-config/src/main/resources/standalone-webapp/WEB-INF/controller-config.xml +++ b/exist-jetty-config/src/main/resources/standalone-webapp/WEB-INF/controller-config.xml @@ -18,9 +18,6 @@ - - - Page not found - - + + + + + \ No newline at end of file diff --git a/exist-jetty-config/src/main/resources/webapp/resources/site.webmanifest b/exist-jetty-config/src/main/resources/webapp/resources/site.webmanifest new file mode 100644 index 0000000000..5ffb9a2c1e --- /dev/null +++ b/exist-jetty-config/src/main/resources/webapp/resources/site.webmanifest @@ -0,0 +1,21 @@ +{ + "name": "Elemental Server", + "short_name": "Elemental Server", + "icons": [ + { + "src": "/resources/web-app-manifest-192x192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "/resources/web-app-manifest-512x512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} \ No newline at end of file diff --git a/exist-jetty-config/src/main/resources/webapp/resources/web-app-manifest-192x192.png b/exist-jetty-config/src/main/resources/webapp/resources/web-app-manifest-192x192.png new file mode 100644 index 0000000000..6568679a08 Binary files /dev/null and b/exist-jetty-config/src/main/resources/webapp/resources/web-app-manifest-192x192.png differ diff --git a/exist-jetty-config/src/main/resources/webapp/resources/web-app-manifest-512x512.png b/exist-jetty-config/src/main/resources/webapp/resources/web-app-manifest-512x512.png new file mode 100644 index 0000000000..4fd823699e Binary files /dev/null and b/exist-jetty-config/src/main/resources/webapp/resources/web-app-manifest-512x512.png differ diff --git a/exist-parent/FDB-backport-LGPL-21-ONLY-license.xml.template.txt b/exist-parent/FDB-backport-to-existdb-LGPL-21-ONLY-license.template.txt similarity index 99% rename from exist-parent/FDB-backport-LGPL-21-ONLY-license.xml.template.txt rename to exist-parent/FDB-backport-to-existdb-LGPL-21-ONLY-license.template.txt index 39625f7c56..34554abbc4 100644 --- a/exist-parent/FDB-backport-LGPL-21-ONLY-license.xml.template.txt +++ b/exist-parent/FDB-backport-to-existdb-LGPL-21-ONLY-license.template.txt @@ -12,7 +12,7 @@ updates of this source code or access to the original source code. The GNU Lesser General Public License v2.1 only license follows. -##################################################################### +===================================================================== Copyright (C) 2014, Evolved Binary Ltd diff --git a/exist-distribution/LGPL-21-license.txt b/exist-parent/existdb-LGPL-21-license.template.txt similarity index 100% rename from exist-distribution/LGPL-21-license.txt rename to exist-parent/existdb-LGPL-21-license.template.txt diff --git a/exist-parent/pom.xml b/exist-parent/pom.xml index 219ceeb801..4b803e014d 100644 --- a/exist-parent/pom.xml +++ b/exist-parent/pom.xml @@ -1,6 +1,30 @@ - https://lists.sourceforge.net/lists/listinfo/exist-open - https://lists.sourceforge.net/lists/listinfo/exist-open - exist-open@lists.sourceforge.net - http://sourceforge.net/p/exist/mailman/exist-open/ - - http://exist-open.markmail.org/ - http://blog.gmane.org/gmane.text.xml.exist/ - - - - - exist-development - - https://lists.sourceforge.net/lists/listinfo/exist-development - https://lists.sourceforge.net/lists/listinfo/exist-development - exist-development@lists.sourceforge.net - http://sourceforge.net/p/exist/mailman/exist-development/ - - http://exist-development.markmail.org/ - - - + scm:git:https://github.com/evolvedbinary/elemental.git + scm:git:https://github.com/evolvedbinary/elemental.git + scm:git:https://github.com/evolvedbinary/elemental.git + HEAD + - 17 - 17 - UTF-8 - - The eXist-db Authors - - info@exist-db.org + + . 1.10.15 4.5.14 4.4.16 - 5.0.0 + 6.1.0 2.1.0 - 1.9.22.1 0.2.1 59.1 - 5.2.3 - 2.4.1 - 4.0.2 - 4.0.2 - 2.0.2 - 11.0.24 - 2.24.1 + 5.2.4 + 3.30.6 + 1.10.2 + 11.0.26 + 2.25.2 4.10.4 - 1.8.1.3 - 1.8.1.3-jakarta5 2.1.3 9.9.1-8 - 5.2.3 - 2.10.0 + 2.12.2.2 + 6.0.19 + 2.11.0 4.13.2 - 1.11.3 - 5.11.3 - 5.4.0 - 3.4 - 3.26.3 - 4.2.2 + 5.6.0 + 3.27.6 + 4.3.0 2.4 3.0 - - . - - - eXist-db_exist - exist-db - https://sonarcloud.io - ${project.groupId}:${project.artifactId} - - net.jcip - jcip-annotations - 1.0 - jakarta.servlet @@ -156,37 +125,10 @@ 5.0.0 - - jakarta.xml.bind - jakarta.xml.bind-api - ${jaxb.api.version} - - - - org.eclipse.angus - angus-activation - ${eclipse.angus-activation.version} - runtime - - - - org.glassfish.jaxb - jaxb-runtime - ${jaxb.impl.version} - runtime - - - - com.sun.activation - jakarta.activation - - - - com.github.ben-manes.caffeine caffeine - 3.1.8 + 3.2.3 @@ -218,12 +160,6 @@ 1.0.1 - - com.google.code.findbugs - jsr305 - 3.0.2 - - se.softhouse jargo @@ -233,13 +169,13 @@ commons-codec commons-codec - 1.17.1 + 1.20.0 commons-io commons-io - 2.17.0 + 2.21.0 @@ -272,12 +208,6 @@ runtime - - org.slf4j - slf4j-api - 2.0.16 - - org.apache.ant ant @@ -288,12 +218,6 @@ com.evolvedbinary.thirdparty.org.apache.xmlrpc xmlrpc-common ${apache.xmlrpc.version} - - - xml-apis - xml-apis - - @@ -403,12 +327,6 @@ 2.0.0 - - org.apache.commons - commons-lang3 - 3.17.0 - - antlr antlr @@ -460,13 +378,7 @@ net.bytebuddy byte-buddy - 1.15.7 - - - - org.apache.commons - commons-collections4 - 4.4 + 1.18.2 @@ -475,40 +387,16 @@ ${exquery.distribution.version} - - org.exist-db.thirdparty.com.ettrema - milton-api - ${milton.version} - - - - org.exist-db.thirdparty.com.ettrema - milton-client - ${milton.version} - - - - org.exist-db.thirdparty.com.ettrema - milton-servlet - ${milton.servlet.version} - - it.unimi.dsi fastutil - 8.5.15 - - - - io.lacuna - bifurcan - 0.2.0-alpha7 + 8.5.18 - xml-apis + com.evolvedbinary.thirdparty.xml-apis xml-apis - 1.4.01 + 1.4.02 @@ -528,30 +416,7 @@ - - org.xmlunit - xmlunit-legacy - ${xmlunit.version} - - - org.junit.jupiter - junit-jupiter-api - ${junit.jupiter.version} - test - - - org.junit.jupiter - junit-jupiter-params - ${junit.jupiter.version} - test - - - org.junit.jupiter - junit-jupiter-engine - ${junit.jupiter.version} - test - org.junit.vintage junit-vintage-engine @@ -619,66 +484,17 @@ software.xdev find-and-replace-maven-plugin - 1.0.3 - - - org.apache.maven.plugins - maven-clean-plugin - 3.4.0 - - - com.mycila - license-maven-plugin - 4.6 - - - org.owasp - dependency-check-maven - 11.0.0 - - ${env.NVD_API_KEY} - - true - - false - false - false - false - false - false - false - false - false - false - false - false - false - false - false - - - true - - - - org.apache.maven.plugins - maven-resources-plugin - 3.3.1 - - - com.code54.mojo - buildversion-plugin - 1.0.3 + 1.0.4 - org.apache.maven.plugins - maven-dependency-plugin - 3.8.0 + org.omnifaces + antlr-maven-plugin + 2.4 org.codehaus.mojo xml-maven-plugin - 1.1.0 + 1.2.0 net.sf.saxon.TransformerFactoryImpl @@ -690,211 +506,10 @@ - - org.apache.maven.plugins - maven-compiler-plugin - 3.13.0 - - ${project.build.source} - ${project.build.target} - ${project.build.sourceEncoding} - - - - org.apache.maven.plugins - maven-jar-plugin - 3.4.2 - - - - true - true - - - ${build-tag} - ${build-commit} - ${build-commit-abbrev} - ${build-tstamp} - ${build-version} - ${maven.build.timestamp} - ${project.scm.connection} - ${project.description} - ${project.url} - - - - - - org.apache.maven.plugins - maven-source-plugin - 3.3.1 - - - - true - true - - - ${build-tag} - ${build-commit} - ${build-commit-abbrev} - ${build-tstamp} - ${build-version} - ${maven.build.timestamp} - ${project.scm.connection} - ${project.description} - ${project.url} - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.10.1 - - ${project.build.source} - - - true - true - - - ${build-tag} - ${build-commit} - ${build-commit-abbrev} - ${build-tstamp} - ${build-version} - ${maven.build.timestamp} - ${project.scm.connection} - ${project.description} - ${project.url} - - - - -Xmaxerrs - 65536 - -Xmaxwarns - 65536 - - - - - org.jacoco - jacoco-maven-plugin - 0.8.12 - - jacocoArgLine - - **/DeclScanner.* - **/DeclScannerTokenTypes.* - **/XQueryLexer.* - **/XQueryParser.* - **/XQueryTokenTypes.* - **/XQueryTreeParser.* - **/XQueryTreeParserTokenTypes.* - **/XQDocLexer.* - **/XQDocParser.* - **/XQDocParserTokenTypes.* - - - - - org.apache.maven.plugins - maven-jarsigner-plugin - 3.1.0 - - - org.apache.maven.plugins - maven-surefire-plugin - 3.5.1 - - - org.junit.platform - junit-platform-engine - ${junit.platform.version} - - - org.junit.jupiter - junit-jupiter-engine - ${junit.jupiter.version} - - - org.junit.vintage - junit-vintage-engine - ${junit.jupiter.version} - - - org.glassfish.jaxb - jaxb-runtime - ${jaxb.impl.version} - - - org.eclipse.angus - angus-activation - ${eclipse.angus-activation.version} - runtime - - - org.objenesis - objenesis - ${objenesis.version} - - - - 2C - - true - @{jacocoArgLine} --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.ref=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED -Dfile.encoding=${project.build.sourceEncoding} - - UK - en - Europe/Berlin - JRE,CLDR,SPI - ${project.build.testOutputDirectory}/log4j2.xml - false - - - - - org.apache.maven.plugins - maven-surefire-report-plugin - 3.5.1 - - - org.apache.maven.plugins - maven-failsafe-plugin - 3.5.1 - - - org.apache.maven.plugins - maven-project-info-reports-plugin - 3.7.0 - - false - - - - org.codehaus.mojo - versions-maven-plugin - 2.17.1 - - - org.apache.maven.plugins - maven-site-plugin - 3.21.0 - - - org.apache.maven.plugins - maven-install-plugin - 3.1.3 - org.apache.maven.plugins maven-assembly-plugin - 3.7.1 + 3.8.0 @@ -918,60 +533,18 @@ org.apache.maven.plugins maven-shade-plugin - 3.6.0 + 3.6.1 org.codehaus.mojo exec-maven-plugin - 3.5.0 - - - org.apache.maven.plugins - maven-deploy-plugin - 3.1.3 - - - org.apache.maven.plugins - maven-release-plugin - 3.1.1 - - true - eXist-@{project.version} - true - exist-release - - - - org.apache.maven.plugins - maven-scm-plugin - 2.1.0 - - true - - - - org.apache.maven.plugins - maven-gpg-plugin - 3.2.7 + 3.6.2 de.jutzig github-release-plugin 1.6.0 - - org.eluder.coveralls - coveralls-maven-plugin - 4.3.0 - - ${env.COVERALLS_TOKEN} - - - - org.sonarsource.scanner.maven - sonar-maven-plugin - 4.0.0.4121 - @@ -979,49 +552,67 @@ com.mycila license-maven-plugin - true + + + +
${project.parent.relativePath}/../elemental-parent/elemental-LGPL-21-ONLY-license.template.txt
+ + **.md + **.txt + **.xar + **LICENSE + pom.xml + xquery-license-style.xml + +
+ -
${project.parent.relativePath}/LGPL-21-license.template.txt
+ + +
${project.parent.relativePath}/../elemental-parent/elemental-LGPL-21-ONLY-license.template.txt
+ +
${project.parent.relativePath}/../exist-parent/existdb-LGPL-21-license.template.txt
+
+ + pom.xml + - FDB-backport-LGPL-21-ONLY-license.template.txt - FDB-backport-LGPL-21-ONLY-license.xml.template.txt - LGPL-21-license.template.txt - LGPL-21-license.txt - LGPL-21-license.template.txt - **/README.md - **/README - **/LICENSE - **/*.xar + **.md + **.txt + **.xar + **LICENSE + xquery-license-style.xml + +
+ + + +
${project.parent.relativePath}/../exist-parent/existdb-LGPL-21-license.template.txt
+ + **.md + **.txt + **.xar + **LICENSE + pom.xml + xquery-license-style.xml
- ${project.parent.relativePath}/xquery-license-style.xml + ${project.parent.relativePath}/../exist-parent/xquery-license-style.xml - -
XML_STYLE
- SLASHSTAR_STYLE - SLASHSTAR_STYLE - XML_STYLE - XML_STYLE - XML_STYLE - XQUERY_STYLE - XQUERY_STYLE - XQUERY_STYLE - XML_STYLE - XML_STYLE -
- true - true - - ${project.inceptionYear} - ${project.copyright.name} - ${contact.email} - ${project.organization.url} - - ${project.build.sourceEncoding}
@@ -1033,150 +624,22 @@
- - org.owasp - dependency-check-maven - - - - check - - - - - - org.apache.maven.plugins - maven-resources-plugin - - ${project.build.sourceEncoding} - ${project.build.sourceEncoding} - - - - org.apache.maven.plugins - maven-dependency-plugin - - - analyze - - analyze-only - - - true - - - - - - com.code54.mojo - buildversion-plugin - - - validate - - set-properties - - - - - - org.jacoco - jacoco-maven-plugin - - - default-prepare-agent - - prepare-agent - - - - **/DeclScanner.* - **/DeclScannerTokenTypes.* - **/XQueryLexer.* - **/XQueryParser.* - **/XQueryTokenTypes.* - **/XQueryTreeParser.* - **/XQueryTreeParserTokenTypes.* - **/XQDocLexer.* - **/XQDocParser.* - **/XQDocParserTokenTypes.* - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - org.apache.maven.plugins - maven-release-plugin - - - - - org.jacoco - jacoco-maven-plugin - - - **/DeclScanner.* - **/DeclScannerTokenTypes.* - **/XQueryLexer.* - **/XQueryParser.* - **/XQueryTokenTypes.* - **/XQueryTreeParser.* - **/XQueryTreeParserTokenTypes.* - **/XQDocLexer.* - **/XQDocParser.* - **/XQDocParserTokenTypes.* - - - - - - - report - - - - - - org.apache.maven.plugins - maven-surefire-report-plugin - - true - - - - - - - - org.codehaus.mojo - versions-maven-plugin - - - - dependency-updates-report - plugin-updates-report - property-updates-report - - - - - - - + + elemental-snapshots + Evolved Binary - Elemental Snapshots + https://repo.evolvedbinary.com/repository/elemental-snapshots/ + + false + + + true + + exist-db-snapshots Evolved Binary - eXist-db Snapshots @@ -1202,10 +665,6 @@ - - clojars.org - https://clojars.org/repo - exist-db Evolved Binary - eXist-db Releases @@ -1232,19 +691,13 @@ - exist-db-snapshots - Evolved Binary - eXist-db Snapshots - https://repo.evolvedbinary.com/repository/exist-db-snapshots/ + elemental-snapshots + Evolved Binary - Elemental Snapshots + https://repo.evolvedbinary.com/repository/elemental-snapshots/ - - sonatype-nexus-staging - Nexus Release Repository - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - exist-release @@ -1276,4 +729,4 @@ - + \ No newline at end of file diff --git a/exist-parent/xquery-license-style.xml b/exist-parent/xquery-license-style.xml index 78160834b8..1464346379 100644 --- a/exist-parent/xquery-license-style.xml +++ b/exist-parent/xquery-license-style.xml @@ -1,16 +1,15 @@ +
${project.parent.relativePath}/../elemental-parent/elemental-LGPL-21-ONLY-license.template.txt
+ pom.xml + src/** + + + + + + +
${project.parent.relativePath}/../elemental-parent/elemental-LGPL-21-ONLY-license.template.txt
+ +
${project.parent.relativePath}/../exist-parent/existdb-LGPL-21-license.template.txt
+
+ + pom.xml + src/main/java/org/exist/samples/Samples.java + src/main/resources/org/exist/samples/ant/migrate.xml + src/main/resources/org/exist/samples/xinclude/db2html.xsl + src/main/resources/org/exist/samples/xinclude/xinclude.xml + +
+ + + +
${project.parent.relativePath}/../exist-parent/existdb-LGPL-21-license.template.txt
+ + pom.xml src/main/resources/org/exist/samples/biblio.rdf + src/main/java/org/exist/samples/Samples.java + src/main/resources/org/exist/samples/ant/migrate.xml + src/main/resources/org/exist/samples/mods/** src/main/resources/org/exist/samples/shakespeare/hamlet.xml src/main/resources/org/exist/samples/shakespeare/macbeth.xml src/main/resources/org/exist/samples/shakespeare/play.dtd @@ -71,9 +135,11 @@ src/main/resources/org/exist/samples/shakespeare/shakes.xsl src/main/resources/org/exist/samples/validation/dtd/** src/main/resources/org/exist/samples/validation/personal/** + src/main/resources/org/exist/samples/validation/tournament/** + src/main/resources/org/exist/samples/xinclude/db2html.xsl + src/main/resources/org/exist/samples/xinclude/xinclude.xml src/main/resources/org/exist/samples/xinclude/scripts/syntax/** src/main/resources/org/exist/samples/xinclude/styles/** - src/main/resources/org/exist/samples/validation/tournament/**
@@ -82,4 +148,4 @@ - + \ No newline at end of file diff --git a/exist-samples/src/main/java/org/exist/samples/Samples.java b/exist-samples/src/main/java/org/exist/samples/Samples.java index 98a9cfe4f5..f5146f45c8 100644 --- a/exist-samples/src/main/java/org/exist/samples/Samples.java +++ b/exist-samples/src/main/java/org/exist/samples/Samples.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -32,45 +56,45 @@ public class Samples { private Samples() {} /** - * Gets the path of the Address Book sample. + * Gets the Address Book sample. * - * @return The path to the Address Book sample + * @return The stream of the Address Book sample */ public @Nullable InputStream getAddressBookSample() { return getSample("validation/addressbook/addressbook.xsd"); } /** - * Gets the path of the Shakespeare Hamlet sample. + * Gets the Shakespeare Hamlet sample. * - * @return The path to the Shakespeare Hamlet sample + * @return The stream of the Shakespeare Hamlet sample */ public @Nullable InputStream getHamletSample() { return getShakespeareSample("hamlet.xml"); } /** - * Gets the path of the Shakespeare Romeo and Juliet sample. + * Gets the Shakespeare Romeo and Juliet sample. * - * @return The path to the Shakespeare Romeo and Juliet sample + * @return The stream of the Shakespeare Romeo and Juliet sample */ public @Nullable InputStream getRomeoAndJulietSample() { return getShakespeareSample("r_and_j.xml"); } /** - * Gets the path of the Macbeth sample. + * Gets the Shakespeare Macbeth sample. * - * @return The path to the Macbeth sample + * @return The stream of the Macbeth sample */ - public@Nullable InputStream getMacbethSample() { + public@Nullable InputStream getMacbethSample() { return getShakespeareSample("macbeth.xml"); } /** - * Get the names of just the Shakespeare XML data sample files. + * Get the names of just the Shakespeare XML sample files. * - * @return the names of the Shakespeare XML data files. + * @return the names of the Shakespeare XML files. */ public String[] getShakespeareXmlSampleNames() { return new String[] { "hamlet.xml", "macbeth.xml", "r_and_j.xml"}; @@ -86,11 +110,11 @@ public String[] getShakespeareSampleNames() { } /** - * Gets the path of the shakespeare sample. + * Gets the shakespeare sample. * * @param sampleFileName the name of the shakespeare sample. * - * @return The path to the shakespeare sample + * @return The stream of the Shakespeare sample */ public @Nullable InputStream getShakespeareSample(final String sampleFileName) { return getSample("shakespeare/" + sampleFileName); @@ -99,18 +123,59 @@ public String[] getShakespeareSampleNames() { /** * Gets the path of the Bibliographic sample. * - * @return The path to the Bibliographic sample + * @return The stream of the Bibliographic sample */ public @Nullable InputStream getBiblioSample() { return getSample("biblio.rdf"); } + /** + * Get the names of just the MODS XML data sample files. + * + * @return the names of the MODS XML data files. + */ + public String[] getModsXmlSampleNames() { + return new String[] { + "02db3b51-146d-4740-81c5-c22dcdadecfb.xml", + "0d569a0b-2738-4865-8b47-a9f8b821a653.xml", + "1a186ea9-d41a-4e03-8f0a-d3389cbcf769.xml", + "1a745d88-0d42-42e7-b911-26f1976bf41f.xml", + "321a0f72-8ecc-419c-992f-05b4000124e0.xml", + "36fe6751-7d83-4155-81f8-c00e515f07d1.xml", + "494ebe80-aa3c-457c-8c20-7de246bf5f72.xml", + "49afb9d1-71d8-49c2-8566-13eff9ff0935.xml", + "58f1eb27-0cec-4e2e-83f5-57d03123c194.xml", + "6bbce50c-8e1c-46cb-b804-9cd020816f63.xml", + "6fd69e78-77ca-4b2a-84c1-b22a24d676b3.xml", + "78f221c8-5bb0-4bf1-ad43-cf0aff6d53c7.xml", + "81fb0a7e-f268-4091-aae2-1e6ccb867930.xml", + "9f8877f7-2064-4ee5-92f5-a1b6afe68714.xml", + "b5c28abd-8a78-4a2d-b2eb-30d06d7dac10.xml", + "ba45cdc0-96d4-4181-a519-ed3f1f9f89cc.xml", + "ba5f637f-2ca5-4d07-b8b3-804dab7fbdb7.xml", + "be884622-f29f-42ba-8903-e5eda73bcf34.xml", + "dae9118e-573a-4230-b781-5007c0579f27.xml", + "f3ad5614-d1b4-4860-a108-542c42dceebf.xml" + }; + } + + /** + * Gets the MODS sample. + * + * @param sampleFileName the name of the MODS sample. + * + * @return The stream of the MODS sample + */ + public @Nullable InputStream getModsSample(final String sampleFileName) { + return getSample("mods/" + sampleFileName); + } + /** * Gets the sample. * * @param sample relative path to the sample * - * @return The stream to the sample + * @return The stream of the sample */ public @Nullable InputStream getSample(final String sample) { return getClass().getResourceAsStream(sample); diff --git a/exist-samples/src/main/resources/org/exist/samples/ant/migrate.xml b/exist-samples/src/main/resources/org/exist/samples/ant/migrate.xml index fc5a16ea88..d5c390008c 100644 --- a/exist-samples/src/main/resources/org/exist/samples/ant/migrate.xml +++ b/exist-samples/src/main/resources/org/exist/samples/ant/migrate.xml @@ -1,6 +1,30 @@ + diff --git a/exist-samples/src/main/resources/org/exist/samples/mods/02db3b51-146d-4740-81c5-c22dcdadecfb.xml b/exist-samples/src/main/resources/org/exist/samples/mods/02db3b51-146d-4740-81c5-c22dcdadecfb.xml new file mode 100644 index 0000000000..60d7a48080 --- /dev/null +++ b/exist-samples/src/main/resources/org/exist/samples/mods/02db3b51-146d-4740-81c5-c22dcdadecfb.xml @@ -0,0 +1,49 @@ + + + + Motivational and Structural Prerequisites of Knowledge Management + Paper presented at the XV World Congress of + Sociology, Brisbane, Australia, July 7-13, 2002, RC 30 + Sociology of Work: Thematic Seminar II: The organisation of + knowledge production (Diskussionspapiere aus der Fakultät + für Sozialwissenschaft, Ruhr-Universität Bochum, Nr. 02-2) + + Our main question in this paper is: Which + motivational and structural prerequisites support knowledge + management? We will develop a theoretical model to answer + these questions and illustrate it with three case studies. + + Wilkesmann, Uwe + + + Rascher, Ingolf + + + http://www.ruhr-uni-bochum.de/sowi/top/sowibibliothek/dkpaper/dp02-2.pdf + + + Fakultät für Sozialwissenschaft, Ruhr-Universität Bochum + 2002-06-12 + + + application/pdf + + + knowledge management + + 10204 + 10207 + 10219 + + Bedingung + + + Informationsmanagement + + + Informationssystem + + + Wissenssoziologie + + \ No newline at end of file diff --git a/exist-samples/src/main/resources/org/exist/samples/mods/0d569a0b-2738-4865-8b47-a9f8b821a653.xml b/exist-samples/src/main/resources/org/exist/samples/mods/0d569a0b-2738-4865-8b47-a9f8b821a653.xml new file mode 100644 index 0000000000..15334bbc5d --- /dev/null +++ b/exist-samples/src/main/resources/org/exist/samples/mods/0d569a0b-2738-4865-8b47-a9f8b821a653.xml @@ -0,0 +1,39 @@ + + + + The Interplay of Cash and Tax Benefits for Children in Ten European Countries + + Whereas cross-sectional comparative research on monetary support for families with children linking quantitative data on cash and tax benefits with institutional regulations and system characteristics seems to be well established, systematic analyses of the long-term lines of development, however, are still lacking. This article therefore aims at analysing the child-related elements of both instruments over a longer span of time. Partly based on a newly accessible database, the presentation uses a descriptive and institution-orientated approach. + + Maucher, Mathias + + + http://www.mzes.uni-mannheim.de/eurodata/newsletter/no12-13/feature.html + + + EURODATA Research Archive. Mannheim Centre for European Social Research (MZES) + 2000 + + + text/html + + + + EURODATA Newsletter No.12/13 + + + 11007 + 1090303 + + Familienpolitik + + + Steuern + + + Steuerpolitik + + + Umverteilung + + \ No newline at end of file diff --git a/exist-samples/src/main/resources/org/exist/samples/mods/1a186ea9-d41a-4e03-8f0a-d3389cbcf769.xml b/exist-samples/src/main/resources/org/exist/samples/mods/1a186ea9-d41a-4e03-8f0a-d3389cbcf769.xml new file mode 100644 index 0000000000..2ee467dd53 --- /dev/null +++ b/exist-samples/src/main/resources/org/exist/samples/mods/1a186ea9-d41a-4e03-8f0a-d3389cbcf769.xml @@ -0,0 +1,63 @@ + + + + Causal Inference from Series of Events + + Recent years have witnessed an increased interest, + both in statistics and in the social sciences, in time + dependent models as a vehicle for the causal interpretation + of series of events. The Humean and empiricist tradition in + the philosophy of science uses the constant temporal order + of cause and effect as a decisive delineation of causal + processes from mere coincidences. To mimic the philosophical + distinction, series of events are modelled as dynamic + stochastic processes and the precedence of cause over effect + is expressed through conditional expectations given the + history of the process and the history of the causes. A main + technical tool in this development is the concept of + conditional independence. In this article we examine some + difficulties in the application of the approach within + empirical social research. Specifically, the role of + probabilistic concepts of causality and of conditional + independence, the nature of events that reasonalby qualify + as causes or effects, and the time order used in empirical + research are considered. + + Pötter, Ulrich + + + Blossfeld, H.-P. + + + http://www.stat.ruhr-uni-bochum.de/papers/cause2.ps + + + 2000-06-01 + + + application/postscript + + 10105 + 10102 + + Analyse + + + Erklärung + + + Inferenz + + + Kausalität + + + Methodenforschung + + + Modellanalyse + + + Wissenschaftsgeschichte + + \ No newline at end of file diff --git a/exist-samples/src/main/resources/org/exist/samples/mods/1a745d88-0d42-42e7-b911-26f1976bf41f.xml b/exist-samples/src/main/resources/org/exist/samples/mods/1a745d88-0d42-42e7-b911-26f1976bf41f.xml new file mode 100644 index 0000000000..431c62d945 --- /dev/null +++ b/exist-samples/src/main/resources/org/exist/samples/mods/1a745d88-0d42-42e7-b911-26f1976bf41f.xml @@ -0,0 +1,42 @@ + + + + The European population 1850-1945: A Historical Data Handbook + + This contribution describes the project which is to publish a historical data handbook on the European population in 21 European countries, covering the time period of the first demographic transition, the years 1850-1945. All eighteen Western European nations are included plus the three Eastern European countries Czechoslovakia, Hungary and Poland. The handbook covers such topics as population development; the population structure by sex, age and marital status; the regional population structure; annual vital statistics developments in the fields of population growth and migration, fertility and legitimacy, infant mortality and life expectancy, nuptiality and divortiality. Furthermore, household and family data have been collected systematically using the population censuses as a basis. The book comprises several introductory comparative chapters and 21 national chapters for each country. Extensive documentation of available data and sources concludes the volume. + + Rothenbacher, Franz + + + http://www.mzes.uni-mannheim.de/eurodata/newsletter/no11/feature.html + + + EURODATA Research Archive. Mannheim Centre for European Social Research (MZES) + 2000 + + + text/html + + + + EURODATA Newsletter No.11 + + + 10303 + 10209 + + Bevölkerungsentwicklung + + + Demographie + + + Rezension + + + historisch + + + internationaler Vergleich + + \ No newline at end of file diff --git a/exist-samples/src/main/resources/org/exist/samples/mods/321a0f72-8ecc-419c-992f-05b4000124e0.xml b/exist-samples/src/main/resources/org/exist/samples/mods/321a0f72-8ecc-419c-992f-05b4000124e0.xml new file mode 100644 index 0000000000..7876ea415f --- /dev/null +++ b/exist-samples/src/main/resources/org/exist/samples/mods/321a0f72-8ecc-419c-992f-05b4000124e0.xml @@ -0,0 +1,60 @@ + + + + Demography of Germany + Concepts, Data and Methods + + This text is an introduction to concepts and methods of demographic description and analysis. The substantial focus is on the demographic development ofgermany, all data refer to this country. The main reason for this focus on a single country is that we want to show how the tools of demography can actually be used for theanalysis of demographic problems. The text consists of two parts. Part I introduces the conceptual framework and explains basic statistical notions. This part also includesa short chapter that explains how we speak of "models" and why we do not make a sharp distinction between "describing" and "modeling" demographic processes. Then followsPart II that deals with data and methods. In the present version of the text, we almost exclusively discuss mortality and fertility data. + + Rohwer, Götz + + + Pötter, Ulrich + + + ftp://ftp.stat.ruhr-uni-bochum.de/pub/eha/ddem.ps + + + 2002-10-01 + 2003-03-01 + + + application/postscript + + 10301 + 10303 + 10105 + + Altersstruktur + + + Bevölkerungsstatistik + + + Kohortenanalyse + + + Lebensdauer + + + Lebenserwartung + + + Methodenlehre + + + Panel + + + Volkszählung + + + amtliche Statistik + + + deskriptive Statistik + + + statistische Analyse + + \ No newline at end of file diff --git a/exist-samples/src/main/resources/org/exist/samples/mods/36fe6751-7d83-4155-81f8-c00e515f07d1.xml b/exist-samples/src/main/resources/org/exist/samples/mods/36fe6751-7d83-4155-81f8-c00e515f07d1.xml new file mode 100644 index 0000000000..8cac8468eb --- /dev/null +++ b/exist-samples/src/main/resources/org/exist/samples/mods/36fe6751-7d83-4155-81f8-c00e515f07d1.xml @@ -0,0 +1,47 @@ + + + + CATEWE - A Comparative Analysis of Transitions from Education to Work in Europe + + The transition from education to work is one of the most crucial phases in the life-cycle of individuals because it often channels and shapes individual careers and life chances. These transitions differ between European countries due to different educational systems, labour markets, and organization of societal work. + + Gangl, Markus + + + Hannan, Damian + + + Raffe, David + + + Smyth, Emer + + + http://www.mzes.uni-mannheim.de/eurodata/newsletter/no8/catewe.html + + + EURODATA Research Archive. Mannheim Centre for European Social Research (MZES) + 1998 + + + text/html + + + + EURODATA Newsletter No.8 + + + 10208 + + Bildungswesen + + + berufliche Integration + + + dreigliedriges Schulwesen + + + internationaler Vergleich + + \ No newline at end of file diff --git a/exist-samples/src/main/resources/org/exist/samples/mods/494ebe80-aa3c-457c-8c20-7de246bf5f72.xml b/exist-samples/src/main/resources/org/exist/samples/mods/494ebe80-aa3c-457c-8c20-7de246bf5f72.xml new file mode 100644 index 0000000000..c017e9bdcc --- /dev/null +++ b/exist-samples/src/main/resources/org/exist/samples/mods/494ebe80-aa3c-457c-8c20-7de246bf5f72.xml @@ -0,0 +1,79 @@ + + + + Who is Self-Employed in France, the United Kingdom and + West Germany? + Patterns of Non-Agricultural Self-Employment + + This paper investigates the patterns of male + non-agricultural self-employment and how they have changed + over time in France, Germany and the UK. It is arguedthatthe + development of self-employment in the three + countries is based on specific institutional frameworks + resulting in different opportunities for the + self-employed.Thus, weexpect that the dynamics of growth, + the sectors of activity and the + socio-demographic characteristics of the + self-employed differ between the countries. + Theempiricalanalyses are based on the national Labour Force + Surveys of 1984 and 1994 (Germany 1982 and 1995). Our + findings indicate that educational requirements + differfundamentally betweenthe three countries and along + industrial branches. Further, we could observe some + country-specific developments in some sectors of activitybut + also a remarkable number of commongeneral patterns in + the development of self-employment. + + Lohmann, Henning + + + Luber, Silvia + + + Müller, Walter + + + http://www.mzes.uni-mannheim.de/publications/wp/wp-11.pdf + + + Mannheimer Zentrum für Europäische Sozialforschung (MZES) + 1999 + 2003-06-13 + + + application/pdf + + + + Arbeitspapiere / Mannheimer Zentrum für + Europäische Sozialforschung, Nr. 11, ISSN 1437-8574 + + + 20101 + 20102 + 10205 + + Arbeitsmarkt + + + Bundesrepublik Deutschland + + + Frankreich + + + Großbritannien + + + Selbständiger + + + berufliche Selbständigkeit + + + freier Beruf + + + institutionelle Faktoren + + \ No newline at end of file diff --git a/exist-samples/src/main/resources/org/exist/samples/mods/49afb9d1-71d8-49c2-8566-13eff9ff0935.xml b/exist-samples/src/main/resources/org/exist/samples/mods/49afb9d1-71d8-49c2-8566-13eff9ff0935.xml new file mode 100644 index 0000000000..f6e1c290b2 --- /dev/null +++ b/exist-samples/src/main/resources/org/exist/samples/mods/49afb9d1-71d8-49c2-8566-13eff9ff0935.xml @@ -0,0 +1,38 @@ + + + + Comparative Electoral Systems: The German Experience + Constitution of Kenya Review Commission: Seminar on Electoral Systems and Political Parties. March 19-20, 2002, Serena Hotel Nairobi + + The mixed-member proportional system (MMPS), first introduced in the Federal Republic of Germany in 1949, is currently receiving increasing attention in countries in which electoral reforms are being considered. Are electoral experts and politicians, especially in Southern countries, right to consider the MMPS a model for electoral reform? And if so, which lessons can be drawn from the German experience for transferring the MMPS to other countries? In this paper, these questions are being addressed at both a theoretical and at an emprical level. At first, the MMPS will be situated within a broader typology of electoral systems. How the MMPS has worked in the context of German politics is discussed in a second section; the conclusion contains some recommendations for reform debates, especially the Kenyan context. + + Hartmann, Christof + + + http://homepage.ruhr-uni-bochum.de/christof.hartmann/downloads/2002-Kenia-Wahlen.PDF + + + 2002-03-19 + + + application/pdf + + 10503 + 10505 + 10504 + + Bundesrepublik Deutschland + + + Kenia + + + Systemvergleich + + + Wahlsystem + + + politische Reform + + \ No newline at end of file diff --git a/exist-samples/src/main/resources/org/exist/samples/mods/58f1eb27-0cec-4e2e-83f5-57d03123c194.xml b/exist-samples/src/main/resources/org/exist/samples/mods/58f1eb27-0cec-4e2e-83f5-57d03123c194.xml new file mode 100644 index 0000000000..124d6f1c60 --- /dev/null +++ b/exist-samples/src/main/resources/org/exist/samples/mods/58f1eb27-0cec-4e2e-83f5-57d03123c194.xml @@ -0,0 +1,39 @@ + + + + The Development of Trade Unions in Western Europe: Global Convergence or Cross-national Diversity? + + Trade unions play an important role in Western Europe. They have been subject to, and agents of, social and political changes that reshaped the post-war industrial society. In recent years, trade unions have been facing the threat of membership decline and the challenges of global competition and European economic integration. This poses the question whether union movements are under pressure to adapt in a similar way or whether they differ in their responses. Do we find a trend towards global convergence or does cross-national diversity persist among union movements in Western Europe? Drawing on comparative data from an international research project, we will provide a short portrait of the main patterns in union density and organisational concentration. Instead of a general trend toward convergence, we find signs of persisting diversity across Western Europe in union responses to both social changes and global challenges. + + Ebbinghaus,Bernhard + + + http://www.mzes.uni-mannheim.de/eurodata/newsletter/no2/feature.html + + + EURODATA Research Archive. Mannheim Centre for European Social Research (MZES) + 1995 + + + text/html + + + + EURODATA Newsletter No.2 + + + 10204 + 10504 + + Europa + + + Gewerkschaft + + + Gewerkschaftsbewegung + + + historische Entwicklung + + \ No newline at end of file diff --git a/exist-samples/src/main/resources/org/exist/samples/mods/6bbce50c-8e1c-46cb-b804-9cd020816f63.xml b/exist-samples/src/main/resources/org/exist/samples/mods/6bbce50c-8e1c-46cb-b804-9cd020816f63.xml new file mode 100644 index 0000000000..99386243e1 --- /dev/null +++ b/exist-samples/src/main/resources/org/exist/samples/mods/6bbce50c-8e1c-46cb-b804-9cd020816f63.xml @@ -0,0 +1,47 @@ + + + + Managing Conflict Through Democratic Institutions: A Tentative Balance Sheet + African Studies Association in Germany (VAD): Biennial Conference "Africa's Diversity: Ending the Monologues?", Hamburg, May 23-26, 2002 + + The paper starts from the premise that the specific role of democratic institutions in conflict management is still not adequately considered in the African context, especially with regard to crisis prevention. Some of the main hypothesis drawn from the general literature on the topic are presented and three levers of democratic intervention, i.e. the system of government, the electoral system, and the territorial structure of the state, are tested with regard to Africa (including discussion of case studies). As a last step the paper deals with the specific African contexts of democratic reform that have to be taken into account in processes of institutional engineering. + + Hartmann, Christof + + + http://homepage.ruhr-uni-bochum.de/christof.hartmann/downloads/2002-VAD-Paper.pdf + + + 2002-05-23 + + + application/pdf + + 10507 + 10503 + 10505 + + Afrika + + + Demokratisierung + + + Staatsform + + + Staatsgebiet + + + Systemvergleich + + + Transformation + + + Wahlsystem + + + ethnischer Konflikt + + \ No newline at end of file diff --git a/exist-samples/src/main/resources/org/exist/samples/mods/6fd69e78-77ca-4b2a-84c1-b22a24d676b3.xml b/exist-samples/src/main/resources/org/exist/samples/mods/6fd69e78-77ca-4b2a-84c1-b22a24d676b3.xml new file mode 100644 index 0000000000..3183b012c2 --- /dev/null +++ b/exist-samples/src/main/resources/org/exist/samples/mods/6fd69e78-77ca-4b2a-84c1-b22a24d676b3.xml @@ -0,0 +1,41 @@ + + + + The Project on Comparative European Electoral History: 1830-1995. A computerised data handbook + + This project is aimed at collecting electoral data for all European countries both in a historical and a regional perspective. Data were made machine readable from the beginning of national elections in the 19th century until the present in a disaggregated form down to the level of electoral districts. The data will we published as an electronic data handbook, comprising full documentation and introductory chapters. + + Caramani, Daniele + + + http://www.mzes.uni-mannheim.de/eurodata/newsletter/no4/feature.html + + + EURODATA Research Archive. Mannheim Centre for European Social Research (MZES) + 1996 + + + text/html + + + + EURODATA Newsletter No.4 + + + 10504 + + Datenaufbereitung + + + Datenbank + + + Europa + + + Wahlergebnis + + + politische Geschichte + + \ No newline at end of file diff --git a/exist-samples/src/main/resources/org/exist/samples/mods/78f221c8-5bb0-4bf1-ad43-cf0aff6d53c7.xml b/exist-samples/src/main/resources/org/exist/samples/mods/78f221c8-5bb0-4bf1-ad43-cf0aff6d53c7.xml new file mode 100644 index 0000000000..0d5f773abf --- /dev/null +++ b/exist-samples/src/main/resources/org/exist/samples/mods/78f221c8-5bb0-4bf1-ad43-cf0aff6d53c7.xml @@ -0,0 +1,42 @@ + + + + Social Indicators for East European Transition Countries + + The East European transition countries have been facing severe problems regarding both economic performance and living conditions in general since the beginning of the transformation process in 1989. This is the reason why this topic has been chosen. It is intended to present some fundamental social indicators for the East European transition countries. The data presented refer to the whole of Eastern and South Eastern Europe, including the Western follow-up states of the former Soviet Union, i.e. the Baltic countries, Russia, Moldavia, Ukraine and Belarus. + + Rothenbacher, Franz + + + http://www.mzes.uni-mannheim.de/eurodata/newsletter/no4/rothenb1.html + + + EURODATA Research Archive. Mannheim Centre for European Social Research (MZES) + 1996 + + + text/html + + + + EURODATA Newsletter No.4 + + + 10303 + 10305 + + Altersstruktur + + + Arbeitsmarktanalyse + + + Geburtenentwicklung + + + Osteuropaforschung + + + soziale Indikatoren + + \ No newline at end of file diff --git a/exist-samples/src/main/resources/org/exist/samples/mods/81fb0a7e-f268-4091-aae2-1e6ccb867930.xml b/exist-samples/src/main/resources/org/exist/samples/mods/81fb0a7e-f268-4091-aae2-1e6ccb867930.xml new file mode 100644 index 0000000000..85424eb8a9 --- /dev/null +++ b/exist-samples/src/main/resources/org/exist/samples/mods/81fb0a7e-f268-4091-aae2-1e6ccb867930.xml @@ -0,0 +1,60 @@ + + + + Renaissance of the German Carmakers during the 1990s: + Successful Japanization or the Development of a Genuine + Business Model? + + This chapter aims at explaining the renaissance of + the three German carmakers within the context of the + international automobile industry. The main argument is that + this revival can only be understood by referring to some + common elements of the business models in place at all three + companies. These business models include four basic pillars, + each of which answers a basic question at the core of the + firms activities: (1) the corporate structure and profit + strategies, (2) product structure and market strategies, (3) + the production system and (4) the labour relations regime. + A business model could thus be understood as the specific + configuration of structures and strategies in these four + activity fields and transformation spaces. This + configuration does not represent a deterministic and fixed + system but a sort of loosely coupled 'regime of affinity'. + + Pries, Ludger + + + http://www.ruhr-uni-bochum.de/soaps/download/publ-2003_lp_renaissancegercarmakers.pdf + + + 2003 + + + application/pdf + + + + Faust, Michael; Voskamp, Ulrich; Wittke, Volker + (eds.): European Industrial Restructuring in a Global + Economy: Fragmentation and Relocation of Value Chains. SOFI + Berichte, Göttingen: SOFI + + + + Geschäftsmodell + + + Volkswagen + + 10204 + 10207 + + Kraftfahrzeugindustrie + + + Unternehmenspolitik + + + internationaler Vergleich + + \ No newline at end of file diff --git a/exist-samples/src/main/resources/org/exist/samples/mods/9f8877f7-2064-4ee5-92f5-a1b6afe68714.xml b/exist-samples/src/main/resources/org/exist/samples/mods/9f8877f7-2064-4ee5-92f5-a1b6afe68714.xml new file mode 100644 index 0000000000..9fbdfe6028 --- /dev/null +++ b/exist-samples/src/main/resources/org/exist/samples/mods/9f8877f7-2064-4ee5-92f5-a1b6afe68714.xml @@ -0,0 +1,41 @@ + + + + The strengths and weaknesses of existing electoral models as instruments for managing ethnic conflict + Paper for the Centre of Conflict Resolution Seminar "Constitutionalism as a Primary Tool for Managing Ethnic Conflict in Africa", Cape Town, 24-26 May 2000 + + The paper argues that the choice of electoral systems has an impact on the change or the stability of inter-ethnic relations, and that electoral models may actually become an instrument for managing ethnic conflict. Cleverly designed electoral systems are, however, not considered being the only or most powerful of such instruments. For example, the decision for a more centralized or a more federal state or the introduction of some meaningful local government may be of more relevance to ethnic conflict management. The paper is divided in five main parts: Key terms and elements of electoral systems are introduced, followed by a typology of the most important parliamentary electoral systems. This general overview will cover a range of states with most empirical examples drawn from African contexts. The third part will briefly discuss the multiple criteria that might be used to evaluate electoral systems, followed by an assessment of the various electoral systems and their relationsship to conflict management. The last section deals with the generally neglected topic of different presidential electoral formulas and its impact on ethnic relationships. + + Hartmann, Christof + + + http://homepage.ruhr-uni-bochum.de/christof.hartmann/downloads/2000-Kapstadt.PDF + + + 2000-05-24 + + + application/pdf + + 10507 + 10503 + 10504 + + Afrika südlich der Sahara + + + Konfliktlösung + + + Systemvergleich + + + Wahlsystem + + + ethnischer Konflikt + + + politisches System + + \ No newline at end of file diff --git a/exist-samples/src/main/resources/org/exist/samples/mods/b5c28abd-8a78-4a2d-b2eb-30d06d7dac10.xml b/exist-samples/src/main/resources/org/exist/samples/mods/b5c28abd-8a78-4a2d-b2eb-30d06d7dac10.xml new file mode 100644 index 0000000000..56d1dd0e37 --- /dev/null +++ b/exist-samples/src/main/resources/org/exist/samples/mods/b5c28abd-8a78-4a2d-b2eb-30d06d7dac10.xml @@ -0,0 +1,42 @@ + + + + Household and Family Trends in Europe: from Convergence to Divergence + + The International Year of the Family 1994 together with the World Population Conference have drawn greater attention to the changing family. On the level of the European Union interest in the family was intensified, as the first steps taken towards the creation of a European household and family statistics and the strengthening of the European Observatory on National Family Policies (EONFP) show. In addition, other international organisations, such as the Council of Europe or the United Nations Economic Commission for Europe (ECE), have intensified their activities in the field of population and family research. In this context the question may be posed how household and family structures in Europe evolve. Not only for the European Union but also for sociological research in general the question of divergence or convergence of national household and family structures and of national demographic developments is of great importance. + + Rothenbacher, Franz + + + http://www.mzes.uni-mannheim.de/eurodata/newsletter/no1/househol.html + + + EURODATA Research Archive. Mannheim Centre for European Social Research (MZES) + 1995 + + + text/html + + + + EURODATA Newsletter No.1 + + + 10303 + 10209 + + Europa + + + Familiensoziologie + + + Familienstand + + + Familienstruktur + + + internationaler Vergleich + + \ No newline at end of file diff --git a/exist-samples/src/main/resources/org/exist/samples/mods/ba45cdc0-96d4-4181-a519-ed3f1f9f89cc.xml b/exist-samples/src/main/resources/org/exist/samples/mods/ba45cdc0-96d4-4181-a519-ed3f1f9f89cc.xml new file mode 100644 index 0000000000..d21c9e9737 --- /dev/null +++ b/exist-samples/src/main/resources/org/exist/samples/mods/ba45cdc0-96d4-4181-a519-ed3f1f9f89cc.xml @@ -0,0 +1,58 @@ + + + + Household Labor Demand and Household Labor Supply + An empirical analysis of the employment of + domestic help in German private households and its effect on + female labor force participation (Diskussionspapiere aus der + Fakultät für Sozialwissenschaft, Ruhr-Universität Bochum, + Nr. 98-14) + + In this paper, data from the German Socio-Economic + Panel (SOEP) will be used to examine the hypothesis that the + demand for domestic servants and women’s supply of market + work are joint decisions. + + Hank, Karsten + + + http://www.ruhr-uni-bochum.de/sowi/top/sowibibliothek/dkpaper/dp98-14.rtf + + + Fakultät für Sozialwissenschaft, Ruhr-Universität Bochum + 1998 + + + other + + + domestic work + + 20101 + 20102 + 20200 + + Arbeitsangebot + + + Arbeitskräftebedarf + + + Frauenerwerbstätigkeit + + + Hausarbeit + + + Panel + + + Privathaushalt + + + informeller Sektor + + + ungeschützte Beschäftigung + + \ No newline at end of file diff --git a/exist-samples/src/main/resources/org/exist/samples/mods/ba5f637f-2ca5-4d07-b8b3-804dab7fbdb7.xml b/exist-samples/src/main/resources/org/exist/samples/mods/ba5f637f-2ca5-4d07-b8b3-804dab7fbdb7.xml new file mode 100644 index 0000000000..949e6ac10a --- /dev/null +++ b/exist-samples/src/main/resources/org/exist/samples/mods/ba5f637f-2ca5-4d07-b8b3-804dab7fbdb7.xml @@ -0,0 +1,40 @@ + + + + A Woman is Born. Production of Femininity in German o.b. Tampon Advertisements + Paper presented at 'Menstruation. Blood, Body, Brand.' Institute for Feminist Theory and Research, Liverpool, 24 January to 26. January 2003. + + Western feminists have criticised advertisements for female hygiene products for creating stereotypes and being normative and sexist since the 1970s. Despite this criticism recent studies have shown that (at least in Germany) the topics raised are relevant to women, and female hygiene products are increasingly retailed internationally. The range of feminist analysis and opinions has also become quite broad. Based on empirical research I want to look at ads for o.b. tampons, relating the tension between the regulation of the female (body) and advertising a taboo. I reviewed a sample of 47 ads from o.b. dating from the 1950s onwards that were placed in the popular German (middle-class) women's magazine Brigitte. Each ad was analysed according to recurring themes in text, context and tone, and for content related to the representation of femininity. The body as battleground for gender is an interactive process. On the one hand the body is an important medium and a central resource for performing gender; on the other hand this performance takes place in semiotic and discursive contexts, which configure the intelligibility of the gender difference. I want to consider both aspects by taking the body-here the female body or rather femininity-seriously in the discursive moment of advertisements. I focus mainly on the following three aspects: a. Pictures of women and girls, b. Visibility of menstruation, c. Construction of femininity between regulation and agency Both a historical review and a content analysis should show a.) continuity in content (e.g. security, hygiene, invisibility) and motives (e.g. tampons vs. pads, sport, light colours, young white heterosexual middle-class women as main characters) and b.) contradictions (e.g. women at work vs. women at home, naming blood and smell vs. menstrual taboo). Finally I will give an outlook on the question: Is the way o.b. (re)presents femininity o.k.? And how can we deal with it from an academic and political point of view? + + Ullrich, Charlotte + + + http://homepage.ruhr-uni-bochum.de/Charlotte.Ullrich/vortrag_ob_pdf.pdf + + + 2003-01-24 + + + application/pdf + + 20200 + 1080409 + + Frauenbild + + + Geschlechterforschung + + + Hygiene + + + Inhaltsanalyse + + + Menstruation + + + Werbung + + diff --git a/exist-samples/src/main/resources/org/exist/samples/mods/be884622-f29f-42ba-8903-e5eda73bcf34.xml b/exist-samples/src/main/resources/org/exist/samples/mods/be884622-f29f-42ba-8903-e5eda73bcf34.xml new file mode 100644 index 0000000000..14d7463978 --- /dev/null +++ b/exist-samples/src/main/resources/org/exist/samples/mods/be884622-f29f-42ba-8903-e5eda73bcf34.xml @@ -0,0 +1,70 @@ + + + + Self-governance and slowness as prerequisites for + knowledge management + Paper for the 19th EGOS Colloquium in + Copenhagen, Subgroup 33 "New Conditions for Managing + Knowledge", July 2003 + + The aim of this paper is to show that + self-governance is the only way to create knowledge in + organizations. We will show that knowledge can only be + developed and preserved by self-governance. As + self-governance is not a natural process, it needs + structures to support the development of this kind of + action. Management is only able to create these structures + at a second level. Thus a distinction between two different + levels has to be made: the level of performance and the + structural level. + + Wilkesmann, Uwe + + + Rascher, Ingolf + + + http://www.ruhr-uni-bochum.de/sowi/top/sowibibliothek/dkpaper/dp03-1.pdf + + + Fakultät für Sozialwissenschaften, + Ruhr-Universität Bochum + 2003-06-03 + 2003-06-03 + + + application/pdf + + + knowledge management + + + self governance + + 1080502 + 10207 + + Akzeptanzforschung + + + Arbeitspsychologie + + + Informationsmanagement + + + Informationssystem + + + Organisationsstruktur + + + Selbstorganisation + + + Wissenssoziologie + + + Wissenstransfer + + \ No newline at end of file diff --git a/exist-samples/src/main/resources/org/exist/samples/mods/dae9118e-573a-4230-b781-5007c0579f27.xml b/exist-samples/src/main/resources/org/exist/samples/mods/dae9118e-573a-4230-b781-5007c0579f27.xml new file mode 100644 index 0000000000..4949cbfc65 --- /dev/null +++ b/exist-samples/src/main/resources/org/exist/samples/mods/dae9118e-573a-4230-b781-5007c0579f27.xml @@ -0,0 +1,74 @@ + + + + Emerging production systems in the + transnationalisation of German carmakers: Adaptation, + application or innovation? + + Based on case studies, this article seeks to + determine whether or not German carmakers are exporting a + German production model to overseas plants and to what + extent the overseas operations have a reciprocal effect on + production methods in the originating country. It is argued + that the most adequate analytical concept is one that + emphasizes interest-driven organizational learning processes. + + Pries, Ludger + + + http://www.ruhr-uni-bochum.de/soaps/download/publ-2003_lp_emergingproductionsystems.pdf + + + 2003-01-24 + + + application/pdf + + + + New Technology, Work and Employment 18 (2003), + no. 2 + + + + business models + + + production system + + + automobile industry + + + company internationalization + + + international comparison + + + transplants + + + Germany + + 10204 + 10207 + + Bundesrepublik Deutschland + + + Fallstudie + + + Kraftfahrzeugindustrie + + + Produktion + + + Unternehmenskultur + + + multinationales Unternehmen + + \ No newline at end of file diff --git a/exist-samples/src/main/resources/org/exist/samples/mods/f3ad5614-d1b4-4860-a108-542c42dceebf.xml b/exist-samples/src/main/resources/org/exist/samples/mods/f3ad5614-d1b4-4860-a108-542c42dceebf.xml new file mode 100644 index 0000000000..254c09cd1f --- /dev/null +++ b/exist-samples/src/main/resources/org/exist/samples/mods/f3ad5614-d1b4-4860-a108-542c42dceebf.xml @@ -0,0 +1,46 @@ + + + + U.S. Perspectives on the position and role of Germany and Japan in international and regional structures. The 1950s and the Present + + Rather than focusing on the relative power of Germany and Japan within the international system, my attention is directed towards U.S. perspectives on the position and role of Germany and Japan in regional and international structures as points of reference with a view of analysing the transformation of Germany's and Japan's foreign relations in conjunction with changes in the global economy and regional security concerns. The differences between firstly Germany and Japan, secondly the regional context of German and Japanese policies, and thirdly Germany and Japan as international actors are too important and the German-Japanese relationships too underdeveloped (in spite of the spurts in the early 1980s and since 1993) to allow a direct comparison of Germany's and Japan's positions and roles in International Relations. The comparison between U.S. perspectives on Japan and "Germany integrated into Europe" is more manageable and conducive to an assessment of changes:<br/> - the U.S. is a determining factor in Europe's/Pacific Asia's affairs,<br/> - Germany/Japan regards the U.S. as a pillar of its foreign policy,<br/> - the U.S. considers (for the time being) Germany's/Japan's position and role essential to what the U.S. can accomplish regionally and internationally.<br/> The weight of these "factors" ensures that the comparison of U.S. perspectives on Germany and Japan is a reliable guide to the Interpretation of the foreign policy positions and roles of the Federal Republic of Germany (FRG) and Japan in regional and international structures. + + Schmidt, Gustav + + + http://www.ruhr-uni-bochum.de/lehrstuhl-ip/Ostasien.pdf + + + 1999 + + + application/pdf + + + + Bochumer Jahrbuch zur Ostasienforschung, Bd. 23 (1999), S. 359-372. + + + 10505 + + Außenpolitik + + + Bundesrepublik Deutschland + + + Einfluss + + + Geopolitik + + + Japan + + + USA + + + politische Beziehungen + + \ No newline at end of file diff --git a/exist-samples/src/main/resources/org/exist/samples/xinclude/db2html.xsl b/exist-samples/src/main/resources/org/exist/samples/xinclude/db2html.xsl index 6ee35b31e2..c697926410 100644 --- a/exist-samples/src/main/resources/org/exist/samples/xinclude/db2html.xsl +++ b/exist-samples/src/main/resources/org/exist/samples/xinclude/db2html.xsl @@ -1,6 +1,30 @@ - +