From a1296ad1b21f8c2d5f98f0e707c23a7b8e2d9646 Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Tue, 26 Sep 2023 16:40:17 +0200 Subject: [PATCH 001/141] feat(ct): enable JSF and autodeploy when activating reload #9590 --- .../main/docker/scripts/init_1_generate_devmode_commands.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/container-base/src/main/docker/scripts/init_1_generate_devmode_commands.sh b/modules/container-base/src/main/docker/scripts/init_1_generate_devmode_commands.sh index bb0984332f7..4914f4fa1e0 100644 --- a/modules/container-base/src/main/docker/scripts/init_1_generate_devmode_commands.sh +++ b/modules/container-base/src/main/docker/scripts/init_1_generate_devmode_commands.sh @@ -56,6 +56,9 @@ fi if [ "${ENABLE_RELOAD}" = "1" ]; then echo "Enabling hot reload of deployments." echo "set configs.config.server-config.admin-service.das-config.dynamic-reload-enabled=true" >> "${DV_PREBOOT}" + echo "set configs.config.server-config.admin-service.das-config.autodeploy-enabled=true" >> "${DV_PREBOOT}" + export DATAVERSE_JSF_PROJECT_STAGE=${DATAVERSE_JSF_PROJECT_STAGE:-"Development"} + export DATAVERSE_JSF_REFRESH_PERIOD=${DATAVERSE_JSF_REFRESH_PERIOD:-"0"} fi # 4. Add the commands to the existing preboot file, but insert BEFORE deployment From 86392d3ba7daf81d15af884cb3b2f51aced1bfb8 Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Tue, 26 Sep 2023 16:41:14 +0200 Subject: [PATCH 002/141] feat(ct): switch on ENABLE_RELOAD for dev containers by default #9590 --- docker-compose-dev.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index ab44dbc1806..dcfe5cd563f 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -13,6 +13,7 @@ services: - DATAVERSE_DB_PASSWORD=secret - DATAVERSE_DB_USER=${DATAVERSE_DB_USER} - ENABLE_JDWP=1 + - ENABLE_RELOAD=1 - DATAVERSE_FEATURE_API_BEARER_AUTH=1 ports: - "8080:8080" # HTTP (Dataverse Application) From 9beef391d1ff860c0b182f5791954b1f8b9738d6 Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Tue, 26 Sep 2023 16:41:37 +0200 Subject: [PATCH 003/141] build(ct): mount exploded war to container #9590 By mounting the directory that contains the web application as an exploded WAR, we can enable hot redeploys of code and XHTML. To enable version-agnostic mounts, the output directory is configured to not contain the version number anymore, but the WAR file is still containing it. --- docker-compose-dev.yml | 1 + pom.xml | 1 + src/main/docker/assembly.xml | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index dcfe5cd563f..eac90875589 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -28,6 +28,7 @@ services: volumes: - ./docker-dev-volumes/app/data:/dv - ./docker-dev-volumes/app/secrets:/secrets + - ./target/dataverse:/opt/payara/deployments/dataverse:ro tmpfs: - /dumps:mode=770,size=2052M,uid=1000,gid=1000 - /tmp:mode=770,size=2052M,uid=1000,gid=1000 diff --git a/pom.xml b/pom.xml index 7ba22d2a076..bca1d097a09 100644 --- a/pom.xml +++ b/pom.xml @@ -692,6 +692,7 @@ true false + ${project.build.directory}/${project.artifactId} true diff --git a/src/main/docker/assembly.xml b/src/main/docker/assembly.xml index 9f9b39617a3..62cd910ef9b 100644 --- a/src/main/docker/assembly.xml +++ b/src/main/docker/assembly.xml @@ -3,7 +3,7 @@ - target/${project.artifactId}-${project.version} + target/${project.artifactId} app WEB-INF/lib/**/* @@ -11,7 +11,7 @@ - target/${project.artifactId}-${project.version}/WEB-INF/lib + target/${project.artifactId}/WEB-INF/lib deps From a7418cfe70c6e268254267d0aa9784fc3c27d8bc Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Tue, 26 Sep 2023 16:45:37 +0200 Subject: [PATCH 004/141] fix(ct): move fallback JRE version in base image to 17 --- modules/container-base/src/main/docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/container-base/src/main/docker/Dockerfile b/modules/container-base/src/main/docker/Dockerfile index 97aa4cd2792..11ad980f070 100644 --- a/modules/container-base/src/main/docker/Dockerfile +++ b/modules/container-base/src/main/docker/Dockerfile @@ -22,7 +22,7 @@ # # Make the Java base image and version configurable (useful for trying newer Java versions and flavors) -ARG JAVA_IMAGE="eclipse-temurin:11-jre" +ARG JAVA_IMAGE="eclipse-temurin:17-jre" FROM $JAVA_IMAGE # Default payara ports to expose From 68eb59d0d4de068c352d5a7b4889dd034f3dc296 Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Tue, 26 Sep 2023 16:48:55 +0200 Subject: [PATCH 005/141] doc(ct): describe extended behaviour of ENABLE_RELOAD #9590 --- doc/sphinx-guides/source/container/base-image.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/sphinx-guides/source/container/base-image.rst b/doc/sphinx-guides/source/container/base-image.rst index 1a47a8fc413..1be0b992b2a 100644 --- a/doc/sphinx-guides/source/container/base-image.rst +++ b/doc/sphinx-guides/source/container/base-image.rst @@ -217,7 +217,9 @@ provides. These are mostly based on environment variables (very common with cont - ``0`` - Bool, ``0|1`` - Enable the dynamic "hot" reloads of files when changed in a deployment. Useful for development, - when new artifacts are copied into the running domain. + when new artifacts are copied into the running domain. Also, export Dataverse specific environment variables + ``DATAVERSE_JSF_PROJECT_STAGE=Development`` and ``DATAVERSE_JSF_REFRESH_PERIOD=0`` to enable dynamic JSF page + reloads. * - ``DATAVERSE_HTTP_TIMEOUT`` - ``900`` - Seconds From f3a0e324ac5ef89a63e3b5c303e44175a8cb5301 Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Wed, 8 Nov 2023 13:55:53 +0100 Subject: [PATCH 006/141] fix(ct): remove nginx from modules --- modules/nginx/Dockerfile | 9 --------- modules/nginx/README.md | 7 ------- modules/nginx/default.conf | 12 ------------ 3 files changed, 28 deletions(-) delete mode 100644 modules/nginx/Dockerfile delete mode 100644 modules/nginx/README.md delete mode 100644 modules/nginx/default.conf diff --git a/modules/nginx/Dockerfile b/modules/nginx/Dockerfile deleted file mode 100644 index 3900076599f..00000000000 --- a/modules/nginx/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -FROM nginx:latest - -# Remove the default NGINX configuration file -RUN rm /etc/nginx/conf.d/default.conf - -# Copy the contents of the local default.conf to the container -COPY default.conf /etc/nginx/conf.d/ - -EXPOSE 4849 \ No newline at end of file diff --git a/modules/nginx/README.md b/modules/nginx/README.md deleted file mode 100644 index 9d2ff785577..00000000000 --- a/modules/nginx/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# nginx proxy - -nginx can be used to proxy various services at other ports/protocols from docker. - -Currently, this is used to work around a problem with the IntelliJ Payara plugin, which doesn't allow remote redeployment in case the Payara admin is served via HTTPS using a self-signed certificate, which is the case of the default dataverse container installation. This configuration provides an HTTP endpoint at port 4849, and proxies requests to the Payara admin console's HTTPS 4848 endpoint. From the IntelliJ Payara plugin one has to specify the localhost 4849 port (without SSL). - -![img.png](img.png) diff --git a/modules/nginx/default.conf b/modules/nginx/default.conf deleted file mode 100644 index 8381a66c19a..00000000000 --- a/modules/nginx/default.conf +++ /dev/null @@ -1,12 +0,0 @@ -server { - listen 4849; - - # Make it big, so that .war files can be submitted - client_max_body_size 300M; - - location / { - proxy_pass https://dataverse:4848; - proxy_ssl_verify off; - proxy_ssl_server_name on; - } -} From 65fb4dc0be3d519b80ee4e44007d720787042802 Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Wed, 8 Nov 2023 15:46:10 +0100 Subject: [PATCH 007/141] feat(ct): replace nginx with caddy #9590 - Use caddy as a faster and smaller alternative to NGINX. - Remove unnecessary pom.xml entry for container. - Migrate config to Caddyfile in /conf instead of /modules (we do not create a new image here...) - Add dependency on Dataverse container to proxy container - Slight renaming of containers --- conf/proxy/Caddyfile | 12 ++++++++++++ docker-compose-dev.yml | 17 +++++++++++++---- pom.xml | 8 -------- 3 files changed, 25 insertions(+), 12 deletions(-) create mode 100644 conf/proxy/Caddyfile diff --git a/conf/proxy/Caddyfile b/conf/proxy/Caddyfile new file mode 100644 index 00000000000..70e6904d26e --- /dev/null +++ b/conf/proxy/Caddyfile @@ -0,0 +1,12 @@ +# This configuration is intended to be used with Caddy, a very small high perf proxy. +# It will serve the application containers Payara Admin GUI via HTTP instead of HTTPS, +# avoiding the trouble of self signed certificates for local development. + +:4848 { + reverse_proxy https://dataverse:4848 { + transport http { + tls_insecure_skip_verify + } + header_down Location "^https://" "http://" + } +} diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index dc245a88847..93a8c49ec54 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -145,12 +145,21 @@ services: volumes: - './conf/keycloak/test-realm.json:/opt/keycloak/data/import/test-realm.json' - dev_nginx: - container_name: dev_nginx - image: gdcc/dev_nginx:unstable + # This proxy configuration is only intended to be used for development purposes! + # DO NOT USE IN PRODUCTION! HIGH SECURITY RISK! + dev_proxy: + image: caddy:2-alpine + # The command below is enough to enable using the admin gui, but it will not rewrite location headers to HTTP. + # To achieve rewriting from https:// to http://, we need a simple configuration file + #command: ["caddy", "reverse-proxy", "-f", ":4848", "-t", "https://dataverse:4848", "--insecure"] + command: ["caddy", "run", "-c", "/Caddyfile"] ports: - - "4849:4849" + - "4848:4848" # Will expose Payara Admin Console (HTTPS) as HTTP restart: always + volumes: + - ./conf/proxy/Caddyfile:/Caddyfile:ro + depends_on: + - dev_dataverse networks: - dataverse diff --git a/pom.xml b/pom.xml index 473b7bd1bf7..c78d540e103 100644 --- a/pom.xml +++ b/pom.xml @@ -1008,14 +1008,6 @@ true - - - gdcc/dev_nginx:unstable - - ${project.basedir}/modules/nginx - - - true From 5630e7699149cbd4731dc460d49dd3e30b069168 Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Wed, 8 Nov 2023 15:47:48 +0100 Subject: [PATCH 008/141] style(ct): expose payara admin gui as HTTPS on port 4949 #9590 It might be good to keep it available on localhost in addition to the HTTP variant on port 4848 via proxy. --- docker-compose-dev.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index 93a8c49ec54..4e0899595e1 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -21,7 +21,7 @@ services: - DATAVERSE_AUTH_OIDC_AUTH_SERVER_URL=http://keycloak.mydomain.com:8090/realms/test ports: - "8080:8080" # HTTP (Dataverse Application) - - "4848:4848" # HTTP (Payara Admin Console) + - "4949:4848" # HTTPS (Payara Admin Console) - "9009:9009" # JDWP - "8686:8686" # JMX networks: From 76b87b0606f3ffff9c7ca6742926678a539a168b Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Wed, 8 Nov 2023 15:50:06 +0100 Subject: [PATCH 009/141] feat(ct): enable skipping all deployments on app server start #9590 With using the env var "SKIP_DEPLOY" or the Maven property "-Dapp.deploy.skip" we can make the application server not deploy Dataverse on container start. This is necessary to save on time and manual undeploy when using Payara IDE tools to hot deploy changes. --- .env | 1 + docker-compose-dev.yml | 1 + modules/container-base/src/main/docker/Dockerfile | 3 ++- .../docker/scripts/init_1_generate_deploy_commands.sh | 10 ++++++++-- pom.xml | 2 ++ 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.env b/.env index e3ececc2e54..ae266af80da 100644 --- a/.env +++ b/.env @@ -2,3 +2,4 @@ APP_IMAGE=gdcc/dataverse:unstable POSTGRES_VERSION=13 DATAVERSE_DB_USER=dataverse SOLR_VERSION=9.3.0 +SKIP_DEPLOY=0 \ No newline at end of file diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index 4e0899595e1..1b507b72fe1 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -14,6 +14,7 @@ services: - DATAVERSE_DB_USER=${DATAVERSE_DB_USER} - ENABLE_JDWP=1 - ENABLE_RELOAD=1 + - SKIP_DEPLOY=${SKIP_DEPLOY} - DATAVERSE_FEATURE_API_BEARER_AUTH=1 - DATAVERSE_AUTH_OIDC_ENABLED=1 - DATAVERSE_AUTH_OIDC_CLIENT_ID=test diff --git a/modules/container-base/src/main/docker/Dockerfile b/modules/container-base/src/main/docker/Dockerfile index 11ad980f070..f2c193beafd 100644 --- a/modules/container-base/src/main/docker/Dockerfile +++ b/modules/container-base/src/main/docker/Dockerfile @@ -65,7 +65,8 @@ ENV PATH="${PATH}:${PAYARA_DIR}/bin:${SCRIPT_DIR}" \ JVM_DUMPS_ARG="-XX:+HeapDumpOnOutOfMemoryError" \ ENABLE_JMX=0 \ ENABLE_JDWP=0 \ - ENABLE_RELOAD=0 + ENABLE_RELOAD=0 \ + SKIP_DEPLOY=0 ### PART 1: SYSTEM ### ARG UID=1000 diff --git a/modules/container-base/src/main/docker/scripts/init_1_generate_deploy_commands.sh b/modules/container-base/src/main/docker/scripts/init_1_generate_deploy_commands.sh index 8729f78e466..161f10caebf 100644 --- a/modules/container-base/src/main/docker/scripts/init_1_generate_deploy_commands.sh +++ b/modules/container-base/src/main/docker/scripts/init_1_generate_deploy_commands.sh @@ -31,6 +31,8 @@ # ########################################################################################################## +set -euo pipefail + # Check required variables are set if [ -z "$DEPLOY_DIR" ]; then echo "Variable DEPLOY_DIR is not set."; exit 1; fi if [ -z "$PREBOOT_COMMANDS" ]; then echo "Variable PREBOOT_COMMANDS is not set."; exit 1; fi @@ -51,8 +53,12 @@ deploy() { if grep -q "$1" "$POSTBOOT_COMMANDS"; then echo "post boot commands already deploys $1"; else - echo "Adding deployment target $1 to post boot commands"; - echo "$DEPLOY_STATEMENT" >> "$POSTBOOT_COMMANDS"; + if [ -n "$SKIP_DEPLOY" ] && { [ "$SKIP_DEPLOY" = "1" ] || [ "$SKIP_DEPLOY" = "true" ]; }; then + echo "Skipping deployment of $1 as requested."; + else + echo "Adding deployment target $1 to post boot commands"; + echo "$DEPLOY_STATEMENT" >> "$POSTBOOT_COMMANDS"; + fi fi } diff --git a/pom.xml b/pom.xml index c78d540e103..52bef929c1c 100644 --- a/pom.xml +++ b/pom.xml @@ -911,6 +911,7 @@ gdcc/dataverse:${app.image.tag} unstable + false gdcc/base:${base.image.tag} unstable gdcc/configbaker:${conf.image.tag} @@ -923,6 +924,7 @@ ${postgresql.server.version} ${solr.version} dataverse + ${app.deploy.skip} From 7d33c2b89c39b6de23c4db0ab1635073d5666af6 Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Wed, 8 Nov 2023 19:41:38 +0100 Subject: [PATCH 010/141] doc: add sphinx-tabs to enable variants of docs --- doc/sphinx-guides/requirements.txt | 1 + doc/sphinx-guides/source/_static/docsdataverse_org.css | 8 ++++++++ doc/sphinx-guides/source/conf.py | 1 + 3 files changed, 10 insertions(+) diff --git a/doc/sphinx-guides/requirements.txt b/doc/sphinx-guides/requirements.txt index 028f07d11cb..e369536ba4e 100755 --- a/doc/sphinx-guides/requirements.txt +++ b/doc/sphinx-guides/requirements.txt @@ -10,3 +10,4 @@ Jinja2>=3.0.2,<3.1 # Sphinx - Additional modules sphinx-icon==0.1.2 +sphinx-tabs==3.4.4 diff --git a/doc/sphinx-guides/source/_static/docsdataverse_org.css b/doc/sphinx-guides/source/_static/docsdataverse_org.css index da4ba06ddd4..726abcc42bd 100755 --- a/doc/sphinx-guides/source/_static/docsdataverse_org.css +++ b/doc/sphinx-guides/source/_static/docsdataverse_org.css @@ -182,3 +182,11 @@ div.form-group .glyphicon.glyphicon-asterisk {font-size: .5em; vertical-align: t pre { white-space: pre-wrap; } + +div.sphinx-tabs { + width: 100%; +} + +li div.sphinx-tabs { + padding-left: 0; +} \ No newline at end of file diff --git a/doc/sphinx-guides/source/conf.py b/doc/sphinx-guides/source/conf.py index 0660ec3b071..6f7d7aff722 100755 --- a/doc/sphinx-guides/source/conf.py +++ b/doc/sphinx-guides/source/conf.py @@ -43,6 +43,7 @@ 'sphinx.ext.viewcode', 'sphinx.ext.graphviz', 'sphinxcontrib.icon', + 'sphinx_tabs.tabs', ] # Add any paths that contain templates here, relative to this directory. From 7a7bbec34b17991f268a991f6c8e2834739aacca Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Wed, 8 Nov 2023 19:42:20 +0100 Subject: [PATCH 011/141] doc(ct): document using IntelliJ Payara tools --- .../source/container/dev-usage.rst | 100 ++++++++++++++---- .../img/intellij-payara-add-new-config.png | Bin 0 -> 67013 bytes .../img/intellij-payara-config-add-server.png | Bin 0 -> 95876 bytes .../img/intellij-payara-config-deployment.png | Bin 0 -> 95101 bytes ...ntellij-payara-config-server-behaviour.png | Bin 0 -> 29639 bytes .../img/intellij-payara-config-server.png | Bin 0 -> 122860 bytes .../img/intellij-payara-config-startup.png | Bin 0 -> 81423 bytes .../img/intellij-payara-plugin-install.png | Bin 0 -> 98114 bytes .../img/intellij-payara-run-menu-reload.png | Bin 0 -> 111271 bytes .../img/intellij-payara-run-output.png | Bin 0 -> 49972 bytes .../img/intellij-payara-run-toolbar.png | Bin 0 -> 2550 bytes 11 files changed, 77 insertions(+), 23 deletions(-) create mode 100644 doc/sphinx-guides/source/container/img/intellij-payara-add-new-config.png create mode 100644 doc/sphinx-guides/source/container/img/intellij-payara-config-add-server.png create mode 100644 doc/sphinx-guides/source/container/img/intellij-payara-config-deployment.png create mode 100644 doc/sphinx-guides/source/container/img/intellij-payara-config-server-behaviour.png create mode 100644 doc/sphinx-guides/source/container/img/intellij-payara-config-server.png create mode 100644 doc/sphinx-guides/source/container/img/intellij-payara-config-startup.png create mode 100644 doc/sphinx-guides/source/container/img/intellij-payara-plugin-install.png create mode 100644 doc/sphinx-guides/source/container/img/intellij-payara-run-menu-reload.png create mode 100644 doc/sphinx-guides/source/container/img/intellij-payara-run-output.png create mode 100644 doc/sphinx-guides/source/container/img/intellij-payara-run-toolbar.png diff --git a/doc/sphinx-guides/source/container/dev-usage.rst b/doc/sphinx-guides/source/container/dev-usage.rst index b2547306b03..9fc9058eada 100644 --- a/doc/sphinx-guides/source/container/dev-usage.rst +++ b/doc/sphinx-guides/source/container/dev-usage.rst @@ -149,38 +149,92 @@ Rebuild and Running Images The safest way to redeploy code is to stop the running containers (with Ctrl-c if you started them in the foreground) and then build and run them again with ``mvn -Pct clean package docker:run``. -IntelliJ IDEA Ultimate and Payara Platform Tools -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +IDE-triggered re-deployments +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -If you have IntelliJ IDEA Ultimate (note that `free educational licenses `_ are available), you can install `Payara Platform Tools `_ which can dramatically improve your feedback loop when iterating on code. +You have at least two options: -The following steps are suggested: +1. Use plugins for different IDEs by Payara to ease the burden of redeploying an application during development to a running Payara application server. + Their guides contain `documentation on Payara IDE plugins `_. +2. Use a paid product like `JRebel `_. -- Go to the Payara admin console (either at https://localhost:4848 or http://localhost:4849) and undeploy the dataverse application under "Applications". -- Install Payara Platform Tools. -- Under "Server": +The main difference between the first and the second option is support for hot deploys of non-class files plus limitations in what the JVM HotswapAgent can do for you. +Find more `details in a blog article by JRebel `_. - - Click "Run" then "Edit Configurations". - - Click the plus sign and scroll down to Payara Server and click "Remote". - - For "Name" put "Payara in Docker" or something reasonable. - - Under "Application server" select a local directory that has the same version of Payara used in the container. This should match the version of Payara mentioned in the Installation Guide under :ref:`payara`. - - Change "Admin Server Port" to 4849. - - For username, put "admin". - - For password, put "admin". +When opting for Payara tools, please follow these steps: -- Under "Deployment": +1. | Download the Payara appserver to your machine, unzip and note the location for later. + | - See this guide for which version, in doubt lookup using + | ``mvn help:evaluate -Dexpression=payara.version -q -DforceStdout`` + | - Can be downloaded from `Maven Central `_. - - Click the plus button and clien "Artifact" then "dataverse:war". +2. Install Payara tools plugin in your IDE: -- Under "Startup/Connection": + .. tabs:: + .. group-tab:: IntelliJ + **Requires IntelliJ Ultimate!** + (Note that `free educational licenses `_ are available) - - Click "Debug" and change the port to 9009. + .. image:: img/intellij-payara-plugin-install.png -- Click "Run" and then "Debug Payara in Docker". This initial deployment will take some time. -- Go to http://localhost:8080/api/info/version and make sure the API is responding. -- Edit ``Info.java`` and make a small change to the ``/api/info/version`` code. -- Click "Run" then "Debugging Actions" then "Reload Changed Classes". The deployment should only take a few seconds. -- Go to http://localhost:8080/api/info/version and verify the change you made. +3. Configure a connection to the application server: + + .. tabs:: + .. group-tab:: IntelliJ + Create a new running configuration with a "Remote Payara". + (Open dialog by clicking "Run", then "Edit Configurations") + + .. image:: img/intellij-payara-add-new-config.png + + Click on "Configure" next to "Application Server". + Add an application server and select unzipped local directory. + + .. image:: img/intellij-payara-config-add-server.png + + Add admin password "admin" and add "building artifact" before launch. + Make sure to select the WAR, *not* exploded! + + .. image:: img/intellij-payara-config-server.png + + Go to "Deployment" tab and add the Dataverse WAR, *not* exploded!. + + .. image:: img/intellij-payara-config-deployment.png + + Go to "Startup/Connection" tab, select "Debug" and change port to ``9009``. + + .. image:: img/intellij-payara-config-startup.png + + You might want to tweak the hot deploy behaviour in the "Server" tab now. + "Update action" can be found in the run window (see below). + "Frame deactivation" means switching from IntelliJ window to something else, e.g. your browser. + *Note: static resources like properties, XHTML etc will only update when redeploying!* + + .. image:: img/intellij-payara-config-server-behaviour.png + +4. | Start all the containers. Follow the cheat sheet above, but take care to skip application deployment: + | - When using the Maven commands, append ``-Dapp.deploy.skip``. + | - When using Docker Compose, prepend the command with ``SKIP_DEPLOY=1``. + | - Note: the Admin Console can be reached at http://localhost:4848 or https://localhost:4949 +5. To deploy the application to the running server, use the configured tools to deploy. + Using the "Run" configuration only deploys and enables redeploys, while running "Debug" enables hot swapping of classes via JDWP. + + .. tabs:: + .. group-tab:: IntelliJ + Choose "Run" or "Debug" in the toolbar. + + .. image:: img/intellij-payara-run-toolbar.png + + Watch the WAR build and the deployment unfold. + Note the "Update" action button (see config to change its behaviour). + + .. image:: img/intellij-payara-run-output.png + + Manually hotswap classes in "Debug" mode via "Run" > "Debugging Actions" > "Reload Changed Classes". + + .. image:: img/intellij-payara-run-menu-reload.png + +Note: in the background, the bootstrap job will wait for Dataverse to be deployed and responsive. +When your IDE automatically opens the URL a newly deployed, not bootstrapped Dataverse application, it might take some more time and page refreshes until the job finishes. Using a Debugger ---------------- diff --git a/doc/sphinx-guides/source/container/img/intellij-payara-add-new-config.png b/doc/sphinx-guides/source/container/img/intellij-payara-add-new-config.png new file mode 100644 index 0000000000000000000000000000000000000000..d1c7a8f2777fc1b61c636d6b8751d9c3f38f580e GIT binary patch literal 67013 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%0DVzlRCP_ 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 F{{iUWK#c$Z literal 0 HcmV?d00001 diff --git a/doc/sphinx-guides/source/container/img/intellij-payara-config-add-server.png b/doc/sphinx-guides/source/container/img/intellij-payara-config-add-server.png new file mode 100644 index 0000000000000000000000000000000000000000..54ffbd1b713c855c3316ef61524ba18851e7dd9e GIT binary patch literal 95876 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx-guides/source/container/img/intellij-payara-config-server-behaviour.png b/doc/sphinx-guides/source/container/img/intellij-payara-config-server-behaviour.png new file mode 100644 index 0000000000000000000000000000000000000000..5d23672e61415026943dddfb4998b2ae1e82707e GIT binary patch literal 29639 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 z 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx-guides/source/container/img/intellij-payara-plugin-install.png b/doc/sphinx-guides/source/container/img/intellij-payara-plugin-install.png new file mode 100644 index 0000000000000000000000000000000000000000..7c6896574de27de558f7d40449a8080a7a6804fa GIT binary patch literal 98114 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx-guides/source/container/img/intellij-payara-run-menu-reload.png b/doc/sphinx-guides/source/container/img/intellij-payara-run-menu-reload.png new file mode 100644 index 0000000000000000000000000000000000000000..b1fd8bea260af87759210b7393afb9cb18f32e24 GIT binary patch literal 111271 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

jj z=)4u3Q(NA({j2G3!#@Rl8s^G>s+xp072$6Y5pi zufnFjN_Ry|iV&~MWzWkl%Qwen7|!bK0zx$k6;`4Lxy6oNstddlhsm}8bf;DTG9+`S`V$J6Tiq}i;xPC;j)J*jK? zawJwGMpuk4ned|gay#&Nacu`$msi8Nukw=wG?u< zF!9j^!cM^;twVNKOL+6ACzsMlWNRP{OWlW@>m9kSu{rP#WI<;Wxyw@c-mhO9a#Ncc z&V^--Tt%&idnMqb^TK+zELjMU_9}ZwC#XsqXY^dE2DTm^@usMi6YFRTA`3>J)+nrX{ z)5?Ltn;;xL9i~sN-YA|lZ!vg0S{NP{QvKxEHzQED=OP}hWlo@3xNR9PE~g=@2d73$ zTMMIDcDY;J{w;@?(sz;UDAgHHUD^ugCP>D2a$m!B_n+n$_Rm%s*C-4R^I#bn`wc)h zEEr)Ja%gnBLn~bB?QYBr(uoLHi4VxKBltpU(j;kT)@Jk1;W{ra&?l8hmjSpDmm>y* zwm=Bo?>&I>>W*hvq!$L<+EG@MiP<)$h|hLW(Xo85F`DW2rS4RxZ8w-@fv|la7Qo*$ zD7B_NG`0ZCOk&q0BA~0d+|uXj#h%o20ux~mJv)uZSvnFKR z#vXl1e$SqPaNjbpO0~@FbxxtJ^=?*IgA7axExdk|}sX*ePSoNm%=UE{tmV@6!n~zhHa<-{L zhh56GK3lw00Kjf}*keuF@3hhxBhL>$su=!OAfG8`#!kW>Kj6m-c*B0XN37dL`b-Q8 zMP*EhwBfp6=8K5rG((0W369Kmt+di$J?611oHaMtjw3H?u+3mgKpfOv%B?MVq0Haz zP7lv^e@Rxo+p0i_W=ZpSF4+Uh_lOqDrS~RT5NUE|@^N->n}5zOp08$|pVhF_~4bYOV1dYm`URtLUe*~KArXKkyF?tY^H zSL<{*akbtz*UCer4Z_5@$Q^A|)TebHjy4`n8HPUTM7EgZkgnZ$b2!A=WJzG4T**2y28Rdos8adwSHpUnX|Cxk z5S7ubW-MvOjMy)?#9Lv*-)9EP?|!r;E3KNF!5dh){p2e9+O41})w%y!NjX#D+|pn* z$%=uSIdTgLu0m!c!~U5m#oDJWo0UKQVN6S2!oh^Il9YYz9W$;=GN17xFC-`f*V$YO z9*RFK@Jq=NG6`=pP*Fj+kO==r#k;XR$0g!FBeXP?y9T<|Q(iTtH~TI)ZLA|ME>5jh z@zbhJeKaqN*qPfx+S^7Ur8<^|ODhAfpYwsmXq7&}DxRQYeR6_cpD}H;7#R=McZ&Fw zsx_N)U{58;yf2R#WXA>{{A=^C!d#>}X<^?R*;$*~P-0 z?YWLluAkcFWK4EA^P??ed=&Jhf#oY2kcm!=Jlc@ArWYZPOdL$9AF};;4R+6>ZPs}n z98s6OknTW3$Ylu|sjlzV{vkHnD1$yh$_ZjS&R@3BbA?sUqoh6IA5G=iZu-Jj-Kb=` z$VA8DkA&iiS(`o5QgVfZ1i0Q#o&&!1kitmR(rET(X-?4(y+dA7Bo$5$MzTG480taO zsnJ%wxpS=N@l?O(oW-2_#xj%1Vh?rPCa%5RZ^bU%K+gzA-Uy=?OMK}{%-P<*Pc_{t zpTHV_v4iwc*k~MYjb=WfV}@h;1E?w7oD08xmzu;olgUzd=x3j*k>k~$NOOZv^Jie8 z1r31;jTN4YDmwa)%M>S1+W29vi#F3}PlaSWj`TCVxkI4cVQ-0x1KjJwB__P5EyF2j zFVp;#%)M?K-sXiW6^%=b_XXdR@cJ`biq_V^diR^Q$d91eNliYQLG?Z#!C7(Vh|e>Y z1NASoRr?=KRWE22fm>cU{*ffhPH}aJT@X_ROI6;bP7y>7*F`^(8k%liqMZ=A`xUL| za*I?1RBQZv$TWE&b_p)#%d?N-7L`1%ET)rxaL)SEP8KXZaE{Y9`atjUj!y-Ink0z| zby}*lT)^?NPq4rCC3XkUwf1+*QtyBc@fQ$`4yyTfwsW}(AoePF!r-41?WfJB+E%(B zvc+tiu0WoEKNIpR{m_ISF&CzRJ%PDzCib_@1i z(I*j9m34_NwX&9t{e|FRR(?>wlfqPA-h>#&R!b^z8g!N2JJ;TuI;LRQM4nE+I zLbyYk+w6SwdVair3fZ2SnYknT4e8!OpD}?5=u<-XyU5qie>Dgr?M*HJBiu(`CH%jH z={zqTMQ`2M@M^IF5B^dRf1-UGfk7^<{l6N%FNOYz^pXD`g8qN$2;q8d4AY?&Lahz@ z31;(Q&j7s{c>8mRiGw1Wl4q)uEX^yQzDz}D-q`+ClvGb!*^CcbcX+9mNy+_-@S#k98Z{rNfp880SWw&mhRy!**eBbV+yH8cB zCs_^3;2v$mFML+$S8-Sy`X%qNxfhBh$vG8+va{>b#U$k50j~RnBXl`^$H}@xqzvfG z6z$tunF$r7J(+RoIVGL-k+7W%&wdCy)IA7NCEdmhLDlGJbG|FSxETCGmkl;E zstPJ9e%+ht>Tm4Y$>GPAR+!9{#{@9Jm^-xW_LJN-d1fRQT{Fby)-r=k6T+LcAcuX6 zD6UM=G%UBMS&}BJcj#GYV2fuZl-yy_PTalNwA-Sukgas*vu8|1$CHMi(zW|_eLS-S z7aBCw=}&3%kPz3oV?1PjXP#Wv5wtzlBoqV%g0Q+AWLw9g$mqy2HRAO=-cnSpG|>W` zs{+I0j~=SxEjy-Zsj;DBeETJ*Yie?zMXise@hPl_EGvzj#W6KPd|mbt|y+G5`zxdercD6 ztNZ~DC6v9p z<-EIb+xM&qLE$_08H9}ByWw>7p-JJiddOvBSTp6dCR(3n)9(MjIS`cfh2qev^iRu)Bi}6i_(7o-Ft)4v)9*fWeH?9s_iM zp1cn|4(=Pwb!NtBl@I7&7i0<0ox&-oPRD;xW_S;oX*XwJSB!N9Ynfksep(c*L}gP+ z5G zOW=kJ0aW46H3umPi0(L-EVt!lF(fBBbEw{|3_gIegG`6aGsb5Eob^wzy38ogeFGGm zuZ!R`{^7Kp1}4rDE3o0jEv zns>JC0<-}Z9E}J#_O&ZJ^511_t1foaSs_orzTK;=0FLQ2Q7}SLDj;^Yiq#wT5E;GA z3Yh$|@gICub?y_MS#T`sjk)ljll_h@>x++JdYsx7y)#=cOv-sVp|o#xxY;S<$Q^jw zr53xz_;kAbi@>h;rYa}26LB(-qg?SLXqv+80VEE=seo7BPzeKFOPu+a$|FU@pN*}X zyU^ky${pEvq4Taq1Iuj$avx*~1~VEyNe$_W`o%`pQzbK6~#wBM5`Zh zs`&A82N88E2Fl?zV6b7_Z@<4)VQ(@e+~z&cLtTo<1f<{%QgjexXxPiQ2H9X#J(@uH z+racB$=VI=q{|aAGw_4lv!23-_J7fa6QQBnq|H_IB}`&Vv&)=rHpC75R3i>1`Y?1` z{o|AZhZ#Svts6TI&#Ql@OIM|Uy~+my^4jDlEpsGMw?fbimrWs5&5-7eAz?laSnPxc zrj2;HuG}bAYW`xo9UqA!f*g#@S27+FD4%I?QR1<#)+1ic4LgD9ZoqnBc2S=+T{U)t z?yffsQ4f+teEul2bRsynUn3ZK9x}S!2QWJ$sZRZ?F%-Ga8_Ab(sg@5wlwQV|Ngsz4 zPM18pZ1V>t1)%5V`TeckY73cq9}AF!r!BS5G^RwSv(0Nd0o9W=K9VR=k-{y#~|JK3+Z1p_Zpo+UiN_#Fv-DI#_i zC9X-$J1hMyTmmuG`r-;Y#s1@i7NAq>Uz56^4J!b4qyU?+lfbK(WvkSE|8Q;j(L^sfUt) z!5{X?MGf|0T4S-n13!7rb6DH~OehK`zo9_S*R0WewIX~Jm-W|=5aL`NXM=C#^7638 zj^)PFI|$}WG13-Cx~SdmZaKz}f(&Xw;c|uLm)g#6a)jN<%L8#aSM>JU!|~(4D|2_k%?hwfa7Cy{|L&&3FnQj(WRap$9TuyR)vz(-wW3S@#m6*$uIiyUB@W4x zGyLM-N_#!Jn^kJg`Qf@c%T5dhw^R`D@kgDX^}g@R9@u3?P-vO<_>v~(LrhSpYJCM| zF}S1>x_qXiqZLqWuK*r(Or-?wS|yb9>c)Skl8Pjz(#h@7{O#QCX1#}lR0a5~KgZ*+ zU7TNVTWPDJ9P&OS6){9(8Rb0R)MR%b3&t-&)HJU;;K$4tKG-W5NBD&g&E#tiVOj9J zK2ff6MVaz-29L8&?>Go?aXLIbt(nZEFZIS9LzCO62NK#dY?8@-S9|>mUrM}Vltwv* zuEYXzk?YzFoP*`?D4KISKPlUuIcMUXPE!i))bsW8L;GkhJeyeQ`?m2>^w()@7?FQN z0n`}!Z034KNkQmZgEQyrR{^r&eQH^jUJ;fCa9IEe%MBFeP>~HpQgze;6ftS`I|42l zC*(QpNwrYQw54dgA&LwE2oh>9H7%n4%hu&i#s0#QS#z#$n>?znMI3fbQ*J<49CDh{ zUM%#jXWT2L$n@3#G-X=*JYDLKXu(FL1HeSY{qH*Du2~9wzZhJpu`#uV8ep=6iUx`5 z2VPht6J!rBDsfE$L`NBxdtK8lWje+O{P z-p&E|9jjDJ`!1zOyI(zgTWk_TIqxw%N1dV%lBL7+jx3O@`!P(_4uUDzwS0>xl_*y% zjx;W5`~yg%p7g-yg0N%CJpIuuCp3sFMf2@W?Ydj}s=|tfBJ{X5YH4Sd|1D4fI;Nn= zn)wyZq6Thk&vk675wL8LA$bhG1Ul_Q96GGvmA>8!9m9vik1g~MFeqg2S=?U%JGo$_ ztnD)vZsI>4IluJDSudg?eYIw|55Ndr56VFx6iKpxSQN2nMHBDdWGei|fHlcQsc|GY zs@LsRc%JMvu(f`Lq{wgFWio@s&J2r0FoXygj$}N2=2SGd%2Fckn}PofX5UGk`Ei4~ zpM8n_x(JX;mCvMcVYVnUF_tEX+wPSGc7hsyG)BVVf}9;Cn9=4tErt}OI`vbZQLjRE zN`EKf&0UpwwPu;LRknWajKc;?Zj=QLZ^&;&1!c^0eT_g43!V;cQfdeA+Q}@tdwG)4ll$3^BsrA4PH6q)5>EE3$-!4L@c>#B*|aunwsm@Drje zZpVsYx!lgJWC@`o6JINEOeZa6cnOt^+-AhphS>*aIyGRfO580asN1$Ooc#MUbpAP5 zTCgpp#Qa4&+$t&Ago9*pee%DJUB>z(%*^p7$6zTBY7v*GF|H{BmB&NhuraeA}2bGPk>~dMFR?IRw_p|#gf`&y1Q>AUvh1%8JfC~&0cxVF^O1mpihjV>Gh6E!k-PpqeMf=K3xXLv07;*I`h zkXg_gzwA0;mVz9E`C824w zBGhjHu+)laGZye=722&&2SUs;PYZ?zz8>`)N?~+t_N-rk!9xA`Y(ult%yy`vb2oj! zk(!JIP}m3EH%h#b6V8dmiaha<0Oes^u@wx+-X-o`Q2OxpMR<$V(pLHmsn{5qd%`v6 zEzp(Whc>9I{pAU=J6&_cjm?#O`4J}Ff3 zx5km?>PDel3)_@MgU7vofz5vVtK9?Nuzn=(BHJo?Ma7#q07=I+J)O5M!O5~pQSw6{ z(+}s%ZJ^9b-c7!I?X^RimMt{W7$7Yd344+`%- zu-V4R`;n7+x-z}J^^OScW9xt$+sx!zq0yo7E9q@g--^So!;9L<`Q|Ry8ugZ(;|C#V zosk|d+7tpFs9DkdN@_$*H?h$}*a&&l^fBK;7`&C5uqQAl{0TGm${%DWF;TQ%%!&90xaUhd~>u%i1e)`OG-1w|+Eyn}^*^kK&m#a!}X&2deg;?DcL5kL#7$)RdMWS%@-qWBqlTpRQ z{>mzt9K<~lc}My2Cj;BJ6ghD|JU(j`TK?LYM$6rO-nfg4i~G%@aZGHj^RmM&`5#o+ zFFC1;vMFH};aSt|74>w0O3a>j;`0O8$05)R|@L!q=j1mE;WV=o~cG z<{uxYA>qf)3p8c* z#;|wAh!}o--Wo+uMVvjhTrz&k0Mkm(FSPG}inS=6A?7U8SXR0sMdPf;Z$1Rx#$+++ zGya?=*wZ@Bz!||}7Q-CAXoFbE;jCQday5Qwyz0G2!;Jr#ee~;9pUC%alAW%zdDO^Y zJ2>`ep>dk;4NEQMtL?EFQ8Oq9aHz=nDH2M!4%LOzm-DT0J4Zqz5JiHgbP2wqZ zjBoFEl|Ppo-#;QN-b(z0`KIC`{QuY(Xvu%vs@%PKB?1W% z5?S98D;wU7Exi@diR(_!aeTBcQG=7gR^BENNj+h7Pm%Z7AiQp_`D-ren{worv0I(g zw=XEM-c4@? z)pQ4L;xNlT_k!UhPx~OSIf0bui!%!?yGU_V{PI&pXS1C`t|Uh`S>jv4ZSXg{#R6*f zfif+zLK7SB6QbbQD^tZiotDUL_1+q@mP)?O@-hB;C&j=SzoxHoADtRN?cYYrN`vGFYM}Q30zUBHBKQU!6X!O}<%7vFzVc?c2Ei ze_-YnDX;(xC#gRyyDh4!iV~0Dbp(Wo8Q&4v%`r2la{tDidm;qu^F|9MgI17|a4$mx zCa($J7ZH#!qiz~H>87}I^@-PKirzws2!x%4@LK2(ho$6-GP%y-<>iU!)qV>KmeuP@ zr90~zc8VgfC9sSv{IA^)CBpJhX zofH)0>%=$O9zRi{oN<%BFd3q*wXSug$}dLrmgcbQO?_8A@}YZ}H~4ABN?m9HQAtTM z3ZbimvIxW;{GZod_dGx&!q>7yyg=VclRk7jnerHhP+X=DKV(zV-QoAwkKZoXFK0NP zpM)KrguUfF1o3wA*hB{Ufe7ultD?JLe-9OEeW?|e#RkjlyEj{TC$I&@GbtOX0^~0O_{yc4I-f|NUMrU zLKLkBI%knF@oWMR%}cGcOM2){m%d7!@KYUD_Vl6ZQ{^@+c|q-sX8P`#E6uV*xKZ^X zcZJfLnH@VrC%@S-7<@UY$V<=5c1IUxU6aMzpJ9xe__p``(tl~}juyDP!@%jdr$DOW zuNl8mUNuI)<(Ty8vTJB3XhP?XQ3S7$S)$qoKT1@w{Zd?Ej{#%_=1dZQ4dfP;_9L*f z#`?(eA-fVhe>zA^aT3?T8IM-U?gMG57w6-mo;8M$95Sad4{Lp}K>3nqNIX5ZLAQP^|Nt^g1-o&na@tvff8bXB<_zq|0r%pJn?g~f|2^`1(%(#8H!17 z36!t)9L}o$a&$DHfN5Qjr>IleY#Ry)AtbdD2mx3Qa@oK$l+l?>=ZWSi!nYO^@eD** z5RBF}62HGKcT__x{9+e0bmuyKtCwpUk2Z;Ym1m{JAn;_fkB6Qw0^`Bx-KaIde=ls)3N zKV2dM4G4FT*a&tL`+2t-pgRTvAGM9W9x(`>3|P&kX1S|=o7#W8nc6E(UD8!`G-ND& zpx&^s3wmO7O3BlGzO)zDPnEVDMSzkk8 zGlRencF?w+lw{!2IE&1HSB%MCX~`k;#MAG8Guqj0QzmIeBQRM#TCiY>_q}-UI#RF| zE3h0^wo%SUU4~`Y04IU^*h71roHD80(~XfN07{CJ_Vc@^$40A_XzERzlN5qgna%%T z{`&}*^`D>R@;mU;Q2Ef(KW$zSBU_5PI*rfAKwqd zvt8beQjDrfX%*Dd>VZ9jIF9(%`G}OWKR-&oRNjy~f*Ii0eH`tqIxsy+awEJvarSLz z`Che`#^6g{Go9AQ`j%x&&5zj>`w>XM>lI1_5f}m6yKogyD(_&9`zSMSK()|4N5k7$ zi6a`g3AS3MH9TgZY|=yy1urYe(UypCIA3LB@R4QCx$9l(mn$M)za*Hac=Jz`yikvc zf@a6P=*s>m^Hk&=H3^Ofjw;RDH91%%!eRw8^Ru@L1#iVyPYVu!EuN$W`OZ6gOI}WKO-il z4Yy2%38S;}KSmI)1kY{$m+KQfO(JZm=9;)!zVS|uWwPu|^7Pjo4E}&c99c~(Do!W# z%1KJRG5yiH$3`bXPu?M}V7&!lQPuL@_(s|*A5zA*SUFi8K`kq*Lf81V4*=w)^6|Yz zv_oxDvg$Pvw6ZcGXjTx!=DHO(LOeSW98a8WIe%b_flnF8?F(zE;~r0*f2$gZXfv97 zP3@uIWUX6RHXR?V#>Es&!3}#*Y+g{n7IGKlKKF_G%Ctx^x-2^uWSe3kQuT)+**K~M zq7sPJs0_3z)~?ujH^(XVk55?bEn>V;q>m%6kR%I%MG%r|?5@(?>N?WhiwM~IfgxsV zQkM8QIEEsIIX59>cU$uBKzlz*qqqO!I+L;xA`u)j?+l?A6}LPgKfS5I<|dRDH?b8S z49ELcZlMrwxu4r@?XtH|1Af^~-&sAsasf~mha7lH6 z&(Ec}oovF2b0n=}-Kbg6R$mNJ^*`Y?S-}Zn;Y@W)#|=MKb5Xu$2sJLA^K)&ck|;!! zCYyT?t@+c4*y?hZdO1G>*B&C`tr!Zd0435l7C);eznOrAuk?`iq@ki=UP9StYnewA^>`GQ zh!6?-ZfLnU40%S#;2ChDFty0W9DS2XW5TDYRM4YBTIVnqKbT|IR^Y1^*rTFlQ(sNq zVz@xdLxr=G$BLp;=7hWeh379MB$c|I@7nH-SdxRo*UoDkpq%~<+smAl&i|REaOM5? zS<3%|g=MS{`aiG~;x}R(Oc8abh98?R(c&~WVXd@nS7Z+6Bj_U^+)~bQw3nn_&9X)x zfSM&Jv`PMxcEP*Rbgn)%3xG@U4*d|hFLz;~^;yjzF)Zej{w8q&7vNX4^y#W{!JI!b zA)$b_v`8@*U`?l9CI;dsw1zSRNiKn$8NEmZSz&wZMz`1S?>N>WH8EzY=fBG^*70BV z9D@Hhh_P!(`7=8%m=iMtHO>Pg9^tBS$7Z|A(I++NcC|Nf^T&eP5y<=h3^9_*gqphk z+YkdqFokK(Kn@HYe*O7tsMkReCv(T{=bb(&qW${S z9zy}EM1-MD!vdF?wyJYz)SW%4l=RwJp2Ze)Q*yzqwf?*ekOD#+KQ`2iYP;uLQB48j zsdp}QXF$Gw6;~JCdvgP(j9nmTwOH?eQ~3ZY=?>d>mr6S}CFbu6AzbBSw7yscp$G;N zOq6=+)$+Wiw{k^96c^$0y>K|)41P~Em!4uZjmpENprH|gMMsX6cIO9?#Qga&r_ z@qYG(qvWQIxHuD<6q6Gc5b1bFS(ED*H>J=NNop~jH`+G(C3^9+wVjXDf-HKF(KL9@ zW3^mWr+jC{?u6$yCDE<@7HBsPbXsiUw|GQ&X~TuBjqvlGH*u_}-uTT%@cmhU;;rkK zeqvuNKEK|R9zB*I|E`{Z)E4xQ#czwe7}|0!Dw^@x(&llTifmPNzng-WJB+R_r^~FaInO=>NM& zfL-+Ox&sEmf2#d(l)vi^LjU#)8TkIQ?f{SY@45r5zv~YAKm0iGuKfL<6^4k`xZiu` z(*C2KLTbX-b;Uu;csz}#Fyyb&1Y|M!KAuxBkM?xFr*#V2hP8Jx+%_Hu2SM_SF?8IC zes)G{VNMmhsnX^PD-sJ*(sw5n$|++ak`k3UWnfoxY%U(h+F6BEq>)1!BmLzXBQIng zV+Sh44%c_;`F01;RQt|0EN)$eR1x0UpN61x|LFy&ZO<7O^SYR>v7jlpH03L@uvQ|c ztKDsj$HxER{8EbO4`?}NVt@7tsW4aXJOE|R)V^|`3N|W_X^wG#dgm}%CmGD4-^7ev zUdv3H8=_qm2AC1Il+~pptEE{_d43Ll1TjU(+gL|t!d$oP?(W)+*3MVx_rlhhFD5l{ zzSU!eNVeZI5!@Z!kBlj+gU2axQDwXJ=nW)7cwaWIW=K+eoI$!QP(!?YSKeyqJjP((^&s=kos-9QYNb8wT0%z!o zYp_$GMOk~_1@@)0&k?L( z?ln%(lky9fd2+hP`F3XsBW=grw}(*r03#^F`V9(NQYxT`n2v&aA2WCQY^>P&j0B~H zi1X#r{v{Ipvd$8-_@Tw3BDt;D-pLgT_RX2DuPZL;^RCddBM}?uRoRlm6K**Dw3Fv< zkzGwRgbBAEc9JkSV)CQ-uT&chUJIE@Lun%6JTji21ha<79I5xEbAUn5Zl6K+2=K3US?1p{G1uYk zC!(vK)^2$$lJi))D)S8d3pLK+2o~8JXdbC~uh#(XPbKZ=VVG`EmwAPk_7?8W#Rl#> zZ;x6aG28kYV0$Q*`Dm#ZVP4Dgy%*OSchKcn_+=N{i#<6#1idTU`Q7H>{pt@s{%ai% zaUTnc`q%bL69DBvA*OO>q_m7KegyDU@nt3ELsLpD;Z_|N@1UUZ&tKC*TgR(sYZ2+j zssr!)6)Zis1YOf2D$hdosZRu}zNN1>JMs0!8gtrFQ5jI#SaEPJ7cYpr3u*FJ?4L8X+t0iB29?_)Mzlwr|A7HcMscj76+Vs+JQR z$4cGLlSsC%9_elEU`ifPZlByC+GYfi7!=y-$s6xvcPTfUI>y?Pzc}HIAT`r87DTC*3(|=sA0Dt2jD13B=gN-_CtdP40h?A= zh@_K4tNqY;deQMExD{|)gFJ?e?-z638V@gJE9Su}s@M9`FVY_%+;=?dv!w6T zred%esoB_zc?XW2G$0pzNw^pU=i` z!6z)1j=q7w_Q;zGI?;0z3Y{JfuAGn+U*aTOcVh@2Z+V-27}QCbAF{Kvqf0gFZMq%i zHwSNW%Ekh7?MazJIqOcPTk(V%EV;rUm6Z^}rF&V^tBbUEPY%m>`+k(^-4~N+-u6ls zR)N)VXxj8|FQhg4{3vgZJS@NeJifp?gvtBO?hdh+GX&?^rpjbkNp3i~ltpbjvvdD)@!IgbliavI&6nq~ zVwj?ux?^NgQ?)$IVH)YjatrD~s9zb9PQQnFjME+`VKJ?XHt%sKb!cx6Ic=Sh*d0c) zeLUuqLG$eslQBpglzJ9#v+tG$+8-O=x1Shl+MT~KIiK?xji^XILee%1s=MxkR=g7@ z0+FShVH8M>r-UA`umjK&|aY&y2qUMnxwnDt<(Cb zVeY8}A~rTC^((H!nH_-pi&vZrI<%qnj*l>rCp>gasGq&@0|3@ulS5RVnj#u_^ghf_ z_YvmQ|BJG34v%Diznsj(&cxQlwlPu1wr$&)*vZ7UG4aH;?|aU9&nflPvYoZubxfmyTW-!42_Y&~#{RKeoG>SHxJSJPoEEE{`|X33WeTv9h){MZZo{ zsA8J5kzk(P#Ka&i6S*xl4zsFr8Frrf_@mFGUcMuYN`fYAA?Vk*w2dja2G*!G0$(VcdY9 zPn}WKuh=h1x+e?D5W274o~UHlej6w6cPj5;FXrBnr)@c9r0v+o;(f??X`F5L+o(M5 z$N4o5U>r8l1~x&-lF04#rpsF}OKk0SY#XopZ5Sf@KM&YC+~~w3?QCnz-doKYBzhtfyeeYA03a7(y0iJj1Oq2j=;HOB_Ar`?p`eUzioOL z8YfS7>5V1#?$|N2R40uxU$EZ;A{MKxw=kv%M7x>O(5#T&iUtPUN@}uM#vy zM#zdh$TGyNj2-KzjLP~>luetOT-{x!;}qH3imZ%)67$1o%G~{`zJ0lMnSFxFf=Q6Sr=asH&yv^-Zq)CQ+{> zS;q2Yq<7twl!eOpzhTZqhE}@n%63OMDlUU;@y6Zv zzENqZWc}QysNUqeME%`~;EZK#@7}YhteYi(11T!WH;InjDSx_h zQp~dPKh@W#@X9HgObnN(7T6D8UG^a4p(f&s8{F3A;;1c7Jbx3JL=f+hXJj&?5{n>x ze|}USu4qd8cGN=K#^|U1*S&egHP~QA5Vtcnf9f-Ej3BjexXc5rtOFi#I3BZ zSR!aYQPO4_-w%VKvMcF*ep1;OX{bo<$vOG>=HBqYMhPbLdem){H zX7V+%_cC6Z#HCj%l59*Cb77@wB3NMQCgr7T!eIr1=yfNMM(Eb~-eq*N{KkB!)+5<@ zI6J{*A(b`D()6s#^be8q=c8lthd4Lg{&X`|Y zWtFk5-z_m;qFhAY>Q#`68n#+L>W5s$Vn0Q|(mal7%MQcu0*8pv4Hx#)G z+{e|{!zRa~DQ4YKKK@CuQ>GsFABi%~a+;P;U5?|>j)?A^E)f$3x$Vq`7vQ;pW_dH- zduSyw#yFU7(9Fw(F2nXssu#^Cc+Tmj=>%P6yQb0B zv0{Jg;v>|HGkf8x_rbe|CaWV_M;nijAMO5L#r5%}C2AbuNoZs5Et05xkHWiY$GZJG z9B>7Jl34H5T1&@kd~kgD1bg4{igGg190|zc4hQhIr5|uA2-Y#1JuAfK4>zt)d-9^d zGPe&aJgoOHwHWXd`#e24q(2tCxSq=UpVP?P95|iD=UbaoV@JcL9WF&iYMsp86bUNG>!^u0WGAOJ!a z(?J{FGcWj_NxyuWI^*{KKz=>IeYjZ!fJ0(>m4Do9EICbW#vB2c^&9@lp;KmI#D^Gop;(4|ZTC$@JyT9oqa(EXAaZn>&SmoZjtLAt6IP)vZ^5XtoB)94SW&1bS z(YZ9+$D3&XU{N{ynzH_vEyA79U<{d5JyK;GG!@z<^G`nXyyXq(Mmjg;_@$)eAB1N162JCxL?k(vmk`a8^*Vbto+uT&a-4A8hhCD^AI8z2VMKWaEvBR$@ zDJb%C+N1b8vzmceI0`0i=B7ez>RKX{&GHlfUeb5&u%#8hy?|N}`sTDa#t2D-C(JV9 z5y+P#JiBM4{~-6VmbQ+VWFVe5lhNWXWVlYT>pt?JM5+6u_||wOagR@Ug2K zs=@?9duw_3f2{q8fUN%`7!NTBBX;ry?hg3dFJvk9pwI&Rko3Qhd@lpZ9os8VW_Km} zLk0jh7X0&}0}OxJk#IEf540fdaQ=!)0B#!F44jmVBL1IjKvf|v27-~CB!?3;#^mpU zv`2nwme9Z01w{Q=sp113A8p*lzv&0|RMOcSYddvFM^MwX zRmp>K>B0=|$W$tGQ;%P8ADQj5yLk%Q<`X=@97~~_8xg@*zgv3>rCN?6i}EvI$0-vt zb_(7DBkR(79@bV`Ga}Qlu1+YP-uqOqjjK<+iWr#41V-vr+@8k11OPlkM+DZ(nb=?A z&9AquEIsaw)-B=5lt~tX8JLq02jKQPHI)74XM|kHpThHP(UpFpTjcbiOR0OKP#_5J zEd?OdO=lgs9g1G#<>R=H6vkTMFB2MwG@F@S*rQKZbt3cjEVHuI-AGTeDcS)-CLqkeOJLh$Kk4O2g&tcV?#4xwMNb5 zLxC_NrW%kgr-RJYht~Yw%=Lm$fU9uaepdT9>;G_dRr}u0rhSTe%24wUfFIDMi=9i6 zN+gNkGi&XrF^MsVp1}|KdDx4Wd131&s0vdUYvX8}eXzL-Wj2klqd$eJqEP>=-Tvxx z7XV`A1T%8Mn-%xbn4$C@uQ{)#c^L!E`ud3G{j7{3TYl7(g|GFB=iPB<^jS~=hESwH z@3#hht{w1>=ue&_ii13PYMrhgVav|?_$DKpid!@jh6jZ-r_eD69o`eT7J(RbOtIk> zXzZ|EcP!K`7i1*dvv02#84TGM#K$^Q?wo#(!<`D#!XreD)`L+WiIi;j3UOR~fz_^+ zpfR>;R^>B8TC-2LEz1{dufSUS+2P{E(i&Db+w_Pp^kKC0TTvPO$E6g|X_)*&3}zif zawfke2WEp8p9Drc#cfZrnbmpbcL5d4(cw0PscD3*at!(yL(&R9M|1GeO?JP5Z6v4zu0k!N3wz)S)2k#mxGYAi4Q9`w*|5 zt(U#690TSpKHY&zr_~sW$J6pbmTo18u1QxU-(Kw% zMC0BTXV}dC%8!Za_!a!7kWEVL@WlP;>(hp&lOeD8sCeEx#BvAK=0<-X&nDk0mNWsn z#}!~6U6wa5$rgbZ--OS@iO@X)d>lx37os@!sX2ZbZvbMjns~B{2uHOsvP}$f_}ce6 zH*AkF`_k|;@-!It`dYIQ5P?FliCg3porGYdC<6ydckFdTfCM6Pm0=Q-%{%q=FNW<@ zxS57V@UOWrqm;N(H5lQ|YEoBKSDWrN;lv8K@UmA;=8$(;Z zJYlETfupo`Te1!u6h&$MQW|D5SWkI1RP1`{5kbv~5#H6au&2f|LF}9yie!~lsItj3 zfR%dRt~B&G(E*TVld(d23$pijSZ5+2{1b}9YQ@h7>@eFb%BXmeC7389!wg(4yvWBz zin>YbUTMNWcyB~~7dt-QDz7b`>KI11UKX3w9vWzO;>+UvxLAF19Qlby|Ebo7=EGxR z6F-r#>?^gA;)LzwT?4J72L~BVP1SyT+M~hSC&P~56(2{Qr1It7%5}}5er(>ZBh(HP zn>_fxLGC@*1>$d&i1bRRDrJVThV%(drGXz%i)8?59lqP4z~QWMW(&Tzi;iFbZE>%0 z^B{Cv-wwj-&yG_ZjCBng_{nv4+ee!NOWG${)U=Ps4bai}XJFBj8X=@=j=HmWrmrnk zt-BSX#L_W&!{Q5Si&!pTN=cm=t)S)^~$0?axTa zx9sjjLx{si{Us1kq_Zprl>cEhWgA?d;Pou;HAH2m+!{U$!dAhXZd#6 zA;V?lNy3zykqgRTrW#~pLrY=bPy)pY{q!jDOY3S43N=~r?@l0E*ezF)b0^j!X6`$c z+zlE7jCWqE%x!T1eDBaVId<-BdlVq>&dFM33LV%nHE%_S2^`B1l#Yrj0hqZTeb3aq zVg03tTt_7R)LYba{N`{8q*JF?g9<4;p$WR@Rp#|NjQ$H`Hi_{3#GpU4(8(}^Z!FR+ zbnDf6`3QXW0+hw}S4P8m8mZO9b#xH~U!aKNs9Ptmma|M?{ILsW!i4A)z=)Woj z+k>%6o}G@OoW*~qNLR1=Qz&ts5(QXl;P^qz2vsjMv2P1Ofdx6gNVHdh` zoa%v3yv92EmWobuP(lWSEQzN5hrTgFMf6--x5e=dby^3^g&&&oTRo-$&Xc@R?E0zM zHa~&fLa?c_C0ZQwML7vMn?r@>xK%CNO1l-w|kjZ*0IIADm;|69@$z#~}-!j$l2$>cEoypSL6(Rte zZNvQZr(KTEbzr1=5Wsf(Q~%ps4kdU)j#XP+nkWJz|Q_q3RB`pHF;h9b~wO6QvmVwO_fwG0 z9<1n$K!OjNN(d_KJhjLXq${W)Vw>{MbxZc1UZSRyk=){>1jAs+wfiEw*t!?Ln?GT6 z2(H`^98a+l4WAdB$Ql=$qO`k=VyYHDJKDMC^&?7hJ><_hREk8@dsXX!Bgy54r3RK6 z`X;J?HPu|?w*4#1{%v5RhYF!$hmOxD3c14(KU&LtvTe`oy|u!NyRsUu`Z2NSaWAUn zX_yYL4_{VwdH!m=oxNU=!twr>dgMjT$kFrK$t}EgR{uDgqVZ9lrN`+CxAzVDxq({Xwp-o}NkazNUKarm!9 z4wwyzglPsAn0|h)$h3wjPT$QLSf|O;tl`y}4GF2)UgPj7rH;UQ$RE)>8Yd|lEdflF zj@!e2>sk}_g`Y?{O46{p50|6_FTU>6dC*lS`^jRzdoxMNL=5qt;BiV=aO|Wr9xt?a zz3svoo7llGj`-`*Ge-h*BZ>NEv1(`Y;UvNnC2WO{F8pwF9-zJdi_P`ugKR! znMZ_+sQI?egjzNalW)#sBHTMtky(G~+1%9w3&=(Pfy#Io_o5mJ-pMZ=8e>`3Pau_K zQpb$S?OTje2*WW_6)X%3uPqv609Gkf65u)FC`@^50!OPPT2An=b-(WU(>5RamxPn1h}Bib-Ou(>MynNN3{T(C z_19i|v%*8I>h*dO4>R*5$9Q|D@QtAhL<|$)K}DW`yK_tO44V=|Mye){cJz~qPz#Ye z*{PGdd&Ymp0Yl~@1w!2&hMdi{S*c|m8wo8>MVz-yPd`hNQ7uMMBHm zR*4`4B;cI*&Om^l3y9E(>wd6*94nB+a9zm%(4zoaK6ynUg8o3-;T8tBDByHnS?uON ziGTkW?HY)HN6$$D*famlNB{rO!OKfvNV~V|erjaE{P1bO=P57B{~HVo;FJ)byEPas z6}PuyX@%!m*p<>%_9q%iNRj@7h6MntH`-O%KiGJYlh(Jit(mb1sU zqvxL1P-~|^{O)rFftc8;M(wd-HaZ$QS#zeO?S1oU3#n}4|Avd1{})_5lJg&2{6IU# zS;38xV1mp$DehBvkVrh_@zZ{jCQZD8$F72FFv4+WdYjm;dERz6L00o;WDo3)jZL8g z0q?iAKLTW&-Gs+G)RU`;hn%>cllrCPgRIlLB$`%jfbar!&hu-EYoSLKCk=VQ<@i-B zA03|)Q?OYeb^EUPc#6W0g_8o)XQ*_qGcWGfnM!-T0wxwGcXh&Wx~BLCN#HC12W7km z{DJo^^DuKzLPxeEnu(SRAA;9`!6=@|)d!~H)RO0s@5lDGxUkP;&(MO%@B7*R%mVmi zU1%vt%uk+N6GTqmB;NE?YIn{yMtd)Ou6R2~XngObMxnSP?Cn7P2SA7C{0*S}XITJ| ziGpTM98Jha_L#9MF-qQFVJPhxsaxXwFj?aFIjdIU-j~Y#SEdG2+mj#C6@@c}0S#!f zZM)3-XdU5B-vST^d?V<-blnpan8eH3%7Y|N-Ya9by|mDa-HKD7tRDrAHa31mIn?u? zXQ83c5YzjQ+Pf&2SCjlURq61cQjvRf4_IVf?1I4>eO=?^9-fQz

<9MXM^9Kl#-CueJN0a@lyA%0qh{kzipodp9rq;|o zTaJ$WD^Kw#Ckzp?hm_(}nZ9nRB`{mHRg#MVYrkN}$upnMr`X zw8%3WHFYd>rW6?pfSHI2mo^f}f=7gc{Z1}fyKL9&aA`_=dXHGG3Tv>)Dx%weg_`jV7m-Av}=CGV4S(9th#S?=XBSZqIol%Jb`wM3fxi|6r?<+|PHB^SDb?u7>7* z?*gx8qd#5S5tlBHa0QYP#THzFkM8gzLxyKmC&?=u2Ayxb{x{)&ua7U}0G6%MK-TDe1C_ zi}(Alf~0ITqm?i#NgkD}lQi%Cm69osRT&2Zh_3j)V4;VqHp2cRqdwKcqTO_jr)?IA z!J`Mg-Tkkscf{vUPicomo{7P-~|pAok=G719ROyZF(Sg+7HsuyvE(i*B4sEe8xqiUM6O}NtP zaR>~7_W-__CnYzGEq2zT+=eYF=Q>aZ5D90FoBau*4J_h{C3>%x#d;??uTQ3iD(Ryo z3ai;1)dQ(Z?RH!lNXV16NptcV3IQ}|U@aM{Cupn-F7~dv(L^ntgtZcy?6aEE!$*a7 zGs??xBJahg(9+3hc{vq7W$8gSJYC92ZL`?89W_$T;{dVH?)oF7E#l_5aPMPW>31T9V@g#`7f#d(mUWzgz;YU4aALb}j?|yT`GEr+FVp zZWQ$UPQ?qyNDU_o$tU9t_4kL&F23o=+3I*Xo}TXu8_knvd+Bw9-Kj6u+tGJle!k&Z ze@xwJ)|exAxI2(w+dP66sk~;kMRKy6tJQz&UcP7*oYiIkg2YbsKIRR3UI!)IFQmGa zcpP4Dliw>SeK=>z-)=iT@bH?lzos1#QQe|N^IZzQ*Es09+O%=-d+c;>b!5~w?FuSc zzVG-T(<>YchU_FH3MxC|o-Ewz87ozr9)&70w~s%wc*A;N{+2LdWGPC~>XI+DNUtl` z7;4WB-KQurR>vEkCm>7!%)MfjkDaL1R^n@o=r4CGq^K*(CfUr9bYHgp+%eXOe!(we&uhnT1Q{Prq0B=;Whqi=NqEQf)9gbXHKakTwc! z55s>w-!uGQ6`;$$Gw;tCYjKcS_s z%ZnGfS093*pqtBfgsQNvj^3G!Zn{LaRFCQOZ@15_)>6SgpU2#=fL!sEzrTzNZNeks zl6aY4o)35LaRfS0;_siZt&X*agqKRR_qVxdkF{&~^zTol4lxEktb3E0uzsY|Ro)Nn zsfPGR@NzCcPl5RHJ`)p0oVWLGFyMO;a^bc3@dqTIcXJi|Jm0te>`UrAPr{mGKSEw# zS7Y$8=^Oz9-+ISL^P|MA^DwW??Q&0+SV%?XM~XH&7O!K^#QQIsI1Kxp{ypbxNiy0Z z{nKhIEawJ@BBh*FXJ!~zd;98C(rR7&U=egmDh?wSMRfd8lTDjdAwd&ZeXG+IogqIk zvM!+KRvoWk2Aa^^-d45XPtTAfclmy9FRPgzX#+rTy}3f0x9?daBc(O zRmx%!^jC-i@0D4F`v(s97u-7Lh8#2Ktj{4;cL`35Hfkbs$TY4=G`SXcTBkFZ#Q6LX zs@Im>28Dd15dooxFRoixsHZS#{6Bdn-ZNGBfWeEU<(BIV-FeXel?7O2%WIwqE&hIpFq_Q1vL93%@5Q6FM+ST0kT!mPZ`&&NEt z)=MAJ75RBsOz#d#QRYrR91IFvkX(5BXUf##U?pb^CI>V%{Hb$X3K@#7?qu7I6IL^X zgl_*~sm?@HosKuIP7fz57-fpOY6RQ1$wwmRwM;1?XS+be3Nsw|g$q#kX^fM*#5;nT zVOaFgmeu$%W+fwLmpo=wWFv#Ww$iMi5*g0AXUR+7;V;#3#_#elx$-*}fBhZic)BkE zjo*l=U@JV+LmuO}gAgIz!y| zm@iomR_|EnnIsy|6F7A1^bTm+^Fs2zE3i;q!u+DtP4Ylze82gux<=Jn$UE`33a>W@ zRN?z$=#)s0#xhCaLHTi855N3FBsBbYM8abO5(!#u?16JOBrg1J0&;@{@qV}w;wnDc z4O{iiFH&bpY&C`bnrvshoZr}H;X)xCtBoi)-WdaaN|*-i?3HdNj17`SdT%3jfpD_c z!$~MHk58>zLF)?u)0O%lR(`jG>N?WVeK-$DV|&}wv{wo>Ax^Af3n^;(Osvw&nV(ZZ z{qx+@Zhu6_FUYB@GHNLI+z^4aFkO-hzstzewL*9%>`WI&4^dL5Cz)YbT|k%;Jp;Jf z?NHZM@b;R#z^}9_uT$+EAi>yO@4eO)m8&C8LBuF}r-TnSzNNI82? z?qw?4LEV(6@XfZfy-*4c+rQFf0$al8qwcVv8f9PPRyOBV791%>`#hEh+pM_M`ho4U z{Z<%?hn;Qm0YCq?hs}K}fD3{gGXLLC1HkirWmR|GQ;I9|eq|R<#g(zd?s!?JTcrOq zIjH0Pjzi{s#EaK5o9!_&^XjI>MFMft|8PCa^MKg&ytCT)YHz89{WOEGW7zMM=}$pQ z{ojogjBjmZ&n-2Wv$T)U7M-|M&Ty$l8XRC#*51n1^W0nEbvyxEis~}{2HpCO@yd%2 zIId})b!VErQVVp2L)q24G6w`2)|Zcd9+kJBY%_f?0CKfyn7D=`ufzq04lPxDp z^C+E$w|br;6V_PnN%THT9-)0G0n3*UX=d)GlHlqOlWOWCm41uB5?2N|&PcTfJ!UyA{!U#v8sb5r2 zv1Zo!;Kp*Mlor7Fx6%b7Lb`lA@cE;$TnpW+8mS*$B46!K9x2N4=-d(sc;0Q7Vf<>` zE{)S}?_gnlM$0YPaS@>qd}e>8)1Jmm=D;L6tw(a-x;g$Wr=V-=Dr4q=PaG7j*(A2?pkAJ z=jTTRJ#&8c9cnE6bCQznWIpT?Xhvh5zE~hv=%b&1W&31hu>$230AGOldjQw*IjVS{CHtVqGnE*K0OAwcTLI3HhUU*bxl?d-m5hAfwE(Z?S;GV8x#Z0n#`WiGv&2H2)-HdsD0UUII&IOx43sCsX z*Ph;r%KF#5+E@G9~D!qNO0hxq@nEF{-$^3bsbx2~qo_WeCd z5hA89rS%gE7|z+w7Tx`sF2)r0N6j>aqtnCm%n31GbkXiVw2kB}kX&k55!UnO<>0{c zeCNGCwIafa`n2iDNlrazGG1=}{QTMR?iLX?NWT6bU&SDBpNG_AarKpDv-PE*iW9;4 zz#b%c=7#Cz`S0Jo@mS^(THBlkeliO#4N?x0jpTmyN#(p6{N(laeS3d0K2E?PF3E;u zaSbqw(|)1)jo-)T@bJ{*D}@D`+ml;kId}{|U7MF)#H>&-dAT*+Iu4sMlR)Q!l#e0( z-Op!?R4U?m9Pwd$s0RE_bg^2(y>AVZ!gVc4lY?MVJz-2-5Hg7{*mgv|+Md3L) z7$C1MEV>QWxj0*b!On*qwTkj;fl$YGSVUS5bDbJnISnq2IDEARYkyXfWF$7#^{Z;l zVAggYh}pv#P1@LLNU8upisr^|ex0#hi@Zu<5uioj??9j$ESs|2jh4jTvf(m2`Vt9-wqt@3>&2c+F#nW|1loHi& zeSVbJVUo3m4%50l+ZgwK?`8F>UK*tw&f}RJ8*I?=9|)0NWnZL4D@Q}-@xFXyrdCcc zO>^bb`t>FGN{BbDCs3l+;J3(R+%j!7CYN*gcWShQ&BEZBLCTEpF~_DA-THDEc05Nn?9=Z+ z67{ZfwE?Io16DdjFEhJgkzui2&sgL4^`2J+o==X&dZ(cm;+NtrUKW>dI%iuYvou7@ zN4{}QMAa-#5uKf`%m@%@8JhQp1`rWL{1W-eKS;2k2S6Ig)cNja2CvKmuS|8d?#0ad z!r(BHqJ^XH;zgy0%un26i8nLaHp>EG8}XB_!Yzfj0kTacCc}hex+$3FEC&e~6CR$& zy}K`TWQNfxt8B>{0^l_BEMj6Y^202&u=yhLXq#<%$Qj(+3n)R5SclzreLG!U6N3%R zD-K#Bv4cNd6qdn>FAGRfVpU&X0`P@8A68lrD9R2gR(`>rDYk!@Y4^bA{ldRRnL2dJ z4MEPO+?Mv%l6HyT3J@>clig%FTA%S|w}l9KnDNd|@k|2)BUeG1p&A~nKRirD1z$Eb zH#Z=FUlz6M)jo#5&4b&&Gvy32?t-kFoSjX+`EmaTTzhvuHcTv)T_oka2K%I7PN(m6NUNNX=}JK zTRfLn+Nlq)?|f^MFngVQvmtlA^epI0OF%><4UmP9pq(+1$t!M%o(E2zjtmbv)K8%? ze!uydX0d4j8<9x|OU@SM%EQ$F_s!3EjK}_2cNl3gom~-!rz5B-kT$+VkKx&Dr6FmY zQ11LY=alTUJxzEn5u0z6SEv`+0wBz_BTH8e9?ycT&5kP5lFM!_icBJJz(#*!ybH_J zpp&44YV_OUJbzp&ps7Ckd7nQQj+wv7E(MPH6f&C%0xZFSoaVT&(nwd8iy|1ih=bpT z+zGDtONQeopkkyLuYXiw0x*FTQo=#(xhDpZP=sIu`+Wu(k>HiV&EuhkczLT;0_6|T{ z%l@MmmOXFAc3&!I5sDlpD*dy)61s;+p03c*as#?7@KSdUhBI2OTKS=i-{v(#G2$?V z2c65UZNJ^d93)BaPkaFL#TZd%Le~u>LTD+k(IhJtgJYdA;DG) z*`L^8S^>UwFJV_0zG@_?qJ>MiJo;UfVo43F&DXN#%zJs+3dO`E=M|~O;S{v_naS0S zIiQm4C%ZM1fR9gzd^E0b>Za1nB&@-#6_pCFn>yV~i$JKOF{q9Px-iqtm8tjZ^PpA! zs?{BJDYQ6x?m4pEpYrw+&&i|uzRg<$NXo55^zFV(hr)nis zC=Uf~f9G!BKD#MFbaxXbs03F3JN`Q_GNj%}%1FFEf)@?Q*Gg2%x_n4Lt!c3xSk{gn z;;9+$Yq$B=JqkVb_U{%wXzqEWo7u&r5D%N~4%ra+OoKO|)y9BBD;P3yE|GRc%!26P zki+a)V%`GTu&uU*U{%{BMW(g0A~P2aaD#HG+&AxAKTYUCqG_K`JjNutqXZ3|zQCgJ zarx397)4GVc{hVk)0bva)WG%Rkhhh>nRK-5ee98Y$jas1m-9(`31@MX{i^H72JHQ& z%z{WY#+5396c@rzPDUtEjYqi^3Oo{Pm+e{6)kl!jo=_<`eQGFv zTOeK9@_1Q< zi4Tu8-Ysst8)#;2sn;n>UNGHPXqK|Y`#knJ%)#ImVp~__5J8oke4KQ8f$cSL`FoI= zt{r=IlnbC_6mjhr@2L?}N@iA|)E8!KwLnzK5w^plV*tYaHdCu4g*_SX;PQvb#dzLM z<8Z)-Pg!Y;yG_ZQx_UT?M2+QA;#u#wvFPAuLD6nl%pm^H-%jZ}aTuwGU)e%_f1W{?021EFu6DH!6A;* zT0yC`iVC08$-EVWuPlYSVf^APSQx4a^@N8Zi3pSiiDGAvC#rdwi(c^Kddr@{&qwrE z`79=?!i?M^^+ZBIUh9_px?p5XN!2?pw0-Axp}fe>0#y}SnNxBjbbSZ{;84;RP#RWM zR^@GRGkkE<%pg%+Z7L9~Qq^K~ussHM( zv4WvZKCC0;+#0^4rKG6BI^8-R^cf?R0h}v}F}>;s6u9)Qyuw0nqCK+26urKe+u0R;et&Dw}*ent?>#Og6+?}n0!KNm#ff_HO(3Z|q`B|TQs zZtr$rnI&AkG&OoUntlr=%lu-?)+8>f zP^G0LweO^BaYz_**Io=Md}xRm7XrL7uiIt9;;#EiU$3;E0XrC};rvEWLR^EmV~U5* zf9cSLzbIWH=%wP~*4iFDwLgIei;%;ChYTP)W}XtJjlq>@6DZ8csj_ov=$*Qq&O@>;pCzI1LPe(@hk!LyHK zBEvXN9n_*6*H_&E*uqZN)+C5%!E`SvDLpI`S0fnI%N!`g7LOK0vb#?QR?c+u$5D}mOvgN3!_r5D;a zvg#}RR!(5!x8yrP(Xvt;^@j2JNBPC0!Ksq5zwKdYzdI@5IO>tgW0;t)WPJ%66U?ql zk0qjOjwMMLuCY}hUtA>t_5U8m4IghATgQ;#A?;D_H^z7KzFQ_ramkbRz?-nmyq$kD z*QQ?E5UKWI5q=uC2B_*4W6d0PC{NGXIhOPy-Mqzx5TNclxkJLkBu$atBL$|aspV`k zT%;Dtb+jk8zkhds0jDo?pAQdzML~Z8p@;QfZwGmPhA7d|2`@COElZZD-k~ca+N?IH zU8&~c1}$Z+HWMT{_iM0D^&@VK`iWQYvMBeQ7q?=nMw)2kyG@En+0!;?Oe1>lwxD6*#bv*~%U$ChUO$4k{bv>c_@^r8Zt5{5KjWbwtT@hlTSH%2Y}641DKc$3qAZm zglltFSRxG5-W2R>xP24B_ zbJ~mRe3;cUN^iZ!Fr6uu5|nmU$?34}Eqt@+74% zZp*~go9_F4kzq+hKB-gpP?CK?Yw%06h`7PQ_72iDv9MXD1Cry+L1q}~$BEkcJayZ5 z%n(F49IQg%U;s7bGy%0{1Y9F#m@ul|AaJg>V6ITcxA(d@$aw{?$;puT3>#1%Nen?sDzjV~EUQJb zEQ%c*^ffumpMOo{xb!Q|Q5fQxS;5Szz^`R74H?TC6&9NbqHNdVVwfCQ+^tK|uL@3x zUpi+EOH4x$fEeb+(-hxFr_tD9y6^-D~R zmL4y1YJpFbHH{=iJa6T!sn1x>4oyY&925mEm`^l@aWu5L#7WJrJ8$OuXYz`#VRH=9 z@MNUH%&HXKZ$0r=kQ9@=(( z_UB9F7O{s(M+?VMp})XzmF7dHw|V>1hq+p#ptNcv3b!9bO&>7}3-gK$bjK%wiJ34S zI&)#O&Cc-A_g)T?ySIzlqbdE?tMxTX`38`tN5muZDh15zO9LXuq7qXGcq~#9#A4)H z7n#Wkus~a)*3Ju>yV%G+jT(Qw;j~1r*{rAHe4peLAkk(f7UoO<2djbpA!bP(p^n@+ zm({C$O2#zL>sDQ5%8|T)C$XQUmqJ>Ypqp=#JQPC@9-8CbUEuVn2|X1W*sY7*ek?+1 z)#HeRPf{ye&oLbVn2vvLGfl)d;qD%?#{>SNm@7;bgI> zK}cn0;k5>GPV%SC#3dvkLBkSVb?3hEE;HTOuFKb$!L~$I*ix#>ox-0gCkmSsjFQC> zrePMGh_W>iOD39ZS*f%Vnu|+5FJ~E1TYn<-^#2(m}V3^P9RTpW} z1lyY+6~!EFgH%942^4m(WLeD-nQtNn4s-w`Mjvp{j!Z#`RfP}{N=(^A`b9=HW#lG( zsqnUTTfaXsjT`E=#&eu#A7iNX2T?kc(XvQzv;6KU4b#UAuY2kqP|}{*GttLrHaN}3)~sHaXj<@mJwJUZFY(VG=Wq)`{}gf;^m@yhQXIN+1z>Z_Av4n|(FS8>GJt9Wt5AucTn zdk!*xWd*C+qPfl`-O0aZd4eu4nFwIF0Jc6dk#0$yz=2ZfXg~LLxE=ylB$Ji-u_m!k z+_fLF=ebNhsk)m&bSzF%mK1E&C~(B{02Q13ONPe%)n-^r@*^a7&K`Wk*tNp7<-O!uF#(J{XuV~!A*c)~o7>>W@OHw<$x*xy)A%vROG68#e3XIye! zuDhl*%^7k^iB2iYH`F<6xw*Qp{K-OS@4PJgFr$qrZX%FJKB<1|&r2?#?a#Z(%1Snj z!NMhw*BsfmBDn>Y&{o-apXEI@7x%k?5Tv7=ftAi?8m>-x+3CF7bPSEl?E+nkT_(bD zT7xY}gOOxqRba1sO`*|{QLFf<^z)2{$=8cAqrZk4wkNx#C|WTySW89XZ#<;AU6yU? zY#H|bewKT;DA;_angTpUGE?ts6f~=)Ez|7s_itpw>UElUf%|~pQs)<^P5W6YD2h^D zoGce_4iq2FDjpH!rEpR#CSy)M&%XjE0uZTC|A9}W=wLwfr0|{RVnk03?MO1nk~F+0 z=g)2AP?eo+#mvBnsp!|kG$Uh?dxs1eQ=0L+Q8=!P9g=XDeO)zt|BYkxK3zkVz>R^i zjK)d^CfdHvSvS#N->7PwxcAyVV_yE}`~LKR`*jc({({8u;9q)opg3jje~x8V&~Jl@ z%w0XU6<5bO!b**`0Bge^3_v99amh>1-rKqPxnrKfI2jq%NotoCD3<{nBK_}-ZhvhB zEF=GhW|jY&sa5?yBe$^riq8sR5pHh;UPnwE5I}KMRpIr?hgTgKZ3_LD?^aczZWRo8 zFG2h3Y2&@Au?G+(z;xI0e|9y}^o~^rzN;}uSDqLTx>(bcvg~wn`Qr5{A{ubS=@u&( ztbvJ(I|3Y#MieNIN@)Sog5yL~(CaKxJAHJ`A;3rRKnDH~*4{FpjlWwLrKLb|THM>> z?rsH&7uVwMZo$1!G{xPW;_eg)6o=vs5InfM-q8Pk-?Q)8=iGhmLp~&#%*<~xv(~fL zde*bVJUaAU^^o3WDoic5haZ5oc|EpSy~#XrdcUV<{9Th+xkh()TalHn%LT)HjW2Qc zDHcSepxf3xK-`E3Q-mvQZvN(dbQk^V_&R3{@iF<0+_+lrs6A#&^51{kNfP(`r?t$xpR-Kq$Vp)yXAcU3+>t+c7PRmus%;GC zK2GJ7egJ(<#N$~yDkxz5G(5|c@akpDjJ%56g4+SQ?j#8%)@!Wt#b1RE9g$T&yKc75 zTju)Ai4zRVAY$?HV+eUy=Fw54$rr?h&xpPCKQ+d29h&3h4|`}(H5NzP?;BY1WH-_5 z?ox{r^!meupZq=4JH$8-H`|+hlg8Uy5EPfUluFxAxgXDZHI*~bvE2?Fp8!c;RhWX z(hixtJg%BkQo^cyG^-$+I$pJRL@DFhn?37d7Cf5NnraoKmMeh+(|#t$j3NGEQ@zd+ zg5F6^RCh6`wk_CSfL|Sm?%>InwZR&^9`6Ru5Ej&q`}Ju{O+DhUyUHTGUquzubd)8` zc%aVEdt*=p7@0ZO6RupH8?Bf#Z6ab&o{LfMH_30YZw^^Ej`qJD*j#D<{ran)^}7?HvNj;t0aJrcByg zhUH--h>!52B|%-uxA|a$jmxSBg!Lf*HHIh0Ab;;COg^KR+xs2^{%48{<7Zh_jVf79 zi`XHgZD;jTG>NF2<4XuS9Blyf(=dN48mlv9q5$b9-}^g}<>Yv$2&cF^;Rj_E8jF5> zs&!->x3V9;rI*ikF9fSt9tMmdN8)pCJ>o=0IwZAtyv40GcE_2T3~IOUOgU4u7 zGRWkxx6%QFC&itYe!}rL>`l7{TU%|IaR^$L1d$!7dk!racPtL8OkD@mg_=&A71>+x zRd(yX5c_mSfk>{$*H1^6rT8~~TMn0vdkqgm><{A9j|J zwQcsqd!!xtK8oCAQ(&KY?^Pfp@>84Z3-CA{K)9=qES^M1hO983ZR~59xxi^3f0Knf zOYaDU^vu={Cf^~ZpzWJ{p+y|7WgP`&nY$|apNJf%dBKCW3caAX`;ANEG~^_yXw-EB zp4X(vaTd!@YON-w&YO`OBTJ>pnT+`OrgB?G^fBsc) zJ$<2|zswtdbP})nBHuW_x$j;4AXYRJH@|lG;pO@jv6f_7CB!$7{Kzx3vw&;HBkt z;|ih_{LVV=c0Ox=%vkTbMaFzOxZ~~W?(YTikr>J^uI^E1N-U$#ct@R+8iq~x@< zS!l?&#MM6>ru&%O=8jXPtSa{hzaO%l5W(#$+k7v}VG;#G-NWP_kR&Ab3wUb3*{f%E zxZuNEb_X}kon|E$UC)LskHCu)Dv9ZO&oOh$7g}gP^<^hsxePYuzj8l6UBUEXO;%>s ze1B6h$=qs^LtFR3dnQz`?iVA@cLw`3hvw)jJFlQ|zjLw}=2?ON_`6bqsILWlu3!85 z`nLPY5lKlSgrP3_{oYc0XZghxjaP63E)2CpZ1Y0r_xZ(z)3(yy;*iFB@FOd*fO++{ z%cido&I?y_@z~kNo7~j@MaLoBLO$l1#Tk2LSF2wwGiacZ$2Ulz%EA1U$3#=~#c#HL z>e_&au1#xZFzcQdop%D#rD^kqo`dl~IFg5{<8F^hsdEd;VD|Dj`4z9nO|+)!k;X@+ zqRoaXs6=>&pqI}h!t3p6{WF&PJvoKbM1ij1Ze#>?b!7{rr+@wzzM79A$&g>$v`Cnw z)C6d!nLo;&-SyjEBAzG2PFJu{3f|(q3$`(R3_TL0g??~bNd&f~xv48>Q)}XI{b}#G zPqP2*3aQWC(Nw{{!rGmGk44uBzPXTgi{Ori-*xKIS=JS#o2N?dO>eO9F-_;~LVkhE z86NH3zT(YRF7Twv;0ZA{C201EAWWccUU8Fk+voUwPgP6ID!I_myxM-JYfB5taQ4};5Mp@l(m)d^l~`KjiuUCnBfJMN&(_niPGXqG#1&E#OIrkX=qS1HH!#Mdv9VTc}E z3l=R`oe)C;i!~Z4Tvr1)P3q5-EfXogO_gd-cpMuiNs7Tz&sjwzge3#npJW!MrpC+r zT(X-Gm$_o%n;UQ8fqa-=6CMkXLGF#H(=~0a{1}(PgeZ*tNoEgCH2zSiA750Uu~3Nl?cd85;+6b_!#V@sDIlk?Cc15U;vg6+Fmez1f>?z0+=Q=^XZv2Xo~udt!^iS5z$T_H`?g|pXP_nZ2+l+Li$eX8faK3*`a&hac? zmL>O$smI(AMxSTRJl`|ddw+2??9I3TuJlm-RZP8Q_@AF)jf*!vJ}xhs!S>O27U#+f z%gDL2+e$vW$p3y%|I2EJ&SB7|66e>5Ncx{4s}@qf6il7#{_YMIa@OHqv?trrbt{*d zSQ4h`&q*&-I;*9}rOW@bffG?h2~^L;x)0Ih{9w;$`xh1$bY{ZU7yH5gkjB|Zkmqjg zUufF&*ugA5#2fQ$T6KV6cxwY!ETaKOlaLFSyNBlP8&Ms0d&11Ev^$iMC1mZL60R8O zfib1gsKQS@4JoIhB{$%4P<5SqVG2_(L0oF~Y zrrQ}=)3sH01Tv%rzk2y1C{bS5XDZWYvyNwSEq2-G{i^_3HYc`>T{%O@R@fP!a^il5jUsslbbho{R^&i5=_63wbp>zKM%3{_bEk zA?|i{9loQyOinKDQ7euL4~jPCd9l+@0#TzvU^n+ zDz)!_-D*}^-1qSY1JS?BGw0t8$o}?vnrpcmEUk10d)Z$vLYr4>?^+J#j28VeN3LJ( zlpYd~?(|krext6u6wU?plDSjU`WmVj3`3NeqN!ekHfT_-KhO6PBD!K6}aEY_0c4w%IDZ6DT5KGdF z{`s{;fH1l$)}%r?C8>bf5M&Klt0ydov)aOy03A9T4O2^-npZi|yK&hWnT5MH{pJ?z z(l0ED9p!R7EiFE_1;bWA1d^W#cu3hKo6z>oPBD0sWg3f8CeCZs_u#Rxp(r z#$n?E-xNoSl!+Kw?#1fBRT?P*KX+c9y|vnC)X>cY${<&wO%b4Qi^I1li2H*SHbiG71|FlotuX$1NX zyqyPVDj)9W3Z&lMXdKUE^%i|c4XaIcd7y9=Y{(A$qTIRm!^B2D^m0~Tr3I8Mj#{(1 zrp+#d7syVNcKB||B>-E4DSDGXVhJH1$#ZwX{%ukyV9C9a3&(`IZax#m*jSc865|7O2$3AK}-_qwbt=7`AkD&d2EXq*PtHkmk+ z3hy~(d3Z!c?G|li;7_W}jXLTO$X&caqet8K{x&9!xW8%JV#(3)&`T06@33JF78AWn z!eTWa%SpW^s7XMO#4}+ZCW)Aep8AHJ?F*iY!dB!vX~y|$6cr*l-nK)vo!j%*R@>9< zp)p-Z5-!S(orq?TxtlAYH|3jALp=N*8<=)|Oz&nu*ov6W>ShS^Fsoj(wJ`h|0UM1Z z^JkB7fqzJ}TViutOig>b4Sg#(a;hk&*-Z_-{qch>%ozzQ+V%+b0v5BWvPh7o|_d6b(NxLPgR`@*Aj?_c#BSuPSO1Ewcl;@v0Xo*sdZEQeH3Q zE`s>RK8{cK=9&kst`ZQxWLE1TFb|2p%QkZUM-0W7&xsG07q^|oG}SJ5{#cW1QcGBG zjPmyh&VhI&O!%aXwkVc^bD)nESIuqE;RVcd47*AO0py$B{85&vX8Uy(=z! zRp`;?P{=$-y(3w@<9#NW>yYW z3Fjw4o-ah1h=|+Cz5{7Z{G3GK^MKMz(CW`D6b_3GpxNlIEi0P>x^ok&yi1wNM< z<6%AGQAD0n?R)8qF}J8}0_Zj-kohQ3ogJ<5aI*#$Z)d!#-jmaP+8q_VjTSGEM@1zK z6VBA^K5)uq{QZJ5#3N8iH$fARW6~w1Qq^UEK1xTYq@1ycfr*T5sVlw|jzCt#=)UEG z*jg;jj$+|2URZ+=FBeB)nUU(}q}De%h}_jJLpi=jwP0`IQXS#G4h=Z5p^NPQc;idR$4F#zSjXWinx5E#HW+@O*(Wow9vi|nr+`4Kx&{j z#*b`>?^ToIrhI#z3POHZeDGe&`4C=&8w(fy;!hiQd?q0ri!_yy*&q6&o6%W=>~bA= zVuB8|m9k=wuZ2j3&@j#wA1)?m_yV+*C6u!`Qmj(uVI09CI)jWv(`pAC2VYdT7XusN z%5HB;13$FAgjEoyycQ{z(C|(_mBSE^ zL`5r9?~1>KuL@CdqOF$PYKUUV3sc1Bw#yT|$FiYl;1Tt7^QXi1X@b<}iu|)=R!5kD zAa`}ffELZd+*#aSW%13``0+%I34vV47!ym#HG{Ha7`+qFO<}Z_y_aCmVZBioS}{X(XkYUIuqf*%gwOTAa2hC z0y=LHl1!-(VNI-cH=yLHgvM$x2U?SmoIlFDk&_3z>E`Hwe{lh9?fJ4J_t0u1LfL-z z2UZf`Jua4Qu}T3ah24e0%q<$)(eFHU#Uj}+5^>hZk!;=J0LJN(*pxBM~5(O zaPjMK0&xn|FDWo z{IVbn)1A|b!9_SqGGaTn^go1+t9*vieT1C;DFuH)HP)Kvzeh*@zo+rQcKhG*eQaA$ zHN;%3ak%haVDaH~OB3<&{XLlwtRD@#S%9_yg>|=R0&6_+(cd0=6z)JFp7ejt&^S?J z>5Odg&Blg!<|o8nxPpGwSAbVLPcHrnV+gb_wDtWEMuidJIE1<_6&dcb4&G%94z^)Y zeH@19hFnfNc$m)*$>WN(2hdfrThrTyC|XQPJ3=Sjenv$AXpB)nB{SN5=N; zyF>=HmB*}oX6aZxFW`tU zhEi=IWm6jAe+JU9`*5?iX|Y@L>8@8-?`UK+GaIHfZ1WU|%22U_Zv&S)CBk3 zomN}WacmGnnWWcmSd3k6T;?U8s~5D_Ht&S7ici<*gP@4rL660EgaUj~Ak(UZATdKd zx;+DROcVl{_)eh?zJ`tJxccQMw?jYYvM|Y$>YWDiO_L`t3OydkXyAscB(8-F;oscx z`7{w!MNd>r0vFLerj>u@Vz635q0$_r}8HTzf8~d4<56X`)bJ%CaAx$+k!VnR$ zwAqs+|NYm9{<_+(^`D-hw>$QQb{>8m^Ft*L=d9QJWZF{H<7rFz;ATTrp~qZ}55sz4 z&!!ZYq@5-#-t~TscN3aubY>ZqMUob8Z^Y*1{Mx@Tc|W9k#bB$5C6cQ*x>rNFNu&FgHGXgJK*?6hq=#&mu~h?3-l~| zec+BlD`siY=PFU~0odg9RDxj1*?!2eSmvJ!fcSoAL|K-fI~{Lo55%*JYEIkw`G8d7 z*U|%6zVY{z%mcj7O0GBLGFuS7B$YFS=t;EHg&msOCzP!G5DJrjkB?!-0lk&l_OKR# zugmiRX%5V$p&e9o6gWq+gy9(vgBnb|7+;zxa4w0qLg8r2wTXt^aN1BMF;A!KmM9s~ zk6I6GZD{*Ho7V{7_Wyb6$zA5f%ek>$sI{Y@YDD`o6N4)}6!<_xfb&28RX?5L zEuVs6LcF+|%ePj-$A7q&uMQdqvz(}YeFf(&UM@FH@aHN!?I2xmFgZZ`ygPrI$RR++ zNEbc!ekl9jjxW0U^H@od`d`JiHLH2k@)W}?Wv@bYZPfHnedAKjhgEZHdfjtZ1;lO+ z#t#GJ&;WO2rd_{FGQxEKxv{P8Be~kLKtLI};w{_dA>qI&XSK_f`z}A3*-_T(B7KSB zLv*z}Z(gFRf|@~@BNNOC!X~AT2F@9r_5H|rr3kC}*^mkg7H|H1g0iqQ7iMF*2U>3d z>bccAGH7_%z^@W}>oLza@@`9LO zxH=%eFe!oxVUtrN)mE#>sK`qNC&p=>_L&N7^4Jd1S89GzgX{xU<8iWuH3B5_Y0RsjU6cFEomb0--*Z?%okB>* znXr7es`qzuNQX$VThGf{G{O6)ldxk2{d%*VR0msme5cNncOnlD(@a-tG+j3!3g>i9 zSRCn1m}?jm_=wE-JL(*`f}y^qe+g%UyL2#c#L{y#tIS2C@BhZHi+oPDm22cV1|SF^ z#Ke}TA|NIlfGhu;auO0FuKDwGESv5tdfAg*dh_x~ii!?OMx}f81RLKBUcN7wTd$TB zpJE4q5;WolE*XJYrD5WuuX=mgT$621KiNz2wmcE?Q+(kJBd(eYd=3MWr``?QqJl!Z z%EJ4LFU)ozQ~O>cJuk+}rM3TuiYhW;?^&+DRCMeZ0S!hETQ1C@dD_#33nP2rv} z$@fZPIrU$g{B7?x@c$&hlHLmPK87FyGWk(T?OwE)U0X(H=9}t-U4|ZPdlOfU&Hj0U zH^U-zA77ueuhCXfm+Wp6160s*T9keC#g^AeBAIEl>Q#SNXI}Ura3ZzZ*BIGgVaLZ( z0DlX!FYwi5q*23S0z{yWR-L|fKptE_*1=uO?}_SgmpvgY@;vCg5r61gS`4I1wG=)I ze@2^GEl=$A>30B|T6l?6{$4r-S>mSOTBJX-!m)ugN;s#&@T`#2KQ9@29l`n-o5W`^ zqRkI%SrId;dfE!_a920#DiSilpS(PYpZz@{3d*u-z6_!iO*R>N7~y6Qi3T2dmwx~e0Iu|ojYO)1LrMAVEbC%fy!VA z2g0i>4)$2)7{Mjb8&FKKF^7P5<9Ck@nOjvl_Gjrrb28{;HQiPm=Gc!wblXaHOURwn zZ9Fxtz4bVY$tm<~i=mwvneZjJ>NuNxb*Z7@qX(HSI!z=RaowHD?H5eb2qf_|pJ!xp z{D|ESjcySwmJW2NL3+b6sEsN`42EXX{qY2_RRwS@59cV$`07n=+(=#29xe{ge`$+y ziF}zt`1=dCQZQ^h)!8Lc=5#2(6jk+wp>3;sAEOM&EK5>!d`& zel2qG{hZo@#G0A~Iy`LO0m3rd)is7POYaRQg)y>p_DS(OHj43mdc46b3y;}lu``%0 z$|2Ay3*}?`IM4}yKFU%}$-pM9Sdcc#(wR|I|8*(LsQKW_tty;R%#nkM%kYh^uElqC z&Zt;!3|COKmJdNTpI6jn&Dnzc;HD`%3gvD1rwTzKP6oS3DlIkzGQlWsFf((d`p1Tp zZGpbPn3HyZ=yL`!s@4t6hme^U$&F(~iDoRs#;I4hWyV#4k+?c*1Sgv=$EHfX^aPHM zV=HH3SGVl_qt+3+jrS%mb84A}$*> zjBBP&GGRToHj3RsM|HuD6n4LF_Ly}ynHS&lz&!xbz7u@T7^<@bdUrF{)+kf6V4v2p zvq{2ooeDMVl!^~4Q;gQ=RgYH!E!7VKK2Ja?LIBtCZyvqC(`h}D?9P|J&_|NJm_j_r zYFTR;I(W?EcBb0PLN-3p>_Gh0S>0V$+Sxi4%%eQE{+0G`{72e9?U_BaX3O*R+zHFdj)Td4{O$YAl*FNDLrct;kS8qC!NqBgUyU)5m8BNPO_)yiE!tIYb2c|M zC-&3t@oH;j`n@ntH&jVKMP;-51!J_Uc<2c-<{ZG+dmh!(# zBj4AUE%aI(G#u@WKEb9(#JIG&3*eOHdFDlvlMxR8ZTAs_-65K~Co1~RgM}q!5#xLL zW?=Wq)?I7iyM^(Sg>k=_AC;|XNp|29Pv4TVAvt|#x@3dL-;36#)sy!_fRoFn&g8xE zE4C&RiNec7@~uW2;t4#xMzKb(N{`+|TW6Lg0Vrp=4wKnj1COJG%lD7(K2|$ZBzImg zcb=Bc)eNSle|cTgNb6zkUgNEa4Z399iHc})r)guc%#%)+trAKmb$iTkSxPNXQEN+# zCe|rose@A9l-iaT{zCk*!0kQgMf3xn*A?mZJiB70DwXP?Y+ytW=7ubyg9h5k1>6&O zI#1+v-A1{zl0cJ}`92Re01mb{NI%z|Ty_eR&sKqpp?S1@d2F3m9S+dxxUl6Ov$neX z9l*f6+s#*;gByb$RXr|lO}4_Bi)rxiYaC2gvecihV+Pz)`DVR3`Y|+oBP$;K#RF2H zFDeSLZ2d}<5{H@rOPZpo0-#??DQfm>2|i$sI{W8faC!Q5FZRL$XshmDaU*?pXKZ?> zBT`k@`IXN-K>4{OSleA*Qgvnb@Wf-76=~+~(BXcu-yBAnYz#JO-Rgge6YJG%TSHUF^7w^#%U@xa z?$|rxwhezx3XkVh+vi50h|dH(Y9|oAQ?vgK5rV<|mmOW{uJ&Xf8+JS!nRqmXQ52Hn zr;q*q#6*n>G{K$*ULh2WWdQ+!ma{Q`=+V>Tj4h-w*x>25lWzwb+sW@?@6KaR00OGJ z%U*@ToJ7X?S6+Z_Kf;NS&l=Lhb*BemTd@DiqY-L#&8m9S>0xpLwi;ycKz{rQRzVP+d*@;wdiiAWT+5Lwm{{!S6Jl?&kRo|w?UoD4D#@r&atK`S2 z<4>4UFD9%!W(IDmA{mq~-buuY9Fvnjpa7${{17(5Sx;-L-@exUulY_cds-j=8>WWvS)|tV&v+kC;4#Qvgf7itiglmqC)0k2QCK?6l@#D&tn!I)fY7Mw z0L6U7?m}%xxG`09ENY zz}*}pYmILq#Pw-`!v@FAWPzQ%##|s_?+j{v4B?ea>CNE9GlO16F7P?Vbq0z`_U9GI!~N%S)l|ncQ4Xv~b#=N8zdCpp zfmh(ZQy(({#%C5z0CUggicE z(3Ii@YV6V7#oC4O7$0oru!H%S57c{naWLBzQK5m|+@hlX)4oinebOnR%<$Mxg9bvN z$VW5r7oJ}tNgmg(E-WVdHY4@S=!ngD?6u=!W6V-xDt6vH!lF%d-yAdW5rW%`vE*O!%=oK-Zyr>Lo zF40eOMae0*pwa01dNh|sA$Sg_>p#{f6LexW>h#6YI zLO4HXHlMiussoi2Hh+@}M~dIYsIH6s3vLH4+%S4&^{OxJ25 zx`E?-aWKL=X;zN{H-|eIn^QhUjbvxNW%V(fR5+@6PnMM~zyXzk%q#T=zTN;!~^6RAHP_LP%PjyvP}LEtmFGkNv9Kqk=ch z;4-`qeL~TRiRL~G?b(^nQ?VGy5>4ylUGk`$p9ZC9R3x~XkJ07aFLfPPk=jjl26n7c zjbsYM;me@_`9Drm>vmT_uW$B%_-CT>SU5DOjv{&kIcsM#KHMv{-W%BatjQ)8eFe`>l$w12Y0O|g6 zteAG+8Ne^^y}UI(40|CG-&idD^aU(^+LXtv?O$@q#LA-pWyrc01%?K5eKL6De*xe_ z((5J6ObAffiD}%cR<~%a`WiqL{s~uGJJ>)x2p!d~yDNK$l(^&-&VZJA)cMH`4OPXR zZK2lSh(fowC6C#~0iQ3?MUAONadlT|=P*mBI|+Dle?Uyu{H>@aI%$^_iwg|Sk|;j3 zh9wtSnOZ=VSiR5?#i7>_^E#K6=pXYBi)gZ%5ZQT6V7D#M0Wly=D6*yZs(SZnw%TdE zf7XBRdO(E7gzwC@KMl_H<>R}?{l!_GR5#TkxEGig%UC(a_M*(ST~(k$FnxNBVBHt-tr#_sI_NBKYn3s_2AWjeaCuKc0*~WKYYoYJaVr0_nxHi zo;x!#WsYPfAX?IpG4650Jf6sV`8goX`@I}_OX3b4N{En}=JcwnJOR4UTy6pD;k_K6 zw}zZ;Bu#-K&#H_&l1TW|8KixL$m&2bPN?@qeJgoB9V_R`)5-FH@f2q zco>;lGvB{~9*b(}s!z+!!n$!{(#K)}Ed9~M0~e5v*wa&$va%o7{Z#lT{UQ)bl9(cG zHTBIQhN_&B=5I`2?N7}``nuh&*gPJy*SuaT4WXtNIS?NBKjwxlc^SvaUJ7 zjn}jWXDI2=#qNmYt?K)&!uBuNJGzYrxLM0?A|jsF2=>6BTxaYyIdOs)L0{XCw_O(f z=HLZ=!-3|(xDe?0>94M#a9VMJ{WgH!ep}IZd@|1%@R8Sdi%!Cy4)qi54`yU~H3$y( zTMxMVX5>PoCUE*58=m$LtHFZ4E##QtDP_x07T{s@GIQk`g$91+=z*f3c%(qk(w5P1 z#K3iq0!^N)L73I+Iu?UZ-E9Wd_7LHoetj~4;D`5}X+dENbwaUDCJGj_->|yBg(_bt z>zoow%uJTITsb0hEv)m|=wnC_ixjp0NaXawF3h&45_Eo*PmL*lF{9$O@~%B4od>_BgOpT|As+v%=xgYddH#iS7HN_?Kd|PS*V55W* z2-q_^wBJaE{p@Jj<>=Qvd()Pk{sy84p(RRs6`eB&pnScrR%BRPyw1wK?(Es7<(zLQ zD+|JNQawT^1tTme+=W^`VU%|xE*kvlnD7QmDGrq6ERYlsq?Nkd@#``3XsI~P|5Swp zurU8VY*bKJrii8Ry|~o+rWzX5ZQ5PF^Ge$%gkPQ)1yP>r?e1ezL_~K05k}KEo9vL5 zdCc5Gixc3^!N`Zti(ChwHX0?0iG_CMHoVN2$%liFyLR#^nGDu2Us^QY?X3wjh5g@R zDJD6idzRWt{hVLhQNKB>M{25*|4g>CKWxDgf86++v-#i8(sGKKHQnhaXrX2`eM zC=N1wd1fXmxD8Nw0C~=PEK2{Jb{zyhkLY_;X0$>hVoz~xL*Ux)U8gUuFAq&pJy%JB z1?=Bc^|I&M$)g_}^oR{$(ODk3Yj$L<82;p)53ESbJLBe*{md(Q4)6!1|D}b1_-|na zf_Hys1j4p34)`}G@x{Lt82&$QII)KMxQ>Ig4js>bC$pne&VyTPeu1%jfdPV}y<{5^ zm>RkS2p3X&(nC7^=r>se2U~k%uZxyc<9=nIb5Y}>y_a`VZ8V|SYf^vn&0$VawuhFv zbyJd=B>vYW&CynP&&$f)ao#RUSy_?se~P-iMhZS#dh!;#JwH-3zlZj&@}7>{gRmft ziE++Ekmh@|TJ!)iY8`lM+zTR;4U<&+va$+rj8 zLD8dz!<3_cqJ9*W`Wp22;nZ@(9Vg(r%uhwJl;qz5qc|F~8%@fr*bM7RuZeVCH(dFf z-XqGrMV3XCXUa`^Xv!(vj3X-DGR*91P({}*BEa^%Q$5f{S?j*_nSm(jlDJ6n^`8ao6dE8Uv9b zf%|*FvM;)7xxB~d;I_B^CJ(Si?V1J zS-jPv*{09kcI0UFd^xvx#xy;!t9&d<=odAe0q_Bay_=BX{6)EGS|^bp1rlP-{v>C1OboR0sW)! zKN5p}9e3PY4w9wGi?^KShP7O_Uo}H#P=tL?!vx<(5r$kus2xFqv98;OtA}e9b&Tj2YhX#38iuu zEP7eVAG$shZ|-#9w$px>PwaW2^jh`NQ`i4dnq9c$W75>~P+2h&5gNZyfdFIkK0ZyC zgNC{Kr@O7WTBR3u8=s4I_B_noJkN&<9#u3tAK#xKU*s32j1oLBU9T}1TT+;_P1Oe` zL;jH4;g^{nL>{eWai=2}%}TC5*xm!)jPkFrtjCX+$&AOuwDA1-#gT%iKg@7MW-C$z z(1*-7nV=+AA9e^${v>@@4dn5AAgIE-VHKz)6r2xypCM`Pbwt5GyFL>f-TYt`mChF4 zO-CJMc61EwDo=dw?1kOhyaIgeN3F@g?ABz6Tg}!|LPk`DAEuj~jORODXr8E|u*w9| z>aF&o%=#c_Z{=7U{6~2i(BU6(`Om)pM*j71t-z#4v#sqAvG;0)>!dEN`P5YL^Geev zDZ6`4dzTal9Vl4!A7QNAdO=X7rZPOi;3lN*|(EgVOOrqy4<(lu7iB8X33o)EZIhN zd)q3ISQBCW%pxI&GpHE^+A0xwb2O)u;xZ>cqHt){_ty~SRVl!vT}9Q^)VQ_`Y&3Y( z?%$J#jjs(wh8n#{2#M9bADyakBgEf*buVhW&_W3S$iG+V2m6Di$JXv{9_OTDtu>TB zmqxW5hb^ACi9GpP5RZcP7PhlNd68iz>Ts$UXO(G+zqcA}9ma*P3@nd`9uLyGFL*{R zZ0+${*6|$I3$cN^h{)u5?Ov~4@Sbl$%Edwj02(LX#u0r8(@2*i(1oA2d zvc~1M34ofT9p4Lqi$mu)2t8zF47m=1AvtKc5rHi~PG`+GVd$VbQm3C#RD@&71t6$^_Ay5nk3i<52 z_C&L8%;CBw#m+91JzYUb+sQmY^=-H+MxD^7RtJ~$-@|OP_M7BY6~@0V8ZCW2M4r4( z<*6U9MYHZSUd_Q~;`*xMj>UAiV*R;9Q9NqR&K7KV*(BAi)Dpf__&(2~H1g~>PMy>7 zd<>7u$(tXMV_TOrS-Bw6Zu_%pGmwdoQgQHq0h$8VFLj0jyr~VuPv{zI?d`m({ z&<^95K@0`6@{D9AUVHg=AO<7au**c?16)cjmJe%iKFj!mYt)4RL!juz1x>HMg=3M%fmwwEF2YM0?3HR|d&r0M{ zU|F8zhx)5|u*v(7?a--IaVO>XWI%yVm;$>3GL6*MLrI8LB>;r)E|0ky`4F2+7NWDr z*@xdah0Hl4arD|nu+&rcHZqL2IuVn=PFa z30>F8uK@}{{8>MhL$G?PfiiRCuig4(ie!! zx8+1aoy(jd94r|@Mqt_51Do(FAuB?p>_LgCTDCq-xYb@A51aKDFHipIbr(Bd>9bg# zaV=uj9f{LnF^XdAROuF82m3tT?(sT&{vhjfA@iAS!I77Qmjt7h#-I!IlY_|j18cyZk1^1SqNJGj~AgmYgW{Zm~0Nx5%^nWCRquqPsbxhtTxDd;ml1Gcyr ze|Xr_VAY|2jGcZ56s8OY-u`;Oa`=PLp``c=dbPKcAUV-x-R2|B~|wUHkxFVhGZk4E1?mR-qvlu zXavUAJLjmU_VlAl{%??k-XL#35U`SVEyg0^mTdo$7w;pnq<*i8eM=Em6^0fy>C`of zK|4@t#D9fsiX4XP6vP7JI3sPU^2x-8PuBHIy_q|s{*Q<8=qc`IBLcB z#Ud6pVKs1A^hQhG-g$unK6L9-{}ntWr z4*JH_wC?jC4qIt1sMVf7N_o}7%jh}lebd#iCV#gIlDLZHVwL^YUg&MKR$&iEmze$v zZv5)#D`dY!wlp0ZLE$UNvnUdqLj9bDynv?H3q?`UOS5jN4kxn85K7puK!ZJD#q6ynb<7v_b_JE8wbfN#zwkIh^mvp#r-I9^vSRD}! zM>y<;DmoAs?jw{f!3=^OdwzbW(r~3?D|7OmFL${mqSC4oQsybI;Y9M^_MEgedv*vSrOee3CI>9b;mgrd{SdCjS zL6N+uKwPZ?`*d2FSZCT{DXNfRz{bbxb#@bMnk3AhYa4{+m0)zYC{S{%{MGn*K9qfc z`EnPD_AMoI^S)0JrrZEdiOJJ!V*BN6v05hOo|wYr2`u%KEYJR&hROWPobv=dvvoEEIfF|M7!slm+S<8hy#n5hV?k46M6U!L9aR-KGCe z6EyI$d2bD1td(Mn=d%+-qoqJUfl)%7c3}ycnEtsq+eL0#{IE#^gBej@)?ehqm^Foi z*w2?&>|CyE8Kz9L#*k;=vQiOzdTpUjwJB`iqmC5Jh-XilFmTa^vi@U@mU2tc;*tHnbZEra6fzOO+fKp?mThu{{xAvgqgcXxMd90CNF;O_439xS-KYvb-Z{p2VA znVR>lcfQPruIlRU+jZ}`=bp3oT5Ipsl;A>qmcxg+aVBMmJ5cV99JanBnQ*56^5Tw3 zE>bmeL_&NU>{@#}^V;0&u##bnNRyZBGA=E;_^N!OK9NcfcX{Z{(<%Obqz$?<^{gF#G-!piFzWHRh@>NWs0|HSehRwcnZKUM3PE8vE?rujEB)A9ZFujHYkGVuag5_4BZKX~GfXf{!#A#WMaZcw<(2 zh3#o+H8DkQFK_VtX#%y6OsLJFt#t&^v&ISQ(a%LfIt$d1$CzJi-NCN3DN2Vf%8;b; z_~c5QkFOBo+Wk)?q~&>#>rJIv__Z}E9ZUx3O<-<8&$?iJ?Re+uyjzx?@BfA^=*3oC zf{16DXZq}caIDF?T9AO4;ep3lLIIewQb#{oRHma;`qZQUE2J_v1yLA^L|KZ|v;(H9 zi=MmEuwIk-L)zs}m55Y94jjvjHjfiCeI~va%Bblp$ZcnE?mle=2H^GedU!e52 z>+#?JoaPKR-!lF*c5PXs0wn(fhlQK#S{V;V7}KslP~3MYOS%G2cgWl-{BV`Z9`Ajz zc4lJ5fqrdQ^ga&PT3~2Y7d)Yu1xkt$gyWOjJ^IGpk$<3p?AR0=0j7;{)ZfF*@iZ0&tVC z^P8)od{4CVJvkrx2Ln57h(9?0&S4t%{Q~+&#Sn`@+#cMy+0d16waMGHhmEg#{T7^c zaTo;+_y8%0+37|co&4VY4|WE+%9uK7De)^i>qJ;7^=vu2eSH8>nQh!koxQF5*m}Mg zwL=WRkK*2G`CN4b7b8+JT@7c|omAQ>T;+8sp*MX{vRnO=mDIp@U}+OY61*ieI@_rw zwfMh_AZ;K0D!yrtr3C2hcfT)P<{ujJ*bLj@OKi`QEq6kP3 z3TMs>&$NuF`@G3Vv?lZ=PCTp_b?xbSwi8B!AJ;jwlD+Ou%0g+La2l08g38hXl?~x9 zP}w^SkI95V8WCzub?$QB08T>)W$w@)V_rAkg`8#C@|nH1<>R4=Ydcqk`t-?sr*S#v zhLbZIrqOGt9$S-X1L^_&y9-FjSJ!dH+|{SeW@}9ZwEC}IMWtHZYBy`##+3DL}0*-@Fh8TEH4!7*mUUU&9f5J9iTu*=aIsG0}xdGcI zqf=U#eDYtsXMo!FpO`AH4h>2lNrbyx*iJJcxYlc<-LDV9FAL})vI$V5r|&R*!?)`{ zPvhadv+>F&mAtck#(Jb|3A1>EJL2-$Fd?%$rO_?(_|6I|$-05i0F5HP7_z=I@)11H9P!#YHniuXyCTYA!awoG(?_BG|7NT#LNm1>V z6t)+qUXj8mIr70^P$_L{P23HiIj(cX{E1;>44Vr4Z2pCPbRL=yDp`vdSAvi|hQt*H z(Nvl;18rv-%+oc1$ij4LoJvFM{YxU460ZBru%@_m{~>W~W!)|+^P@oNGh-*(9SOY# zeoSZEKsV3hy;T4YzRPRpgG>lub}D(FTqvONo|0`w!lOF#$&?UNKxQz-z;AiJdoKMa zYfB6?QU}Z#1Yejc|5#WfWBI`3|B8S=n19mWdiE-Q`K5tzx6M)E-{8wHyi45}zL0e1 zp@R#@o84FGslpZko3S}XP>E_Npg3A$Y=&pfp)OR1oQ+|h|IMOD6vXg&(Hg~BE!MaYM>-~ngD?AxtE%Tg?o+{4 z!}*IJ1vc_vArww^^c(CaIW-yv9^nree*7Wy+)2Ch(RexAx7IfkhEx5$HMD*-!R~5f z;Eq{&b*+2qV;S9Z)LPeSa3Tm$B+kWfTN9V7z%d~ZhMwI(IYv_;v_k4173427t z*YbcV`%0brSnLxm0a%P<29IM>?sfkgzM105 zM8$8?b{y8_XIH}83U5EciPzY!wHq>@$5l2|_G~rpzB&~CiAn)4Es{Pp z(F-QeMk*HD(Zf+ZG*X-?rcypjDZad7u2i;rB8D7FPadJ+7ZJCYPntZT5}PM5T@}xL?jYplTuEOiZrFSZ>h3 zdSLI!>)nmwIgRI~Z0lubUhi7rxd{HirfvLbnF!MfeMs|0_uBid7l8zp8YW=KUtu1z7d7U)GD}}uyw6c%i9K}wJQ|1r6mBh2q(in`{%wbRqp}sLR-P&pDeBn zL?9XkmaV@g`VyH__bsOkmBK%bTywK}o+TKyrM3zQm0h1j?&fCacbn^r6 zA9BDcjVxYkaIKAAHVW?OFXqQ$1LDjh#)tZH_I*ikC;gDP?_G(1p-d|Oe?yxuYo>nz zORz7M$p2^l*@??(`=35LA#sVu8Q@`Isi>_b?UV*5R2(#5;(ZazJfaHxtx_O46Zlt% z)K>!(fgA}#1k_+2Tc9K^>ocZc`tQHYHgonL{3O(EWlAS7z!(BafvyJzEQ(P7=0V`U z!}(JG;NK}ODD95Fc^AdXdGbI-fHyW`+0_i)XqOLS9LfBx{y5K#-u)NO_~;OUn4&SB zHHdv@d{@rO>HP$V&nKw#>K#t(MIckck{waQ&4htOW_!u zEFxo`uy&5!S9L{Q50DRJNd3JZ%<{K1Zp5snfTg9S7w@Fd&t2oi&IwIGz~vn!v7OzV zyJyw-TPu^CH(gBhi1!2jKIs+xf3yH(?bR#7uCDAx0})Z@m1Hw+`{N%k-;TT^xSyS4 zjYwtx4HfU3Y>G?tG2%_m9dCVl^ou zWEexlfR7Kt2$VjxL)n58KRtcq~YU^F>_J=yE zVov_fllyX@)$UkZWZP%C-t}1la!%ZdGf-1TP77Zfx2 z)~^d8jo7vedU-3iR#w6rI`h5m;`j8I$?zGjD!Y8iytO49ss7Y*eP)$xX!F}jR&?W< zw#)s*#Ff4Oe(KW(`@E0w=5yV^#c1W}2S`jRRx>1ng(JN!%VP$`k^RV9X$^bIsOXJ? z&Iau<{@^N*t;rflX~^8>udyKsY$wsxNXF8sM6xs`o+Tnd`Q>+UxI9kHlAgLGT4Sp3 zOo(S;s1HJbSv;l`>BUnCLhj=)F(po2qP;=4CsohME^Waq_vPjDuYu)2xHjsUp8uvO__l446iqLg)3{)ITpSwbQ}fZ8U0nT>ZfBbt{5M@+>?-`K zO}HeaXa?^oQ6|zCbpB2Qc&ScL?ulm8nuk~gov-1CmONa^2;k$&sw-NPjz4ewxm{T8 z0h<=u-`^L;EONeXghOyI*phoaSr3TVZ3m<}QJU>}^*pDoF&}TbSk6}%4~9IZXRO^7 z0saNWt6o|-5%UB7u00`fnpyt$$c9}CrQJdsehw8D>l0-muy>i}cRC9$q%mi{7;-go zW@o#!^LEr!x!-C`)?6Jyqa;;Td7n;pBK7zO%0&1^qpV?3T>mXSj!f^Dp5fBn2&(ZA>O^mlwqOqW${`2;7}|_ZLLl zrrR+$Qi8z4Py6@*D&IKJ;sVF-Lm3DQs3!D1_`&wqBTSL%|g_I4c)^kLA{D0?=? z0PZ}5Ph5gM%sbYUX|XlF_eBwqOxy~=`>bYv=w2%FQJRwf7xer8$b9YEbAvzrge1#; zHVW$B|r}tT-t!FI2Nw)XNoy{yGWt7VI zHDdq4^yDGSR z68%G0k_D&f?|a<=LKltrAhvRN_LCu++4*n3(&Pmn>R=*Z^cA(E{bI*QIbq_vp0VE= zdKWa!_3hl?oj_5${jq{kccQ_|fppEc1pL0Qmxg@B@c!GzTfIuSNWw?Q=F%gSBOeof zn0t!U>9c)k`xx@fFfA`;lp2SKM60E=Zdn+2qtAP*^Hqk8Mf!pu%Y$r(3dD1v4h zy#oP4ATYpcLGkgzx|6*#m9-+x&Cqk9N%T`v`{2=$mI`ca(~84z~_~07mcLvTB_eD=$|1#o|?rFjw4aOq<{qL{Dp!7SB)v@Rl;|-sSMSH@_b&S7u<#lfuEcLVN0k|MAN)^mL2x<%?;WP48+IF2&RMV00mce>PIVq~?M2=n=8`o)bn49Yd!WHk1WlF7& zH&|P?sYuejgWnj!n#t8epbamy|K2~LD0e#~VHlQg{rc%|pdJaLlB?L97*V@e#G)LQ z)VjXw0jmXWIFI&ux@RVM$7Uv8Qa^S0g6`jGi=O8m)(+e4{?V!aahe_T{$-Zw83f9F z)?@hAK9on-IN2{pz4dxwk@?`o0pxpxn&_(bCyrhpdiV6;JzJc~Ubxy?HYCs>V)v@9 z3a0xPWl^3#*=&l%tyT5)U#m^kXOq=H32(`1JVaQA_DvqyG>#wj(p0`H7Ta@%NOBpF zr*&C|ckza`>Jnpr`c!m=vg2WiI_oj@aNeH#84|~Ce*T*S5KByQrd9ec_pkGz9icE^ z*&6NJ?fPVmNip{+e(o!GH7vgUv&Xx7cIqj4+G{iZ>+1t5c=(Gx7qJF!=L+%=0skGB z5VQ*c{P>;raU+PoC7zsETeIVf=Ar2Wz%v9&BK%(g-v1w5{{KN8py|~U zYFJGk7i-;X9fE3Yk>A-PB@XUgYr-6xoG6+5-NKuIWcPk@anZ}#Nd7B%krsUOkws{q z8Zv5XqyzQ+IHRRTofjV5g5cERvTJl$f$viGo7Gg=hdw+=45=@#>p9?&V@Usy0)%l| z{wRtvK{AC(iK$wXk79NcVvRm)-a+AwBgBG!@Q~<0KqGpB%gKQrX)a18ssuGO9uq;d z)#vfmOkARSYxGMGsvfgFwI=#u3Qck=*W)E6vjk^{V7fzvF?M2rksZx3Gt@C!sp3n%ezlN zQyL_hY%gqA6`hHVLCGfg1@*|VTxt^?|V z&bCaBfFe_xdTu7h1J}x+3SiE%JZ79GQ!{KBB6{q4FsX56C5pE_iQjl*Y5Y)plDb_^<_i;vV#t9Ql)RQNUpZJLXkHq^9L(Q>Jm%Q!`tQ=3)-*0u|CLGn?_RV(VI+=pmOXmL^KV=K6`u8v@v|2>oTvo>MI0%@6CrkrhMc!pi2VLk6AHN*%&i@_$8NayBoal#~qq^ zY1o3F9A4FD)O^*hIkyd1rO;_>A(jAi#{`86vrXxFc>o3=p{8n9MBx1KarX3@7y`y> z;G<|!@^|K(pE~j9biHd&9_JRBVT#qJt`2X8s&6;X+6R1=D3}{jDvY4eqc1r4MTPgZB-9vbd|;E-P)+6& zT7QJm1vMOzCN z=p9UBHT_-Y3l040Gf;7j09J@4Kok_Cu<>UrF)+$Vfj%DzSH!08!=3ADhXT69WH|Nu zDMh*F5FQ_%S!%fVoX-uzKs>WEX4E3{tthimL-B`W|AXXbA4JL34fZ=PRT^U?*WB3? zgQgKNVYWDSH^8ID7$)Iet`%}^oy;uOY4&nep8E8Vgj8Sg13ZpLFW2@z?vl6vpPxE9tJFcdV8@TNIa57zxv|&qd-x@ZZk4RP?AM@2AqHveee3 z(OF!&c!)tMf4y^_M$di!mWm|I!xaW4oLWN93qf5h%1T*>Ci2aY#Xq+%l4848r8a|0 zL`*IBlSxB9PY@^l?D>Y6&2dwId?4nD2cZdr-mxovb1D9xQP9VZl%P9Cf5KCT`@)|= zPxE|ae0XV4`6*+5T`tnMgoDa60t4B|gnbG%`NlC8keJY>o_Ir&^l(R7UF*w(Mqs!n znlp=hH>Mn5UrZCxW8NnaSQtc^j_W#_pz9TbniCS!XUv`0O6k?9iA-p@=78cNnVa|i z8pim21N0&L+Nok;A=%%w(GcKgI3=%At&So8qq-|aK#xqe0|w}Qe9b;7Ek*6OKKsP6 zTfmuZzy{TMmL(@?ct7!e;598MltJYY(VA6Q__@}G60`k)cT@>%6tl*;?35GxD>ag} z<+MiDX^xN9-+@YsdFKzYWZ3%`PyDC&E^t&h6(0A+EgIo@byl^xq(XiYeR>F=C1SOk zK@z{!4Q?(1$A2AJLyq@=s(5h{Q2=K$;6p$S64VDFJk2ICg2EEVjhNfh(w{dudARY1 z1?9IG0Vy%3 zGU3_mB1;|pLPdnp%2nGZv!%UL+jib(8nuATN^2bsP-cUj^eo;{e~PqVjH==rgBK_Q zX;xJ+N9LFJ7*kSb<4plFPF~2Jol}vq6sKmd^_s3NQ9EXyu90^vW_qtnia`7b8M<9D z^XIh?*~!(wZ*sRs<`W{x17W$z=a4QUWHdmIB~AKgsUxmTU+~U5SPm*a;qNggW7FtA zw(P5dJ_t;;a$w^el3>aM0H7W0;&UJj^5EkHpVQI}0Y!xB)KqS3VZsw2}=NvJ#k z%ux#dYUz4%4@&aXc8j2thFmF8phT2RMi8}bdJoq|I{2zmlnb~YVHMWG3_uG&N2LdB z=e6GGAHXdNhRz0|x)dMFWvxUG>I`?)TGb_F7KH{Rf1L}ND&DR@ zxa|fS%XDN7_qM;MwHlY?CC{Yt$^D$Heovjk9?K=8tYEbq&{!4%J=M; zT|EzMZZN$;noGt(73fHwRWqQi9KX!mU?FE|eOmu34AM!{Q!$U0`j($&nRIJiZfpI0 ztQ3d=D$yT1>`GK(rU2#(`3D5FxGO(eP89W&5ke0hrhQtg zC^nWV@oH&@lVpS$xk4^Uj`nhpBr|J}lW~g{5TOv}4?MD^!*_L6)p%Kna=I$m%l9V% z3((EOC9dWTJ?>aAp4WdYlVqYXiFK9Vr71*^>${m5$3&Lic!kY?x!!4bu6t@q&7Rnu zH_j|vg*mM@m{^IZ8EBM$W=QL`$_gL!(f03_ZY1aIS3Xgf+8ZFQ%PD!eUfqLFGl#B2 zvBQlG1xtitmYle^Y9qwv<4hJGp7pUv^fv9*=DOv3QcGR>^pS9_$4x(IYVxpMd4ErF zA2zaZB-3HfDT-63WwYtd+o$Fd)Jn$R zieU6UWH4JWSa&Em$y0K%!yN^!_7^zs1H?_2$-S#ON~*};!Xk2AG;0GgpR~Tu(U`9X zIT6u$KyzgkZSf3Qk`j767D<1-J(?=x<009Xw53t86RvV|fSXv*mYTw!w92I1r$_m& zqTt>6q(Dy5NWZpXaWcXwpc1GPXbt3rQK=XS=0!)~3Lt8?Z69<9q4UE3eP5KznhkaY z)Ke3g%Uk%dFyn@NVsBy}_^g77DZ}0Fliwx6O1Q+C^CRyef~_!{6-Pep#l}C;;_6jd zjcEUsST_H9)?ntKBN;>@MS*zCFb4(k1zU@Suq*_0^mi`*$0Sj zJ6xiI7z5?JHEBl0PV89zy2X>eZcgK8tTiNUaAJ3ubKgx;-I)_Hl93A>UZpIowWjuJ zYk);*Xh;uQSUX81sJXEDxRI6mOfQE^Vay zncvjn&Wkj`&&8H7mmJ~eoOkd**GpDVyYUABuvHp|dr`a^L{kHDc|9*0BuLokVCF!D z1BoM*+XzD-%x(2w6UpGfb|ZVk{KB@#Jd4-OqAah4j)qTO!omIr>UQ$KzfX~SvBC9l5JTwF`fV$A;X0UNSa83{?A$~RVNL|M=dPvE z=9<)HJD3v76mm?7WcUtORlEC(vH9VETGiv-_Cq1kwMNE<{l?&J^S|)ZkOu!4Ag>1Y zTc|HDTa0cE^6)7vm+sZacMnt2H5tE7GNVfVEL-L`h^IisI9%s`;Q?p4-G zX_@={6Klffix~36W8s6R1IIJ|Qc;m3Di**YX`+r?jMhz3@O}*r zNk=nYVu0R^3~7^533caN{Kr-=BYau|fmFo%?VVXMbz2vuuu}MnhUxK`2|Lz+FXe`k z(mf|%bDEDXs+-r1NkmI>atmEkND|%RqDzPIcp$=J7CFey5V$MlYfAUOfYKI{>k3^x zz2PYN-gz)4-h#xs7^o=6L)vmneYA8=FKMlKvT-c$b&&RzV{^-BXi9m!(m(EL_M3Kk zc*30_&~LZiVnQd*VoKi$hFLl%kI_bjEjO|&1?&tKg-_wsgz8cHEN zG#Bqll^6JVYR~^KxXb8#7w-IE>KM>o8U|$!ai%l+`l{?(1K%xPG(rq2KsziRAm6s( zzi8rr4aO>X6Q7zrG%Orzj`=Z_pe)j#XY-tlZ8~A(M3F2e4dMrtZ)b{ulyXaqweQH^ zGu6kX;xc!G5s-9>tWs_VKj>y%q0BeG1S5_(`4P6riWaFWyaJ?C`fZjhpf)^d_@|NF_mShy0{iI?^mP!F-^U!F2Yi22@{+6rsU80kkZGX5f2gL#JSsu2qAFsipJ5vETbj0t+ z2W^x6+)2T2WIqFQ7|hM5=$>tVociRj)2o)_iTtbX!X9ESK58oskE+6LV8C&nIPAE>yvca9SZ#FU-&Mn?icfR=-yU0 zP|o50J*{{6$Tgzn)k4?vIg7{3gmL?5dbp!a_q+y)NQ9Woyr4{@p$i|{Gfm#`d79q_>D;G2trEJ`KtA?>KN~5{XX#*r z9g`xF)z-tmDAOag==}+bal$>2)p299!i4=@$6vg?R_qMPx7KB&ehA9 zVd$S4YFWJTJ?s5mH?NS|5aS(Q&r6O`?3wecSc~ZrH+b_|ckrUC&z*Z+jEth0Mt|#g zI4%VTLZ~uD=Q{Nsjv|+MJnm(rpJtj47+;}*QPtTH=E#=m!3%e8JlWLLeyP92wI%pO zAT3BbbG^clRLhwW%tgvIRKzEKtTEpch!+uBsn=K%_VdC`4lO7BICWBQ=zO{u=mB6q z`#h#rbw0&bsU@NA=?u0pGV1%XiXGw4>-6qiX468Vw29K9V4CX8q03pj!xyYSHC!ep z5V~AM8L?II^G5&H{dNuFJip%GFm+tpoSpw=_m4>Vqr)=iVNYA^V%jwWfv|_SM=95{woP^%n{FbzW}lE1@AKN*O|_iBWdrJFcuDwcAK0!OCn}+ER}P zy^HLwRCng+@z!t>cm%go%>9II`A8gR2t0-&d?yde%PkbJPz8J;Q9t5{94)Y<+#g#S zrQ4o0);l|c5Sl_cgy73SyuIlOD(1IjLo)WDi=J{|v)PkUyGy~Rq8{Pf0e7DJC(F{K z`O7oYxl~Dp^NuLJaJFu#vt^`N?fFm@tFW}BHr zNHmRTbldQEdoXE0AZ1~Jd$O1rux9&-0Ug}?@V5l9JO60#jH>uLT2?fhc0$2himEJN zEHZEC&{7taExhdQ1z>jOmUjR7ET6O$1GLTqYjRq5!Z+Ma*nLc0)Lg=DNkl;3wG0M| zz*{r@Y?$bJKe$ry9+X?gXe?f298sz0xZu@Gb-kcyuUKgg7W*&8#ei!R4`u(#b&4YD z>k;qH`2`%Ndj8qmIq1`0mi{B@86*8qwc`IhQmW7W`-6~u3E3e;-G5|FFn{$n^_t*o z>j^hsVW)HZhaX|T$&rl!pOvsxOjZ_lyEr(%(emJ=0ZY8iD~$alK9b;A(^U|Duk8o;JLn3=XKpk$<_I9Z9y_ zWW_05jLXDIc(6Bb$c%1YJ?`A90u&HD6jVv2_rAnnfu(u2!bK$xhClY-VvBSy@MpqC zk^aCThkx)J+CTT;lLbt3{Php}8;1U;9Md6;<58}Vw&n(JDecS@X7ZvXBYqbI?xsw# zm${jcmfbgPCCvULbF86P2$Mtvl+>o8j5`1G#`w9m{^Eg9Pv&q`1Ul0C&4I2(j5%OA zv=ppq0^cK!M%lMNZH5M$kG-62aVddrtV4%3oXdHm_ZIJ4>b|zX1R~_D(0SNd!s!3SUPLD7>at}TWTv%)u;_z zLUnG9dso32cbe!z{b$%UE8_UCkh5Es8r{&UY;K<3RdWwKE;-)ZK-72qm(XcPVkubC z@DA!cDwr$0fq1N{GM}fv>V}1vIm}gLAA~R;UoK|cjyNk!^-;^x5<;St=k~^82A3?0 z#s~#-iuM=)6?~zyOB|nl_I({cM(bGFe>L2Z2y;|W)O2cQh`Gb6*W@+&40dXIbdZ3A z4mQQ;vLxH1dW02F4+T@Ewt->A2%UlaRLp7=3#@(M1t&Jb1zC9fQScG-DH! ztxLB*Biw#2q!t>M82u=VT~J!#-uUpB|(f3Ke!cdGXeZo;HD0@IOHYZ3WLX$5kX z)rI^umta;n#ok6^U}If-gh6ag6yef)++=>1A-MwHp$QiQA!67zB!%{Db#IMWeL|zI^A~D##ix?!d$lOfPKLB_{TI{Di?s z=%@(gR>l@{IAbQSs`I)j7k6+6Aj))6!Z0I%`9uVYMLBQXaXn19hm zv6~9(u$KS*D8xUd?Xz34ID??FJ#7>hG)kL2vjSKUK##C;OI(V6kpZ8>(QTx5G zL$ut`lsjX_;(EmMK$He&Pw?b6PTj+yxuM_`! zoDsz0X@M)kKLPqd)oG$(vgrdUM7bc#8@||o&T8>QC+)K-vkts5dU_b|nx zv^~b;r;ocvQ*)=!VpDiLM2dPhJn8fMoXt)iwv3Bs8!bqUTB!^gG$ka@hYutsuClsh zv(sqYM&^YiIMaen-(yC&X_ZyeICmOB$u3fMh6&ks8RAb-5iM_Ct^L&5?w8GLZr)-T zr9a&&qKAC6xPLB|e@DcRm+|ij7^yI{{r1a1s5W$AF0lz;pzF>-?8V)R4?}{mRw6q3 zw>jd2+2jI|Ry1cGwizNJ*aFddc@|FkEqvs=kVmZH&88~)0h2iguVP-5MTXpsRyzzJ zT^0p408(f03~}L9zlRdrwCpE&UGQz$ozdZ3OfN|BTi4sgrxi;GFU(5K9uzD>+*HEH zeg8@$webtvy`2JzW(e(muO@x&M$^P^+jP4{d%?x?5Ngb2-_(9hQxYYREn;UUbF;Q4 zMVgdJU0AS{YqUg@zr@NQ7pCtO`XJ5>2`@_f)+;o+sS3)f;S0M~H26C9f2LL#Zmc z*Q3+_!p4cWBFinAj$771-?X+-`CYcTqCMnkCU`=^!hJ0gQJ_xAcxGzO@S_vy#Z12_ zhL%G}t)JhFRh`jwKcK7~ZA?hUd%Y=Wa7RSprNR8N(=YHx$AMi4$yqAhVIiafJhe?6 zPC`TM{r%%)e?PjKPsnz+xX$&~l;6jSh5mj+8ms1ts#(#RPI~w$zkuq~o|f=$Z!P}E z4ESS4N#p`P3>&_UzufU@Np(3slK4D3b0vVcQ%H^+3s$oXm(NZhADs4otTT9V+7A{( z@CNGD#zB)}bBG=J7_^_aPw0}bPr4p9_^7f`S8g4Nk{x(EZugXFWZ7TsxGi75rTr*p z2C}{;_VlSF?u17Vc0Qc*Tpn>vGx#QRi-C=qWw%04ZoM9glGH6{m|WVEpG{WFfiHRQk zc=;g6UMb(hJ$dR{j`s)@g>0L`u8Iw$)12Vv!jTXOKFh5q`EJFucuLq=zHU+;w6R*t zlkmTE5pvvoj;+ui$(qPIPe$=W$FB62xwWzB_}yU(PP9dkjF!`{HGqS8UP_wxPpg0Y zk`YdxIO;3TS*`A{Pn-cNS(Lg~W|KbLI-~Wt-&mMhV@r$O>TQUxf1kKpSI$}<+oKg+ zuiX&GgfUR2EDB{^j~bm<=g>AQX<=ZgK!;ck@D*NKAg!R^I&hZIFe!2mFsAi>FrE&9%LH+Wk zj?CGR`m6&MfPN7X(sw6ANV;Ax zxKB*2GvP09jYUKE1HX8;95R#nqSjD4Cv3fmZN1zGj;K%^XBM6vL>fR>Vp)6EYv}Kd z1FncT#YRg?N)N`KSnA`(%Nuq(Vg11C{orUOx}z)}>ldn-ee1j6=b$rf?j1bDtclI} zbL35csr_5;#Kq>r>FWLbohZf^bF7iabBqSxz~PQ5lgSn#%>E7R9h+JPD|e^c=<=3V zk8w->XxA zIrIL56T?Z!_i)NaQ^NCcpBTnQ6*geuL57 zTz;OBS2a7+WuDYxIgBb7ecHJH0pi}iVh8g@Iu*YE#BJJhyx;K6K@iwTus)Y2O0SKy zG!moadHwoL=YpT;jiZXa*!rhe|H+cdPt=Vi+*fpRjOrC=%P7Hl){A%BHU$kR4FyM z!9K~dU~s2U@>{n!y3bq8BOF`1r{lxWLL59OAGHEP63{Ui2^x}O<$T#$;_}Gij$a2S zY;l~197cw&*Vo7>ZjwuSvA>I_Y(l>!|2g`W?f`9c^t{?;#`ui^F}(HD$k1F zwk=!dH9;o-D$)F~b9VMD!ZvB}Ue9j7h;7C4-Da=u9Ej>7D(8XIoz|9+rM-sp-Ucwl z>`v|zxtH0S=&H-j-E#C`E+UUb-CjE!8#8FB!{3>(+Bw$>NN{2}4u4#zur5b>=~bA4 zy$DV*!X+s3oA_?|jcRH8 zf39Shv(l&^9=$*#oP;doBg0j$2_y!3kT&(yrBS@E?4zubTs=X?AE@V!3E|8*P{^(M zU^J~dW4xcInGf)LvA&Y-9g10y;_u126(;p(XYPu*tW+U zVFY!KhzH>(F<04kWqN(~ec)~E$vaTO#&mbmceU&V6?n-GENhFbl9E$TBiTueLb9d>8Q8nQK5ZfSh!l{3+SL}95u&9K3F6ho5}C0KJRFZjN`qPkY@p-ujedh&E8N|x+gudm;>8m zqwbHt-amZYq}v7jW)ezlX_y**G~78!UfY0#L|3Gt z&xm0~)S}z3wy8eQk$(L>IQ93hsF&mTJm#!zS2^8qU~mgQZ_UzM>|_zaGnnk z(KdQEW&?${B^wnmtM&90`1*s^)r~NVApvk~x467`MA2|;v-r(( zQx}V$mbyBAy{=$IT%I1R10mK3rIyr_G$%uX7{6$$B8uKrIznNj0+OJyT_)6V#7}0E zkR1>Xa+&bhT5lwO2S>-+@Ym(#-?_}MV%q5qC2oI4yZQXyFY29uh=WA5dS=9W zgbYT0?)R?8$tEskFRs2sK_9zcUfv!UjrEnu4qJkl;a;8}c8(#a-?e_sl`ANmS=*0P z8;%(Iymzxmi`sK_n19XdF_Jzb?ez5|(wn=hV0hN1bmN`9cWHJ6sb;o#TAhadc!!%@ ze4o==#j7Si>BO5{yx&XHCT_>+?ub?+dIP>@MZI>hJlE(kr_%R%l+jdO&Ue{)QD{95 z=B>E(=lAO5p=pbO{x7<|GAxdz>lT6q5AG7&-8DD_3+@oy-95OwySoLq!7b?E?(Xh- zC+EHAyZ6WYJo?y9b;z1G@$``x{s)!t!`o8+&lEPg`k!fimrZIr05w>WQK zeb+#kSO1-&hQ{R#Vwp1$MpGCMdf^!(u>l)`XW*C&&whw_9H1ezUr`8P2`4mHMGr^v zrKBA$Y@SkTZQZ_PVNYv7C%8k=QpTI!rd?Dz?>nF`V4==ZhS*(*=EG53jxBwhp}6xN zbX;haTlYG|^r3SIh#$lNBIRqHRR=tce5a;;kHaeI5SL4BX*5S_Vsr~wSYTV{Qq)=H zj(C)E{}t!$VsMr+wEckm?5joA>(ZlH*QweT1L1-s=m?d2%zVhUiqh#yLP$AwGGBT9 z#ml%znXG7rV)IV*mLlKTMthBPmJ&hFof<>Ryb!W*q`b_WtbLTKV*az-9+wK0LRewR zF_qwt-7dpl!J|z%5ad}$CSgLu4>54!7TNoyJ;rrkDuiXvRH_&TBg=gJB`BXVlH-u6 z=Cct-T`o_`*BXcTcr=}%T=cY1w^iUQ8Sl}RNMIFQuJK-*CZ^2STz?2(DlbvPBCH00 znBpQKKTrPgh(33&(y9^)`+bw9k&8Gd2z#<5ad`hOISUwC}%< zeERg@k&Y}8#d|7J$k5)Qzq$TN*OYyr2(<P^YS4cF5qd?dn26e5cBdp8|Vx(}JbxNvx;L6(`di_f}$AgP(+H#!x zw=&z7Sne(idz2eX+MWtS%ZZBc-Znn*B{gS+v5Fpnz4K6)r@KSOHsW#}X+EAlM(%5L zRB=u4^YM2&cp5Eq;kBH)qC?nFvydJ!UC~?Yv`_A?e{A3SNC^IKSMu>DUne+%T63Y8 zF`Ygz;Omi8!Z3OXOq@3I#_gK-1N~pO${laXcyj8y7KIa;#)UaLGGK+^;d8H?|0F}^ zd@jAvbk%6i0vG&v-yrP=r-gyLdGkCul-jqhF-?OMe;`BN?x}@pkRMjtRAd=KnlsTT z=2f)2XIbccBnl7$XHRZ8Md}B+8eD$fsrVrbpqCTrMD28Q7s!T(vAes2U}`(tt$vCZ zq+i_uQbvGg{~-rG5MV5P?Z!8j{f0kN0wivi=Fs!KaV{V-XVDt_i^4s6$-?~f!3}~p zxp7+MU%eaRY|(YzWER~Lcx1iFe&&q${;4yOUrQr?CPYFvL$ZM(y)>U3@VZ*^o``y3 zvhIBkah`QWccHB!7FFY)l=BvomGXEXdt>z&%Gty>c%kP>kf9@#(&b;}$=_IC{_>q*30%j(uK+IAySCRlG)A58uF76?kcnonZLghrdg zJGfdssdz)K$Sz+ES!`lX*5#itGQvW($sr6l&UJg>X~KGz7_UG&E2iq;Bpo#R?ft}f ziku`>pi<|0h6`BIIpoPjD=$dx@I?A~j=LRH&hsZ)XB~5#4J|w6I;$&wrCkt0!c|zL zN2@br9PiUKAO`#|dxThCDNP7>te{u_*YiVS=zv75E9UhTuo-VMb8;7n!y2sLCmx%W z6g0H+mGOdjG?~HpsE*u?4@KN6fZD?VErE&qJ5|*+8(`ENcYtX9UjE=g#~EKWA)(Ge zB9wQ4$Dk7Su>5?aveItfoLS7xyku6 zc^(~iZ^dM{MsBuI*xB&IPtVbT3ntP~i zS@M+|AD#N|Ur_LvpmhLeTtr1ms2@cxr%zlep;@UzIVA~_v9f5ZoXX-DM{<&ntK7ej z4>6`AaXYt2q9&}33f750AWbW*AEr3~gqM+CC!7`*hyTA`_DS1rWqe@|TvH_4zeJ?wt;&kmgRhbz8C$2!sZ#i#;}Y6`J>CBo0aG54`d|KElQj)P_Vbk%2HS}$(?6GFYR*zQg$3+B zNP;SnEk_wh44+61ZFZ6^0MniR%l~C6DmzO26-IPtWJjpK-&{%hyBWe<1r)7f3AeT=gS<7lbu>II#4E zFnU{B%lXs7F|>yBT01u9sBco({mu!{wI2a$8V-N3v_Ua=t3q}`E0P@6*9lij?_C|{ z^jgg-^(xhA80}uf6a=!4d)tZuw^!QIi$AF+z!I%UK`>hs_B0_i86%kovPxB2DRUic zpPihig&DP(R(n07j)F2vvUIGNm8gXhsFc9mf6?h!EFIy`;7oRtIIDI$^oLFkAXYfk zaIY{1(C*?jbixaUUWwIYIvbkfelhoy$PxZkMJ9|oHH#cwEeLyF6+vAQ1!($eSS4(giQ+1T z_*^K1>K%knRpog|Jk1P(T9v|_(UsIu%0VVFHlBQgYEV`1vY|?z#&WDdgOa*7M!t96 zi$cZXn40ZHw@#j)LFt+rd#aLDcy)1MDXN+^`Rx=enW;-*!B;3tVQ`G5@@JN>fu;5D z3(mLaYbhtTEol$y-taXGcz|%wZDR5q^>{j_^89z~3Jl7znYP7u@a}dV+HVyByhfXQfp8G85c=e~JfM(K(!PRb?8^mePE( zlq40)m%6O+Mjfo)6K8kSn|HRHENi~x;XhO+7MPrZuo^UGU(SRK+qAJlyo;T+^qVyM zm7fL}-Lo-xM4fPVJ1?zA^TRUfED>4!5;H~T4AzC$-~K=3Nh+cBEcwXG1{)Z#Q{Sh( zcPMq_0UZE?Z1U&Q5l8UMW`ghWYmTkm0;VfT#jEi-z#g?Lryb3<&=7lt`DbplvApco zefx#UNETzQ>!P)G9D%xiQXp&b_2VoDo!fDZS7XUNg3)2$p`75&qIEO#Q?izulR0ie zaZEu%^q)6unZICBJ0F)ZO#&r<|ABU|ELLH`_Sb_xiPXl;FJka|KbISPB|))9%oKIN zknP?OIdjsf*}{YT4v-H{Y>GGi3rhN% z58@;0r7ZKcFqC-I1l;g|YpXFfn3D!GT)x*;04Gx-mRtOVHUi`lEzh9OMRPD0&kUqE zHrj)Lr&ca7z9+i(OHZo+iK(H_&!>3^_YC_57s!t_ zdO4qm?9R4F4@_^aTwoODotB%M^KU5P(zVsVlLEmL++HVSFyHrTyimBDHhKH=OLNeHxLt9tKP)fpl)F$5Db;XYhvf(zzmF0bzMnxb6J2em8u&ScL?4U6s z_M!U#xprCg*3{6t>Ak1m_5F+9<;#$OvGXAIIX=cl?s@Q{8%w-lD4a&ompcWge)W7N znxAY#3EAjT%*sKZjw39(tvH|&L&Xl8cc$0BeO*?SW)@Fartk|a-Hg99j$20e(fZnJ z>G7>K=?5BW810g{LU)za|JcpS(tNdhE7XWBXeacveZ>RdqIAfGnrO8Y5Bv8+&!}#O z3#x6rx3I9^DooB^3M1>gZsqFc*j z0Rc~?<-+c3S9cw)&x35`2vAf#%{ku2iHT5S=sOH~Exp3RfN%?>jhI<{U8G<8xyA2o z-~N%B$vXRg5e_V#Icj+i&H$HNYe@USS9H31VWMn6M}vXAjI^0uMtX#`mrF4cXgSLA ze!s8j5|oNFHfsa+AV)9&ri7?6h~1z=>wYztvt$4>8OQzVMF?m^vsamWq+?!G^XW?< zI?vY*Sd0#6wLR9jomWw+@>p!3Lr$VF`5bZFy_lzq33!C(g_yWX_h!6V*BEo3ZzI-} z7`mz1zc3}s#ikF$iKv?XNO!SrPl;)TQfrS_cG2q_Hh!q@ z%l)n5vqzbVas?sBM@!C_0^G%zb~iL~D#`82mAP#ell9E46W4)(iFUGI`)nAwg8t5j zcdxWy(iXY4Mj=PghHB`(*5c{#e0>W?cJRVoXs zlp@XBiUbw%E-h_Q<)egd<~=U=_^=_ufb*{$)$@bkcY;v3D}_iW1n;h^Rp;siPNKFT zqKMVpLi>UGfJ4=0e^*MP_bZfnByWF8qU`?j5Iy~l4i|MjSqgeFn1M##XbTZdFDTCu z??=9^7v|l`Um#Uf(1z6}5>>4R!fF1_rWc-oH}p;k!ocO5=W1sQWJ%A+A}@u*$3RHS z$BqbM7c4@WHt!vs0ah2V5K4^e7L*L(rBQ}R?~k|bY5w<|v0v*nqq^yRrmb?JXT2RU zIeo^o4(=~MK~p_5Y#yDLe-TxK`v>`YNpUI$|g5i%Q+i}i}{p5d=j zqsgMF0oIg|j}7qCHb@4*1BK1=8inec9-*#C>hmsmn^T*c;BH=;yE2|)tI44ADw72% zYZrYV)?D_<1-Ae5-OB2-AuNL-OUk+zFXTR`EWm`3}+$amJa-seZZ8&YFFufCGW>#bz{ zNF(=wE6>j_rzxKZEjmln_K|~ubGaY~X$(+e^1v8)ja3N0kyk&6Wv-FuHfgfom*cv4 z^F?sKgxqX4FgKI|OQnow=M0BgK7|MAE<_giZpl}29Y!q1&=+huv@w^Mq7s#p27UQ- zxZn#WkaN+D(n70%fa{9r>tpuG*XL3E{cV93$7xeyT~{S)xt6!jnOFVyaL|&)*WpwB zxAHf24`(vgLoL<+aNLh(`U=)?hTPJftKY=B2yZ#S&Odc}?9mF0JELLbe0v#FchY4o z3xjKm*1@UVyBwZI^~Ei%2(`tsD#`Cb`Gk##tz(nx9x1s zhOl88Osmygaaegf!<7MA(lS~&ozMTJoOwmK(7nV&=}= zLaT^lKoJX1)@tDEr+V%V4&J8a=YPA#&f4*OJIc3uvu#xTW|15=HfQu9hu&yC7!II6 zLefZm>H{&4MUttC4zNu0zM)$1LIdDudUhJ$cWmf4sE4_v7&=1g4%1w&f&y5F}{apkoYbcd2tIz)B>k^tRFO zh0>@@bp^8(!`L&{dVJZ5Sj7DL=|*+2tbro7vQMxTESG{j_OvV?0DZd_;&5QcY5Tsn zK}UV%AK$&#bs?(Ot)(Fr#GWVgT=11TTajN&9{l@AqMB&eBIg)@qj6_Px1oObxWnMsWgJ`_6udrvK&kVuAy|_h&_XCfvyFEco zDaA4(Vc*#BLEJ}(yt?v|(^C9rYyaYAoms97wa{2i@8vOl-0G3(LBIC&0TthOM)`Fg zhBuz(62l9}mc4mqDoeH6m6^!vST??U#qd6;a|!xYW;SgMG4#a1=eVLjUPyT4LVhp$ zvbQ^Ne}Msf7ER(nt`4(3ua995Z1(utGPreq?$_Ou;Xp@4ioP#+FgI(11Ft8l9P?}2&b+lMp5Q?(Hg7m<>mMp-YxP+w>*t`>vI(p+>=l_sBdjW7$7^Mux`WFZDpMc&wAO zhHI|+GCl{=?Z(7jfaL(6@y;t4chk$T^qrF8UuGQnSU%Kz1@sHAH{kvO9O5>Nd}98Z zsRNBCSOTkFw9UHNV2;DqGVtX?XJSpMW@j8elgo>} zQu}w9&H)GW5%-VUEl)yUL&$_0{2^akwmhXgiwzC|_aoBI#gm}YO?uqxzzTV?brJ!e zD?|L934`el5$5Fm>!oJAL#9rbc;|mXks`>0wJ*@d z>#{Tc(kUC)gh7Ij{O_dXfKC$H0@J%?>PJMdL46Z1b7~#N1c>@|>phRrE8< zH7La6_Uyi+AMPtvsaX`D$n)vCqr(eFn>f&nQ19}sRmq|W2LvE}VpDsg+Y$bJm4SKe zMfq3Z9jX)#%!cpWlz3J{5wyv<3+NG8e!~FZg16 zgnP;EQ>WqZ_eo@Wc>Rk{ZF9FMc7|B-_?{o^e+RSpHb0X4Lw z-VhUzV;;75ooKW?)Ss({?xLo4<1U0kd#ch?0n&*7EhV~}8FtY}z-kHYi$6_eLXpeEHVVv?Q2hHdH5q@xF%+F}bfVe$)Zf6*1 zGbQjmL!9SnLZ|HjcBLvncudus%6mAS$d~|P>iiY)J2#VJz`eDCb(e{D);kgjcBmtg z0);4xfuI1kq>CI0EqIr>4ViAaUm6=hDD zxti1_ip!LF^(*#`x1_#oD;&8$L!~KcX(MJu;h}BW=Ozj)yOv%*mfCNaTFZH^J}%nl z=2hlYIxe)Pr6|c_A%#A{B8?$XU8+ckZNZ27hqEBz==Z8Yn~0-p+g%=XbBz!)l~S>6 zA4ZnuLXe#rkp>pc9LbgNb|~96UW|5h36`fEA0M+55Ig7sXMi)#&5p;j9S1(=tq0jB z#P~>i@|ci9ZVNocQzqKwBNQb8k@>%ub^L9bP?Xu6q&^X+4_`)f3J54`WH;|a2824( zr+D3eQr%yJi2dH|uyim{$QSpCRD>sqq=0Bf!`R0Gr^M$`al)E*;LJryvoW5v=8`0=|WsU4BY1x~b$5Z2Y z_EB);tbea%5$Mtv9o54i|;0pvhT35dlsI?V+i#Z z>}-f>45`ZsSM}3f41UlfWzJ_>n~S0IRw}&(kfDhUxX9FJ$wqRWb+yNMUUa1Re!PDS zsnv94QR)!w_ukP+;))H3rIO)jY4AIf?`LAbADD)RcjO0uKd`z1CzBCl2)EXh)6C_j zEu*GQFN#s(SgXrFax6(&+HE3}iT++ri$BxZW#O!#x+3GK!)>F+F%BC)EM+Wi~O4?;?%__+v?+bL&L38@1+nI9E|dtq`k%hM9rp8HbS|C6Wwgq?`~O8E8?f zWHiwslQdN+rmhT21|_SMqRTvCLE}AO)n}qgc>=y<)MqkfQb;{aQOSWvQS>7!ZY_GQ z5WQ5M%xFA(+#-Lod}m{!e6J)`rR5d#Tb+W2-uJ^voApB;8To|@fCJU9_PpSoDS@w_ z{V#1)xCk?cBxpvsN*0GXmsfDYhbT+bH0iWwRuQ@lMf$i{spH!O9;!|sD^A^nwrrcK zw|Y2{Vn4-}b2(a~+45b<4kC2drCC2@13Q5my%zxJdRTy`2q)JI4nVy&c~G=$?mPx6BMbD_N> z$ZLPFCaQCl-|?H9&JVVH0U4&BaAmPpyHgl7#2o1S>t(j)U^)kN=Qr0Uh_m|N-Q%tOBSCFKrKq5$nSVr^yK=bxjMF- zpk*&5#i9tkp}^Rr8CHFu+m|t;BIm&7pr{irat1+$>A*^xqd2fkk68GOxVndlo{(nr zVTsR-tFE9gJYBizoz+oukHU(6dPiB`IS@oBU!Xze72q@PFFZ8yO`!Y z(`y#MW%IKTm=S)|#a85Zyg!&SWj?waH$0@U5V5s$m4-T&+?q776li5VYVJjbfo0`C zdZ&KmzB(L_ER70FFe)#dq_qOU{fR&K=F{=Gxt7roRZ-=jv_K#X?5xhLjmuhF^BvvA zP0ciLXWfeKww(7MeR^@3a-O4*tNlo(>|>By`VlOsJvf*^_j&;jTh3|I?Y@bk zo5OCWMy+>8D3`!0nVwKQj&;5M9`bacrj!e20q^{-_1KGXCW`RQawnYoI)Q`zw|zoy zeY1D8o{MPrm2T79=$x0^knVedD~T-5f~UZ!T6NiO*h=SwZ8TZ;C$kfGy;0Yv>$&Eg z;YG8zezlgn;24L;=Nt!h^PTCl6a(K^it1MtPW#4iN1I2Um74SYnvXqWlf;&`@cA)W z?T^*~QQ2{??R(p+;fIenJR*YJx2=rUzSo*nvuCxYwHF@qZw^*_32Mn#At!>P1#jju zh!+Rt$PJ3`w_pK71s`3+bcq5Zan)Zk_PyX zCR3_J(7(ATCVGWoW#5}JeoInR&0LLi+I7$7#uZmPWwYW6pjk>tSmbK_Ttez&wKifz zDK?DdezZg^t^l9Gkt1XH01vpe0$Wq=Ya6F6bH1O!sWK6(2=c?qDW2uHMc%BZ0L*m%1cF` zgzaHW$?u15hEd6Hh=`c2z|)78mRa=bFs_OzjsV=!rCH&aHo5=OBP7-s)_L!<&B{UY z*`JtBW$UHbadG$e3{KeC=T%D3&~g$dv2x&IqQ)hvD%)BpFno%TO*nT;H!Ucsb?$(Q zEnBGz3h$7wrDUrgRMTp9NPZ=Wxroqbq%WF{+e|Xm>#Ma#V`sr$UpwV#OP4*NlN6(@ z&$B=ld>YVKwbqWJNUGB}B(Lf4`qkSCLxy&D;Vww@*bN2vc7&UA)hQWW|WrYN@z@Doo7Q@*%(>fz@V-DChjV2i%oUvF1)VoR-* z>AvYscxZ+vLY5f+PBFwt%S2F5Uzq16^+;M?kS%Xl&S83q#HYAY$GzwnV4(YnY zBXA>6Dc_EPcS$&LKQ}M2SZ|pMirLbay(BuCm(uE~Mt#ufOGD}K~+Jw|B>%Tbb z1Qy9vJACpfz=L0pY&c z5R(KinaluULlz*e>5&!x5*>F5uKOF%{g>9XOsSM0cgiUCFqafXw(%5|Id>XG31m1< z!tl>MsiMQfNCGcE5yK@zM-#L@tKt%5Xz>XNh*&aW*4{id9&>Yz@xgtP(CEpHJBl?@ zX0m!5`mLPxcx&vX2xKrPmb9=m=(g$@TXaz5xGJtNj7FOVhK zd1v;1UC(T_!MZL#RS(pXDofJa)pv8}xfP*!vXSr7*aSBQyO?}GInpG_4j5qv6eBAZ zqcx_a2K*miQKsQHz>~wm2jaXbgjnPINre2jL?;A5YsyuDg0iNt!a9VQI8WdL9!?Ad zxpD@4^GxvfaP@9!;$+?aRs)|1r1g$r^b?(l*Wnpu4LbZ=m?cm$Drx${!TF<=S_okC z#6JH?F!$&)$%bI8=l87q7r>)<&VKvKc|pf!u`{&G1;y>&!!@|7qtnHksCee7{40G1 zu)@H2VRTg|SIk#+SRmW?h$_X_tXDhtVBhOWLH>zr;oaT;Q)l2kVfFON=bvi z_FHj6$j6q+eYQQVUi%dd(#GS(X%6%8-XtW6;eMEJ;oMim>vKA{7G6SWgdZQkbB&jDQ>GI!7e!58KCwsYt3d*g)O7m6Z_p5|_ zVUX1Ih!v2vVThw}<%K{`1^RZix?+mHyp-&Iv<0EMDLYN>fhYLr3|*g_lprJ8LF$*I zTUi~xA}>$u)LK<&@uv>`LVBhd9Fm8Ft!##FW`;a;Gziu_I&SGZRzh z6bO#??0}2Y*+X9-^|#0nP2CYE`l<3(PrMB+F2R(fSZOO{0|&kOYZcZN!z?$6CA@Ap zztGKEbx@cza-y3UE1)D{O25+)zf2yFa<|?K+qCXz%DGC#!m{#hl7r&Lpnr3)pN0|W<)#g< z<2~`pfzrppX$zXhpsX+NbOU5W2CA+~if}_hEIo)F;tRAJ1i?2`x^hF3@$5|m}Iy_4yW{@!{_7~W* zDBge7A?50}D^A}Z+_oBxuqpwGL~6_Q!H3cz52@qL31TN#5tX^&YZ_y(M@>Z`Anz2* z)kBih|J4Fm66{n7)7&q6e2*mVIa1@ZEeq==*c=ZC0VVjTG&2`fDLK|RuWpY8i_f~I zf%jVvxJ7cqCOkecGo>sLhb4Exky4!+Q?0~AD=**8QYSYWkCYl0T>DOCaUaN7W-_Lk z7Z>0#jIP3|z<@a8d`Zmj?TvtcmS0~G@vAlZ*+JSxt1diUa4fbmm!@?sWq&jwFkgcS z$U+iF3}`nFjlN@^^mRJ6B}=vb7Dv}IlGzW<%YBSv(C-*{-a~bNjXLH?v>8!%nC$Ay zGhWa~3bLuj_}A8;Br@Ec+#r2Dw)}X(2C0A-T>T~0^m{4tuH)UBcVDx9YV~q>e$mAD0EH`6Hha!f5$vi9m2af^&5+z&D93Pa~Aj zEzowO%X7c4{AQZ_d6&`c$a}&51Gq8Nk<%5lfdJ@6BRIGmxDb@2%iU=RS@QnK;yYvS zp6y@4(i2`Gy05RVh=}9>9=z^CZmAbSbGzk+Cd>m;s%U2loiJphSv}l{2>O;P-v4as zizH=BTDHzhm0;S1;xc&Cx zuA(Ke66|Oe$AVqwPl%KMlC*%G+1d+;Tx5Fl)11$AMyis6kdsVota8QCvZAs1>WRl}$C&B=r|;`R$c z&9X-OJwj6xuF;QJ0}-bS-y7=_mIS<(hueF7Z0I)#LK@l;bDb#}wFeYMcnhQWL5Pja z`Wh7D(i`V*y{dCERV$I=1oTZ`M0EHcXNa{%%WNxq7)&RPq4@c}*%z@3zC(2f$$gU{F7XZF&@x3(4?ek~0pW_Z3DB^8b#PhDs5FXE`FD`y;3eJ3f4%IDW)ksmQ>7 zt4U<>z;ro+#280oq2!u%!&FG!1vMO$g^4nS=2MKUiV7kj@Z0;YI|kgUV^VTUStVV`izH(eZ93MZb#V{|yXyA4 zg4a7(o*kWOPQq`Mnj)d|t)ISJTDpoTa}`=lG5GnebkPhM)YjUv8i0uCp3lMB!ZU3Y zRy~9~o`aIOa7`mgZ0-K|=h&IYnCx->jluJnQ9YaJrPFirQ9 z&iHo8tOCvQ8g3wNo&?}~>sbGg8H$>&Jt49jarYt*%k`C&C=niRUVi(Pc%0kT2tBBq zhJ#NZD#wGOwK(wf2|I1~7Ji@4gGTo^?Zzs?t+LhN&1ulMl8@u$OxRvoLbQ;GH~kMT zI~eSnXUUS81~&Gw4QuFteswGu(t#G~)fP+IvKd9l5RW4wB&^qQ@{A0FVR>JwfP8bR z!@$?CY6)()`xaOKO zzcRzn2-kt@>k23>udtt?MIIq~%>CMj3#Xba_CERF^|D-n6+nQC!;mR!;W*3E&r)pU z4(a`jnUXO}&sxSDYT(5>Qno6;iHaj(U)M}|%Op!u9X^T{WT#CctKwlA{xU2rH$7%1 z9&Uw9ob`JlM)_j!IIN&8v(PI9)Jn{F%HkM*vd_Yu2t9sC(U=~e_3Ra9HYt`?PzorD4btXDP{ zG%-DyJjl9FGpf^1%0~z;$-kB1`X*XFU=ja$_aQ_pKMhC&3j&t>nFg4)N-gq>$HZNT zv0&#^h0>HrFo&TB+wuxh=}ULOf1})NbAB(S!}FEGq`5y!Hn^t)2` z)ptjQ)Gv!PN=(%+DV*hb$FzWwHpf9C{cd%P_-ja}0RaCO^3tBxefFedo2@diPLdmp zRVYI5$?Lm~*?^IE3;EoFt6tw3=y#7Ko`4b@jqqb(aby`T3xP(_A@V)@P`S&Q)L+n| z#9Wp=ypXsAa7%=f{*GFWfAo_v#M830N>@m$BRo)!2h*sbJz>kt#?~z$5GY+Cd z8r2T={OOwPbMLhAE5faMX@%DKvIPVIPP|WW%q_iE3eL}?f^iUV0J&@h`2*#*yZ%U0&@f2qWgnJ!qC`&M&0oTEJH1$weui`Z$(J#nSU0iV~Qgg}cD zH$42{hPZgVB(bPNcCL4?aDao*m-pK;6&3cU8AzcokV0J9kxZl=Td!rH+qzNQ;P!?E zT?nbqGu2H78X;NO1m8g?{r$*&A#ua{&tV{1;6LU6{k8@9)!+4>6F_ANg>LHnx6}KX zI|_&OUG3JNE=+d@WtCM`KQXbf^>=!Ex^G`?puvS)&;Q@cK!c+&Vcs_NiQxc>>#Sks z=~hMUrq>a8(;EStT3CSjrlUiU0pyApH_aM`c-R=K)?qxTqW;?_@JcEw0d7QLpx#L& zZv^DHEFWq6JW)RFbJ~Virw#0vNL%3C4(J}B;;gb78$KtGx z8v+TwrU@EyOWDl7?P1c@2n^cDpL>>L98Ww7R^ERw$~T2{JJWnTlq+#R*Avw_+WB47 zgNUWS4G%PKI25=*3Q3UHb7ps4cOPo#?x^ncYkLkJ26l9Gthyf%cs-X_*mGqj%-l#( z@Y*!vHLu9t4Mw!Q=F2L__`2}QL;yG0SP-$+`ss;msNL+rerXSu5xqm2&hM8LPC8BO zz2+#bN`i?8JJE=V=Uj*ne40iFky==bPRE`tui^4}R2PxUlPag8@rAF$pr=8ZDAo+f zab14`T)x7yYOcx)p0R;FN6X1xoSp3j9q4TWZYB<R*hW=hU93SnbcRcU9U42P zXYUuedGfk15h4jy!twi&t$w2?8{3dAK6@1@UOa9_lm=UbzN$!+Xb_EEp|BrTR8c7+ zE!-}BIB-6P zOHFTZ92z2`V*}VQM0>oh0=*|+4ZT*dP}cHl%^jH`K5h^@nID-uKc+}u-%@-AQ3$&G zsdL^4^<*}N8z1nwI(5Q810`9AB4H~phwqPZir!Nb^rds-94HOgGA~bARatRaZFcs$ zfRlILI5DnR5ji^bjMiC{)8`t_UagNPI3>D)mhiJwj4WlkP$1FQj((-}=`wYExl=J! zHc}}%R5B{u%xKO7U z*4uUD{75&mq}_8!zYnq9kEVpialhuZT5(yx_iO(yHN!JsrImBzii$W8WLv|)Bddg$ zV$+5GvcqY=S0XT~qNY70Z*Wlmc05CsE-7rCH{pw{*RoC1`FbM)=^{8z_@I$F$K}($ z1c{HyP$9e$0O!GL54zOYLzPutA04K zS(Q+#PeV7LT~cJO_?=B`*rmd2MJiQVt z#NS$iM&kt`Kq&SI{_=K{D_ya7j+kasU1~c6QxaQ!c`GWs`Sc={t%gW}XEu*X9Ol}! zK!#4ctNog@ue63awV?aqP-JxUK4Tr3#fj=fyxwlMH}h#x(W2DlNPUg{QwXQR%?^@> z(!coi8Yt`G`ufIAfai5H3-a*Th+tQwd?zPoON#wGb^pVj46Z31i>&jW>I57As7{PC z8jPgp;?*V5zChqERRhI44 zToq`lg=OHhTX4>*n??l)2>!=F(`d~PJ16a^w6NalJ~?};I2isyaAHVYal2@vPUcxoZru(Ci5*9Zt@$XE0q4XS}toO)M-w08mR5ilIU@rRl`etWm zr|0Ilt)HjXb#0!nqqOaM#8&OzHtc6Md~trIr)vg>gp|;?WB>nPJ3G!L;UF3K)!M4> z3#qotaFW*@+T3Jw$dIoGQOqeWL(2`Ok*M2KXGV*q{5dW~)9S5~Kr*ZGG|5b&4msBl z5=%U*644b?c~zfv0x@(f3Hw|Jfu!AL85Xlnds1=^;^ul=*i;th%#B>DAT5X>01MBz z15L)C07Yvi7MA73Q0JhzitE(n`zk~9?L9LapD<6BiLvxd9bZ4qe+=zBqd$LWMEP#- zJwgk?mt^149asclL!`->9a8&56bgr(r;W%kNLeK1flSQa7M?EL0SvTvKeg#&Qr)f6hMDb`^eGP8&xGXu45^+)LDo*VGEoTpkx2wSF108+4 zP2f9diMu3Kw(|4za?)rMX=#uF`14m&x?&~i8(BD>x(-S~g<)(9IPp%YhBSeM*#$hv zC}bVAPutEzOSWPhNV}Rklgh1T$WzBNw9@1QC)Tf`0uaeC=vU=-vW@@DNx`XL3_LCN zk;O4*T+G6)D~=;PFKsCRACxf_|=fwGQX_uGk=oM99eHb7XBSYUC+DK z5HuL-{B=^LOPUZ%p2;BB@|-krQkE%$d12miSh`d|dHns|P0b0JJ$mqO?S^|CJoZ0~g=__t5v0bMQ8rtb?8`8fU!W}U9c0B#G z6~r_~LKrP%Dr_B#mUFh)ewyNK_%e(>jxLd`oXXbxlJY6JhLPnBU=1Y@IdJ1Xb$+{6qEgUl$f8{q;zR9 zbjm;grO7X=k{0!$4T8bg@X~ZndH21?>XJ=6Ua1#k6#1e{iDN3~G#ossU3$(@pIB)Q z!}{-kP{%S`zr`a;KNAz!4l<1;RjRK^K3xj&tViZokh4`+7tbCWGaVJTEeAI5um__- z#}`GWPm{1w3&jI=s2>)wCyMpik?aqnm~e(=%pLLO_6#9mNU-ZLLLfe^)v)4^|5B8B zJLVbj7J}YEOXHibOD$j^4g<1=S5yb_j7#9-F*Jua1KTTgva!|<-ohveO>fdN%+1XH zq*CSw` z%%1<~NNAH}<$iK#KZrz>Ye)sh!8s70Q~Lv2Y-SQYD^@V@*luFlb(NTTexOH00@j4C z1*E+-S<}R&J*{t=l!E_G>Sw#iD`21*eE8?f*YTkG9~4F)bPS%8=?KTk$Oz{Tx2AUcV(&-8!QSgcwde~E3uYS$)Gonjq4ZqFz@@W6#Z5{Y8DaL7-^*6&^fYx= zy$0hx9P~wctth0Mqvtc?EZ^y}$WU=NhGtOmr7&b6ZrRLr3Q8Bl#FCh|3vM4w9~xVu zqpZ-;`z{boAHYdLX*xyNGwRNAJrbv~Nf9LKbt>po5r-$4%;~y?M-A@Vz`n&Ju$ZYw z;G<(`C=CCkD~;A@S&BZ<2oe?|Z21rX*)D@Ph8+hMW@ekgcs9F!FBhcfaQi^r79(E4 z_MNZ)hqSiQGZ>_?K6UI*BA-?P9-T+ z`gsb*_Zc`4iYka@!Qy$ zh#`v?Q#R&}BT>{>7k>5ETK&KT0nNpsRg_g)lATw8Bx;?9oJYc4@^M?S|7Lk_X~dZ< zDV7B#&8)D#kFk7`J~M38B^T|73{U5Qz>mofAV49es|;5MWIwn>|KyAw7aU8JIP|I{ zsbqm#C$M9X7ni3BO@>M24wOv89F>Tb0$qZq%_q-;T}>Wmc9&$AJKoL>cgN}m6p9`aE&Y5Uj9~*bzV1_Us-ku)GPubJiO5BDSY7GTK~xFWXj}w z>&AILG{(W5f~u;pbRy)|hgJYzus@J98i8ccMK%?*7;6C&00kIWTLLIS=9VH8WQv7= znPO(v`g2&Lng#w19uZLd4Ug<8=tTX5?R`+}WL~di+5dlPUH1KD)k5Zr*E2M_H{Ca< zpZJfw>x*|BC99Frp<4)`#N!Nsp8oyf{NYAkr}6aj-DBwf*C@W$_;bBy9{#H0JhCjP z(OAyjfO$OtKdQvl2|HhZEeifN_v6!mYm~2sS6V1>$NpG{J5GF0BkqNHzwe*Q_9w>5u~@O4$mIfP#JxWILD5tnG!AQ~NZ6#nK|`Nlcy_ zs`k7ODU^23X7tvu8cv!c!c2=*Qi@PL%ABKt;39ciWn`h9{&Yoq4F|T&C@!ZSsqYQ1 z=Rf;%ypELB9q(7)`&V7xv9q3LW<`t@-`4Lsv_&@BKSLc>B~Pw&@`{t4nL9aoeC7p8 zphWlXzfPiCU0Ps~2(KObJzJBYmyUVxgW^-+g)E;4UPt!HKa|W4h4`qavZa`&!BoDa z2Gdm)Q>s(iE$L|Orw94GBA5xBDedt$N_OFq@O6spnh`FaIJIi^hMJs`q6^98{~~`6 z7XM%JHyKv_i$&)D&G~|IFp2vYe&H*RN*zguO_;!df&zNG>|&gLp7vsBs7MOF4!Q5T zw09}Voo+mhRXi{#B(>Pdtp2WU5kJ=1AK96Z1zZx9RDMld-3J6oBHsj8tFS34vhdO5 z#=NHJNJvxd@rdXg40%}4~}2=iA(b|UL87v|2%AQka< z_)LrC;a^0g0|)1!Xx6Pnr}-TNLc*(5b83es@R+JnUvRi&-XFZ50$qRpDD`7Kmd5yY zZotCHI}SO`K=hF7k~XK3D*@{;B>f(neW_?a|^q4q)Os6RZWn)nh7uN z=x7^r;V!AF7Jv6pD0V%89z$-J5xA)8Ps+r@H#GE>cZ*bj+13+()BX%6x6>zvnVqr! zhj>=&WE?f;+~}9O*yf~Lm2BfdCXbbIdsq7QzJW6g82+_yFwUThm&;>QNCi&_+&|Rs zaj==$2#+&$<3SNoTj;a^WUwTjLi-~>3cgPb8_8kvgY%*t9jVpUFA0bT=VfgYdk@c< zLJ4qLyaxA~$^HRdYsesS=*9#77{5PT@3H$ruaA{1L1w|v;RsQeAESaGDvyp)>){et zl8trPTD>{2Pl;8MK&WewahytGqAILRkSW9D=!jfHWGE9=$j4WwfaL%qOP=_}^1L%$ zQPI@f&wVh?1T~c_DZ6@UpO0;isFVyu zTB&?>9xi1p9SjU2hF1w`Wi+%gD6F8*NPKR5DEU;YB&pkKRTgdooU zaj(C<|L6bp=39+W=QcK0ji>c?JAcIYzn;kuCTba5ZFy<#g0OOi^j|IjyKik|%lTXK zi{|vdLC%;`uzADx{vr<8-V9g6x#V6Rn+T4oht_)M6J{z`_#JN6m^MzVtcZRdoR{$c_N zzlWPxYOLT`;t>OZ)Er_Gq`8ZxMh3cK`0{uT2-Y>5$#zU!J^m&_pWQ|5ZVSPH7Y{9r z@L#VTPsh+VZm-eoJXiSnrSR4D{`)!Lqcnv6K07~`2-UYAoW5iu>b9VLExk+S0=5wv zuI&vv$r_WswvO+md~^l7HmhIt{NP6pKbNHzR^A)*etCYGl?vDN5@9s6rR28zyy7+R zzQt%`_CML)8#7Z5gv<5%U1U~2e>P!kZ{&LIkBPhSnnV;jf0@L^N@qi7zTjWq5}zu3 z>|R7o7|Pn7n|tMXiFUn~F}U2!&3_cCSoYz>rZF@^;|_gAy3B0B%VjnLBTJ)e^rP3W z3ERSl0pOVJhS<`?w6hIgfxCCr_CHB?#MSzccRcntJY>?pd;0uCWVc(S zxp1ZM!e!+C>+SJ9^ZCMcgv({Ix;B9#uhzD&(u@^G+-9QWsBl}?;u0OEv+-hz#n_xI zLKGdUpcKC$MoiHHMs(;#5Bx7NPOzbo(lHHqu53W^5&^X}JVnt|*7eK?d4@8R$O2J+ z-7xPIU-3+#-*IgBI7nY#dzvPPTv6L}Ss~5o+c(YQ_H|~v}kYqah!~s+6 z(JL>1qq(>q0iS90FnYp0FS-^R+#Bwdq?y{=qp8QC9uGPB0r1 z?p;;1k8RM0xEBmOGvkwEa$=FlQYTDtWjU$k8nk38szB~)slhbR99KV9lH%wAsK;tN zSMyFUbJh%UfSs3`ulEN6ljbccK6M+J{4GRDU`^!aP8WK9%u8fxuO3C#rajMk ze=)x%r&SCyp}MaHcsG6l1MdN|$QhgTj(BtkBl_>AY#H;4ocNT%}JA*3;d^gZ%k+tZq+`b~1X4m*8|q z;fa>UBF%&Ap!q+DW2r*cz2=DapTQ=aWO%VkbsjE@X+ND`6bmWJk&5_#fO>-UNy_UQ z0lH(qhG9M2eypv1G2$XK7Jub(tbf!uE@I)r1Tqwk3(8QCF zJotcF$=Vl6h#0ibS%Gf2=zrf3q$8%< z^f7mvHM%LTWQ#!jh09~=wx{P~(E#uCzO2mVnA))d`l>}6IIL3ER219a#A8Z5T)q1$ zYG^7=EZmd($6UBJV-SM(G%EY1B^>ViHH%+>0tfs2-1hS=PL8^kbij(RxG#sNwhmQJ zO*O2=4uM@%-=ryXeq^adQN$D@2VY?2PN&Uj_H`s(T(Ez+1Lb)X<@u&33 zu55N<6BFu0YBgn5F0pz09DAP~A}Z`s#eOa~W0GLH)bH#SIn`wSU2C1c#ZUx4?-6Hf z;Vd{}u}+6dxcrLI35y5eLErO*8bo4%FaCKik-Giez*z1Wgao2o^FyvRh7SP!*?B4i zu-VkBM)$Y@TZU{QXt|#h_{?p{& zh97s9;F@-$tT?1+IK=hPZTZkwYP>qIm@_vRN$8Q8Th`~7C+Q`m@U`AW1E7hpArHw?r)70)H z`Qx{YYy9zBzJ_5?ikyyddEe>3Kqwzdmli0YAh;vCY;IAhBAn1lYxFA(hTvCzxLS4OwFM+%_MU@ds zD3(+`i<`7?b%u+bTjz`#g6O<6?qQX`ZesrIVcUMLR2GJMJt%kfc;`DA|AFcB=)sclDCZhqukW1HdYzA+jC0~ScN&u`rBOIBe0BRBgxKA}p| zl<}duK&9_!#Z7|D#Ux ztN*`r8t9p+;sq7(01$UsRx&4%%vYTW%1A}XTv_7_W*p}foK;Yo4&i50f>DaYRrNDH zj-dW@4vXmzj*EjZ_I)L?q4_z=ExB$M_pgG2Q;F^*L0N9Iq?AuuQd07*OcFqdwETYd z^a30naA5O&&pn9=h!)Rmq=oT%bMt!=@7}RDmVJa7nUA*j&oinn&Lg@s{`8Slr3E_~ zxeq%fmA-GQ+a{!HT%LzN_T%Ar(@Pv}wslks=a6htth2Y}5=hS#c{C#jM5V)nX|usEZ(LOuf}cti?%N45V@4Woyc(LvEdX?igW)WMxd|1lLxMHo}R zhnU0x)j#x~;DUN&h})7@MY0Q$P<=AOw3xP!5vf8|BPI#R2ymm)VFEK&;Fm@s?-U)0Wq zIsg1Y9o%XznPFnB>l@SGb$h&^s8rPCI!dOc$$u}j39qnM(Z^HR`GfOfV34M`3GmcV z19wRcDNDP*VCN7!cvVCs&)A6lRnEc=&)S%|OAM9-7YJ~rk}z+dQ2tZo8P`=}dGozH zwLmgH3ES$RFC6(J| zNznlk z``4UVj$`|+J4!gD1<+Vgj`EMH z6UTB6BG((GPZ?Cc?y0_ry8p9^{T!w6w;GiDZ)y<5zo|h|f2%=J$p43%ix0k6Q7KM7 zc*uDgLnEMa_BXR%?yNVUOnz|2wBsoZiVev!QEzr@5*E3daCXdkO;YiTYzDsr#RK5UmO!FDy}YU zpWBJV{71es)g*5~Z)7(FyPp`+VVmgmeSk@6PDM6im-!ByMp~NHcyw+^Pz|~!~K%m!gUvXP*~QXVy8|2iLSwSOZT_B z|E^|N3!fwT`eQ>w?arsBTld*P)(p2d(Tqh9Il2C#;R0{&^?=s?o;mL55}xaJhHQd0 z{>sA+SPxUmAo)~jfs86Gzq5m)u8@Cd;>dK?@0{`SgsMUne;7$_uM?jvJYNG;VZ-Yg zO0@b0^G#Gz?`RpTSY=aSh>R0U<2o3{;znY}3E_Px-hFlGh&U&?sANj}Y8~{c6i@G2 zFDMzfI74E&ieBdL(oI)>wCGsvgl_lZwd1~PaBBZ;r#7lA-kC_qf<9K+jI$Sf+1K99h!ByejP?)y0z277FH7daV9jd^iKzxLgHN z%x_>#zQU_?5u5k|_LvM=Nu!lju|zZ@lU~)xjssu`EGqPim@=$wgN%olgQp+oHFclV z^y36lljro#loI6W`TIxxmle{R@{V-%f~?>Xy6B^_95YEcS}idBS%&Ru5kcH>fc|Ga z<{itVx@Ju8M@p`q_}8&E;oli2_4{j3iyK)+M-GS9xZ$gFa@80nxnX7R(i`v~H%Hs33pOF9@^)boMs18AbB^V*gi zt39?EKkps0jf;|pW6PB8+mE~cM9i&>wjgizy1F0dC1kt`OoV^g#ij$n}rDUDqX30GF_;3D%kUA0)xbt%$y1XUqh z`))kH9L`kQ--Yt;CKfs;CDDw-L5#NmO65!Y==Fi4)NI$o^eaGRM(3zUc4S?HFA$r9 z&WuaTLgk^fSiy`hyy}Ky z^CFg+M&i4QlImf9MaquSwnz@l&6e&<$z;*RbIf*bulao-Ovn$D(q4Vic#QBEs@B?M z9F;i^U~pIg{gBSHdiNQEf?*&Gx|2?O38IN7qRFDg?lSoFW^TV#*6q&JkO*dYK9ZFA z?j}B4uHD`||LJbtaYt8jMbi&v`ELa!2cdLF4oTSemy6UDJ3~mm{`etsyEWHpdm%;( zT#X0K;r9G5?sRP@xu6LK`J=^Arp|qAd{GRI5xsR@iz)6v6DepNgR=*$9F$?sO$=xP zW#8^gH+`QZ+CD$-Uo-TDizg<-XItP?L{CG)FCFBr@#*C65025*zJsxO&mC_`ldqeeU5pm6 zI1MwqgS9Jm!mKJbhf2@$?suZ?-(Vqe2EGGt&jsIR3m+yz_=k4Y*ZRk13v0bBM}~y1 zv_IuWtJj-aSlS4r*7BfbcC`8}<6)ZI*tu5uyf(N|nRR7chx@U1Tm9thKRe@K9RPGU z&)Up9^DY!a3r;L>Da-SX z1tZXZzMtKuopmThb>ofV3@);GI0iQfhE5%fVEB5AT;@2|+?YVSoWOY%dt$5OfT-Pb z>~?KYc-hRJ(REl@mRnuZD98^hiM1vG-VTePx_ngZt*tk-QU4vylwfIi(=xcE+5~JtX!h;U|?5%UrkLDMZHIwDe zSKkvtS-#g$eLks^ylD+9aOxKv?EBxfwvph)TN+VFwp)crCq}z4r{ChTw&jbqLA~T- z^x7gd%acsSaTdyZ!&y6UJa^WRc3k!i+C7bAv_HYlD*gC_EPj zJKGmB^uBMW)4gQLx(YsU2|$y{6PG-uT}q4UYq)MjAW_r3J7BRfQE^q)`x)Eq`mnI3 zz6q;b=h&tn1MjCS()W0(fEkT|lQr&Gd?I6+D%X4at_x<&^x^P%?a+BsVKtn_wnVo! zy^NrFJ6eH>EF(7xKhdNKg-_~LfS?Yk-#@&*qNavdyR}jhZl#4iDAXoQjErtpeXSV49wxIvI;uQ3@lr$E`BT=XFipt zmUck-#P##mrqIsdXY8iW-N_0tMOC&=TP#kMr3Iz1C%A-46#cE~Dus$!q6D|4J_S3m z+tg;k<|x8+pI*M0>+4Y5>H`%mQ8o$cY@(yfU}EKSfZ=+3a$V{`B+vYJlG23}7ZrCk z*xhlYn1q*0RR=|quiC}N+~=J~MrU`OGEt)$d|!ptortn8`w*OIj4NI}e`=CE0d~7Q zvp_$nRO%UhtXc1_6?o4W4K@&EEXBpyYdUxAtcvP-=C;P}C9n6h zHWLTl&`;BpEnfS;+Lh-S?{*Mwuzo$2T+WtlhSB43Z&zEp}~~<+q<#vHB^L0dZ*D z9RxUaG&iAN?wlg43Z=W%79|F%$tPlc!jePwo^;}aG#NT|rmTw=DIiDj)!1awo_FXY zkLHXm?xcP#R4>vb;cpN0lKg)4UHmenPjyl!eKE{tO+Bv&`KvL8$JYN$*J%L#>a**I zM+~T7)I#5VJTiE&OgDY@p5ZyA?buKF!Qa2vWOU%9n;lB;c^!rma)Z-YS$5`PVAQ~d z5m|ZPyGgBK3M!hPCl#d%r+QPXH^X!bYWIR3u^mtVKsbAuUu*iSqU@1bm z+<%cvrs?IYi8d{@9E{X-E3uXcL*QhVIj{IY1`lIy^LUj|CY(*PcsgJua)3GXt6p8X zIOx-;rP*G^^C4$O9nJMI{22nX)n!o1%Do51iXMXI^n|c?gvJN|M5;JTkkY@}Mp%;s z8sAd)nqfyW{7NKc;Ll9tIRZpCFBP18zz8uv&=JP(f+gB-9wjk+D^@r;W8)pH zJb%^;(wF4lTJcdBhz*I1qpu@x`SWU3wpF$)YMbv~yJa%2^(lO5E7x(la@4Nk?dx7FSm0kmFGDtXZE(uRx2 z->mG27-}*rY$Rps(hBZ8Ud9*#H1Th5*}8Qr8RDvAa9CL$s3-E^HN&Dpy048%vO=bp zx}wTaFye51rJ-;AK5v7=&@6@yfL8-(BS;Vws5Ix=69h~^lYs26&|2uGO94V*$xA<^ ze$%U5fq!_m`YsQnhv30l`Mgosc$LAn!t}$x;q~4A4co-UX)j>K;RaX!(rHhH&dU{B z4yKCLeoyqg^E#T`&Hbv8^`2+odM>r~KH(F6>(?HpXZKB0bn~`*jyqc~pEGpQQNFjE z=|YRflkk`IhRVDpI>N;gP3N(~$DL*7m)mjrSRH}418(=1V)#NmXUc(7p9lovNBG-J z`AgSpcsiaI(vGqn!_$2IJ!*6pgLEokMwmgl&p_Ax4P8ezbDHt>fJ5&0etltb$4Aw3 zgWEW+B%EtGz9)cj;rYZJH9v`oq*xLvOLEp;{92DQyRQFvwWnLvJdHM9)u5R}<8iW# zkAKwFwX`aZGAH!PSei0kkw=~h$om}9kzJvjt*wt4WBBPQY(3YnzD&Fh9)$L9cG%CIl{&VYe&FiECbR|wAK}>rm!T&=|Gn@nR$C; z9X_gjitI+eKge2=2TT0ctvY#y94%FWecAQIaK(N@yCzQ6N^M%@7*HD`r=@_0NkqH} zG}M9uP8x1$p{`8@QN$5prLO2PkGk=MkMiC2eyfL^%~nX$3LTFp#gaA7X2uIOzJIi* zF=78ekiDeKp-Yz$J^8)yUoHS5s%HJB{hsggo%vvTBB&4WT%0*V zsfSYw7691SC%QdTW3$Cd_ZDUyHS*fleHmb<-z<@CA6%VpR3wqO;pqd{Z%}~ecZISDe#q++i}F1eAA8o<3S|)uSlCM_70zvz2VizpnGC|5+u8pL-y9u z8U_cLZqNFwk#oDP3VzqUbwLVsJej+f(+_XopU9i`+ozkJjoGgZnjY)Sz+_L6X#e`G&@#IF>=%7|fT1ch7HCa0!}Pg#FUOD8P{ zV9t~CCR2HCo8=itAoOBj$0+Es(%9IVO1e?7(^=m(y_Sit0-27^HrU z600$@_JX;d-8AG0j&jn<$B!<{Vf(%HG3Io`Nnsbm?Aw|+2^bZinaolbc@V3_QgQvD ztD9(T9oUJJi&8McM^>(xl}y|8JcBK*&YNDB98c!zm#5wu|aU9q9l>9KIZXg->s1R4JKDXhT z+AB72XB?3pIJ(`F8jhT9$Ft_6l#%F`2T`4;N3_8o^Fpf95KToY$&sWdfK6(6J-0C( z7bp~p8J$NOf}%~v>TRg1?wioUhw$!wy9&8|hn~LfwMQqK~U z6||@PdibV=O43#vzqvIYfi^c8SozJ96vr9&_tMj1y*UmX%zW9^h;j(D4@H~UVi9OP zd3{SH;!y9zog%$p`qj}pKZqn9x0lh1XCb9NrX}o}n-d(mX2Ax<+ARz!V(kMwYIxC8 z2(_|)Z1b%>MP zoZVET!#wkq$i&nR4hGP=^aMDQG!fQeCf|D)M!P4ZZ^GnaS6BcK9v`deTo8H(i}8-s zSp*J5_YUE?KkZR!Vj%#yBNCPvgDjlg#RLB0VYcb8Fc!H>6;hzDiW=ZJ2P*hS*IKwT~uTor8-V-0m z#PeJ|oHI%_?&VC8K(gqq!if^-DI8C4wbzG0|7Pk#6^tx%k`6yo@f-wX!UO!GTM)6a zWX}!7Ny^)-u*#X^8xt_xgCki4XJO@nxxZnoz&2sll%a~re;kY6Vofx_+JT3QQCR)p zC1=qe{;qsiNrxs-oX7U-^P)EaeaqPCC)hRp^gGCdkRMIS>#KL`J8Q0J=sM19_0}nX z4&O}dw+Exeaa~w{`@kBq15XQPHAj@uQmoiW78K%i_jWrOcFu|VC8cU7-svl6mIp6D&Cs~q!5x1B{5{sW-+klIH+&}ON zI_3qprxME$(=d`EsCF^%*F=43^!;VrQZ!VFOXt*>Cl>oOT+C9X_Y6sYlC82-mWaoG z-O)*TTkZMk+Ds2%wR1;P33VEKqh7e8C}d@$i(3I?)AvbM9%Y%+6h=uj0^^8 zFbB-OEt5p$=(7V2 zJqk?2Fe0eVD44ZkbRxheO|4JiwKRJ_&f$R(m;EennNs0jNC-Xsg~j@>7|o1JqsI&p zRdQBA2Di;^!VVMUe`-CM$QvrA z7;m51R8$sq3^37*qpnWGabd$%o6pe2geF-`nANXRbZI2j6j2$RyyrCBDSUkrh)da2 zfCS0ub_eTzGku$c9)I<@&u2v4?Jn3j`ihq-kfrB4K96kypZlg9YuBDR&mK_13p)4E z*=66CryL#mv>GCsrp;;@ZfR1tKFZWGNJ9u*?;56ZHL2%=e~-FKC=%W@pw_*IGdA3* zfj$i#^cqlay3WN>)<3vt11}Em5&lcZ?6w-~g6&5N?iP40GBlO!-7*=5Q1vIk!TV>l zWk_b_KiR&ejtdH%krUjY_5RW@L4h4{?BA{P6xmP#2z~$P!w3DH<72V-Gou&>ZQjmHv9_V%J$>N?4S1(&L7ns&)ay6W1FqWrm73GyoMd~sF^ZP?ZP!7~C zbwb8BX|u$F)JUshb`=^ zehD#7AYh8iVxJBle{VZdR|I{2s7F7{ml+sjJq|U*IO7mV_F#Wfs{2*{{y9OMqjBg& zzoim@7433xm%r1E4!^OKwPD&{^X!fz_3!u>7MTDDtJUSCI&J^xKcmWtmMo7cE;rs{ zgJ7OfcD+Enn(>gtuF$keFG6l7uVRkMDy{Wx^5a8EFlIC<18!~MX$z*x_xU-cSUh7B z9&M*&;_ae}{HdP|Si=fl+xhNCpBkA0#d1x;P~bEzxbU9{UG36Zr+=642)nLycL3ff z*m;o$cI#rX<+GoX6>Ora*fUaf6#5l$J2PPz)$Ef?R8-$B? zc!XGZ9f1xOAb0a_uqI-Dn+yw^UQUYxC`)iaFxQay_F&S&h@4$f9%OmX0Q?U3XI=y@ zS(}?3KZ>dGqikt1&$|OoEzGDkJB736NkyAPwqihJ?xe^Bhy|Or8me5MU4jX}n&P~g zR_Rq7>TvuAu9m23M7`V;+X&SeQ#T()*sh)-O}1M>Pks@)oKn$(l08%0#6B#*oFP(LIkCB*LDU7+Hyw zBm)={XfJB5G&Yr>wlV$Qr(td*f7gNU<`+*pP@uMULY{S=fcRJ6-E2lU1x=r|TODsL zTAxQLTfOR3eVZB1M#c{^~Fe?emAqxdkV*HyDL zM;Gf@;8EYwouh5b>;2BN_J2$Yb&LiQ;#T{Ta5>jj6vB=4d!AaxNgo6Io8zf5A9{Qp zdc3(O|8tV4I;ZEP+;w-d(^a`PBpe&B>3h%Zz6q*h6gK@jXX?HFQ}#!f`raN(lYew0 z2ME*T*rVCbE(-C&b37}&;aQH1+^enJbwsZq!Is)6S9CjEqrWciK=_p`ivqD(S5{FE z71Gl+aq+2&zsD>Oh*#_H!%Pjl7^8jk9iFApRt>;|YET!RW4TelCszAmkRO(}M6f3A zYWK5@)bPL2K;wfyu<|3u7Z~|ODYM@pgcdN;UM?(2Q%7OUE348@YPqTvUdR;&(m?0I zF|gq@Ec;=of-(a+_=$P;G<-RNXN~$Hd9&WUntqs~BC!O&Rqw$4Ok3i;lBM`%}6D4BfE_4`i^K^ zmHNDLDyG>$FVFrc5e{LOCnP!Gk}C(>_7^$MCeQ|duT1&q;o2^wYU1!^7h%Qhoo#-( zee|iNVTZb7hDDp0yi9q)emL=^nfe2Oz3MF;fAfVLurJO_4T}AI`>qG~A1~}YC6<%y z?>g3p3fCHfZjr$LWQFV(i`4Z@*)xuJzAIg(`>%F{ z|Mhyt#rJZd$5aos=KebWF!J2;uoK;KHH@~;--F|9dAyOsWSY?iKt`;>L$(}Pc|PPT zKXJhZC_hf*v+_KpMqics;A(HTG`^IfLg3*W6d9fU?h0__gYmbAD7t)BnDtI>2o;HI zUcv$k4i+DRICQMqih$4mW~C=;oBIZTJ>d4cy)17TsXr&E1tS7GRiQ*Ug2l*M5 z%(B$YZ@UI#%5Y!05zN&F#pZpGA{|~zM*bPWoHAB9P~lqrn%KKjXAbQ>Wr?+`*Zf3o zcFXheI$@lMQ^g2Z3DQ|sFmLkI8ZMvFl>4o~1?xD@34x4k|MEYu$~-BwydVD=R_?$a zr5z~>>00B;8cMl%$x>TbN>sPe*H;}^*_&t_G{xL1>e~^o+`kCvGmvnmP=5; z#RDxr{)*;7Cdj4ElDn19_6zwGE;cjOK|t?z(gTjrU4I;t9R7MHm^Vc&V;|s^N?MpT zHr1Czw>*mfcI@Iao7fLZ8;gMcm&N)gL+r5q zbN~-0Y!tL#NY$53dL_rlLo2Hb7M#0nt>@n7+x~F$+sgWFLH8v{-``QPU-;(!O8exY zTaT`k-Q#V*@8x$ZkuH1b@kw2#EXpz$Kd{g{_Z7El`UHpQOKjdfUwSgNHg2NwkeB5e zmW+j6>HmDC-tH<7ad?(YGjAzh;i!(tGM3{56i{I|wew%Mo%477(&Pj6KxOlU%M_)b za^Er7a$L}A0!vs+ElQlvTf{Udjbgu&8JNcB-Oz-(y|H`vo2ZFSgE0d&&TYlw9Er4m}Ft;Bf*Qz^=MrvY&4Mv`f3}_3i`=wI zKgjvOkuOkP`aG;_LK+|uHLy5%T!X(j%@d_D{O3fiv>*G-sO;i0JwF%w2b6||5@b)e zvo5s7k)jDDavCTvwKBlee8OuAcxJOUW3Z9EOW7YpH-|GHQ^SrQoFsZNS5m94eQ6ryyMLM+&t3=a8V+NMF(qX{yl)@u@ZUU4+Iph!1T7uD5CNIEJ0O^m$(Zgq)-~RR zxui`yezgoQ-c?3GH{cDO7M^%5M~ZqqXFaTq`fhoKrS~gWYy?|X8Xc5qKWLYEr4f9p z)a@ZQX4cclq?gG07hRISGt@W$G74Q1AkcA75v>I!t_UWnrNf`Og-XnQJb_Si`;I!U zk!QWasQ;MrSh^D7yyI}t#NfSruT(_j5a**PH2hU-_%_^;htL^!08_>>r|R@jbd7fkWQo6z1~r zKTaTG0}%(^<}*eyhp$7Qq6!~8_rCJkuQ})-8)y%4>OXvFXl>byQSoozrUZ;-3g);iHzYM|MJQW|rB&7N<4xES7tbO^b)Ps>?Ff}TlhDkK zBD($Vb@J(hKPyEw1GIauUzL7MLU-DLW_?sPV0I6 z@NDpj9e=&RGeSWgnqam*p1sDMY?AZ2ynWw9nfFQc9G8w)$;i`xfoXX4K`NMGB0g6a zt%%oOx#RcRTGD>F>@Wd-LyV(eAD=&Wj}p0Ty#~5mg)jT`5Ab`#-Rs2|`omiHL|?vE zp6m4HrXt_6dwd?|NPaxZUhx@H@@av7OBQcl>n1;YVk}Mxo#*Xxyk8mHHiT171FZtX zT&QbLh#PIY2RyTdw*jm(H%NRA%pJ)I89gw3^2BAK(*+*=3N-{4DMejw>fQ`Qh&l&o zq6ov2Bu)SJpbbVe$t9UqOa0MHgn~z=Hal2SHw*9N!lQ5^-*(*i~W#g;dtu8Dig|bCL3E7d^M7(g#AA(Mj3X_v`mavzxtD zC?&hAZ{84KGE{x-?f>lVE6^9okX^%8QTKjus6>L3Vky6Q8Vzy!Uc2+?z4qroVImA` zgKyt{xm_6&5td@5ee_@(_VWtXQL_OpG*$7CKJOS8g9+iEy+^Ho=qwQy3{t#< z)+dunE%*w8-OSMqg+&ubQxBp0aCQ}0zbeyTj@oSw5@dhFx)OXs>mVsDg2nJCwyWEZ zhMt{5&z$cbubvv%j6FGk{R@BjQi-cwyp3-+Zp+gESb9LL3soMp802TpksdP;f%zkN zTd%cdb}}Iyz6ov_t%MQaDE_nAxLfAGoNkVfG+V6L|8lw!$^ULaR{XaX8rg(!Z@g zaEUwmaP!5*#uE^!4JE1F$Bai57tMOk5sw%R@gu)5^v2F``kJ>lBF7zF(4l;1rIde& zvy{s15qkc+x;Zqut`Cu?&m}kjN4Fb$+`@2YlYB9ePS3$tQiY`*Fuk@QC@dOPefIx! zcHTivtnC6vL1`igNDIZ#rT5;1AcAy)lu!;J?a-ALX(9qfB=iy>0@8bt9zyRRp!7~a zL?rYYX*cKGbG>)wobS7L?#}M)&b#j)JG(pY?Ec>0^E^5VxRWi=;R^0H&}XKk5{bXI zycvn;x=C*BF`}%pTG+NF`swq=53++s%t>J5rYe5!#&MZAr|TE7);VBiR^e?jp0p&c zBnHPocD3L^BFsdV0p$rKMCGI&0oU&K3m<- zo@5;fC~r-WuLuD=zCE=S{{P`xg8C4dgB8Co+i6gJta4JGV^HYM{Iff~;9QulQ%yzy z;Sz3E-5Yx%#Y{xpj1-Gr4}K3A@le07i+|_dRBd-n?X^D^QZu-{gpj-25c4kLO?MBh zy9aNAe4d=G!6!N=MTN+2xlw?5Z#Dr}3!QU0qqe6b!g$V| zE5#cx5)j-$Yl0qtSIA4vo(s^2>>36ikFnV?5bsVuQ=WEZaudY0Dbm8JO34YR$TVK| zv!1@Us-A(qSmu%r%?dMJdh&BMfnws(>!v!o;)Tv!ZrVS5LsvCpafT*?Q5qqjixik& zoD(_JdcsVlC}y{cEA}`e}8eJgz!q`CaU1 ztGmQIa2o%0M!Ard4e2rbYz-syedgsMTi{NoN5R&~Nwu0h;^=Bgo-y!VKVZa7y(i3X zg>k#(Nd7!en5{<6{NK6njx?8c@KwDcb*~A1(Np=B@j)Ae@=l_s`sS9ks9gOwpGd@jOGuwSmb@BXrh$69t@e`)I(vU#@( z0OgexN8#!neJ{m@qxp($ZTiHhzfzuCNS_347YA0a)^2Zno?G@jm}m`Aetv}i zO8WeHSTtzsV2cv)$Sobc%j_ z)gc%cE)V6aYYW0hG6U@xZYrN`#5A6UrLZOwEV|c=D~LUmp%&C-r-lD!M(2wPx?E;) zt~M#liW$}tYkp3C4?|X0+2yEVcfYJ$rgH%e@`*)WOO}*ePNvW{YtLZFs_>Aw>a#ko za!tw{dZTF{O`~rR%}a%g&sZ~*%SAS>~;ngir|c#3r;S!!6y?` zJ6QHa!dTDA+A-dfYP53b$2xDb8<>~?M<<&x4K-_L~igwGJ;YiX7D57B}VohLtB380$(? zgtoFAFIyH_>wcW+w?jGBvu+Fv9-ivuO>k6kP&m2BqK^Q9+Z@(5eV$b-gwkFIwLA7x zj={r1jbY>!D1t4&sXa{ONqm*$?(k-7kK^J}H&4iX(vtHJttSkb>*6NvJkBl{LhHsP zO7y0%#Z^gY_=4AciWf^sAARr>@+u9nBEmF-W5;EORU_r^;=pmQgO!tqJ8 z!qtHLhj0zsM!71Drax`IaO!v8F*_EvZsmDG7Q!aRXEK+W9MgeCJj9&1Pk(t;NYoyMIWRr zt5Ke&r0m_KFA*8{%5a{%u>t|2={cpZJS!gwG5_>!s>`dy`qb1)-(i^1ovP!^H`g%= zPz-iVZ7+@a`2v6`H(}^EeFSG>I=|~=7$NXKg~H2%?RQ8&6@kq77cv1+Z#=-XX`7U-#uZW~0?NuI8mS8^D?&JHMq|o9kbLx|Z?3K;7_vfx4?I zo>s-5RC?$82DUuNo>}$Ve&(acv}?-g!;6s~n6wa7dI%>#_TX*BZf9m-`sURdL$eXf zqqQHL|3nlK0xF0Lo3$R8{WCFNmfxkgTec6U1UXoXy%K~EA z?sYrUoeh|_`lnnalco7ZlZuX%sbBXE?yHk_Q_$+D8ELP4mMQLqh$tzlJ>^u8#g5#Q zmD9E;>45xBfWrR{IBdYV$J#&--=EoXlSD?~9Xd^$>rbRKwMOFKtcT?AJaRCWpb+u# zHp=<%B}y%+>Wkgs$@<8Re&atCLDy%p;yO-KgWeQ8JgeVnKktHqb3>DWta{nAZn$;Z zzd3a`(2MMUX?(xbJ%@KyDPG1?G^HM?mnFX2@;J`^4wX(bO!kKk*xOL9B$)!rHjAxc zpdF~^4Rli9C9+K2vhbM>i{!)9(eVa$aaCT!QSUX?chLcb#ffo>zv!B%Hz(aKt;4j6h)8(gYVUfcti9d>H>P0dkz z=j^iEh)+%(Zw1Ff+VBt7I!*nVP<~}09N?qwR^ z42CjY4jTHCrF-jKkx{9lH(x}M+yppL$lYV%P^d}4>GFtu6`fE5Q%75_wwfFx1HCb_E zPD&RNOm!EbWsLj6&j%!l2+7{*)af6~y-Hfe!qZY;r1nj(2HIUvZU{`g6#QOZVwzU2 zvAy=bi2ljC&BM-jXJJHOhO}G7YqR$x8%g4x!jKjbjIz61am7=+lhV^O`+eLuDG0)* z;mQXEI`p2#5XJqT6)uN=hK5R#YKV(#bbDKPyeEAH+qv(~q}TWgP>z0^UE+@MI3QXg z{>XX*bLFwKXgk-mNdOPIT4!dnUdh!=!>cSDz9ZuhDpb+pw)ifFWViJSn^ zK%kJCx@|(%T}lNV<62!n7R>n#F*m0_LEY~;6SJgJppUf@I;QjU*lGCI^!o97dw*Jk zFV@>Rp>5~jRM~f5Ips>W^`P}!Kx+6(dztm^Sj(q-nL|QCGGqSXX7L9LhdmvI-q7|h zZ%^BN_U36=~4h%JS-Ng0idYT-(T!DHEtwq_b;{kvmZ{w>Gmq zG+2xNQfJm@PtC@aFeC4tC1a|VN$Do){ae4WDOS&;708e*6UmtDxN7NsSk#j`!j#56 z@}XjgX+IlpL2DBV%lg2GV_y!b;8;P1b;{Nk(Tl=t zYnz!Z(Z`jcjC1WQl)))G%2c~&^j0?R&eqXF_-qU4!MZLp{Jch4=SCn`;DCJx#zOZ z<~Ih!F2Whs4u{G3C)G8gY=PDw!qD3yop(yRom7N#A8q>jdV}cMYUuXf1CPC>1p{_x zYkYmEqz2~Fn|w#Hx&7cMy2I=JCC=DI^kKd99WmO08kpaOM0_^QA!%dNDQb`=ub}!5GyK7?kK+OR!%RQ69(7f+yg`PZNYAB~Fg00oW zjQw%p8%?q7EHza*;!kvm-9X=`gXB^2ozZCTn@Z)@!LZsDWQ}@B$fiRL;TEkaJ{xPj z2ECD4I;hTXw3J++)XuzFhw7(OwTHqd{Ou&M4*JT=!xm+?63-eGmXi5Xv=!Ze6&yje zm2h;P?;;{$X$BqQ70*^qcNh+?g}kPRU!-ZYUT}^mf!Q@^j>oNKyw1Ng2~nFS$#;Hy=S;@cFLDX?8(gmLOxgmQKe|_-MR>OgkXWDD{Zf z_V@_SMQh3`7nQs1b?bB_(|QHFu(UkxvHk7q)cfT%#E}cF>YJmzZ@A~p&`S&Zy$A$S z$CysC=dq|LosG$o8#DIyZf$6uMYT~1!jzd8A^|G55$%a;Q=~mosY%OnX^9tvF9w~+KS>aTirnB<0o;5b`swgH zzAksn!sk4RB31by;_Z9868RhAnGBZa5NLi6_2CxNii+dQ7=z()2_w)HR!w-UQIi^n zzQxSkb3(wQlU-OsbWu`IXsH#SdTWu5)+IHQTa+%l!h?-CK;qg>8Rz_p=6ZJ{2ZHfz zOs7lPtd9M|`a9&+Lng-xpzRgnkrX4o%c@aTNN$%!lWE?GsZIBslO%br*hJkD85ycE zx-gyFNN{Z`t+e-&;dQ-Fr6OG{0%7l_{5ro9BIiVY_Yrr>nwQ6JU~1fx*_GJz$3_+h z;gEG1zNkk-9iQkoZ|9K$>+-j^t+;t;lDYvP8&jYvw?8~AWMRz6CY5ZfVo0-Wh$?x1 zFL}LKYL-y}th)RB+;OGmip2~f39d;wLMUvk zpQ>B`)NU<1%+5R0)6?_x(>xXnUw@IW5d-uaty`8P6%ll=x4-Yx_h>8hDejvIn+}i`I%wMSSh* zt@~*|Et%6{Z;wlM95WZ7z|YLZg^wQ7Hne^Fgd;&oMMHN>{{bBxol|cKCM-N0JR&0e zx7=|Od=oax^JxnCTL$?|FX`XEw0kK_x|j<8TIG$%iDUh(i}@- znf}wT>JdjA)En&4WMuW3p7!m1C7F#9Auq*kFR@9XnHM^D`%tIi_9cLV>`$>DoRPAi z#9iy@Yr(-}GS-Xm!P@ldmf$QUiR3^~368fhY@RZ;(1n`(ZB6EHqQGsX=AVjV^6R}7 zGoy4I&46+&?q-(>quUNhJO@E6V9GW5fOLwX&@TDkbZWWtmfuDoQVzl}Tq>!`>74f8 z0Oo0dR|zE_hSSS+OG@9NFu6U?en9RqQf&(K|Bj?eq%N-u9lYPDaAa5OE-YsHH$!uP zcpXvyTqSSsuaIRb!5Qht@wrj(g*4>W5PyztS7t?D3%u;r3%>qN{7_JYvRQB0Z<5j)TqY3%# zC_VAaw^nv)J&=Bs6VSn(|A7n zm#30(8VI5>@%cpQT0F5X)uXR`l;P$51;}s>f1|GRF+f$fYzx-|7hc&q1+TKA#NcMJ zN4>=aEAY)DOmCl);ltomnMV6)W!+!ZCOqM~JZx7k(`@|lT!jAf#QKdU|G3Wq>G=1> z;eEh!po{kv(`G_&qlMI(RBl9e9BSds%7WXjF26kU9X@fp+Xu#ZJ+hqKcQp$-->nwk zMMRSFEc#|;Yh7KCB;(il$?AB-L#>XwdJPprkX#=4Q_U*5bD{v)t{&O+`@!(ZtE|Oo zVzN}m;)46D4i?SYjdUtN0YuK9Kz=8ZLMM8Yo)S9S(Q+QgsgEZ~zc?{C4rAlQ>z@*8 z3etK%D}E@VVuqtd_>Y6PGh(anYu?e;$4|euRpO?hf$vuVx`Mp^oJ}T_+^SiQ;bR z!`G8iI((m&+2gy^RoP96=1V;v;ORDx6TRri$GC`v_8hk|d0@#P&%4Gxte_}z9BqGw zl$M(kuq9)BaADY=SAFCeLqcLh=Xr3dxBxVwA^&vQW<-HJIpE65(!g$vqATZNExF!+ z-geBF8!f&KKNL+P@Xt}?xSKBiLFW-eXVcl1a1V9luJAXo@YNlGx8I7-J%FrJFtLvr zR@-q86nJ*l)4_u&i6fd0)Y%%Uw6OJX2_8=Z*^_l)^~f8N>yuF`fc5>oABY?XRkbe( zpkPN*^R-BmJ@TlTuF+4@553JdK>~ zknCSu3iMrIjF8`jwtE3J95n(2s&2^HqNE$2*=Y!L^BAcnhI1A<(jJQT_Jsosx8L6H zMaL_qCXK%O?O?%RNYJo?Gi-^ha$bA6A(4M;{D_5p_QZr(SorAmc5pedxPfor~Gqk*pkQs@@T5ud`p>g=RT8?BS=jfaF}iu$byEucCbW_o6Bc($_-WfAev7g zL!{8tXGpD{YPc^86#ZS=3a2X9(!dDn;%B0CnFu#IC9l|su{3x*+3mQ#+_M_?&>lr% zpPzFd(yEHS0#PzqHFY&^J@Tk=-{QG8^=qumr)Kt44CC5|9X}oBf9VL>_{C5*xfhL( zMbuN&(_iI$OAR9$Nxa>%s#;V0SDAy;Py=VHbjUdkw9u^d-yx?lM9d7hsa=c~TG<99 zH~aR9pxG{qP{u+o5yP6LH=np=2c9=5&NATiNbQDqwHnXpys0G(mIJq|Y+S>E)656T zguQu(I1c_z0mPK!Mn8$>Va{gHlUp2^OxN5f`=Rrj-}z!{;8*nObO-MI9&FJHkt;}< z7DvE9Q6_*T!#Zz`abb0TFM4d<&pu0LDmEcp*Bjgqbdtx%ZJbEzau1(Wwcl~-LStH& z+iPpJgvzZgvBCYaE8~XCv!7IaGGwF|^-QFQI`>F)tgjVAa>;V>ycX3I7Rqv}Chs@$ zW?4&dU%so*=@x+gVGdMAqPN8=?rE;PXlZ&|6;u=+Gk|B%=6zC4&gA_?S_xJwcve$* z)t=PHee+&z?7K6qd)$8eaIYlU2C1PWE5^BNuQF(usqRCHRbg57cyrTWit;udz12+6OghlZjd( z*&D0jY4oQ(dETUNeORkt+L)Ff5?in7uPH9DH%N` z2C|zz*hx$*omBWUminHUwEu0`N9x9)SSHhLF7mfxRf#D_@FTb}$egE2?uFjN_vSJT zA2_ckDjg&)ueI)aJ*f%4`pEr8$0rELEePpGgoaz7{fx;iPXT@e;`5)-bGFE&T`@-q^3=b-{EZ$2|wOfPBK z_YFx&k7aS$yzlYYzg#mMDZa9Fx3yPPZ?v3Xu#wzabdWVZ+Hu|Ezc1DO7HE=asi3)> z(nvjQLE`=SuUb#rfnFXG_ok28VCxgAY-rb)2{NZC9`BK|Rl}e=IfEa043OTgBm(cf z#PZK9u9`pp4s8&2w-f2#z96%oJn94~{DYvvT#14ue_Mn&;vxQ5gK6V0d13!%lvs_X zBjBJ{b<2z40UcrVH+U}13ujIjX{?7}xb&Msl>Z?T-zg~zI*@NErW~4_s2uVgtm-39 z_@5pIVF%&mR5Xrsy$3JLl0_CTN~>QFJgG|H?3YvJk=>$D-*W!7N}L;qy#Mp`1AE>7 zFD(AQ@N;Dry1Ag58i$JI{@fsH+74vW=kQHPF=y{U`* z&A>nwN){t}gZJ0|MZCsBbC!)W!**&0FRf~51E3^twCVAS>A)}^cXNyb5kS}74a`Z$W0JNk^^ z`!DuQNpj)PrnW<@C+nQQFgvsE{Eg^`o{@QFFj$=LX{CM|Mg$i`87 z8=i*Tpk`CcGmbfPsXhZ2?GH$#UMsFuWrc~c+h-lU!RYK&#~Hd+xBXKkW#uRO<*)ZZ z=*Lc2&=SVW!IMChH>`t!fiXhlvMM644@=^81E>c8gY?zJB_uXyXA10A^CWnn&oz+n zx}jSycVF1&qxBBRO7!8bo0t=MSV-0w|> zcj9pQyM?F2B4Q}VA75MmNCLI<{sD*=@P0q_oo`8co_*> z9zmMBEYSc9*K}B*>AD-A$VHd+vcU$k1xS_e5L3tcUnJ5uo!@csxbJ{JSFV{j-0W05 znq&v>vg)mx+gu-3x1xbu1jAiY8d}!?-L|PwZ#ru}R&V#@1bTy{z1*Zxtd<)?r3u*W zmdy+8##k5F)GUCE$N}%g-ok+jtDHQzD!g!mxB~QXKi!^6n~A@TiP`k{aoQE|RO5d7 z1TX2R?F7pTP=&o)o=6+nT`v@1T{bav6y_iYAc=A?~xN)xVZLvGDG83Fs z@5i(yV4lL_WoQ-n><0#gqFPdi*ta)8-Xfx=UKgJv27NLSk-&&o7U>8i?q-!*TPrHq z;R15e>3(3v#f%IAW#y60Hku-&BA8=#n*!6Qvzzn8-uhF##` z3`=S%{rO&?C;D}26*!xNnbJPrX3JxfvQB}E_&@$RNDd@af-Z42sK#VEW+0F)V5>wT zD$|}&D4R5)i00WDlrSC@@!}<-WUZROM9`mde^PU201=kFS8kn_J1Fcw#v-z4mmGJA1TG1SHr};~`WM zd8S4R^W*Bjz4G`~%TNQDb4 zXBQk?w3vwt1Poa=IvtUqSkQ&C0O`oEQ&Z*30Z^+05~B8P2y3+_SW2>db*v6Pt~6Q& zzw$|H4{70B_rvM@(3iDM;c(-NtCiew2}UbjoZEOF#pm`fW{%8BOdd&j1FUAL!6&zR zODP*+a$DFDefoyhE6H{J+i$+)5jGsXaMRhHA;NXaB>#9|^)g?Ew_7H&ODVIhHnSIF zcaZJXuebF!VLKu3cn2SzdA)~MTDq1(aJx2#j+4NXQDqLVPIl50sfS2xHW)gMr-vbT zd3p|vF>{iSjuJMfN%tEEHBnhd!Sw3NM)mf*=`BEBk2^BDv3uLh009F7GCXdk=kONV z@IFC%1(JEdssca3(i{tx-0{xdY4@o!bCwU{$_&$8qgY)z8F}|%#$*KD%JhAs>4HTa zQel!J&xVG8^35&++ zOtteH+&FM7s+_GX?7gzcTM+StDLSNJd^oe#Hy_fQ@pw6 z;2J_AN$RfVVx#42=C6DSzr=w+#MY*fM~gG~VX5Uw;8_jD&p{3Kui(o-4z}w@6M^)I#>qb5$ zBM{s2%cs@%m4k&G%b}s6Y(Qqa)pF}QUmEAUOAyhaUiXSu?1Kl;=;*5^yEKq?6S8yb zz7*3`Gcum@>Q_R7yq3c9mn`@ZUt9JXy*HcuQ(1DwetuDBleCyLiUaHlOhYB)jo@A+P0J8qw9W*@iTV`R^GjT)b zC}PZ|fX16xN%g1WN~_gIs9?juw!X(QDs}1I=Bz6>CRXAD&ZcAY-I1c_aktt1YhbB| z{q+@Em@lH-fg>Xm*K|i?jBs#3L|=Z{7y7~?xcjFH+R9Jm{df#n#8?F3V+?A_AOzSy z_;mhgC)$GYF{G!;+B1NVUah3Gc>RG&mbW1~$fwdpd9Hwr{8tqNT$tsyq8bM&>yna( zbd`pSZnzavzr06aMrqC~X6hhYxG<^Cx8z*I>jvrEa=JMLm?z|-!u0U{%5e!QzBAh2 z`@Ot^3~T4xU16zO3+_6T43jZVUvO6*z)5SJu4X*bd2qvB_cy%7IAxA`cWE;`JpARJg7G$t85dp0BMd;$8Cr-!xe9Z_o9wx) z=3K5NA|UbAZC?K;0d}N*xXFdNA};ZcW`BHhh;iHa#+Ag7aFFoi{bD$WQwV(*e2HZ> zJtzs?33-9X8)rsQ(9>_=Z7%eITzqik)56RhB&8`lDboj2Roe}d^BPC~{yDe4qOhiM z%_hU+3@?)B%IvHWEE9xE6x6fXslL@)rT%4j*^6FFUIjL2%)cg&_57x` zjF_BBAC0|fbGI{B_<)8=Gd+oMIP5^ILU_6I&@ zX@=H#qr$HnV34l9d?WySf;MB~xbk-U%mXqk5ucAMuYd9c!D^>r>_Ti*sV>_h%zzx% z;YNPpv4r%^WS(~(5AV&~Gr4W}`7kZ1cke;J>Uk-X0J%mIua?QtwVeB`dAzFApN(sh zTW)Yg80E}%p(MMHkg4a0L^Vhm@hOewoE7dzEu3au# zN~K@egepirAIPC2JPgt8AREMa*^9vmeMUN1YhiC#wI|mp#7QN8tC|lGUE6!xeQX6R z<=0t@8T#Xa8Qza2u@?^R8q7yZLAThbsJ>F{`GGvy)1Mf9$svzu>-cWCPWJ^*-?_z< zomffhx^hdpXw?M-(CzFPfBpJZO>Svg7`QE+%69eQVJtvf^6d}t`G&5w(`_fBNpH_3 zPS0!^7^GYuB?SjVqdbaXPm>*_T zl1NCMNXU%KK(~atqr2eVq9R_=+bBfL3tk-tEj+!qjpPAKdg5vOdt zo6Z!VLHX&^kCLz66E!bbk+6}AEpFL@xFjt68R@u*CVc4{om#KCbZMJqkT2w#1WYcZ z$iKZZOGXGTw6&RLTG!CTXspoLXg_f%h`aLFO7UqiFuiT4nV(_wl0B2`I`Xt4bq-47 z!}QHT>HB5+Yvz8ZUHh&}qDzOKy`au>;zZhfMU4<+M8_3-PN1-kv^*EJ{ge1#?>hMB zDWp%@Js0o+aC;W6f8tF-X-1*EESCAw3p(d4VKk|-5daY>ywhThh@oX+_Tqe3^6lN3 z8>6#g2_5!V9#6t10n%Gz;;7)Tu;1|Io|xbAK0p0oZw9jqW-`ub?5m23zVvJ_@q)ay zpXx z%(%Xx7JGuZv7@QdsR@|MJ1Z^c;R>FoT_br74Ji?kYZt=5l#RII3l9Xl8XLEEus=ph z>bYz^;d1XeO_wo7njJB0bE~QHmpalYh^GF~sUMFO;q6@@`=P*iLYJUY|H6s{*y4Ho zKu`0B0U@JXxwg_2KJxld<1z0j(_ljz9@06p1NTeH8zpL^rqSm1GfLv$uxQNulGwQf zZ)0Ev(?rKXwEW}gB}4=ve!%^1YhX|uS$vaYPwvEx3Q9QAIg_Z#ZY_Ph#PDwY&Os(5i%q#lgb-A5i`v><)b#mx)L ze;gd$)NVUj`OfWp;0&)&NtBz%_Hqyy#5rTI>N;|c! zyGBb+9XeBp@@eWwcY7jhVu!hL|JQ2`s~1=OPf6eMMK0D~YeP!jTIJ$*GhqgSAOSNe!nWMgmQsH~@dILMM_WZ+fQgrPSr@4=7yiu{ zwv>|VsTne%Q50TJ zT?4C%%9`#p?MR#vE7O|8K_u!@%{ZO?MMxDp@Dr-54?6G(e1?seDWN}6D+;I={T$ZF zbX+|+HB0@n1XiDC)uZ71n!&~w}eyDm=cf)bK zDxXN{JY2~5Hhcw0zI9;S+%C90n$m1~Y{J4!g6Azvo1igOVmhu^8l^+91YYtuIeY;C zuTe(Q$IcDy;=rTXx7Uk*%epI7RQK+xmO8j)KICqFKO1Z))};1qK_R0l`?clC>;%|0aK4WtXBf4)V@ba= zZ@#q3#l6yCWBID>JO575inD^gKRTbkt@PN*K93j0x8|t=8ocnvIBsyn8MjDBk zS3ziLf5gmb-|O#+4Zm-nF+~H*HwMBOL{Xx$8p-^7;NLL1G==wWN(kFL1Uijl-`VYF zfO&rPYSusC%puia>M_!)(e}As8q_&9>C(jnOn*Ixfs(ywI%j9yu@skyD=m297+7@D zAm$AR7*Lc{%Lz{MBhHECwR+@93e(b+vv&CQri>~8*VJYsFz^irY+B31o=++VC~O(N zLaW_#Te8!ioI0iVOka(6^HVQ=Ramb!bG+iiTB9r9YD~D-;CobhU}vtmP8m3u zVZAxIqul8OF@^w#jS9FqAY4W!d!ca22*&kFt@cX`-$QZ*_4hP%WP;Su-y(QMMlTlQ z-ph%uVxlD+0Of0`pZRvl=Dot{#~9$B)KE>IyWMaNS99;Ljw+nvE|gp4T23Kh#Cm!%i&HIxvQU?l=~-zx3x5R*!kF3niiy+UgWq8 zHT?CH&gBIXfvHx)cefvyCwqMHSYKp;n>F@Aj^h)5ca>lZM5z$F#Y|K@Dd(-O7G^pd zrPAWb#@STbOO9ERG{V4B$5eUZ|=faU@-{w>P6^5_XW z^h0lRH`iG_6XYaMwKW$mF=mn&J|!mUi_j)1{=m8Tr6Q+Q8<|M_6cb_H=vU*pg1GK# z_XeOwcthkucK@u8$a(MG?ax*@@yX+sZMcGDP{})mQAd!=7NSse3U_-Ja-^Q=CDqPOes9g%{TW|M8+>lu5t;`@z zW9NiL(EIU;3A_XQgVk!MBs*^!4p$hJ@27->laRqy+2wm;5=qA%8unCcG*^4Is@cA3 z9Fl>9QKx66jpH&(YdC(lV8-hou7b#&Z}odQ_pc9bbY7q8G^0yy;hwea8}*CeZ6pFqqO8>9W!_1IzPt{0@)k+j67Uy4D&hDYNCqtcAu!F0HieRuN{txhm6YCW$b$F zP->(8nH>-L783>O#GwQc?Hm+8ThBABx1I~NBQCZ(C+8niCGll!O|Z)=E$FIZleE`|So-kCb;vp>$}k8# z7C)cfo-DVm#Id_D1FZ?hZ=-a@oRTGk%~(hHp28kK!_bvYU{Ca#Z{z)DNDstoYDZvp zb9i);#+pIMul_ywT55XUM9xj&RYy5hDamrD;lIiLcES6fIO3@ZQZ?hjRo5>oDsv|} zIvTpq?wyB_K0YT!KWmht2(_2Ys2&YvndBKC5qN=3^xj3wFJDT`9is{>m;HP6`;>P} zyym_mooebKAyE!12+1dxLPR+H)B=P;-vwN4eJ@E>%UZfsN2b-OQC?Y89JssG!vZWR zKsWL-u_r8**u9^7mk}t{Z#F)~czt4FQIfrX0ZW{3>)a_=^E|#V3gv>sQL_O^*eUoywU3z1Zz~eEwmFN4ML2i^Ts>UTeW~ZaKO*ebAW|Se3`Oh0w<`9rRahP5K%B?aTcova zCsE${R{Mn_@=&aQyM=fSM|$k($MQwr-*6e(H1;WCanPDxXCU0Mu0Wi<3gVmMK$xAc zn@OqgKUJrkCvXnpY@5n}e0$ zIdyW|ZR33A3+PJq_i=1U%%Hj~|G4~0hoQ3m@k|1`7gH1ux8Ep0b?VswH8zSfsCSwO zmZWhm+WH{A)iXK$Tm@wZf|j|3Mw#AQ%RI5OdWdm&zBE2e7kILM4DP{y;S%^A=~XkF z$xPE&V;0Md%Z4kK*6uTF?i42BB&Vfx9t;sj_HA-Z7C-ZNS^BVfH3Tg$d~6WdHZ(k* zY<^Y!ehI*%SRkdR28Bf?;7vO-Ay#jpzBC|bYa&6P3siF4Gi(Wfx0^OLwY}LOMJ8g5 z-6R)fV(F65a3`%l%jGz$ok?D73#l{jOY-Hl`9zuKOqPp)rr+DCR^n`;&^i#eplQ;u zLPZZa%XWR)J@#1^3sThI+(hv-`BsO0lfhuhSYcH6AbA2&FaEhi&?^gYl(n8-jpk+J zs>k|*g<7>{n{)@_U=_L%yB(LMY3@(CAX)D4q}9wtxnj1Fh) zku|*t&a~r<#u$frU>Enw(foNsTLR0$IT*LaS)$>zEB&v)QtLj3|fRfg`0Ij(;z;Hm*rq zuXPd|^_)7gE;YDE!V+?R{T1;NzfM4;e|@`?bQp&lbN!A6G2oETk%iQFWzh0Qh6W0* z*Q;~Ad<|)2QE7{RB$=Qr?P5yE*iQCNN~}wDnIH{P9s43PRq+TsVoB)r69^}qP|(6unjlT7VLwCZWtB5J_#)?a!FX}+g+r3N zOzGRY6JH>xUaV|W#>)6{RNb@$B!xxrrvcDkls&Tf$mA>DZl?rpWZ8t<(IZJn(?(Pp zcO!c}H!{8}@_`(2Gbb~C92wuaFRV07ZsOMuO@=2ydeGbo)puj$ou`Orzx zp@9983lDhqgFD1#!kHUiY7Kv_-%e`sl}ULCX@x8aZJ_SOfTd^GgaYs$K7}xK*_xes z-Y=@hCLu4G$4B~&?CSkzw}J@bmjRyQpbc#PHlWcSJ(lg57@lsVsPEXXejK@@;!*AR z%H2i*&d{VM6b)JNue-p3K&CxtX)d1X-3-y#e%T`#4)kSw;Gl>&3fjDr zOKw84JjYM)uK)4;L<9ShS!>TQjx{o9KcB$bliKkU&|cA%?)gD%AxKG53$d+~{Zcyv zusK|-#1w@q1Q4SpSoS83{6lU0SjJKaS3r6!zav&cKg2!mgl#-)PfV?!eb2V_J)>El z%kum=>1VHElear7wDpuCA#q894=SJ0@F-YAN@KCEvwuK(e17=+**S|K{N3#mV2P_QJ|g ziEa(8y85Ljqb5{DAiyBvhI{I zx_@0#?%h|f78@M(ssA+t)x`2Q4S5vSZ#@N~Y8+j=O-l2|Ry9AT!x+fA=_U`-XaDX{ z3srHfnDK21P^jCAC$lrwv5!&lsmsr>ROzWfdExShkU3+DjZa<>12)+(_)glD!TWG{ zhld^J5CULNV;=LtL@*T? z1+Q4l#!c$wukLnD@<=@pz>ioa_2xd+ckd(ghKg*<*%kbc7mlt4=+ zHeisQ932+kItMkrD^PR4lcq4gDgMc61;_8*5cW(_fp?F6{;6=ffkG@w=d~#vc?*1} z^i)Fm&V6ONKD)tz&x737De4xvfgK572CfSh_d>;|o_Bf%DHJ;NzU&vDhv;ViCPvUr zCdY+1{#u9_ApTy2as;5R`|*D7V#DI9U8tx=4u3%*mLANs#KrmQB?`9c5B9CWq zq~*2d>TQk~xx&>3i!O*GSgDTCQspp^hsV3M>m3hi4m5{tA7WT;CI+#8o3|L_azS!5 zch2If!qsDIU2joYsXsSl>^wHF`a08ViQD3_aXX8kF!SlcYXY0VIUGmTi8MJCacK3| z_l}``#*zuHJ)3)gRPMHZ3Pn(U*DzfIe6F0d-I>hlye(myq3xbY+^M62#(gKb3;N;l zJX+JYm=q>j$Q!chPz$zdF6%Ffg%s$oeB&GK z3hlH8-RDnk(tl~jMVc7czlR|Wh%_WDE~C3qNNG+8V;o@Q8HG8y;k(0yUxYyxd_w)` z_-M8MXhGUxZ9C0NRdAQM6fl4xRRq_W=jcWKW{vENR^5+GANB6xoG-CttxD&~<(^VF z@%hHT;!jbF{2ELZ?v6d{e{w`wQp{KB>7%auo)TDSbIU&2t8k&3dMZ=_lKlqk^9*SS zTv)LzURBl{R^OqBW;OFB|Ekax+ua;sW?F@z{gh^l(vY?qK55bbyjWz}(Nvv7kF$uX z3v7Hhz-YFjQUAbyU5rJ$7PVFOk{8edQ0*j^aBNJ(FT}anVzqwFdc8lCl79H>9)HO9 z3xS&80jJeRJEs6s75OUih?^VQFbis`!BrV|ckDj8)x@I-%_Nxw!}mfTPJ9K-u56!v z6~@gy-2EX1Ie)M^l)TVj-J{#biNL&jqWkNH8JaK7V($;NdV+nt!|P;#TIrPJsf!~S z8%=TnMMWRly)M=3Jvvt}b#*{z&S$QNoWo&lN`UW%HAtRa7nTX>&gArbF=ByhB29&> z?E4l8zdhI4#+&w)o7+GzvfiLK^w4`Q8!w2P)~?D{x5MM};~Q&FfQj!ZtWvqb`jcf7 z`v0Vr0xO`h<0-?rx_pU`}Pq`snPK*!Oe#K*%f-L5@u(Ya%z=b*{t>Mnx zzLP&uv46LpvEBWFW-4K>^|4pxd)t^5@O<&vO{mAot4q?sX5(%@vq#;Aa=IqShlf3r ztmf25;>HBp-)$Y2>^d%$w)@qej8Ms1XK*#0I4h-$?(t^|Q(Tp??v?+RTp7ZOZf!&VtanxUt_&$DTDWq9r5q zonkM}#6!nB)NPlIk5BmB0s1%{+uNI=q@wbK(~!dYDNNk*bKh=@E~x^vc9Gvp+Rc@r z;`etgZ_48!x?drBl*U-zl_HG(AtCR26g7nNfo(xSYXZ^g($d;Z=)$f)B2p;kffg@& z{3Q(%GCEu5vsL_P+yYv(^58GG4vvpz;2sYF%3>1)t2VA_T$HE%t?Qz#sKl#C7)mTz`;d33WU#HKy=J6{azUty*$#Ch#E78%- zQI2sV$o>e`nQid1dessN&sW)&dsY^fUukLSkiI`>hwqG3$spfWF?IG}M^)ru_V3z5 z7^`L)Dr@S=B$;8v)HIo1M`gvCqD~1n^BHT+^3YSf7{esD)5o;v3+4%MxxlwTiWTPnQmzo8-Og9dMI~15%`-QRsov)m zyngzMk>q?n1nRqN&9{;{WVao^YS~5Lcly>G?_a3so%e;wN--)&2T~Ss{@aJZ8KM5W z?x2YpUfb6$xw;B(Ma;RsSa8KT5&89V$*pDg0fSK zSa>=ArG9Q0ON|!$Yx|DFfXUgg?bG%sE&|PVR3I0X=4X zE<5_ai0tWPE65vb{W^`Nhu9HV*Yh=>mt@OljSxaDK_MY<_}@q6VbpQwQD+TjQ&5@~ z`o#R}@V9gD>{M_>*YWLD7wG)UpG3WvB3{VwL~+YZPDTzMxi9`bt#Ic;@^83C(3ya^ ze}De}xaIX9A^bnCgZ*y}e||+*_%o7!vv^s;+0TC@{-?bCpVVEPoc|VucF=$S_kYjv z)xV}+BpLoL`Jevs{vUydkMD{FkUO5==sbYc2qDVaf~x00h;vcYM0PvWLsOLmSh3y# zw+0~wg4?`auFx6#_;j3}pN_0M+Wwf0mY2e{{B3oKUjjaE_J3&zK9wWM6!L=J*H`eh zYq$9zG=q8DK^`D7GLI1m#Crv}lGs)v$+OmAh)gy>JTiEt>*^ghqG}|unI;AmUp*mk zGi++HyY{LGh1405+ybY!9nU;$VSvCpGJe&^1?O+6Pr%4ab7mR|Q~v(7cQsABbwFFq z51hB{Vz?~#Y&tqxeuqHM%w-%9@I%LCF}(}J(G_JAB!rgF^?`G5pPgM{jE-bc2lUK3 z-Tkl(&wO3o!cnoq&vUmA7`%I8UtCE!%tRL*zD%^;b=#JpeNGc2Ns<=T1`75&TuUz4 zCwaLzz{vJf@;qOd8r2(+&@$$7UjM%4v@t^yTn)6+o1O zhOvOTM?d7-)at#d;&u(18iIWn20O;pnRRPjKZ=?-&nYbN0hF$x?FuQIa&;^&5&1Tq z2Ol1uqTrqD^#d^Td^5LvO6qZ&S&OCd^3XW7J(Ft_l<$R_F`-)ntSpB>EF<!RcX=*?T_N{7*P~;Xwax9f9hs=`89w|A_mB)q-RBq{dTSmZJHpqb zb0OOy?}V0auLtr#QFf}6bD)L}qNDAZ{QHiepPw_YAIA;Y5(r&&x4w;RA1@94uH?&a zw2%s^8wHF5io7fSj6$<94^a zmCw1n_bPc7d=a4M+;niGrs*Wflh4g6gFb8CeD_iEr3URe+CqXS=-rU{^G#H`x2}%P ziI?nVP)z|7?YiLRGQI2Z7+^_dm*9=$=ob?$uDI>sN0Sfr&?nAwhzD#ktDXd3A_Dzk zf3v?U>alijcN1qGp~t7{)b-6rpUUj+*OIGh<4q?#kwnu(!KKls9pjtnXm@F$W)(hu z_2-H!Q079WoR*00*-BT?SmmOY{0h`}rD57LJAXw*Z_q;1KE}2%Z@u6H}5wep0aWXrxBL&R$0Ay#EcT30nms1^l5XH$D4D2KmR zUmiU)_8yoi=3aLQlAI@J$7nDjo<|R!;pRg;udiIGh0;X;#2QFkJ&~K!9qDDYSQhW! zY-)U8kD?hgpCr4u@&lP#A71ajyw|QSD`##VG!DJ`dw3j8fXg5vDT{=is~&**E#0dZ z!*+~J+z5EjzYe0kwrs%Rc|zlH$`AAb1CPs!5L-Qkr0*y4HulwduJqyOf`Oe_q5*GU z(llRqf=s!D^WI%1QnN2{6i$X?2pv-;4(gWlPn614TXTIzzdW)$QGnoIU6+O+4D-BA z_8%ThTZc0vWbQqEoJ8|PkX^a#0pZ-%8XU# zyPHR|2;Y&0t%v#>@ai-a2x0+B!G6}Ux*SBK zeV2;r-BBx=wY`usp)1*;O9zHh>3N-AMm!#J`$zHBg`O97t^h7USZ1e>>XIo>-j?Pd zZczON*t)hA>Xfp~ckoc}=@}rN?2In7&^9#Ffz8T@3VWpa2r~bHyk9mF^=Us>OigK0 z52c*Pr&tpL(?L1+9eBAdu~-|DkAeUT!!6NP^0+mm*?4%SDk04gJR);;x}r~>V)(Ts z^0MOGb+h8Q@ixXqLb5%{vaoO#EoAeH-VlN8wOzlQ=nD45!hT22bJ9EH+E=2q81x+} zBOnv*`q9 zhob4k_*tG^6MP*;X6RK{VE^s)gWdX!l$$p?$csep#!DKhJx8y^^Gye~Q{zn^l<_*y z)YU6j;CujndKqy!nLhdQL5*VkIjE*7_~D?qnukxH7GvLPqqUgXm%ti9dJDD#uJ!&Z zPAa+mhu1pT)!z24O<$$mB&6@8HY#LGb|IJ~TViLRmB}1gmInk64F`xXM2dhlr0RLC^a7Dgoh)C2ad52MFvsT~Bg;A+sVMx4pu2ZgBFz>$aOMy-h)JeoKj9_ZRm z!LVyM*+hBUQtB^l-F!ajD~!X%lHQbSO~V#*eYr7=)lPbQ>WI@|#=YdpQu<7DTBRq? z$}$!=9z}2T#OuUpgD9IQM2!#KaP`KjQH9(xK}ux2z4_F%t6o{e1t&F`Q6ZTkXT=<&{B$*>I;Yhc&RGzf zoJTBJUO>m#?jdD9B)Y3K^TJL8iX0av-`QbiF8}fnyQkbZu-8f92~8$R&oT+$h;6cN zi(w2`y_y;*9e%!E4|hSAgTPf=b`9N%NKN{Xlum?$A3NZJ>SGXUW)LGIX^j;((UuA#PIW z-Kq*ZE)wHG!V?Q1ZKx}MCFJ|UM=(RjSxAoRK*0lbOdhPL&DW+NQ5_vVx27gsx27HS zvNtFu#gg0bc!V0wsYpxsM#0sbEGg|o!`h)$IGI_`m@tlH&VXI30{Aq&kqWc3lSN#T zU1TbXkqQ2qD7er!J$us-xo-Esjs4d+O`A9} z6#KA+iw{$&!U%hE4;Al%PjzoTc$|_Ok@M>g9I3-W@%fA>`+hr&kvU@%)z9Y3w>hF# z0>!j4Q0+kPPzZz8JGRb5(mAGb zAE~DTZ)ZZdJd=!w2E%vFT*>ZJ%R7p^(&>OwpaXn1ZJ~z4M4w@b@AP34?|=SNV|0&G z$)P#?NhGM|Q`Q#<$NwSjy`!4w*8Xo45fuSJ0qH6or1uWeyEN&9-g_@0L6D9hy%VHL zN9i@vrFW3tdksAyBtP!^+~;3C}*UC!P%c+4s*U!zMuaUTmW0OaIF4=sm8pi zSUOi^tfIBfX4!&(6Df5Ji(eT*tNZ6)8+$aMoseqf>xVz9~0?e+%l(VFzAu zs3B>m1KohFhO|@MbB*24iHBvWjjh+;-QVg?{($Wkk5Q4 z?Oi=415%q8;?s=IzuKL|Ycr}1T_kb*?YPWk7^#*k+y8+WMLcAAw!o&d=Rw&qdL#6H zCeLK3+HYDyRHMo3VY+cifJZCg1xZci#Ab#qwVd?sP}g?22@vN78hCq2M9}U0r3H*# zM0Frl^mF;QMiI{IS$|z%(>Dio#C;tqz~dR>fL$Vw%nRZ5L1-hRS-!hlFM9*6u{1s# zc=R4`xL5+ctN8|(u@85q#|+|}3hkWjOPe)Y+Sx}Jl@--vjQaY~HVDPv=XxWg4;XUc zfj$vnTP7I0E>4G8LlSPS2j1`s;!KI+ko#KDGsGDd@T~DgQA-4=~QUSSV2|GTL^mx+@lJLUtWk`e} z9AOojhajl}v>hxDoU$)Mog8<^#Ujex(XWIw!v;GYt~Ukh7niez_L$5Jv3dyx)oSkr zV0*s4Y__F%w(zB-hRb>|NIRgyDp)_6lm42Q>Ck@n)aa->pXXzzTZ1CrXn~uIkB>YSr(?CE;TXGQ-t8n z_cXz?9_~sLhy2K$h4?`8;fr`@c>x$WMIC zbU*k_+1H6Vuc?E}@Z&(M^?uCF@}xXbU1i=y?UP3X^&^AVu6{^uCM*&XlB!LewO}!8 z0V--bW-4gMdB;^y%*=MsS!~`}^ZLbvt>E`A`iB$WtsgZ{hs5no#i*7e-#^ERHE^~V zoJSXidCx}9sRDb>eaRKNBxbY~wJUQfnp#VnwD(KO*kcfC?-jVulsrI$l-@OBX-v>L z!S8Kp=1>$?7-bUs%?v^J6pmWT4{CYF$onr}TE#?d6|IGaHDmLC_OBo0XEJ*NdTY?J zbd%z?Tk2xj(v(PMv@^yQu_#Q#j26Z^q$nEk8~Zv^J_)N@qxzjK+{8=!`c2T2<^80h zZnw)!eE!Ql<*G2OQXNsD3-azS6`qmglcvDJejQskcQrCUy(&a~f!d5Lt(*)Iu)JLw zZuPRUabr#GeHBRs8=Ed`NT-Gx?Uo^)iqN8RRYp*)EV)qq#cD?*4p!7BP=sbtwawH% zoBpIr=TxPjcQhz@Y|)+scwipXdC8RjV5xoLY>OK_O=AhRFXUSp?yKZjt=PKO$8q{t zNiN$*uOCInJRRm`q`z7oxHg-Zp?{;Zz~@VVJVE*W@cV4-BFqlEd5#f9R2na3r^qLi ze}92lAB}VdG~84qph6JPYPLtF_10iqU1)~ z-rPAAm*9`HM<~jNqt%{V{+EeOU&A8KRl9ZM%NK*&4mE#&Z(J+I@!F2{%H~$TyBD_# zWoZR zaZb65ma^`mB?kKWUMkUeh!`sQQ{8%6>kg%{e;Jmox&qyL-pPKOxoqs)vyo3T{P8vz z2$|s?iT$I+;(gQhDJZ3=5SHtzgYstYDbcr*i*7b`G|_i{l=MIRjol~i_Ci4m^tyT9 zo`|EmO;D#T7(v4bxU7_t?SW84Jz1**U*twq3TI1FlDeqb6XH>A1UaoW*nsScuGd0( z70X%Ib?c5#W7!Yez)UGiyDY`+l34RMQ7LQvl*OvdAM4L^b{h|YeicD#?_{E1ywhRL zy9}30t#hHshDS&r7W+naZhf~^+Sx8N6RwIbj*{x5 z3!|}LHlN=yRR&x0Q0a5U`HPuPO<#8iW)Hw>m9AZXyJV-{JZsA*3^fl0!e(4aZ52k%=AI{i%R1w;v|^h8@; zB7yPdvETXEMADs$MHIhxJ8k4u&Yhg@5PTZZYi~bgXY7^#-7~XXYq8;ewv(K#=!bOm z%8qQeLa-#{B5>wrW=~}f^B%a|oLQoW7e5skNkpy9>i{-y&SEAq9I2bv)p*)uZrL4{ ze;6(rR&Aza?hW=p$lHRYVo@1K3if(Nd-#Tt6F6&{ z8&C7C*IpJpgou-90Can-zg8yyQ`1&1Bj zX~^tH1q7j3EWDB3PqzLMLrI9Kf6peWRHNUnU%aS27^nzrycjZur#R~{ujQaRPA$jKlf!qC{tEbrs{?UJ>R zON>tJkxH(Qbz0O_)Rb7ziRN}v4_ht?hxk;s56g)b#o%PkOY6LhrFbngDJ3+VQlzihBAdzZOy&tCJ<2+-R{udPC{Usyb_$5(;iX6krX{ z>N?9Vr0qEj)8KKPM(~xF6G$i_jyO~s;uAD0JSYmo|G;W>ik_W zKCpjTfQeN!xaK_i3HVc`Em_fUCM&w;pN8UT(=>Kf>|`<~#-)4d{<0oV+n22fUi=p; zB~c6cihmoO!EIDX`rASUxmyDB-!+Z+nFH4IPaO(SPlu+g9Qo7XBbV)J_h>AiJBvZ% zUEuYu1z?QsQU*0viV@ro5>Y0HEYSgn<1kZsi~6`cg}KF7|| zBqTVMH6~*eUBhr4g_ih1MLq9`_F`i2Ga`41}c#^!m zEX-b5tfsEXBrJ83ayO8-E0CvhpONP(0UkZ4BzZQaR!;B^N+7knNdJtVHL1E8x;atl z<@WWYA-ofrM0O5xx<@mgOl8a$Qwh8q5}Y47->d9rJy+CpcD2(pDWm3+pfp=lyW=^S zenGkI(SF?lM{!EQ_WBdtd&kARac~O3J$;HG9Le%C40h;T=5n^4yp0z;594To!;VeO zOKc=v&-pv=SHlsOwogyfJIn(z){pHz4vOoZ4`NdkTTonvuX7K)%fm)@;?zP{i#KmL z$c?9x*tIEH_@e`&mcXjpS?|S<0*;6f^liOS)KmrV6W;|e3i|eU=3C=Dj62?O1zkU% zsz~34oX>c*#sXY{Q>9GSG<}A|6=-EN3vV@J_PlBBDZ?f=zgI=MnP9!V z5nEF#%wO_usIW~2O3Hr5dzvPc{GCaC@OJlp)0$enx|)m9 zFd4B(eTGl$hjYj^t(wTQ&eHwi+^F$=P6r=P9&!vV@SG?|B(_2C_e1HJK7M{;eY~{3 zhR_?mo7;P`o}~w__tbA+P&YlzkXM^0GY0!%!;TzDkq4U5P~mhm5RA8Ktehy$Tw=EV zyWiT^TTa$Ac>(_&_~3dVrn8Q-W@%!d7JYO@s&L^Yw{76lY(p zj6a#&kqN-Xer~GPg{!Fq8uLZz{0P?}TxC^yZ&S4Ldb#5^!00!hH=%g%Rvx)fy1Vrw z1wsya71hpx8Eoxx8CJIV0|OjDcTj94i>>J{{S4!?&(56I6T))C;(dZMUP#56^mP>4 zx`JJZ1e7_{1$Z&3?|r&Zde{$@D9MLz(rdeZCusGh6RxMAVzrCRT-Lg6b+JAs&H*9XCTX@q zXay!!Q7uvsDb%`b2+RR7DZawpYkUSfq+;77{c^={)1k4W4aFl?b_kM&=jE26x)EDHMr&1-4*nS$vALn?w}8oy-j)KOv%S~6H-HVAtV|L9XxGq z#M^hK2i|-;SjXMX1V0Nej%Ss zkKh0aknVdPNqw>J{~Wzt(7}IA{I(>t(03dT6I>wWg=`9veItHbI8IVkb1>9;NN&yp z{A9W}Q?}%iN~=lv?T*&s{@%wJb0z4#koptCMmOIiZ$75^l&OLnC2HX zQPdMERs>8Ly;M_d`^5#RBX)CQ5R(F*3yz%H3!3VFHye<{*gAVze1tq4U3-N8nFW}$ zGQZ2_H0JeV$A;L%3@ErLPX7(}v2B*>??M69f~;Jx*t%LZ=tg5;FQ}+AguwZ&C8LQ&=nu1=B8r*&jg~(bCm-DelH#bwZBE2Us;OBHidv^$ z81V=>)ll+8U?cgeH#TP?xX4DW&tGIy0OLqmV&hq&)g+1)Vohmm0(NP(2A7rWJ`X?5 zo+Q6`H|E+4v&}ul+P(N~^eG#f!bW)uU%#S#x?nTaD2iymdOW}uUb+44vB$7(_rBWk z>#;oETLzUa*p0c*;e2(7ePS?b0=bJgq2Y-Drs!-@(sb*G8DKxnweLlILQ@4hF@wMP zfOcsO6}zBL7$s9Fb9HC5*pux#p9?<>IjpTYt|2h-*4eWk5GApjeTj>YG{B)QtG(|U zE8Yi@JS^VbimLP`>nm=GxTc78Hbvu%W9D3s)_A==+bU<6oeR8yWVHWk?nrGFduZg? z-Z|f&tNmyMzFAF!A_~oJ9_hlvA&` z03%LGiZ4$oub@5w1l`*Q*Ds!BFUy=^zi+Xf<$)BOWm|<5VBHpp4ei`?_-^iVKdRJ@ z=-DnfM1qj_5Lb5X?4@d7Dt+9|uQGluU*VYwhUhgg{J3e2736ig=WPHrTMF{YMmT%x z0|OGJ($lUFN5ogJ+xjbZM6Ur+ibEM;Zq8YGWdX;)Su91@&fXDnadEZ8j$vr#?Ri~* zl8;$5RwZKbC71ib=0#br4*Xit1C3Wb1iJ zdILX!yE2BVR~WkQ%9IF$H78A)t{ext%K^{yRx>gpdvu5{VlnMp9yy+`mo??bCHO|~ z$Vu63wuQ77fc(FJt*EgHae~@v#1pHGUtjw&ekx|ZI=ndtrQ zZB2{6FrF4TM6TfCD3$UBcsFK*{bfdS6OYrE_OAuajbF+oy-q#hiUjcN69pvkJRp@mM=lUpb0boe3Uy-rB<88!Fytl=1e(}|y+G59YnH=yN zk~L4)TO3FoIe3+Ui717=u&D6M;bs`X1f%ZSv8&m;NR?F_xu7YS;glLR(tgdyi=rsN zmY~@?F^%_p#h#qE8nFQQGkfwM0XkfSnLZOd{ofKRYcM+Gt@c#3_|2xy**{!f@4+FC zzyWy7^)3*T1P;e6GZ#ZJbMFocfY`-12*$*`Jc#(12c!E1*sx1H&OwLl4_tsiBtz79 z2^a7Gop6cv0Y2`vX1?J+Tm?KwjG~$oC_E08>%EE({MKK<1E2gszR1XYec>CMTV@-Z z@z&po9d?wvk4;d5^KIG(&TR^wbPe-1g-;*9^4K*vU=sI>_E0^##!Bgm+93j_vMS>T z%5F6tmd#IQ2vWZL27}_zlIk58^3++Vm%7oP)$54=U(hrs{PW8jI62b++Ku2QiprXL zbHbW^a~>R2+DDUJJRyl2i$V=2sH<-`s;cws#=BLy2N)g>4U-(av^~usE1c22$Iu& z#c74$xZjE!uX?yLuWkQ3U@Wu|iKEQ{t@#v1JM}34!+VUbP{Msbc1cj}qxb8A@#e28 z#06rYiBI}TI5iR!&MG9=bI9_g8RB;e2nh`_k6T`7cyf>cJh?~DHP#Jg)U|4_BV8@` z4MSZ}v!v+m<-~gvx0(cb%sr6x(^79#c=$Af`{DjKG$l33l-dhObxAI0m_xG-vjfIt zW_9ag1&lCUKMmQBVr;YL5sQl0!k3u6uIZ0v_uouWyrVJ^hsEq;rAjKpjh;o_A(UmD z0VB^6U^?^2Qho5UO39wuO&C3Qp%R%mTk1&Rw*w6ZFI<&+lkdL;pysUG>fiL1?>BvL zD_&CfyP96$uEG7j4D5|tQ`64!n}6R;F{1`^k_xjbrqB-v;-UN{*c-DLCn8cM>N(}| zMyaQQGUf~$D{3m}>+Gl!zfy=ZBN3Z(bALX`T_8aD9=PKor}OqE*)<1Qbd1-Na&}8| z*BKQWQQ|?xlPvw+FmPBy+lF_%K37o)v!a?5c{S}WEq?!+?s}Wq*YTWm=fz?`9 zdWFgN#J7zl04aU!Etf52ibhrM+|WW2q*G(K{@zCcvEIS_{{ZOMV#fZ?IJEs(`q6!8 zy%>L6hN(4zSm4{j3dMiAJ$f3j@qrmVu$>Y|D3|NakUm{5i3oYg=F>d()sh3%M-nkJ zG_~9^FhIgNes`X~sjW-Mi=?W>JM-OB*1Hs~m@Bs+2NI zAO4j-8N8artiP<3{av3mCrL61YQ9C9MHi7n%=X+D<~+IZgWvYe0BR zZ;|olkGuiqC3T`9Q>n-c`UZW{Fjt2i zb^YcSH-XhO7i;>_rYo~+EW+2_Fk@MfpS-FVah{m) zY8iFgOyTFB)iS&u=$OfHxViUrLvl>m4UG(|^cBe@{~ye~JSU6I{JWX9o4iV&EcS~^ z`WpK!gCDxPDFU8CQ6E~5a%FJ&4R6!kdv~l!7hAp3ZX@%qDaOqrA}_ugrF`&V$?@Ua zESyHsZAPuJSkwc#cRwq~9Eb#g!|t6sWDRDE7C5CA{O4>2Th!Ngc9=(*$S2Q_>|!dl zCEF$VpGN1ZeNfqQ_6FI)x-6&iJ)h&Gux%20bH?WIU7RR~votiVX8TNm`=e z4|%!6l}7s%m3#7x0~RLYReG(hfb)mogx$k&8u;$Ivx1Fq_H5MBYHhFn7vdzXc7EQ9 zFJ3Vd)~!3E+aLCPbd{#B!XK^j8>tlM!nWUg4pS41A+#0`SxO*`ZSQnMK&8!~kb|CW z2Y4<_@0Sytej1SvXr0XuK8u;PCb;L&v}WHcLBjMvNjbPW{?D-=p1ij9>M^MdyD;%hYLBRzZwl z(MU)#IOyu+bqjLXV!`dXVD*)IGRVJV;WPMd?o@KVyZKymBF3ZUDjUA+4FMcSLz9go z4iL8{SchBhs^^`HmeK&a1e%uc9^SGnOR=7UV%{Z~NYEACR&=T$UzB<7V>v z%JlrlOo8_OhFdsXWUj=*H?67$$3`7^W7kKyf51st2fOfQC511DG!+!ZQ-L$Hip;8r zzy%^H>-H%p>s6~FoL8@b3Ur8-*ta)AWrJb&yw+JR(w~qj99$#a)1yfT4&ZRwUMh3v zE?=JIj?RwjCjje8V8X6@r?<<_7{!8JYjF&`I@uvoN;dlp(I)eF3dm}LS;tGyO1eJu*~ zK9!33n4S1(?(UIvUSpJl0MZ9@tVhf2MmepRrbtfjLiB{rwmW)>(?x+eevSNNI)n1B zJ*K$qVtqc@;`FYjLFBuZc+0L|k1t#k7XN^4>(&lYzi$82fy*GT+HxH#JdoLyTL_{b z$$t9k=lw(YG%T5U*4ppf>RrDL9_jqlLYj444ynB6WKD_w zMEk^9-#EFt7l#R#oR=2}jPl!_lmC;}GfjKtrJ)_DkuNwj_+VRSR!1!i3fhu%*KKJn zUT2b9gT}EYMip+6I%?Va0@>tcfyC`|I#y?z+NjhI@%j6yf3ke7g`g%5kABAcd_yKn zJ-OmEe?V$&!P>|8Lus-<`4fDPB`zEVUW~9QrwS(yZnB^1`6Mk3pRsSU2hdFsUviE_ z!yAwj@mhD7P`?&$VycbNa5*xA2$@Yv>mka@AbV5>qo(TZ9*2KrP@ z>F;tH1%kI3TBTFFZ~s{{p7!y#AeQ34OT=qwZ~T!z_{(sU(=U~he=fv(EPlz*`fJNw zilIq;x0$NguD$KU%!QlWlkgZFI{W6aL2w;D=*df_44*T2(x>@;sA4<{^rA9bq}D}* zU-uqsP;KSlRuRsW`1W6Ri<`9l6884jRo)-!XU2rTo2cRHeM^ipl)<;AVR)aZ*w!*e zn}lXpXG`TK@wuf`Tt1YS#+@9e*BLX`Njc!A;xz29KfcReI-W6^ILWiHxM;gnLr_GM z8wp{b%PB0hG_1ufp>ewKl7chV5O(S57 z>23v*^4P^O&0W8rizw!Ox5ID7*gF4Ut+2q&>#81zm{MhXK}F)43e^Z+8euiDm>=&P z=z%4ToJ=Qcx!&A~MU-z+e=VD$GghhsBAI+bqs_LiCHRJoejbysAo9Dji1DEv2^V1V zqmH4jwDP>ikvclrnZn7JjRv|Lx7@1fWd;Pb!6YUV2ulJy{)iknU#N2Q7Sh zH`Pf2@@nz9#pKS67RI72Kj%-k8w}PK;Ua6zLeT)2T&H~w7q$CY-G|QQHpr4mZT)N}( zo9ugNE?;el-(n#P`s3goTxpP4*btG^`}Vx4;OK+&pG|0o;&EK&K>Mgmo|uL9ww39c zQu|d4k8V!GM#EfhXA>!hCkz_w$G+WY;-lmJj=IK#Ye7Eh#nG{nE6OjlL<#GFE?4Bt z(goFW(rDw!x&u8bH)pyjVcXbI2ZaT8N1r27F1;z1SwB~6Q=IhiE zR4QQ%P#0`F+!6PB_IViC+3ZY7Gkfk&5!^LOH;Cd&&s0tDQ7*nqWJum>BubD?y1!nV z7d7nXes!#N8B#D>3Zi_Q`a3`JR8B@)a$tmpT^tJBGmG@bmL2xV%vhV@IzC)(&^4@L zY;C-397l$%7XgD#r4P+98pbzJa<=YBsiof;hO1jfFq>Ye?BZZ|rB$`)_go!;PQ`>T z#9fqnKeH!o7nbQU=!7b+r2_w7qxpNRew5W#0lk7o|9=Dep!T5o&+EPc(fuVPIxZaK zlYucJJZ>DK`q-=45b2Gj3t&^>j$-RNiW{R|ww@bkAuhys-rJqrA9BJ9tlbmtcrxIg z3H}(lof1+QjP49pIPE;AEKc5_HwL1;5p&9;d*WQ#t z_%JK*QMB-9};2=HP(>Cw-b<00)>3E`JO_i8EXPbUXgR6b8FR{G4V(0 zC-&-LO3p}X?&q%?j=5XTe@k=#3>B{b)UMCy?k)7zq-4NuaH3|ja6`X--NktLIKz0m zkCizYftkw5+K_K3;duItJNrn9wG=12f>^fYd*au?IMV(|Qiz)&&PMV*Z%vv5Osls7 zGRbPf4@E_jIIl8Ir@hB^8pgavX{k=;2jf!!4E;6|kTFdkw-XtwG7-fJ4zYU$^rE4k zb1n*EQ@O$H#k@k?J{r!GI5NGIy+slIB>6Mu-UNOq<0g;u?bzi64wpRb?aLkPWrnxS zuiCQn=tl+3i7Lfg!=z)U&mlZ%y~nYuwa!r$lfpaVLy!u5@plQoynQW~I5o;V8$5r$ zYVs;myFTXJDLf6kb9>c}0%_#_!yNs9Vn<;$HwjAMl#SigAU)d>eTDc62Wm~GB==M$ zetr2~FD&m-kJ_xx{OY@Pgzww5D;}1&tUKZtwzA74!z=)ZOKYZ5xN%QW0l1oq-Y0eRBa%xo2c^0dvF0z0^72N@C;>!~^(0q?X8l z<7dgi0%Gd7B|(}OB;D+(;<+%Eekf4HQmY%W?E}OaVUIuOU%M7rB<( z>KXInvh~c8u$w)oPx9CGk#dy z9o^hlFj>lL)|Sy%c44Kq7Lz)->~!lU*ocxsrHZ7@I^)0T-BYyNk$a1$^5dq@GUQ+j zBG-||5q~yPwOU(C>sx2}bE7Xh;N-=GxS--#Se$GRNDK&~h%`-PnKAT>E9qMXp>byI zsk@`_u9iQei#=PK?SxZA<~Uu(rL$l9WTyeLJ3@oJZ(c{+P`9TG`pa_~?r^!W;b&%O z%B*8gt~{ID>DBX8pkX+BITjl_+8==9uXI~ShaMEeqa{9g#CC{JSElm_l>H>%_O}CB zlS-$A+`!2851jF)P?eccM}(!hVk|sOrqZ!T{|2v6Y$DasUEBoBXR;A*iusokJ@J)b zrjcC24(W?v@^4y9ck`Us4Ck zPOf&+?n@ZImFs-o2zBBhHXB{se?NnMgIyOEm*^~U>WY`Coafx0($OWoAIu24Bie^k z(6uK?Rg*=&>wg3TvRX|Kcf;VGaxYqi__}o>XuIVt(S@Q&`*+lHVDI?gimcsfwj?9x z%s13su!ub!y3AteE6^(9%}ZzpGRjytj#(c~@%gwUbvgc=Wc8f>0h+!rb;n|w<3abC$8;qil^VtkFMK3@RYcr}3 zcKkw$2QKBU#7wrp0mJkD6E0L*8Dm7xM5zFegG6#tO<^ZQ_ z`nsYv=}Ia!fXDS-0Oo4KtX01wDTJ4OilnK0~h|lyAPpNIPqS}FG1CS zZMe*v@?q;iaEHi#HczwhQ4bvAsLyA@({5BD=@+ay_H+PV*Tkh(-m9mMQV0CYuK7OC zR~Kw6?F1_zYm1?HLmGlLhzGVpU)*CTn`wM~O#JssR;80Og%4aZ#Tj+Wh@TFH8aL@N z1Eq>xeCM_4TYnL49e+cIP}Ik+?S&L6^^wzK$S{RZV7y;Aak*M4bUi*@ZOGNJ>B?jQ zHM+l`o~tSCT)is#;h=_R^0j+(hIFxlAlbY~Y3nC%?*CSsH(QLc@bDP5n=$zg>yv+oLr~%ntKS9s9Zl z%-84{qza_n-iHtl2Z(^B*JoT&Z*;tG-KE>7*q>FlJczGm@zdNsa8)P)X}6vlQvYvM z{SQ1{k2U8zEbTkCdU?ci;?*r$CF<>AFW<4tjkQesykJC07N;pn?xA-tB9dgc2!z;)a7ut8wx)ido+WXgtiFS)nvhf5pX7<*3aAL29RisWcOOoDY?L9((+euZ{K%iKRj& zA1(;OiRc%mC;+8FK_8u7zLe3)R{rk*n`ZH+;jK!QL0dQl`W@aMPYRk^=?e=9p~l2z zD97E2T7o`xb*%NyuDgx~5>C~pMh#YaHxC;$KF6yRoerw`mLCtNd!tXS+;v=qlKJts zFn#=DV%QZ?MnZ{LP^84S@4G9MJLz148}IGB=2C8am&Ug4ZPVc2e%{Sc0wD0;7T5f< zM;SvBdJ(SV^B^n)oNqC?0OvJ*X|JP%UFM7 z3Wj=UZ{%lsaJBByaoPQr%TyV$>bi+C0D|;LDvaCyyEvQv!|!rn zv%c*c#+Jrh^IYTwBS;_hc&Rh&lRey(ENCQ`wf&85VU;~mWJqgByzTX*Fl;m1Hsc941L3{ zjv!1{cN%!>BxSJsaQ3R%iAoJ@`KND!&Wq>`BjmM#HC0C4Cy*0!9p*r4lR%;&UEn+f zGLl!Wn4I!hsX36iyS_4c!F8O9#*`cYo{5he8Ok&8W8Q`J&iXPxG=S+8x(l{>Jr>6! zAAasm-I1b|i;w#Cqq4K#u=_hX;10b0k~iz!hD=xt>ROGAFbH10^rsolgA-E`_vl;; z`EO<@|C_WNA$%lDIIq*Db{H3&)^_rE;VdCs>_>!ioiR^6YG?b=?ZvC1Fjdo~FJuii zXRukk8KW6ozEGdPy=G6vO;rHE;IFHsz zqN%x~pQ_6Gje-%vpC&&jJiYm-1`^P$LPhjI7{yj`K~I0Eq6f#*#7V^JMh{jEMu(h! zVC@HUfG|$)GDBqzD4AJ{qxGAMEK+{cdrG3^jDG4jMbDb-NNeRpI%-1JPX^U!&5p@F zAfM@3fyne$DMU*NH*?zP)Nvrml!TAJCv%ZmYs;n;YsEUlp9j6QpQ zYK!56i$_b|9|Zrm+PGLleELqlj40B0Urzk?-(}#s=hopRadV%-wv=gBGWuG)a}Y~a zjM+x19Nvs+1AvWcm+E?Qo`Hz7W$h9utpYdzd^h5vt}52oYOr?`lAOO+bUj+)`HG?5 zfu@d&VTakw!pVH~+VO7F9eI^5b9~7MCJR9ROePxHHKIQ2JJvA`_M2k-8#9;f;WE!4 zkqips;++75;{Raa^DDDG@0Gt9al8lb@7t!zl9I{dc?@swtJAOwc~wtFKAnb@gpx^D(-U{JEp??O0#_bD%M4ZBTHlsE*&xqBEK8sXq;?kT{uGU0 zIjvN)qgD*ra`;xi&T2mX-HN3o&#;G$_$r4S?4?Gl{>V4Bcb4E*Mi5)jXe0zBuitk1`_gL5#A*E z&%qRfAMgVHS^ZSVzcRD=JB^21;$O#hSN~fwOEIXeO@zevnK^g*I}LUtEzgl!1%uPIkrQy>=ocZ288j(QV@$v!F^U;550c=KZzJIK#3!-X{8a*4@86SfLvES(* zO5FX=gM}Xtc!`1k>BJS36V83!$FrI!rm&c>u)CMIfl(r^xyY}3*2QXPJ!uq%O`pGc z;Ev;;?Z+_sc{)T^5-L2wAX5*+PbkCm{Z4_awt;GD*A4%=lAa&D{vSnRq;36r8i}v; zd9F4_aG@?-g7^a6J+Vu)LLAsHevVen@_1x~evC?0VL`bUDtDo=z$ll@>rDUvtmJ z7R+ec`tIaR>lJHEt1yl4O7idnhb8$Sd-A4F8`WT60W1>5tRaA|OX1m07%}JL}wufY9N@h|MeN| zj&EXMwrbswGR^C8y8FY{H*SRmE=;I}uuwh8LPn4JmO9rau*io?egXcv!{yuODe@J6 zCg(LfSqX#Ry{iku#oc}V?nOK+8+{3z#(FYOaaDA_>nheIPS3qw&|pu(3^V&BD|Lgu zJQAshbOWzkTW?WF%)WShk7R-51&ccquV(c@-M7WTK^`TQ360WuvpSo-)|r+hy{&08 zTg!T$lzyj-g2t6LnnsNKk&*Xv-^>egL&Y%!Uu}y7n-oKjZ!Stwth2dC&H|Est+Kh@ z@j`Jk1|s{N>OW2>Y`)#h6rg0#gAYdmeXF7=co|fsI;~iY33sR7*igkw85%M-_LF-? zBALEHk4_KDj}W;X%uAq{$?~^pjY)KYM+RXAp)Egu`kT*kTH`eKBZ||k>z=pPQ;W{Y zy5xR%QN-Wc{q;;wTLk?2)3bMvUUvaHPy4OTcg9-yOgrFc*;p#vz?2k{fE%$u2!uUW z48d5blKN9T+xH=RGs!ag7+m01OxxqSMwnT%Gxr&RGWOANeitiAvqQQY)%hSZOwi|7 z?DV43o0gI+=GWy7<>n6<*4J6K6;!RCgyCVk7^T#G(yleVDpkqIjvcL(@{tTC>lJi4 zp%`j9&r$HCZYky6s%szNYS2_M1SjyPk~!lci6O$5JJlLqj7>(^F-<3$-t*I|j{W5JnGbk5sm| zNFC-p8csMJnHm26`yHoQlcd~MiAxV8?xxjKb=$d@%g|Y(NjmWrLyC zI!g`aPUtEhNUin|hhuCp<&q2*Zgt{wc_GZNw~7d$aGWhr%KMft#gDkNYR|-TwsP8{ zGsJ?J;k&el`h7E{u|!*tfu(M4Jx-HXG==A{zbMDoRhnGpzBB|=%nbhi83~v>-T9q% zem>^vkTH}>I<`@AM_u%;;M+Vexe^teHxlB0gbl&uTpl)AIDNc1W%&*2G0g=p-Ho!y zOPi|{G9G@bfnR2cVi3mJt1N-YG=AUz4I35TNo-3Eku$n1%SVR%ak@V}1B&CjPzS$g|Vi<#S(GXc1r zE5BC7*HirdYS6pz`%cICPyXSKckScT`+K3m;ny4OKN|gqqgr+zdTV$ZF|>RzD$y#| z5ZcY%*w}F4p(E|&P-J-g&+36;!o{`Bt{;b=kOVd(B=2pHUlG$@RW$C&m%W;y*@XGuWQbkmkPs{ zx>?+N#zb|4ODIXtP{1WBKT$CZKLPJn1Shp}ONtP(aH z=4+O2(~4dD+&dF9{@H?`y`B71+B!p)g&}k%$mx5*+1cXu#o2byk8SD_@@f`Lw01%$ka;w44Uu?V&M1EyA2_x=6PEB zzOnxjUb@Hd=~>bSd!t3U0H9+3idM8ln%jOsUKT2nK`9Bg?pn@Rb6aHV(q=kdp~Caw zrTY<6?h+LWt|tCebYSWns#nz~PgC!NU2!on+BrYg&;NNML}6{j% zSRw)YZA$PkVFWk`+Jschk#o69kctp#3!g!A1{DD^dY94zNEaChoiSL$V`8IMdKReD zE*Ippvl{}XF0eV)vJqGeBHB&N=(GMkfa_+%+|99FCFI$fowuzxGgRyRJsEEmLA4E? zYtiY)03-((kF<8gbmrCa1JNCQKhcHQ3f7L|J$VMxGk)OZ^0Hti&JOMlx9!t*avjqs zJE^QMb}wP*_4QZ~t=PO)5vJb>?m6jXN=8PQ2Az1;r=bD(c@!^2-(6UDW^~6)vDZsPAgWEmn+Kp9bFLv0uJBK>cf@?f4;sN zD^%6~LHMB>k$OR$|3j;-=u-3j7JlGIoi0id_!V^QjWk2RNd2ZAKrL~Te8s4g2LEYG z%H`)E*s!?FTHUd3g9}lFAiYVRI+W=tzHX;J-UcjSk)GsYWyGd!%ZVp|UVcg*x+JTVRuJxi5>#x<3$ z(OK9Pt3CUr?jrd_MORd`4eAkw%w6s`#l1z_9@;nlP5=yuUp<%0do`!@>F&%rN+ z^_KB(Jy>3n49j_VUia{P$|hE{`q}dJ=Bw6@*ZQpB>`jKB3jo7GBetBVGr5MUX(XZ& zCr(fiqmqAg6gV%PZ1dh zGua;Q4ET|T0bUvQtAT%P4W8FSoh0LgrX&=4g zeY2swvo)SiR;dHS?$#f9*$$_!9>!hDSB)3&3@n^*p7pw1T<6#2TX0}$?x+*sEpweo zt-oE+AA`2nEmN5YTz{f+q+yF)yK?;k|LbsZy;K=*X~vV*1>6Gf^&Oh-f{lS4uZpW# z?2KCTbreK_LbJfYMXQQS6?wKe(B61-H+IqPwHo|q<}`(2uiNaFxXZLGiyvnPF~PQJBc^@f9@6oD8vuAIdj$pn4K%k-NM=H zIQebrC%b*Z$vxYwy6mS@FCEvGghNx3_g3q{ zbR8;7QT!c37nHGsXZpjFSQ^hT(z_XJr+PegF2|A1nd*BxT{RT16FJO$CRYvuw=IsZ zm=RLcLkCR@AV0Ll6%4jX+&q@?T4Vc8_7A=MRvt3lYws`9JAF0CHmccyDDI~8euon` z$pR@{Wo=ueXiM2&V@nYodv&D9M;dSAZ+t!Zp+A;;lfi)SQJ_jAJ5F0UDC(p^0YBsl z7UfM_kNL4M+i>431#!Rb>E+g?n~~Zl)Yg|@bQj6G%LF@M&a7RvgF>aHwZ6H~$px-R zn`ePPMehSioc3YcXVu>bY-4WOn5q|GaJs~>-S?^DG$*G=Rl?e$XO+el=5!Hy;tKjm zGYFuWnLW8>7hr%(I@V*!sk9;PsO~FNuYF_JZrFOpr0#H({oq&pHM%xL>})BtXWs4s z`wS!cj_YO>oG2shGGEzp0jksshA1h?rfy1+yiV-Nk{u9w-A?DzU*zsvA>>SFUJ&r4 zX*v(IShttj@F9Or>ucO<)7HJ#CIM`L1x2Bn6%c>6NqSeL<>IJUvxF zM;|r)nMSK3*UH(9St+2Cj4^Poks!8M#l4`z2)(OtKa{p6Pz{<-65Ia0R#q&b=)^d= zhoQ%`$KOk|?GooW?&tN+!Ol30dV%3<2u>fSmt^tP1(Ty!FGzKWqTK78CWEjk`UH^g zLj59+;hu(t3_@eB8~Jc{B~c2t3|;^!m@hB`@YKyvhZQ`CRvriR-uGYGKGW|hb_7Pl zmR&Hiurr@gqciH;J!O+vDc>Wh0CV8Y6c z+?oI}c4lwt?|0zEAy%-qut~k34F_P7$o%p>S)|b>4r7$d^WicVQsdY=sPWuyfTYmyx}#(O;Q4AOsJOMJH6aoUuhqj%XdMpWb9 z_&bVEg4Oc;vPx5z!)~k*B6&SOILf#)$w-(X)n+V2qnMrSYF$)C=A_)2B%B3!dD<4Q zYH<|`z7>q4Er#9WUH1PVNS*v4f3wHIe%86Sn6AV0%7~K3yJ+?MM*fBd>)H=--YKHV zzvf^9-k8#o9iXr&F;(*RROb3NEUgp4cU59%@l@NQ#N<57b-mzy0(~E4R{m`Dy>Ja^ za=n8grF_K}Wr_so0t>Q-rDRZkWG8VUSAwkVrMg0tA6e=ApCOQE=fu0f)n;J0g72c& zvdn_WI?2@~=Ak%gv#$;BEj031L9ULVb7AYu9PvML_uygx14G8o)MW5;hQcgi2 z8Gc^214p0n*+YYTKvGe@k`WVu3#g;*mULV+HGNSjT=GuX8R7F`(rWDf{A7dE42rNg z+lfQh)5HU`Z~@29mne^Sr>%Nm@hP*04l%Hv`%(_$4a~>5j-QoFVQir)-$W-EBFLnu zJ%7GuuV`C*>}Mcr@W|BNtpA!;U%%0)V5W?ol$X@&-PZd1+UbKS?=&3tb~Vi6N}Uf5DL?08subfv`egW zY|ulx3P-^7nSNne$q%Edq5XUd8^8FzD?h}=G_Ftf@U?mtJQXZJH(73Fu!~sjv4)vZ zRkGC9N!f+p(19{3SXlVY?Qb#dz_i7oCFjNO+71o$ktWW-=`*87DBIH}Qp6t*HhDW2 zp8pJectI-uM#`4zu9>XP%yOGlXQ(>~vUI`#ZRTCmZ*<21(`?f~Sge@>%TWIC@ zmoFh%l$qk-5dI*V+E*?YDSII_)?%5|@Sg-fR!Mp~Gb5$F-Ky566!H|KeGo{c8s(Sp8A_Q3jZWJfvR zeN2A2>ZKuTkAoFLsyH6}w#r2;U_~V+FZy;gvMqLOL;fJm8dnq19m;lh=S-4Moj3S6 zpID~0pcKf&3|iD$jrTBp`S&1&2XZ1#MTUhty;b0*&!AxEg| zEL5aa5yikS9e%do={wDrlKaE8t&*!)N1j-3hmi#ZKKA}=ltSlW*11DEtB(rpJu!#} zYwuU-;EG6F+D0EHYdzN<2U=YEJp2NOZ3$C2|6{B}JQad=U|Bfhu7k?zOM!VNF2iASlfk)8*Y=fig zx8sicn3H;Ha8HmLlsY@$IhRfhnB=ANs@LvRI-5T32)9*Sd219A%OuI$F_544wv>p5 zOibX$^;^7D_c@b6%97;DZqVoeI%wJ*Ft%N^~~q`)s; z16yH>;@LAl-0ThuHdwgFrt@z+TIEsbJi2<6CYQWYrHaHidVuODs<{ ztjF`Jnh}W88td%@5r&dS&&BsXT=%o$TZFuUEs#;Uo~3GoI&|qvUehbqZQj`fHiUmH z+rDJ_Zs-jQkcbT)zt#VdrC+wL1^JBueEF8uSmgt}S_oGiO#@mtpjE&5#v@~kg29)1 zzkx%cVH#jT;5WO_f5)f$4>XYY7Zh2mUG@2po{^{*p!e4NziU1`T26PjFv<&)VnUi+ZSdIDMQ@W-5);27^my*BV))Vi6XSD9 z4K{+fTBT%{{x&(}e0w^73;hb*suI2e8(#m`S4b4|1LEk5%KV0bWm+@vBH@y^yFWdu zeet604Lo{_3iKzZvj86Y^D!$N-_P5?>9`nwyDKw+NelgH^9!;0%9^zGVYZ3u@aB3yx`U$+UU#DBh|JwkFrEm+xYrU4D5ypetWR za?_h&&$hpm`iC2{HEvXPEa+>cN8f53F}2Wnstu9T{tV@monA*$wrXI3UekS#tjc=_ zop`>0G?2(Ll?Pg_1s~U3l=49h)VUpEw$*R7-AXcnmVH%@1sf0`6K`)AC6sv*>koc} z#BSw8(ad}Qi(piiWA1gr+BxQR+=97HiVNjyiD4qCwo{pP-k`BtaFmGovC#@k< zi4!h^6WFzudoI{;H(jk7K~&f0hFs>Bwl)T*BDn#A?xC>8<>Gz{x;s4aG2mNcNMQE$ zxXRR?uk2z+POk74GJbXF!{?j=uGq43qa=Z_=7i@-(fT7p4=3DECQwJo(iX)N`tSP( z{d(R`pFHWh4Kq}ZYl(9nRyDho%GhgDR3A!zKua<|Cm%5d0FKu>H#?e6 z-dm!X`tR`va3*$Y+$|nSl!GKmnm^Qm>X}~ib_%3{deQcyG`?a&`Gt$Obh%iV>FG;< zJsR&-5(=9lEm)H>Sg;%qM3*N+-8*gpMcZQUGpLkC!ad zg_D+BR%jE;2vOYmrm=ad4X^dm<_v&EoXs>tb?ScF&4iDbeinL;IC6aMiBZR5KG~Ac zYT!9_!Skavd3h8L3JQLnQBzZ%>q$Gd2vb)77b_k0Zgerec z|DHuj*aX3&-G|sfqL(8UR5N4@2A&#^?C6H}>jfDOp4LMx+9Y8>*FiU8wVR!;FPol= zLKf_Kbt}Cs&SO{Q&#s@F!ByV|VeW-r{J2}|Kf z%&#dsbNnLml6(k7l<8~Z1(_)^_(aUa@=C>WPz$^_Wjn~4Q*eY3Y8&6K1@90Pwezg( zKR1h94n`XeocU_ALLIRsC2@lBFl{%*95t(JrUX$1$wf8&lB}cDTS158`AHQ;;H!xh=W{V1&ZwzOKjOr@fOg4 zV73js)3dP(d0vnXUo#EHZDYGYB4jN6MHh_;OWJR;|fPK;((K#-#=C*F5IEo;abn>OkMC@eR<(bXgGG zdU~@y{_xI8zf^SmUG78G{vxGmPI><#Bcr=cshJBH(VXD=j~(~f+Qw_r15c6+{q3ZO@qa+jj4us~JXVe_ zIxa1Qyw1_(K46P=)a;VR=YT~OD7#t#-Rkj6>U+_s$XHAQv3_qDKUScxbKxBjnEIv9 znHcM}E`MHMADr=jnG{!{+)%JxmwJ~%qNwDF^_|7le8j5)W(H}cT z|1&YV`M(8NNl0${{{X65;b)nU!&?|;ZsvCi9$fpb*VayflfuYPCi8~3=K+6k5@q<& z`0K^{b0oxg$TV+*YQtRW*-YQV8A?{SYKfKwFYeyI=H zfNecx3-EU6qNX_gP=)q1FWwzkJ`@m^E`brFPGR1D8529ii#RSra!=^Qg1t$2AJ0LF z3od=V6>lmZ$cXv0Z$ zIlH@hV5z7#f~+~|U##wT>TliipY!7sX!1zVsY!*-pKsKH(W+PlN4mtN&K#CD$+U4) zDovKfCRe;`%LpJo(OuYjy&pN^6s>mZ@(`hue>-6LVqb7=MqY;S=3GV45!TAS$OQ7- z3B&Me8E}9STG<)TI3|4!vOMA)STzR59@1595?MicEX1V-5 zc{=4fp0e4!!^H+{GrzMs?}MYW@AfZSAM1=5g--rEouY8{W7c8`r|q_U{_RBNkl+Vz zSgxLFj};!9vK#qGJ(o_I+LGygA@jw^9$7i}k30VYQ8&Zco+kEnVv!@%dt+ZOQ~jK5 zmsBGkxJW6)-vf`Vpg*SE`>y`m1#rxwdJ9avlssRa z+x|HqdcW@bd%r$1JD)>T>*LmiZ|@cP-{{$Lni;vSA-dbf9p^xeflY;0LmCoT_yu%s zoVEd=ki45ZUsiP?#oREH2`@Y)1XEK*GP?2APhv`g=c$S0hN{$nswwMero8yk2waTOK&DxVBE$eKSotqls^c}rnDwauW)QDQ^a(7lW53T(Q_ zBvJKzg4w^uUwho)N6)L4{g>IMLkmc!F=*wDerXZW(N9Lw5utLmA`=4-klg}HVZK|c zgf>&XGM?1ei%l};m3bH&3Fp?x$@>Z%qLCeGaG>F{FIip@L;Q>pyA(D-JP@3wNMj}J zbMT@)?IA^3*E~&9M+GSJS%fTqLTOrHd!;2M|Nf@o= zQIJHN8F26KTK@HR^@&&@2}YPeE&Pfkz0++^rbF$g?dX(#WZCxCOB$!8?t2KsdK_k} z=U7-wno>FJr%J3Ycbi~K-WTJ_#Nci?4mETDW7{Zz-4L%{sNV016C*q^l^nG0?+VV8 zc%9i@KA-ye@@ZpUGMjpchxocQm}soHq-v3dJJo&ke^}~nId3w%tVj6xOa(tk99@lF z;zc@KtnaM2+{j-yXZXE}8Zsf6Os{A?^vVY$6h4>Xae-O$96Gv^d|bURZQl`>^3E_{ z^zv14F8_1CB7|)8!|^IB`i}0%N#c2;1Wk?|X~d`p?g$7ZEs#ql(H86c?AW^7Iz-_e zlx;G%ELWGc)q&d@mk6P4$dl^W=BLU++~(5iS2OHH-379>H!peo2gJs2glAv_ZkFm# zVCTP88+wnjXl|B3sVg$VX+FBg(1tghoB3LzpNimlhf!xb$eVn_-c1)=(!6!nc>a(>4K!6IVB0+|F%TFWr?X(xJY78(4+VL9GKQ6n%hB3P4-tu61*u?&1?-YGB`PK$68F+#zT*kvuak-dOquWz2 z1lcvy2C4@9?OQ3$d9n9?_=hz=2AD4Yh-}3#>61D1y0CIc`3qI9sEJJD{TZc{0)M_( zrkXlIeSx}i9dw9?aI~F5*u~F9AMDs=%W8P2+;(w`y!*BC6K1;DskmsJlk>gfeULJK zi{^+05FJU~bf+A`nzQo2720yK_yhqf7>ZOxxpjY&1X%aY%3kwjjfCI~aC%=|h%*np z>8f}Cf@6T0JpR7onfA1U3ay%hrdotW*@U2JlI>%0jr;g#I+a>f{r72Z%q3KN3}3S) z?&)!bhG{dRDTTqu%pK>I!73;y*uE#j#N_kq)5nWflG(*)k60qKxK{YWNYzDtW)gaB z!#;N^7CF^A0eO4fMN))gY>Ug!y6Xq}bv*&SdO>W`dQUXSa&6jd&zy4666@!i4|_Mt z)_B(&gLp9+CVQsP=-lre+Y54`ni7Efy_!iGLGua^{i!$MJK@bjfOWte-$>|KYXR@>s;cR0y!R zQ5Q_HkX&^a1{|=$LXi1+GM#*}fUK+gvb3vq-E31KuBw=4ER~q62tg`vBvXk2XA#Zh#nWO1X$70R<<09}6i;sHwynI~RkaaLp!N4Th; zP^$}7FM%9g2aSlZBR2*p4AQ6TPia7=XupgS?C9%I*VoLdPeq)qw>964zAfrRu`J*= zWYt|PJTwz$OV|6L_74j;X_)M?|;0#yxC&x!#)u?Xx>dVGhM}_ zV1U!t@8^=r5>+?{*- z-_YWNN?BfFncB4CB5Iha>`IIsvMlkevnM6^?Ts~_0?FL5^_nZh8aSs-=B>1yoAYt2 zdgqDaaAk#Peza%s+8`H>w`XIF=!LDUya=acepqKaa$(F@1AzCth&kDZg;H<6Pqsx` zZAY)XL#Nt>2R$b`Mk(3<;*Zc5F7|(tI24q?9d;vc!v0EqXIe=eb7~`yUdV`@IKiyE zl8h*b3r605dD{0Acgp)pN)8<0&@|t&TiF)rJf2WmMQHOnBoR3Ihg-fYi{3ySN;>@* zp15?2{Gb3tz>%km^EdDQi(Xoy-GRgasZOE4g7wwyXm5X7_&3W8yK!JbEL3-R6s-Ti z;vc>0#)i92wEipT4FmocztQG3Up_F`Z|5qkd5Q>2sYQ6d+fGj7t;f>W>U(@5<-Dcl! zmltj_Y8j}?ATyFtbKsd*_r|*Lzvw_}PX~>}1&ztiVp)6HlHtBHHkS0(t7)66p_P{z zCz?1cx0i+du`~Btmagd)@|Nrr8^!0ryK&o0j3M!&iAu~VhucQG(x$1EYr^0P8S|Ws zzFhjs?x8PBXkzgZh=w=Dcy`%}P-46Vh(E6TY!zf6E3%nI^BlM{c1<=hS;&1&gbMRu zVn~=uZX7G~v*+Wd`a$#FdiR`~<)`y4-?|a28)UKQjkN8@b}3pUC0z~i8mp0ws%J0P z%*qu^An*poyaV=;{6%Kkb(hfcWq)`Y^_;<|)PhdGT~choDK3%05j3Lb+4w@deUKNZ z&(m=+m@^)JU@D<8sb;ZB^AZH?>DrK0tNK|}NYu`pG}@~aBrf#3{wg>E0#sxk^DN$H z2LF=Au^+3B*X5b%^8ouG?&tJ}wFZ(qY0qZ=v@7V;l=Ja!KMC55DZr&SLwL+5LALYtQCgF%Isv0jW^lUZt;#Szn?ID!rgtXq2BIM}l%3{H-W7_XE_sgaE zo#tk9^ylI^))VTH%$;h|y`94pmuEs;*AEUX%F_<-5!46zg(x#UNbch4TAWjbiBTpL zoW;B?NhAQZT!-h>^qbW2|0^hc0AD80&iRO{TEjx3swO^)10a3zJc|YMNiZUf zap7kkmF+yZQpMA!Za=`L`Q?h(S_%PfT{7$n1vIwW0lkZ<@Q=KhE`e zr!kFJ-ni0OF!K#l%5W-<=xB(zJ~VU2=`b#uc4Tu?+9i8kr-JwZqt3G?9+jBQN1qjD zNM+kST4HyOlvYlWS)HwZMUy+o&T39-2V(O_qYF_UFhI}HbMTRXn*|8(ad3Dq3|n+C#_yB;fp}$JCj$4gsMv`w1l(Z zAib|>xMqQsF(&z=sUMB)e>B^U{*mk0tC=L6E_T1_m@IQ2*%w42BGPYZ2%$5c;9O+; zqlk6F(Pt|o+`4*WAB-Rw9ZufsZ{D0vbm|B#p^Kj^oUl?bRNfUX{^QX|6>-V<_E**! z)f**QoDTEk3Ir^}&C#^kkH{>+KK{V7k?SlT>@GX{_jxVF%hV~^w2>y<%aizk{iPUi z3pcdmh_j4>G-J%W+b{UtXb1zmR-XB2g?US~L{L(ax{%mIlVzl!wi%Rt&*e{Z$j+wP zlHP;{cql!-VG*Yh*H^h#Ml$q{n{Uh$Pco>`=`6N~(LPWIhcXe#4~3Tm2Ic=i4D$&n6HuWsi`XSy z<_YuYrVu#S2G$9Q-H}ir>A>SOZu?ONPCjbx)Vk^fl2-}MnAfu+6l-7*uC>J4=lMk7 zJMqO6{|pIRp2Si_A@%&QSKOYz<%dvuKZ02H5aQzj=O51YLU0DCDjv|Cp6OKxRTQs>SyQvnqCI z=k_07J!+3*N;aGPgI}2J6z*Zr8U;VMWU)LwxXx5hWUv;wq!Pu!AE|5F*7y{j=6_{p z&7d;KI9g9D_4Ffz&S5cW7<(Gyb4SH~*VC>8n|$jiIIiL(9)qQ5MiAS$oL(PXs_Ow)bVkN*)JY~?Zliuyr%Z9_saS$a1LrCW0Rd$s zbcwd(6V+x^5rr+RneM>DL6{PwG~S77B4_E{J zQ2SDg-Y@n6(+hBnds1`w_qJ}I$lM$GJy%I^nveR+3L4&)o0Lbe!8ATD>U zz9DsZ|5Lb1K{||P3?IR+{rKBzxC{x#Y>=JU+^=h~X>&ZdcYBfTsb)WoNJux?RB%g? zibN?F3sKGdd4u3@lLU4@M4`SM7`)PPE5xS*G?_Q+UhYiBfbgu1SC_h1+L%n!*}p+1 zEx$dH*(40lkHxQVtL3LuvDkb3>Al z@RlH(0Pf!s9^kpX{~L0)&A+2>FRE<*jPDzypazK}R6pQO*xiGQ2L2!)_1St%%UrVA zAEmbrT!k&8uucwG`-@`bXMpVI8o(g!iKYo!u_w3| z(ICm_Wq_^+O+Na@vymLf>7en2Z0zFyDX!Hv1l=sR6$UpQ57`h7eJk~}5#7YK#+NTwhR5I`%uC_45vx6~ZZp((e82*h{P!jI#NDihMUPEHHZerM{h>3z4L2wZ2GDh_9^<}IWLNno!hvH=o z3Z(zbGUbjRcC#%(6s7)G3taEZY=UH_9%xA3LY5919pnsd9+NG2TA77_F_DQ&AL^qA z?RGO~Lu%a0lyR+gbHYv>s&!fKS-aiF)x6xy54E84cv;vVfaT8zW?8vA7p;qntMSpk z#z4CGUhI%Ur^aZO)SHTF@w2IGc>$XsDuXgLO^kThl|uKUuuqlXRof;c1Bg($cgXt& zg1>P4p7ZmOPkda}@dnHZ&A9OMEB5Y#T>RD3pWJbLjbo-tYm8i(a|2_$H@7{MlrA+~ z(Mn5mHgAc9QX^E#Y%p^Ni^*~PqH{lUE*mrTL6Ah~oOF)##0jf{JXW6&fo&?Vv+ zf%E{TC+g`rAfC0pv5}aP5uKKzo;_j_^ku^mR8Gf+s#-x-ac=_EVf|`rqgmFs6)niy ztR|b=3~x&$2WA^w2*K8}CtdihrfrBvE_jpoi`(!=wd5Ta5!&1yfj4x{|6^3+7 z&M#bz!ipOeSy|gWv@F;AU2xgbX?%B&=x%dnyJqdumLrOKfKR!1FHIie>CcPHvFZ=< z2~i0P(_j{b4vidU{z-b`qF1b zRlWf%iGdCIAKu=cR%+%HyRDn2hU`rI<~VbsJm-Z`9FfhfNP`$`J_6khcYq#P=^37@C$04%ccmE}JPuNtsdMH;`)-o$LRE%H6$m-LSbd zQz|wDq0BIDZcze54G-cs)Ak=D_EqB>X);T0^=@mrxo-vaOS#Kv)gERspbuAikCQpP zdDU%QZOC#l-&d3G2nzjNGWHpsd*s@32>p2`qFtDBn4H1HNfi zsbhc4u^5dG84|-*;pO!@RJTrhoAk#eSaz}Y*z_JS=-ZD=y21oQEH{}me-4e-La6(y$d_om*iq!6OnV#o+@ff4X==@;Pfl-hreyz33(WYP zhezFaOHQrm2SD($ojo<%-u#;%AceD;{hp2{l~>lM7RUJ(;H%2GVb2J)(QEnp{5n_W z#J!;BUi(uY7kaMfR`gVTWtR`hhS>=tS0#u^d@x#;-hD~Ql_`91rdP}7Z`gUEqY>&f z;S;JZbJaXYq8>x%kpYDe^pAPhy!qp`2w}dejs0T{_R+{~akrwtGQDz4#a`QG$WgRm zA)^kZUL-*OV_9OiyV{kpdDEMiV?YPiR5aC#2%=@ zVG>1i?tKmVN4Us;mvAV-_kRL_fo$olgjUuqe|7$ZQ>@NUd1dwE8HaD3qBJ0hy@&i; z-#@W2Mn>KT2g}Mvd)i*3IWAj;$>6j8ExEG84-^^in+DVnk*KtWi<@t;Fb%cxGj3RL zwy=UBhX&h~himAA(2dMpk(f??9Qk(yPZWCQ5M3IAsxpf@;|VQ9k1w9pygv{oM6nSd z=q5Q>F&_kNbPIZ84dQOFq&EG34S&T-{{#HxieC2TKK7lxV1X%-+??xz(mFhtFwm}l zuoD6MW5_O8B?*5yO^V~1AlyXP2Rt@B*7V+H<6hq2@{@Ipbj}K(nq3eoOP;eJwk81{ zEiWW}iu?KYP50{O)d$DCZ=;A)PfrC=Uo`KzwgL1}z~Yni^TL|dnf?1eMofb EIH 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 literal 0 HcmV?d00001 From f386a1f375670902d13074c840a2ef421f4269bc Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Wed, 8 Nov 2023 19:48:24 +0100 Subject: [PATCH 012/141] doc(ct): add SKIP_DEPLOY to base image doc page #9590 --- doc/sphinx-guides/source/container/base-image.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/doc/sphinx-guides/source/container/base-image.rst b/doc/sphinx-guides/source/container/base-image.rst index 1be0b992b2a..5f9ba31ce48 100644 --- a/doc/sphinx-guides/source/container/base-image.rst +++ b/doc/sphinx-guides/source/container/base-image.rst @@ -220,6 +220,11 @@ provides. These are mostly based on environment variables (very common with cont when new artifacts are copied into the running domain. Also, export Dataverse specific environment variables ``DATAVERSE_JSF_PROJECT_STAGE=Development`` and ``DATAVERSE_JSF_REFRESH_PERIOD=0`` to enable dynamic JSF page reloads. + * - ``SKIP_DEPLOY`` + - ``0`` + - Bool, ``0|1`` or ``false|true`` + - When active, do not deploy applications from ``DEPLOY_DIR`` (see below), just start the application server. + Will still execute any provided init scripts and only skip deployments within the default init scripts. * - ``DATAVERSE_HTTP_TIMEOUT`` - ``900`` - Seconds @@ -274,7 +279,8 @@ building upon it. You can also use these for references in scripts, etc. (Might be reused for Dataverse one day) * - ``DEPLOY_DIR`` - ``${HOME_DIR}/deployments`` - - Any EAR or WAR file, exploded WAR directory etc are autodeployed on start + - Any EAR or WAR file, exploded WAR directory etc are autodeployed on start. + See also ``SKIP_DEPLOY`` above. * - ``DOMAIN_DIR`` - ``${PAYARA_DIR}/glassfish`` ``/domains/${DOMAIN_NAME}`` - Path to root of the Payara domain applications will be deployed into. Usually ``${DOMAIN_NAME}`` will be ``domain1``. From 07e1c737dd538d254d43f57132a9b8939472d979 Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Wed, 8 Nov 2023 19:53:21 +0100 Subject: [PATCH 013/141] doc(ct): leave note about fs perms for STORAGE_DIR --- doc/sphinx-guides/source/container/base-image.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/sphinx-guides/source/container/base-image.rst b/doc/sphinx-guides/source/container/base-image.rst index 5f9ba31ce48..b43c201fe9f 100644 --- a/doc/sphinx-guides/source/container/base-image.rst +++ b/doc/sphinx-guides/source/container/base-image.rst @@ -307,9 +307,9 @@ named Docker volume in these places to avoid data loss, gain performance and/or - Description * - ``STORAGE_DIR`` - ``/dv`` - - This place is writeable by the Payara user, making it usable as a place to store research data, customizations - or other. Images inheriting the base image should create distinct folders here, backed by different - mounted volumes. + - This place is writeable by the Payara user, making it usable as a place to store research data, customizations or other. + Images inheriting the base image should create distinct folders here, backed by different mounted volumes. + Enforce correct filesystem permissions on the mounted volume using ``fix-fs-perms.sh`` from :doc:`configbaker-image` or similar scripts. * - ``SECRETS_DIR`` - ``/secrets`` - Mount secrets or other here, being picked up automatically by From b7e079c86a9a8e15b3d68de3446db6ea449a23ad Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Wed, 8 Nov 2023 20:59:27 +0100 Subject: [PATCH 014/141] fix(docs): downgrade sphinx-tabs to be compatible with Sphinx 3 To be compatible with Python <3.10 and >=3.10 as well as the Sphinx dependencies, also upgrading to Sphinx 4. --- doc/sphinx-guides/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/sphinx-guides/requirements.txt b/doc/sphinx-guides/requirements.txt index e369536ba4e..63be499f741 100755 --- a/doc/sphinx-guides/requirements.txt +++ b/doc/sphinx-guides/requirements.txt @@ -2,12 +2,12 @@ # For your convenience, a solution for Python 3.10 is provided below # but we would prefer that you use the same version of Sphinx # (below on the < 3.10 line) that is used to build the production guides. -Sphinx==3.5.4 ; python_version < '3.10' -Sphinx==5.3.0 ; python_version >= '3.10' +Sphinx==4.5.0; python_version < '3.10' +Sphinx==5.3.0; python_version >= '3.10' # Necessary workaround for ReadTheDocs for Sphinx 3.x - unnecessary as of Sphinx 4.5+ Jinja2>=3.0.2,<3.1 # Sphinx - Additional modules sphinx-icon==0.1.2 -sphinx-tabs==3.4.4 +sphinx-tabs==3.4.0 From 408b4f307ebb3563fe973eb67581a2d8c272212c Mon Sep 17 00:00:00 2001 From: Ian Nesbitt Date: Fri, 15 Dec 2023 14:18:05 -0800 Subject: [PATCH 015/141] Adding DataONE to integrations.rst --- doc/sphinx-guides/source/admin/integrations.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/sphinx-guides/source/admin/integrations.rst b/doc/sphinx-guides/source/admin/integrations.rst index db566106b49..7693d4a95d6 100644 --- a/doc/sphinx-guides/source/admin/integrations.rst +++ b/doc/sphinx-guides/source/admin/integrations.rst @@ -214,6 +214,11 @@ Geodisy `Geodisy `_ will take your Dataverse installation’s data, search for geospatial metadata and files, and copy them to a new system that allows for visual searching. Your original data and search methods are untouched; you have the benefit of both. For more information, please refer to `Geodisy's GitHub Repository. `_ +DataONE ++++++++ + +`DataONE `_ is a community driven program providing access to data across multiple `member repositories `_, supporting enhanced search and discovery of Earth and environmental data. Membership is free and is most easily achieved by providing schema.org data via `science-on-schema.org `_ metadata markup on dataset landing pages, support for which is native in Dataverse. Learn more about joining the network `here `_. + Research Data Preservation -------------------------- From 87f45e3d3a0357fea4707bc0c35c4aada2abbb7e Mon Sep 17 00:00:00 2001 From: Ian Nesbitt Date: Sun, 17 Dec 2023 13:51:47 -0800 Subject: [PATCH 016/141] Update doc/sphinx-guides/source/admin/integrations.rst Co-authored-by: Philip Durbin --- doc/sphinx-guides/source/admin/integrations.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/sphinx-guides/source/admin/integrations.rst b/doc/sphinx-guides/source/admin/integrations.rst index 7693d4a95d6..5225746ce2a 100644 --- a/doc/sphinx-guides/source/admin/integrations.rst +++ b/doc/sphinx-guides/source/admin/integrations.rst @@ -217,7 +217,7 @@ Geodisy DataONE +++++++ -`DataONE `_ is a community driven program providing access to data across multiple `member repositories `_, supporting enhanced search and discovery of Earth and environmental data. Membership is free and is most easily achieved by providing schema.org data via `science-on-schema.org `_ metadata markup on dataset landing pages, support for which is native in Dataverse. Learn more about joining the network `here `_. +`DataONE `_ is a community driven program providing access to data across multiple `member repositories `_, supporting enhanced search and discovery of Earth and environmental data. Membership is free and is most easily achieved by providing schema.org data via `science-on-schema.org `_ metadata markup on dataset landing pages, support for which is native in Dataverse. Dataverse installations are welcome `join the network `_ to have their datasets included. Research Data Preservation -------------------------- From f4b94837a8dbfa1f657ab31ba66a83c5abd4d5e7 Mon Sep 17 00:00:00 2001 From: GPortas Date: Tue, 6 Feb 2024 12:32:57 +0000 Subject: [PATCH 017/141] Stash: getFileData by datasetVersionId param WIP --- .../edu/harvard/iq/dataverse/api/Files.java | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Files.java b/src/main/java/edu/harvard/iq/dataverse/api/Files.java index 5d400ee1438..6a9b1803583 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Files.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Files.java @@ -4,7 +4,6 @@ import com.google.gson.JsonObject; import edu.harvard.iq.dataverse.DataFile; import edu.harvard.iq.dataverse.DataFileServiceBean; -import edu.harvard.iq.dataverse.DataFileTag; import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.DatasetLock; import edu.harvard.iq.dataverse.DatasetServiceBean; @@ -13,7 +12,6 @@ import edu.harvard.iq.dataverse.DataverseRequestServiceBean; import edu.harvard.iq.dataverse.DataverseServiceBean; import edu.harvard.iq.dataverse.EjbDataverseEngine; -import edu.harvard.iq.dataverse.FileDownloadServiceBean; import edu.harvard.iq.dataverse.FileMetadata; import edu.harvard.iq.dataverse.GuestbookResponseServiceBean; import edu.harvard.iq.dataverse.TermsOfUseAndAccessValidator; @@ -51,6 +49,7 @@ import edu.harvard.iq.dataverse.util.SystemConfig; import edu.harvard.iq.dataverse.util.URLTokenUtil; +import static edu.harvard.iq.dataverse.api.ApiConstants.DS_VERSION_DRAFT; import static edu.harvard.iq.dataverse.util.json.JsonPrinter.json; import edu.harvard.iq.dataverse.util.json.JsonUtil; import edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder; @@ -81,7 +80,6 @@ import static edu.harvard.iq.dataverse.util.json.JsonPrinter.jsonDT; import static jakarta.ws.rs.core.Response.Status.BAD_REQUEST; -import static jakarta.ws.rs.core.Response.Status.FORBIDDEN; import jakarta.ws.rs.core.UriInfo; import org.glassfish.jersey.media.multipart.FormDataBodyPart; @@ -500,22 +498,22 @@ public Response updateFileMetadata(@Context ContainerRequestContext crc, @FormDa .type(MediaType.TEXT_PLAIN) //Our plain text string is already json .build(); } - + @GET @AuthRequired - @Path("{id}/draft") - public Response getFileDataDraft(@Context ContainerRequestContext crc, @PathParam("id") String fileIdOrPersistentId, @Context UriInfo uriInfo, @Context HttpHeaders headers, @Context HttpServletResponse response) throws WrappedResponse, Exception { - return getFileDataResponse(getRequestUser(crc), fileIdOrPersistentId, uriInfo, headers, response, true); + @Path("{id}") + public Response getFileData(@Context ContainerRequestContext crc, @PathParam("id") String fileIdOrPersistentId, @Context UriInfo uriInfo, @Context HttpHeaders headers) { + return getFileDataResponse(getRequestUser(crc), fileIdOrPersistentId, uriInfo, headers, null); } - + @GET @AuthRequired - @Path("{id}") - public Response getFileData(@Context ContainerRequestContext crc, @PathParam("id") String fileIdOrPersistentId, @Context UriInfo uriInfo, @Context HttpHeaders headers, @Context HttpServletResponse response) throws WrappedResponse, Exception { - return getFileDataResponse(getRequestUser(crc), fileIdOrPersistentId, uriInfo, headers, response, false); + @Path("{id}/{datasetVersionId}") + public Response getFileData(@Context ContainerRequestContext crc, @PathParam("id") String fileIdOrPersistentId, @PathParam("datasetVersionId") String datasetVersionId, @Context UriInfo uriInfo, @Context HttpHeaders headers) { + return getFileDataResponse(getRequestUser(crc), fileIdOrPersistentId, uriInfo, headers, datasetVersionId); } - - private Response getFileDataResponse(User user, String fileIdOrPersistentId, UriInfo uriInfo, HttpHeaders headers, HttpServletResponse response, boolean draft ){ + + private Response getFileDataResponse(User user, String fileIdOrPersistentId, UriInfo uriInfo, HttpHeaders headers, String datasetVersionId){ DataverseRequest req; try { @@ -532,7 +530,7 @@ private Response getFileDataResponse(User user, String fileIdOrPersistentId, Uri FileMetadata fm; - if (draft) { + if (datasetVersionId.equals(DS_VERSION_DRAFT)) { try { fm = execCommand(new GetDraftFileMetadataIfAvailableCommand(req, df)); } catch (WrappedResponse w) { @@ -547,7 +545,7 @@ private Response getFileDataResponse(User user, String fileIdOrPersistentId, Uri try { fm = df.getLatestPublishedFileMetadata(); - + } catch (UnsupportedOperationException e) { try { fm = execCommand(new GetDraftFileMetadataIfAvailableCommand(req, df)); From bf3c2c7100b996e4a1a5d4e4616c99c880b9674a Mon Sep 17 00:00:00 2001 From: GPortas Date: Wed, 7 Feb 2024 12:13:55 +0000 Subject: [PATCH 018/141] Fixed: if condition and endpoint path --- .../java/edu/harvard/iq/dataverse/api/Files.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Files.java b/src/main/java/edu/harvard/iq/dataverse/api/Files.java index 6a9b1803583..95117162094 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Files.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Files.java @@ -508,7 +508,7 @@ public Response getFileData(@Context ContainerRequestContext crc, @PathParam("id @GET @AuthRequired - @Path("{id}/{datasetVersionId}") + @Path("{id}/versions/{datasetVersionId}") public Response getFileData(@Context ContainerRequestContext crc, @PathParam("id") String fileIdOrPersistentId, @PathParam("datasetVersionId") String datasetVersionId, @Context UriInfo uriInfo, @Context HttpHeaders headers) { return getFileDataResponse(getRequestUser(crc), fileIdOrPersistentId, uriInfo, headers, datasetVersionId); } @@ -530,7 +530,7 @@ private Response getFileDataResponse(User user, String fileIdOrPersistentId, Uri FileMetadata fm; - if (datasetVersionId.equals(DS_VERSION_DRAFT)) { + if (datasetVersionId != null && datasetVersionId.equals(DS_VERSION_DRAFT)) { try { fm = execCommand(new GetDraftFileMetadataIfAvailableCommand(req, df)); } catch (WrappedResponse w) { @@ -558,19 +558,19 @@ private Response getFileDataResponse(User user, String fileIdOrPersistentId, Uri } } - + if (fm.getDatasetVersion().isReleased()) { MakeDataCountLoggingServiceBean.MakeDataCountEntry entry = new MakeDataCountLoggingServiceBean.MakeDataCountEntry(uriInfo, headers, dvRequestService, df); mdcLogService.logEntry(entry); - } - + } + return Response.ok(Json.createObjectBuilder() .add("status", ApiConstants.STATUS_OK) .add("data", json(fm)).build()) .type(MediaType.APPLICATION_JSON) .build(); } - + @GET @AuthRequired @Path("{id}/metadata") From c8f8227ffa2efe79d6840fe7641a7c23690caea8 Mon Sep 17 00:00:00 2001 From: GPortas Date: Wed, 7 Feb 2024 13:11:00 +0000 Subject: [PATCH 019/141] Added: new commands for getting FileMetadata --- ...etDraftFileMetadataIfAvailableCommand.java | 19 ++++---- ...etLatestAccessibleFileMetadataCommand.java | 35 +++++++++++++++ ...GetLatestPublishedFileMetadataCommand.java | 28 ++++++++++++ ...edFileMetadataByDatasetVersionCommand.java | 43 +++++++++++++++++++ 4 files changed, 114 insertions(+), 11 deletions(-) create mode 100644 src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java create mode 100644 src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestPublishedFileMetadataCommand.java create mode 100644 src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetSpecificPublishedFileMetadataByDatasetVersionCommand.java diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDraftFileMetadataIfAvailableCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDraftFileMetadataIfAvailableCommand.java index 14999548b34..4673f45412a 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDraftFileMetadataIfAvailableCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDraftFileMetadataIfAvailableCommand.java @@ -1,7 +1,6 @@ package edu.harvard.iq.dataverse.engine.command.impl; import edu.harvard.iq.dataverse.DataFile; -import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.DatasetVersion; import edu.harvard.iq.dataverse.FileMetadata; import edu.harvard.iq.dataverse.authorization.Permission; @@ -12,25 +11,23 @@ import edu.harvard.iq.dataverse.engine.command.exception.CommandException; /** - * * @author Matthew */ -@RequiredPermissions( Permission.ViewUnpublishedDataset ) -public class GetDraftFileMetadataIfAvailableCommand extends AbstractCommand{ - private final DataFile df; +@RequiredPermissions(Permission.ViewUnpublishedDataset) +public class GetDraftFileMetadataIfAvailableCommand extends AbstractCommand { + private final DataFile dataFile; public GetDraftFileMetadataIfAvailableCommand(DataverseRequest aRequest, DataFile dataFile) { super(aRequest, dataFile); - df = dataFile; + this.dataFile = dataFile; } @Override public FileMetadata execute(CommandContext ctxt) throws CommandException { - FileMetadata fm = df.getLatestFileMetadata(); - if(fm.getDatasetVersion().getVersionState().equals(DatasetVersion.VersionState.DRAFT)) { - return df.getLatestFileMetadata(); - } + FileMetadata latestFileMetadata = dataFile.getLatestFileMetadata(); + if (latestFileMetadata.getDatasetVersion().isDraft()) { + return latestFileMetadata; + } return null; } - } diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java new file mode 100644 index 00000000000..306221ed86c --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java @@ -0,0 +1,35 @@ +package edu.harvard.iq.dataverse.engine.command.impl; + +import edu.harvard.iq.dataverse.DataFile; +import edu.harvard.iq.dataverse.FileMetadata; +import edu.harvard.iq.dataverse.authorization.Permission; +import edu.harvard.iq.dataverse.engine.command.AbstractCommand; +import edu.harvard.iq.dataverse.engine.command.CommandContext; +import edu.harvard.iq.dataverse.engine.command.DataverseRequest; +import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; +import edu.harvard.iq.dataverse.engine.command.exception.CommandException; + +@RequiredPermissions(Permission.ViewUnpublishedDataset) +public class GetLatestAccessibleFileMetadataCommand extends AbstractCommand { + private final DataFile dataFile; + + public GetLatestAccessibleFileMetadataCommand(DataverseRequest aRequest, DataFile dataFile) { + super(aRequest, dataFile); + this.dataFile = dataFile; + } + + @Override + public FileMetadata execute(CommandContext ctxt) throws CommandException { + FileMetadata fileMetadata = ctxt.engine().submit( + new GetLatestPublishedFileMetadataCommand(getRequest(), dataFile) + ); + + if (fileMetadata == null) { + fileMetadata = ctxt.engine().submit( + new GetDraftFileMetadataIfAvailableCommand(getRequest(), dataFile) + ); + } + + return fileMetadata; + } +} diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestPublishedFileMetadataCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestPublishedFileMetadataCommand.java new file mode 100644 index 00000000000..147a0fdce76 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestPublishedFileMetadataCommand.java @@ -0,0 +1,28 @@ +package edu.harvard.iq.dataverse.engine.command.impl; + +import edu.harvard.iq.dataverse.DataFile; +import edu.harvard.iq.dataverse.FileMetadata; +import edu.harvard.iq.dataverse.engine.command.AbstractCommand; +import edu.harvard.iq.dataverse.engine.command.CommandContext; +import edu.harvard.iq.dataverse.engine.command.DataverseRequest; +import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; +import edu.harvard.iq.dataverse.engine.command.exception.CommandException; + +@RequiredPermissions({}) +public class GetLatestPublishedFileMetadataCommand extends AbstractCommand { + private final DataFile dataFile; + + public GetLatestPublishedFileMetadataCommand(DataverseRequest aRequest, DataFile dataFile) { + super(aRequest, dataFile); + this.dataFile = dataFile; + } + + @Override + public FileMetadata execute(CommandContext ctxt) throws CommandException { + try { + return dataFile.getLatestPublishedFileMetadata(); + } catch (UnsupportedOperationException e) { + return null; + } + } +} diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetSpecificPublishedFileMetadataByDatasetVersionCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetSpecificPublishedFileMetadataByDatasetVersionCommand.java new file mode 100644 index 00000000000..564b81d62ac --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetSpecificPublishedFileMetadataByDatasetVersionCommand.java @@ -0,0 +1,43 @@ +package edu.harvard.iq.dataverse.engine.command.impl; + +import edu.harvard.iq.dataverse.DataFile; +import edu.harvard.iq.dataverse.DatasetVersion; +import edu.harvard.iq.dataverse.FileMetadata; +import edu.harvard.iq.dataverse.engine.command.AbstractCommand; +import edu.harvard.iq.dataverse.engine.command.CommandContext; +import edu.harvard.iq.dataverse.engine.command.DataverseRequest; +import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; +import edu.harvard.iq.dataverse.engine.command.exception.CommandException; + +import java.util.List; + +@RequiredPermissions({}) +public class GetSpecificPublishedFileMetadataByDatasetVersionCommand extends AbstractCommand { + private final long majorVersion; + private final long minorVersion; + private final DataFile dataFile; + + public GetSpecificPublishedFileMetadataByDatasetVersionCommand(DataverseRequest aRequest, DataFile dataFile, long majorVersionNum, long minorVersionNum) { + super(aRequest, dataFile); + this.dataFile = dataFile; + majorVersion = majorVersionNum; + minorVersion = minorVersionNum; + } + + @Override + public FileMetadata execute(CommandContext ctxt) throws CommandException { + List fileMetadatas = dataFile.getFileMetadatas(); + + for (FileMetadata fileMetadata : fileMetadatas) { + DatasetVersion datasetVersion = fileMetadata.getDatasetVersion(); + + if (datasetVersion.isPublished() && + datasetVersion.getVersionNumber().equals(majorVersion) && + datasetVersion.getMinorVersionNumber().equals(minorVersion)) { + return fileMetadata; + } + } + + return null; + } +} From 8cda7ce79278797767664291ec3d4175a11a14f9 Mon Sep 17 00:00:00 2001 From: GPortas Date: Wed, 7 Feb 2024 13:13:33 +0000 Subject: [PATCH 020/141] Added: readability minor change --- ...pecificPublishedFileMetadataByDatasetVersionCommand.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetSpecificPublishedFileMetadataByDatasetVersionCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetSpecificPublishedFileMetadataByDatasetVersionCommand.java index 564b81d62ac..84a51f6b31d 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetSpecificPublishedFileMetadataByDatasetVersionCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetSpecificPublishedFileMetadataByDatasetVersionCommand.java @@ -17,11 +17,11 @@ public class GetSpecificPublishedFileMetadataByDatasetVersionCommand extends Abs private final long minorVersion; private final DataFile dataFile; - public GetSpecificPublishedFileMetadataByDatasetVersionCommand(DataverseRequest aRequest, DataFile dataFile, long majorVersionNum, long minorVersionNum) { + public GetSpecificPublishedFileMetadataByDatasetVersionCommand(DataverseRequest aRequest, DataFile dataFile, long majorVersion, long minorVersion) { super(aRequest, dataFile); this.dataFile = dataFile; - majorVersion = majorVersionNum; - minorVersion = minorVersionNum; + this.majorVersion = majorVersion; + this.minorVersion = minorVersion; } @Override From 397dbfb7eb68848650ca8a233462b91532a92970 Mon Sep 17 00:00:00 2001 From: GPortas Date: Thu, 8 Feb 2024 10:41:11 +0000 Subject: [PATCH 021/141] Changed: getFileData endpoint using new commands through DsVersionHandler --- .../edu/harvard/iq/dataverse/api/Files.java | 77 ++++++++----------- ...etDraftFileMetadataIfAvailableCommand.java | 1 - ...etLatestAccessibleFileMetadataCommand.java | 3 +- 3 files changed, 32 insertions(+), 49 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Files.java b/src/main/java/edu/harvard/iq/dataverse/api/Files.java index 95117162094..be2f093fdcf 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Files.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Files.java @@ -25,15 +25,11 @@ import edu.harvard.iq.dataverse.datasetutility.DataFileTagException; import edu.harvard.iq.dataverse.datasetutility.NoFilesException; import edu.harvard.iq.dataverse.datasetutility.OptionalFileParams; +import edu.harvard.iq.dataverse.engine.command.Command; import edu.harvard.iq.dataverse.engine.command.DataverseRequest; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.engine.command.exception.IllegalCommandException; -import edu.harvard.iq.dataverse.engine.command.impl.GetDataFileCommand; -import edu.harvard.iq.dataverse.engine.command.impl.GetDraftFileMetadataIfAvailableCommand; -import edu.harvard.iq.dataverse.engine.command.impl.RedetectFileTypeCommand; -import edu.harvard.iq.dataverse.engine.command.impl.RestrictFileCommand; -import edu.harvard.iq.dataverse.engine.command.impl.UningestFileCommand; -import edu.harvard.iq.dataverse.engine.command.impl.UpdateDatasetVersionCommand; +import edu.harvard.iq.dataverse.engine.command.impl.*; import edu.harvard.iq.dataverse.export.ExportService; import io.gdcc.spi.export.ExportException; import edu.harvard.iq.dataverse.externaltools.ExternalTool; @@ -49,7 +45,8 @@ import edu.harvard.iq.dataverse.util.SystemConfig; import edu.harvard.iq.dataverse.util.URLTokenUtil; -import static edu.harvard.iq.dataverse.api.ApiConstants.DS_VERSION_DRAFT; +import static edu.harvard.iq.dataverse.api.ApiConstants.*; +import static edu.harvard.iq.dataverse.api.Datasets.handleVersion; import static edu.harvard.iq.dataverse.util.json.JsonPrinter.json; import edu.harvard.iq.dataverse.util.json.JsonUtil; import edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder; @@ -503,70 +500,58 @@ public Response updateFileMetadata(@Context ContainerRequestContext crc, @FormDa @AuthRequired @Path("{id}") public Response getFileData(@Context ContainerRequestContext crc, @PathParam("id") String fileIdOrPersistentId, @Context UriInfo uriInfo, @Context HttpHeaders headers) { - return getFileDataResponse(getRequestUser(crc), fileIdOrPersistentId, uriInfo, headers, null); + return response( req -> getFileDataResponse(req, fileIdOrPersistentId, uriInfo, headers, DS_VERSION_LATEST), getRequestUser(crc)); } @GET @AuthRequired @Path("{id}/versions/{datasetVersionId}") public Response getFileData(@Context ContainerRequestContext crc, @PathParam("id") String fileIdOrPersistentId, @PathParam("datasetVersionId") String datasetVersionId, @Context UriInfo uriInfo, @Context HttpHeaders headers) { - return getFileDataResponse(getRequestUser(crc), fileIdOrPersistentId, uriInfo, headers, datasetVersionId); + return response( req -> getFileDataResponse(req, fileIdOrPersistentId, uriInfo, headers, datasetVersionId), getRequestUser(crc)); } - private Response getFileDataResponse(User user, String fileIdOrPersistentId, UriInfo uriInfo, HttpHeaders headers, String datasetVersionId){ - - DataverseRequest req; - try { - req = createDataverseRequest(user); - } catch (Exception e) { - return error(BAD_REQUEST, "Error attempting to request information. Maybe a bad API token?"); - } - final DataFile df; + private Response getFileDataResponse(final DataverseRequest req, String fileIdOrPersistentId, UriInfo uriInfo, HttpHeaders headers, String datasetVersionId) throws WrappedResponse { + final DataFile dataFile; try { - df = execCommand(new GetDataFileCommand(req, findDataFileOrDie(fileIdOrPersistentId))); + dataFile = execCommand(new GetDataFileCommand(req, findDataFileOrDie(fileIdOrPersistentId))); } catch (Exception e) { return error(BAD_REQUEST, "Error attempting get the requested data file."); } - FileMetadata fm; - - if (datasetVersionId != null && datasetVersionId.equals(DS_VERSION_DRAFT)) { - try { - fm = execCommand(new GetDraftFileMetadataIfAvailableCommand(req, df)); - } catch (WrappedResponse w) { - return error(BAD_REQUEST, "An error occurred getting a draft version, you may not have permission to access unpublished data on this dataset."); + FileMetadata fileMetadata = execCommand(handleVersion(datasetVersionId, new Datasets.DsVersionHandler<>() { + @Override + public Command handleLatest() { + return new GetLatestAccessibleFileMetadataCommand(req, dataFile); } - if (null == fm) { - return error(BAD_REQUEST, BundleUtil.getStringFromBundle("files.api.no.draft")); + + @Override + public Command handleDraft() { + return new GetDraftFileMetadataIfAvailableCommand(req, dataFile); } - } else { - //first get latest published - //if not available get draft if permissible - try { - fm = df.getLatestPublishedFileMetadata(); + @Override + public Command handleSpecific(long major, long minor) { + return new GetSpecificPublishedFileMetadataByDatasetVersionCommand(req, dataFile, major, minor); + } - } catch (UnsupportedOperationException e) { - try { - fm = execCommand(new GetDraftFileMetadataIfAvailableCommand(req, df)); - } catch (WrappedResponse w) { - return error(BAD_REQUEST, "An error occurred getting a draft version, you may not have permission to access unpublished data on this dataset."); - } - if (null == fm) { - return error(BAD_REQUEST, BundleUtil.getStringFromBundle("files.api.no.draft")); - } + @Override + public Command handleLatestPublished() { + return new GetLatestPublishedFileMetadataCommand(req, dataFile); } + })); + if (fileMetadata == null) { + throw new WrappedResponse(notFound("FileMetadata for DataFile with id " + fileIdOrPersistentId + " in dataset version " + datasetVersionId + " not found")); } - if (fm.getDatasetVersion().isReleased()) { - MakeDataCountLoggingServiceBean.MakeDataCountEntry entry = new MakeDataCountLoggingServiceBean.MakeDataCountEntry(uriInfo, headers, dvRequestService, df); + if (fileMetadata.getDatasetVersion().isReleased()) { + MakeDataCountLoggingServiceBean.MakeDataCountEntry entry = new MakeDataCountLoggingServiceBean.MakeDataCountEntry(uriInfo, headers, dvRequestService, dataFile); mdcLogService.logEntry(entry); } return Response.ok(Json.createObjectBuilder() - .add("status", ApiConstants.STATUS_OK) - .add("data", json(fm)).build()) + .add("status", ApiConstants.STATUS_OK) + .add("data", json(fileMetadata)).build()) .type(MediaType.APPLICATION_JSON) .build(); } diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDraftFileMetadataIfAvailableCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDraftFileMetadataIfAvailableCommand.java index 4673f45412a..e0f8ca1fcf8 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDraftFileMetadataIfAvailableCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDraftFileMetadataIfAvailableCommand.java @@ -1,7 +1,6 @@ package edu.harvard.iq.dataverse.engine.command.impl; import edu.harvard.iq.dataverse.DataFile; -import edu.harvard.iq.dataverse.DatasetVersion; import edu.harvard.iq.dataverse.FileMetadata; import edu.harvard.iq.dataverse.authorization.Permission; import edu.harvard.iq.dataverse.engine.command.AbstractCommand; diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java index 306221ed86c..980563a5489 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java @@ -2,14 +2,13 @@ import edu.harvard.iq.dataverse.DataFile; import edu.harvard.iq.dataverse.FileMetadata; -import edu.harvard.iq.dataverse.authorization.Permission; import edu.harvard.iq.dataverse.engine.command.AbstractCommand; import edu.harvard.iq.dataverse.engine.command.CommandContext; import edu.harvard.iq.dataverse.engine.command.DataverseRequest; import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; -@RequiredPermissions(Permission.ViewUnpublishedDataset) +@RequiredPermissions({}) public class GetLatestAccessibleFileMetadataCommand extends AbstractCommand { private final DataFile dataFile; From 65de2a532956f690aad73b1784e9ef1d0f55a3e3 Mon Sep 17 00:00:00 2001 From: GPortas Date: Thu, 8 Feb 2024 10:49:21 +0000 Subject: [PATCH 022/141] Refactor: using Bundle string in response --- .../edu/harvard/iq/dataverse/api/Files.java | 17 ++--------------- src/main/java/propertyFiles/Bundle.properties | 1 + 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Files.java b/src/main/java/edu/harvard/iq/dataverse/api/Files.java index be2f093fdcf..a8e6aa74a42 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Files.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Files.java @@ -2,20 +2,7 @@ import com.google.gson.Gson; import com.google.gson.JsonObject; -import edu.harvard.iq.dataverse.DataFile; -import edu.harvard.iq.dataverse.DataFileServiceBean; -import edu.harvard.iq.dataverse.Dataset; -import edu.harvard.iq.dataverse.DatasetLock; -import edu.harvard.iq.dataverse.DatasetServiceBean; -import edu.harvard.iq.dataverse.DatasetVersion; -import edu.harvard.iq.dataverse.DatasetVersionServiceBean; -import edu.harvard.iq.dataverse.DataverseRequestServiceBean; -import edu.harvard.iq.dataverse.DataverseServiceBean; -import edu.harvard.iq.dataverse.EjbDataverseEngine; -import edu.harvard.iq.dataverse.FileMetadata; -import edu.harvard.iq.dataverse.GuestbookResponseServiceBean; -import edu.harvard.iq.dataverse.TermsOfUseAndAccessValidator; -import edu.harvard.iq.dataverse.UserNotificationServiceBean; +import edu.harvard.iq.dataverse.*; import edu.harvard.iq.dataverse.api.auth.AuthRequired; import edu.harvard.iq.dataverse.authorization.Permission; import edu.harvard.iq.dataverse.authorization.users.ApiToken; @@ -541,7 +528,7 @@ public Command handleLatestPublished() { })); if (fileMetadata == null) { - throw new WrappedResponse(notFound("FileMetadata for DataFile with id " + fileIdOrPersistentId + " in dataset version " + datasetVersionId + " not found")); + throw new WrappedResponse(notFound(BundleUtil.getStringFromBundle("files.api.notFoundInVersion", Arrays.asList(fileIdOrPersistentId, datasetVersionId)))); } if (fileMetadata.getDatasetVersion().isReleased()) { diff --git a/src/main/java/propertyFiles/Bundle.properties b/src/main/java/propertyFiles/Bundle.properties index 157f2ecaf54..4ef78c8fe7f 100644 --- a/src/main/java/propertyFiles/Bundle.properties +++ b/src/main/java/propertyFiles/Bundle.properties @@ -2633,6 +2633,7 @@ admin.api.deleteUser.success=Authenticated User {0} deleted. #Files.java files.api.metadata.update.duplicateFile=Filename already exists at {0} files.api.no.draft=No draft available for this file +files.api.notFoundInVersion="File metadata for file with id {0} in dataset version {1} not found" files.api.only.tabular.supported=This operation is only available for tabular files. #Datasets.java From 153d7d38ef46827a2e4d7651eec3de7b3ee2c1b7 Mon Sep 17 00:00:00 2001 From: GPortas Date: Thu, 8 Feb 2024 11:10:17 +0000 Subject: [PATCH 023/141] Changed: FilesIT testGetFileInfo restructure for upcoming new tests --- .../edu/harvard/iq/dataverse/api/FilesIT.java | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java index 915f82a6de2..feeeb40c133 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java @@ -1036,7 +1036,7 @@ public void testRestrictFile() { } - @Test + @Test public void testRestrictAddedFile() { msgt("testRestrictAddedFile"); @@ -1141,9 +1141,6 @@ public void testAccessFacet() { UtilIT.setSetting(SettingsServiceBean.Key.PublicInstall, "false"); } - - - @Test public void test_AddFileBadUploadFormat() { @@ -1398,14 +1395,13 @@ public void testDataSizeInDataverse() throws InterruptedException { assertEquals(magicControlString, JsonPath.from(datasetDownloadSizeResponse.body().asString()).getString("data.message")); } - + @Test public void testGetFileInfo() { - Response createUser = UtilIT.createRandomUser(); String username = UtilIT.getUsernameFromResponse(createUser); String apiToken = UtilIT.getApiTokenFromResponse(createUser); - Response makeSuperUser = UtilIT.makeSuperUser(username); + UtilIT.makeSuperUser(username); String dataverseAlias = createDataverseGetAlias(apiToken); Integer datasetId = createDatasetGetId(dataverseAlias, apiToken); @@ -1416,29 +1412,23 @@ public void testGetFileInfo() { String pathToFile = "scripts/search/data/binary/trees.png"; Response addResponse = UtilIT.uploadFileViaNative(datasetId.toString(), pathToFile, apiToken); + // The following tests cover cases where no version ID is specified in the endpoint + // Superuser should get to see draft file data String dataFileId = addResponse.getBody().jsonPath().getString("data.files[0].dataFile.id"); - msgt("datafile id: " + dataFileId); - - addResponse.prettyPrint(); - Response getFileDataResponse = UtilIT.getFileData(dataFileId, apiToken); - - getFileDataResponse.prettyPrint(); getFileDataResponse.then().assertThat() .body("data.label", equalTo("trees.png")) .body("data.dataFile.filename", equalTo("trees.png")) .body("data.dataFile.contentType", equalTo("image/png")) .body("data.dataFile.filesize", equalTo(8361)) .statusCode(OK.getStatusCode()); - + + // Regular user should not get to see draft file data getFileDataResponse = UtilIT.getFileData(dataFileId, apiTokenRegular); getFileDataResponse.then().assertThat() .statusCode(BAD_REQUEST.getStatusCode()); - // ------------------------- // Publish dataverse and dataset - // ------------------------- - msg("Publish dataverse and dataset"); Response publishDataversetResp = UtilIT.publishDataverseViaSword(dataverseAlias, apiToken); publishDataversetResp.then().assertThat() .statusCode(OK.getStatusCode()); @@ -1446,12 +1436,17 @@ public void testGetFileInfo() { Response publishDatasetResp = UtilIT.publishDatasetViaNativeApi(datasetId, "major", apiToken); publishDatasetResp.then().assertThat() .statusCode(OK.getStatusCode()); - //regular user should get to see file data + + // Regular user should get to see published file data getFileDataResponse = UtilIT.getFileData(dataFileId, apiTokenRegular); getFileDataResponse.then().assertThat() .statusCode(OK.getStatusCode()); - //cleanup + // The following tests cover cases where a version ID is specified in the endpoint + + // TODO + + // Cleanup Response destroyDatasetResponse = UtilIT.destroyDataset(datasetId, apiToken); assertEquals(200, destroyDatasetResponse.getStatusCode()); From 2fb5247386aacc53742b1d3657e68b3c5df7d420 Mon Sep 17 00:00:00 2001 From: GPortas Date: Thu, 8 Feb 2024 11:39:36 +0000 Subject: [PATCH 024/141] Changed: UtilIT getFileData to support new datasetVersionId optional param --- .../edu/harvard/iq/dataverse/api/UtilIT.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java index ec41248a65f..c2d43584b22 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -1084,11 +1084,17 @@ static Response getFileMetadata(String fileIdOrPersistentId, String optionalForm .urlEncodingEnabled(false) .get("/api/access/datafile/" + idInPath + "/metadata" + optionalFormatInPath + optionalQueryParam); } - - static Response getFileData(String fileId, String apiToken) { - return given() - .header(API_TOKEN_HTTP_HEADER, apiToken) - .get("/api/files/" + fileId ); + + static Response getFileData(String fileId, String apiToken) { + return getFileData(fileId, apiToken, null); + } + + static Response getFileData(String fileId, String apiToken, String datasetVersionId) { + RequestSpecification requestSpec = given().header(API_TOKEN_HTTP_HEADER, apiToken); + if (datasetVersionId != null) { + requestSpec.queryParam("datasetVersionId", datasetVersionId); + } + return requestSpec.get("/api/files/" + fileId); } static Response testIngest(String fileName, String fileType) { From e98ea11a75ca9b808085ca861d86047cc200b77a Mon Sep 17 00:00:00 2001 From: GPortas Date: Thu, 8 Feb 2024 13:34:54 +0000 Subject: [PATCH 025/141] Changed: do not overwrite findDataFileOrDie or GetDataFileCommand with bad request --- .../iq/dataverse/api/AbstractApiBean.java | 1 - .../edu/harvard/iq/dataverse/api/Files.java | 8 +-- .../command/impl/GetDataFileCommand.java | 17 +++--- .../edu/harvard/iq/dataverse/api/FilesIT.java | 54 +++++++++++++++---- .../edu/harvard/iq/dataverse/api/UtilIT.java | 12 ++--- 5 files changed, 58 insertions(+), 34 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java b/src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java index bc94d7f0bcc..fe9ee518d75 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java @@ -392,7 +392,6 @@ protected Dataset findDatasetOrDie(String id) throws WrappedResponse { } protected DataFile findDataFileOrDie(String id) throws WrappedResponse { - DataFile datafile; if (id.equals(PERSISTENT_ID_KEY)) { String persistentId = getRequestParameter(PERSISTENT_ID_KEY.substring(1)); diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Files.java b/src/main/java/edu/harvard/iq/dataverse/api/Files.java index a8e6aa74a42..4116bf18973 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Files.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Files.java @@ -498,13 +498,7 @@ public Response getFileData(@Context ContainerRequestContext crc, @PathParam("id } private Response getFileDataResponse(final DataverseRequest req, String fileIdOrPersistentId, UriInfo uriInfo, HttpHeaders headers, String datasetVersionId) throws WrappedResponse { - final DataFile dataFile; - try { - dataFile = execCommand(new GetDataFileCommand(req, findDataFileOrDie(fileIdOrPersistentId))); - } catch (Exception e) { - return error(BAD_REQUEST, "Error attempting get the requested data file."); - } - + final DataFile dataFile = execCommand(new GetDataFileCommand(req, findDataFileOrDie(fileIdOrPersistentId))); FileMetadata fileMetadata = execCommand(handleVersion(datasetVersionId, new Datasets.DsVersionHandler<>() { @Override public Command handleLatest() { diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDataFileCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDataFileCommand.java index fdf47bbd2dd..369f3cbfda6 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDataFileCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDataFileCommand.java @@ -11,35 +11,34 @@ import edu.harvard.iq.dataverse.engine.command.CommandContext; import edu.harvard.iq.dataverse.engine.command.DataverseRequest; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; + import java.util.Collections; import java.util.Map; import java.util.Set; /** - * * @author Matthew */ // no annotations here, since permissions are dynamically decided // based off GetDatasetCommand for similar permissions checking public class GetDataFileCommand extends AbstractCommand { - private final DataFile df; + private final DataFile dataFile; - public GetDataFileCommand(DataverseRequest aRequest, DataFile anAffectedDataset) { - super(aRequest, anAffectedDataset); - df = anAffectedDataset; + public GetDataFileCommand(DataverseRequest aRequest, DataFile dataFile) { + super(aRequest, dataFile); + this.dataFile = dataFile; } @Override public DataFile execute(CommandContext ctxt) throws CommandException { - return df; + return dataFile; } @Override public Map> getRequiredPermissions() { return Collections.singletonMap("", - df.isReleased() ? Collections.emptySet() - : Collections.singleton(Permission.ViewUnpublishedDataset)); + dataFile.isReleased() ? Collections.emptySet() + : Collections.singleton(Permission.ViewUnpublishedDataset)); } - } diff --git a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java index feeeb40c133..d84b0ed77ac 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java @@ -12,6 +12,7 @@ import io.restassured.path.json.JsonPath; import static edu.harvard.iq.dataverse.api.ApiConstants.DS_VERSION_DRAFT; +import static edu.harvard.iq.dataverse.api.ApiConstants.DS_VERSION_LATEST_PUBLISHED; import static io.restassured.path.json.JsonPath.with; import io.restassured.path.xml.XmlPath; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; @@ -1400,22 +1401,22 @@ public void testDataSizeInDataverse() throws InterruptedException { public void testGetFileInfo() { Response createUser = UtilIT.createRandomUser(); String username = UtilIT.getUsernameFromResponse(createUser); - String apiToken = UtilIT.getApiTokenFromResponse(createUser); + String superUserApiToken = UtilIT.getApiTokenFromResponse(createUser); UtilIT.makeSuperUser(username); - String dataverseAlias = createDataverseGetAlias(apiToken); - Integer datasetId = createDatasetGetId(dataverseAlias, apiToken); + String dataverseAlias = createDataverseGetAlias(superUserApiToken); + Integer datasetId = createDatasetGetId(dataverseAlias, superUserApiToken); createUser = UtilIT.createRandomUser(); String apiTokenRegular = UtilIT.getApiTokenFromResponse(createUser); msg("Add a non-tabular file"); String pathToFile = "scripts/search/data/binary/trees.png"; - Response addResponse = UtilIT.uploadFileViaNative(datasetId.toString(), pathToFile, apiToken); + Response addResponse = UtilIT.uploadFileViaNative(datasetId.toString(), pathToFile, superUserApiToken); // The following tests cover cases where no version ID is specified in the endpoint // Superuser should get to see draft file data String dataFileId = addResponse.getBody().jsonPath().getString("data.files[0].dataFile.id"); - Response getFileDataResponse = UtilIT.getFileData(dataFileId, apiToken); + Response getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken); getFileDataResponse.then().assertThat() .body("data.label", equalTo("trees.png")) .body("data.dataFile.filename", equalTo("trees.png")) @@ -1426,14 +1427,14 @@ public void testGetFileInfo() { // Regular user should not get to see draft file data getFileDataResponse = UtilIT.getFileData(dataFileId, apiTokenRegular); getFileDataResponse.then().assertThat() - .statusCode(BAD_REQUEST.getStatusCode()); + .statusCode(UNAUTHORIZED.getStatusCode()); // Publish dataverse and dataset - Response publishDataversetResp = UtilIT.publishDataverseViaSword(dataverseAlias, apiToken); - publishDataversetResp.then().assertThat() + Response publishDataverseResp = UtilIT.publishDataverseViaSword(dataverseAlias, superUserApiToken); + publishDataverseResp.then().assertThat() .statusCode(OK.getStatusCode()); - Response publishDatasetResp = UtilIT.publishDatasetViaNativeApi(datasetId, "major", apiToken); + Response publishDatasetResp = UtilIT.publishDatasetViaNativeApi(datasetId, "major", superUserApiToken); publishDatasetResp.then().assertThat() .statusCode(OK.getStatusCode()); @@ -1443,14 +1444,45 @@ public void testGetFileInfo() { .statusCode(OK.getStatusCode()); // The following tests cover cases where a version ID is specified in the endpoint + // Superuser should not get to see draft file data when no draft version exists + getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, DS_VERSION_DRAFT); + getFileDataResponse.then().assertThat() + .statusCode(NOT_FOUND.getStatusCode()); + + // Update the file metadata + String newFileName = "trees_2.png"; + JsonObjectBuilder updateFileMetadata = Json.createObjectBuilder() + .add("label", newFileName); + Response updateFileMetadataResponse = UtilIT.updateFileMetadata(dataFileId, updateFileMetadata.build().toString(), superUserApiToken); + updateFileMetadataResponse.then().statusCode(OK.getStatusCode()); + // Superuser should get to see draft file data + getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, DS_VERSION_DRAFT); + getFileDataResponse.then().assertThat() + .statusCode(OK.getStatusCode()); + + // Regular user should not get to see draft file data + getFileDataResponse = UtilIT.getFileData(dataFileId, apiTokenRegular, DS_VERSION_DRAFT); + getFileDataResponse.then().assertThat() + .statusCode(UNAUTHORIZED.getStatusCode()); + + // Publish dataset once again + publishDatasetResp = UtilIT.publishDatasetViaNativeApi(datasetId, "major", superUserApiToken); + publishDatasetResp.then().assertThat() + .statusCode(OK.getStatusCode()); + + // Regular user should get to see latest published file data + getFileDataResponse = UtilIT.getFileData(dataFileId, apiTokenRegular, DS_VERSION_LATEST_PUBLISHED); + getFileDataResponse.then().assertThat() + .statusCode(OK.getStatusCode()) + .body("data.label", equalTo(newFileName)); // TODO // Cleanup - Response destroyDatasetResponse = UtilIT.destroyDataset(datasetId, apiToken); + Response destroyDatasetResponse = UtilIT.destroyDataset(datasetId, superUserApiToken); assertEquals(200, destroyDatasetResponse.getStatusCode()); - Response deleteDataverseResponse = UtilIT.deleteDataverse(dataverseAlias, apiToken); + Response deleteDataverseResponse = UtilIT.deleteDataverse(dataverseAlias, superUserApiToken); assertEquals(200, deleteDataverseResponse.getStatusCode()); Response deleteUserResponse = UtilIT.deleteUser(username); diff --git a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java index c2d43584b22..f6f2c9a3c03 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -1086,15 +1086,15 @@ static Response getFileMetadata(String fileIdOrPersistentId, String optionalForm } static Response getFileData(String fileId, String apiToken) { - return getFileData(fileId, apiToken, null); + return given() + .header(API_TOKEN_HTTP_HEADER, apiToken) + .get("/api/files/" + fileId); } static Response getFileData(String fileId, String apiToken, String datasetVersionId) { - RequestSpecification requestSpec = given().header(API_TOKEN_HTTP_HEADER, apiToken); - if (datasetVersionId != null) { - requestSpec.queryParam("datasetVersionId", datasetVersionId); - } - return requestSpec.get("/api/files/" + fileId); + return given() + .header(API_TOKEN_HTTP_HEADER, apiToken) + .get("/api/files/" + fileId + "/versions/" + datasetVersionId); } static Response testIngest(String fileName, String fileType) { From 8abeaf06ce1c24a5b0cc7c17954c307727746703 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Thu, 8 Feb 2024 09:06:57 -0500 Subject: [PATCH 026/141] #10286 add breadcrumbs to dataset api --- .../harvard/iq/dataverse/api/Datasets.java | 5 +- .../iq/dataverse/util/json/JsonPrinter.java | 49 ++++++++++++++++++- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java b/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java index e3505cbbb33..60c07815b71 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java @@ -186,11 +186,12 @@ public interface DsVersionHandler { @GET @AuthRequired @Path("{id}") - public Response getDataset(@Context ContainerRequestContext crc, @PathParam("id") String id, @Context UriInfo uriInfo, @Context HttpHeaders headers, @Context HttpServletResponse response) { + public Response getDataset(@Context ContainerRequestContext crc, @PathParam("id") String id, @Context UriInfo uriInfo, @Context HttpHeaders headers, @Context HttpServletResponse response, @QueryParam("breadcrumbs") Boolean breadcrumbs) { return response( req -> { final Dataset retrieved = execCommand(new GetDatasetCommand(req, findDatasetOrDie(id))); final DatasetVersion latest = execCommand(new GetLatestAccessibleDatasetVersionCommand(req, retrieved)); - final JsonObjectBuilder jsonbuilder = json(retrieved); + Boolean includeBreadcrumbs = breadcrumbs == null ? false : breadcrumbs; + final JsonObjectBuilder jsonbuilder = json(retrieved, includeBreadcrumbs); //Report MDC if this is a released version (could be draft if user has access, or user may not have access at all and is not getting metadata beyond the minimum) if((latest != null) && latest.isReleased()) { MakeDataCountLoggingServiceBean.MakeDataCountEntry entry = new MakeDataCountEntry(uriInfo, headers, dvRequestService, retrieved); diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index 2eaf6b64579..197c46ac474 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -55,6 +55,7 @@ import jakarta.ejb.Singleton; import jakarta.json.JsonArray; import jakarta.json.JsonObject; +import java.math.BigDecimal; /** * Convert objects to Json. @@ -303,6 +304,45 @@ public static JsonArrayBuilder json(List dataverseContacts) { } return jsonArrayOfContacts; } + + public static JsonArrayBuilder getBreadcrumbsFromDvObject(DvObject dvObject) { + + List ownerList = new ArrayList(); + + while (dvObject != null) { + ownerList.add(dvObject); + dvObject = dvObject.getOwner(); + } + + JsonArrayBuilder jsonArrayOfBreadcrumbs = Json.createArrayBuilder(); + + for (DvObject dvo : ownerList){ + JsonObjectBuilder breadcrumbObject = jsonObjectBuilder(); + if (dvo.isInstanceofDataverse()){ + Dataverse in = (Dataverse) dvo; + breadcrumbObject.add("identifier", in.getAlias()); + } + if (dvo.isInstanceofDataset() || dvo.isInstanceofDataFile() ){ + if (dvo.getIdentifier() != null){ + breadcrumbObject.add("identifier", dvo.getIdentifier()); + } else { + breadcrumbObject.add("identifier", dvo.getId()); + } + } + if (dvo.isInstanceofDataverse()){ + breadcrumbObject.add("type", "DATAVERSE"); + } + if (dvo.isInstanceofDataset()){ + breadcrumbObject.add("type", "DATASET"); + } + if (dvo.isInstanceofDataFile()){ + breadcrumbObject.add("type", "DATAFILE"); + } + breadcrumbObject.add("displayName", dvo.getDisplayName()); + jsonArrayOfBreadcrumbs.add(breadcrumbObject); + } + return jsonArrayOfBreadcrumbs; + } public static JsonObjectBuilder json( DataverseTheme theme ) { final NullSafeJsonBuilder baseObject = jsonObjectBuilder() @@ -326,8 +366,12 @@ public static JsonObjectBuilder json(BuiltinUser user) { .add("id", user.getId()) .add("userName", user.getUserName()); } + + public static JsonObjectBuilder json(Dataset ds){ + return json(ds, false); + } - public static JsonObjectBuilder json(Dataset ds) { + public static JsonObjectBuilder json(Dataset ds, Boolean includeBreadcrumbs) { JsonObjectBuilder bld = jsonObjectBuilder() .add("id", ds.getId()) .add("identifier", ds.getIdentifier()) @@ -340,6 +384,9 @@ public static JsonObjectBuilder json(Dataset ds) { if (DvObjectContainer.isMetadataLanguageSet(ds.getMetadataLanguage())) { bld.add("metadataLanguage", ds.getMetadataLanguage()); } + if (includeBreadcrumbs){ + bld.add("ownerArray", getBreadcrumbsFromDvObject(ds)); + } return bld; } From 572b9cbbd0264b068bb324c69a6d2a2a06f6337e Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Thu, 8 Feb 2024 09:30:19 -0500 Subject: [PATCH 027/141] #10286 move owner type to beginning --- .../iq/dataverse/util/json/JsonPrinter.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index 197c46ac474..0803001fbfd 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -318,6 +318,15 @@ public static JsonArrayBuilder getBreadcrumbsFromDvObject(DvObject dvObject) { for (DvObject dvo : ownerList){ JsonObjectBuilder breadcrumbObject = jsonObjectBuilder(); + if (dvo.isInstanceofDataverse()){ + breadcrumbObject.add("type", "DATAVERSE"); + } + if (dvo.isInstanceofDataset()){ + breadcrumbObject.add("type", "DATASET"); + } + if (dvo.isInstanceofDataFile()){ + breadcrumbObject.add("type", "DATAFILE"); + } if (dvo.isInstanceofDataverse()){ Dataverse in = (Dataverse) dvo; breadcrumbObject.add("identifier", in.getAlias()); @@ -329,15 +338,6 @@ public static JsonArrayBuilder getBreadcrumbsFromDvObject(DvObject dvObject) { breadcrumbObject.add("identifier", dvo.getId()); } } - if (dvo.isInstanceofDataverse()){ - breadcrumbObject.add("type", "DATAVERSE"); - } - if (dvo.isInstanceofDataset()){ - breadcrumbObject.add("type", "DATASET"); - } - if (dvo.isInstanceofDataFile()){ - breadcrumbObject.add("type", "DATAFILE"); - } breadcrumbObject.add("displayName", dvo.getDisplayName()); jsonArrayOfBreadcrumbs.add(breadcrumbObject); } From 889e942f353953aff9df192c46fa2c0ebd4b0c51 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Thu, 8 Feb 2024 14:32:44 -0500 Subject: [PATCH 028/141] #10286 update pathparam name/terms --- .../harvard/iq/dataverse/api/Datasets.java | 6 ++-- .../iq/dataverse/util/json/JsonPrinter.java | 32 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java b/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java index 60c07815b71..02eb13e32d4 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java @@ -186,12 +186,12 @@ public interface DsVersionHandler { @GET @AuthRequired @Path("{id}") - public Response getDataset(@Context ContainerRequestContext crc, @PathParam("id") String id, @Context UriInfo uriInfo, @Context HttpHeaders headers, @Context HttpServletResponse response, @QueryParam("breadcrumbs") Boolean breadcrumbs) { + public Response getDataset(@Context ContainerRequestContext crc, @PathParam("id") String id, @Context UriInfo uriInfo, @Context HttpHeaders headers, @Context HttpServletResponse response, @QueryParam("returnOwners") Boolean returnOwners) { return response( req -> { final Dataset retrieved = execCommand(new GetDatasetCommand(req, findDatasetOrDie(id))); final DatasetVersion latest = execCommand(new GetLatestAccessibleDatasetVersionCommand(req, retrieved)); - Boolean includeBreadcrumbs = breadcrumbs == null ? false : breadcrumbs; - final JsonObjectBuilder jsonbuilder = json(retrieved, includeBreadcrumbs); + Boolean includeOwners = returnOwners == null ? false : returnOwners; + final JsonObjectBuilder jsonbuilder = json(retrieved, includeOwners); //Report MDC if this is a released version (could be draft if user has access, or user may not have access at all and is not getting metadata beyond the minimum) if((latest != null) && latest.isReleased()) { MakeDataCountLoggingServiceBean.MakeDataCountEntry entry = new MakeDataCountEntry(uriInfo, headers, dvRequestService, retrieved); diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index 0803001fbfd..7d9bede9a61 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -305,43 +305,43 @@ public static JsonArrayBuilder json(List dataverseContacts) { return jsonArrayOfContacts; } - public static JsonArrayBuilder getBreadcrumbsFromDvObject(DvObject dvObject) { + public static JsonArrayBuilder getOwnersFromDvObject(DvObject dvObject) { List ownerList = new ArrayList(); - + dvObject = dvObject.getOwner(); // We're going to ignore the object itself while (dvObject != null) { ownerList.add(dvObject); dvObject = dvObject.getOwner(); } - JsonArrayBuilder jsonArrayOfBreadcrumbs = Json.createArrayBuilder(); + JsonArrayBuilder jsonArrayOfOwners = Json.createArrayBuilder(); for (DvObject dvo : ownerList){ - JsonObjectBuilder breadcrumbObject = jsonObjectBuilder(); + JsonObjectBuilder ownerObject = jsonObjectBuilder(); if (dvo.isInstanceofDataverse()){ - breadcrumbObject.add("type", "DATAVERSE"); + ownerObject.add("type", "DATAVERSE"); } if (dvo.isInstanceofDataset()){ - breadcrumbObject.add("type", "DATASET"); + ownerObject.add("type", "DATASET"); } if (dvo.isInstanceofDataFile()){ - breadcrumbObject.add("type", "DATAFILE"); + ownerObject.add("type", "DATAFILE"); } if (dvo.isInstanceofDataverse()){ Dataverse in = (Dataverse) dvo; - breadcrumbObject.add("identifier", in.getAlias()); + ownerObject.add("identifier", in.getAlias()); } if (dvo.isInstanceofDataset() || dvo.isInstanceofDataFile() ){ if (dvo.getIdentifier() != null){ - breadcrumbObject.add("identifier", dvo.getIdentifier()); + ownerObject.add("identifier", dvo.getIdentifier()); } else { - breadcrumbObject.add("identifier", dvo.getId()); + ownerObject.add("identifier", dvo.getId()); } } - breadcrumbObject.add("displayName", dvo.getDisplayName()); - jsonArrayOfBreadcrumbs.add(breadcrumbObject); + ownerObject.add("displayName", dvo.getDisplayName()); + jsonArrayOfOwners.add(ownerObject); } - return jsonArrayOfBreadcrumbs; + return jsonArrayOfOwners; } public static JsonObjectBuilder json( DataverseTheme theme ) { @@ -371,7 +371,7 @@ public static JsonObjectBuilder json(Dataset ds){ return json(ds, false); } - public static JsonObjectBuilder json(Dataset ds, Boolean includeBreadcrumbs) { + public static JsonObjectBuilder json(Dataset ds, Boolean includeOwners) { JsonObjectBuilder bld = jsonObjectBuilder() .add("id", ds.getId()) .add("identifier", ds.getIdentifier()) @@ -384,8 +384,8 @@ public static JsonObjectBuilder json(Dataset ds, Boolean includeBreadcrumbs) { if (DvObjectContainer.isMetadataLanguageSet(ds.getMetadataLanguage())) { bld.add("metadataLanguage", ds.getMetadataLanguage()); } - if (includeBreadcrumbs){ - bld.add("ownerArray", getBreadcrumbsFromDvObject(ds)); + if (includeOwners){ + bld.add("ownerArray", getOwnersFromDvObject(ds)); } return bld; } From c95ceb282648d7c386e8dce88aec416a872af567 Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Fri, 9 Feb 2024 18:42:10 +0100 Subject: [PATCH 029/141] fix(ct): make base image comply with OpenShift file permissions To enable the user with a random, arbitrary UID to write into the overlay filesystem, we need to set proper file permissions. This should not affect users on Docker or other K8s distributions, as the security is more lenient there. It is not ideal to write into overlayfs, as it impacts performance and may lead to unintended side effects. This is a workaround to at least get going. See https://docs.openshift.com/container-platform/4.14/openshift_images/create-images.html#use-uid_create-images for a detailed reference --- modules/container-base/src/main/docker/Dockerfile | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/modules/container-base/src/main/docker/Dockerfile b/modules/container-base/src/main/docker/Dockerfile index 97aa4cd2792..3d2e1f782f2 100644 --- a/modules/container-base/src/main/docker/Dockerfile +++ b/modules/container-base/src/main/docker/Dockerfile @@ -84,8 +84,11 @@ RUN < Date: Fri, 9 Feb 2024 18:43:58 +0100 Subject: [PATCH 030/141] fix(ct): make location of boot scripts configurable By defining pre- and postboot file locations within the Dockerfile, it wasn't able to change the location by changing CONFIG_DIR env var. This is fixed now, allowing simpler backing of the dir location with an (ephemeral) volume. --- modules/container-base/src/main/docker/Dockerfile | 2 -- .../container-base/src/main/docker/scripts/entrypoint.sh | 6 ++++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/container-base/src/main/docker/Dockerfile b/modules/container-base/src/main/docker/Dockerfile index 3d2e1f782f2..663b3d9dd51 100644 --- a/modules/container-base/src/main/docker/Dockerfile +++ b/modules/container-base/src/main/docker/Dockerfile @@ -49,8 +49,6 @@ ENV PAYARA_DIR="${HOME_DIR}/appserver" \ ENV PATH="${PATH}:${PAYARA_DIR}/bin:${SCRIPT_DIR}" \ DOMAIN_DIR="${PAYARA_DIR}/glassfish/domains/${DOMAIN_NAME}" \ DEPLOY_PROPS="" \ - PREBOOT_COMMANDS="${CONFIG_DIR}/pre-boot-commands.asadmin" \ - POSTBOOT_COMMANDS="${CONFIG_DIR}/post-boot-commands.asadmin" \ JVM_ARGS="" \ MEM_MAX_RAM_PERCENTAGE="70.0" \ MEM_XSS="512k" \ diff --git a/modules/container-base/src/main/docker/scripts/entrypoint.sh b/modules/container-base/src/main/docker/scripts/entrypoint.sh index 47933bd42e2..bd7031db9f0 100644 --- a/modules/container-base/src/main/docker/scripts/entrypoint.sh +++ b/modules/container-base/src/main/docker/scripts/entrypoint.sh @@ -10,6 +10,12 @@ # and zombies under control. If the ENTRYPOINT command is changed, it will still use dumb-init because shebang. # dumb-init takes care to send any signals to subshells, too! (Which might run in the background...) +# We do not define these variables within our Dockerfile so the location can be changed when trying to avoid +# writes to the overlay filesystem. (CONFIG_DIR is defined within the Dockerfile, but might be overridden.) +${PREBOOT_COMMANDS:="${CONFIG_DIR}/pre-boot-commands.asadmin"} +export PREBOOT_COMMANDS +${POSTBOOT_COMMANDS:="${CONFIG_DIR}/post-boot-commands.asadmin"} +export POSTBOOT_COMMANDS # Execute any scripts BEFORE the appserver starts for f in "${SCRIPT_DIR}"/init_* "${SCRIPT_DIR}"/init.d/*; do From d77cf4a9b2d6d07b66414704c8d389ed3fd40257 Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Fri, 9 Feb 2024 18:44:49 +0100 Subject: [PATCH 031/141] style(ct): fix typos in base image Dockerfile --- modules/container-base/src/main/docker/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/container-base/src/main/docker/Dockerfile b/modules/container-base/src/main/docker/Dockerfile index 663b3d9dd51..5fbbdd0c1e5 100644 --- a/modules/container-base/src/main/docker/Dockerfile +++ b/modules/container-base/src/main/docker/Dockerfile @@ -155,7 +155,7 @@ RUN < Date: Fri, 9 Feb 2024 18:45:35 +0100 Subject: [PATCH 032/141] fix(ct): make DV preboot file end up in config dir The location where to create the temporary file was wrong, fixed now. --- .../src/main/docker/scripts/init_1_generate_devmode_commands.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/container-base/src/main/docker/scripts/init_1_generate_devmode_commands.sh b/modules/container-base/src/main/docker/scripts/init_1_generate_devmode_commands.sh index bb0984332f7..28e7fd68b97 100644 --- a/modules/container-base/src/main/docker/scripts/init_1_generate_devmode_commands.sh +++ b/modules/container-base/src/main/docker/scripts/init_1_generate_devmode_commands.sh @@ -16,7 +16,7 @@ ENABLE_JMX=${ENABLE_JMX:-0} ENABLE_JDWP=${ENABLE_JDWP:-0} ENABLE_RELOAD=${ENABLE_RELOAD:-0} -DV_PREBOOT=${PAYARA_DIR}/dataverse_preboot +DV_PREBOOT=${CONFIG_DIR}/dataverse_preboot echo "# Dataverse preboot configuration for Payara" > "${DV_PREBOOT}" # 1. Configure JMX (enabled by default on port 8686, but requires SSL) From 8547dbf4222597dc48c83f45104bb9165dcce843 Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Fri, 9 Feb 2024 18:51:48 +0100 Subject: [PATCH 033/141] feat(k8s): initial commit of new module --- modules/container-k8s/pom.xml | 59 +++++++++++++++ .../src/main/jkube/dataverse-datasets-pvc.yml | 6 ++ .../src/main/jkube/dataverse-deployment.yaml | 72 +++++++++++++++++++ .../src/main/jkube/dataverse-docroot-pvc.yml | 6 ++ .../src/main/jkube/dataverse-storage-pvc.yml | 6 ++ .../src/main/jkube/dataverse-uploads-pvc.yaml | 6 ++ .../main/jkube/deps/postgres-deployment.yml | 31 ++++++++ .../src/main/jkube/deps/postgres-pvc.yml | 6 ++ .../src/main/jkube/deps/postgres-svc.yml | 5 ++ .../container-k8s/src/main/jkube/profiles.yml | 12 ++++ 10 files changed, 209 insertions(+) create mode 100644 modules/container-k8s/pom.xml create mode 100644 modules/container-k8s/src/main/jkube/dataverse-datasets-pvc.yml create mode 100644 modules/container-k8s/src/main/jkube/dataverse-deployment.yaml create mode 100644 modules/container-k8s/src/main/jkube/dataverse-docroot-pvc.yml create mode 100644 modules/container-k8s/src/main/jkube/dataverse-storage-pvc.yml create mode 100644 modules/container-k8s/src/main/jkube/dataverse-uploads-pvc.yaml create mode 100644 modules/container-k8s/src/main/jkube/deps/postgres-deployment.yml create mode 100644 modules/container-k8s/src/main/jkube/deps/postgres-pvc.yml create mode 100644 modules/container-k8s/src/main/jkube/deps/postgres-svc.yml create mode 100644 modules/container-k8s/src/main/jkube/profiles.yml diff --git a/modules/container-k8s/pom.xml b/modules/container-k8s/pom.xml new file mode 100644 index 00000000000..470abb753ae --- /dev/null +++ b/modules/container-k8s/pom.xml @@ -0,0 +1,59 @@ + + + 4.0.0 + + + edu.harvard.iq + dataverse-parent + ${revision} + ../dataverse-parent + + + io.gdcc + container-k8s + ${packaging.type} + Container Kubernetes Materials + This module provides resources to run Dataverse on OpenShift or plain Kubernetes + + + + poikilotherm + Oliver Bertuch + github@bertuch.eu + Europe/Berlin + + maintainer + + + + + + + + pom + + + + + ct + + true + dataverse-k8s + + + + + + org.eclipse.jkube + kubernetes-maven-plugin + 1.16.0 + + + + + + + + + \ No newline at end of file diff --git a/modules/container-k8s/src/main/jkube/dataverse-datasets-pvc.yml b/modules/container-k8s/src/main/jkube/dataverse-datasets-pvc.yml new file mode 100644 index 00000000000..50e9ccb3c92 --- /dev/null +++ b/modules/container-k8s/src/main/jkube/dataverse-datasets-pvc.yml @@ -0,0 +1,6 @@ +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Mi diff --git a/modules/container-k8s/src/main/jkube/dataverse-deployment.yaml b/modules/container-k8s/src/main/jkube/dataverse-deployment.yaml new file mode 100644 index 00000000000..5d1ed67f635 --- /dev/null +++ b/modules/container-k8s/src/main/jkube/dataverse-deployment.yaml @@ -0,0 +1,72 @@ +spec: + replicas: 1 + template: + spec: + containers: + - name: dataverse + image: ghcr.io/gdcc/dataverse:openshift-poc + imagePullPolicy: Always + resources: + requests: + memory: "1Gi" + limits: + memory: "2Gi" + ports: + - containerPort: 8080 + readinessProbe: + httpGet: + path: /api/info/version + port: 8080 + #args: + # - bash + # - -c + # - "ls -laZ /opt/payara/config; touch /opt/payara/config/test" + env: + - name: DATAVERSE_DB_HOST + value: postgres + - name: DATAVERSE_DB_USER + value: dataverse + - name: DATAVERSE_DB_PASSWORD + value: supersecret + volumeMounts: + - name: storage + mountPath: /dv + - name: datasets + mountPath: /dv/store + - name: docroot + mountPath: /dv/docroot + - name: uploads + mountPath: /dv/uploads + - name: config + mountPath: /opt/payara/config + - name: dvtemp + mountPath: /dv/temp + - name: tmp + mountPath: /tmp + - name: heapdumps + mountPath: /dumps + - name: bootstrap + image: ghcr.io/gdcc/configbaker:openshift-poc + restartPolicy: Never + args: ["bootstrap.sh", "-u", "http://localhost:8080", "-t", "3m", "dev"] + volumes: + - name: storage + persistentVolumeClaim: + claimName: dataverse-storage + - name: datasets + persistentVolumeClaim: + claimName: dataverse-datasets + - name: docroot + persistentVolumeClaim: + claimName: dataverse-docroot + - name: uploads + persistentVolumeClaim: + claimName: dataverse-uploads + - name: config + emptyDir: {} + - name: dvtemp + emptyDir: {} + - name: tmp + emptyDir: {} + - name: heapdumps + emptyDir: {} \ No newline at end of file diff --git a/modules/container-k8s/src/main/jkube/dataverse-docroot-pvc.yml b/modules/container-k8s/src/main/jkube/dataverse-docroot-pvc.yml new file mode 100644 index 00000000000..50e9ccb3c92 --- /dev/null +++ b/modules/container-k8s/src/main/jkube/dataverse-docroot-pvc.yml @@ -0,0 +1,6 @@ +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Mi diff --git a/modules/container-k8s/src/main/jkube/dataverse-storage-pvc.yml b/modules/container-k8s/src/main/jkube/dataverse-storage-pvc.yml new file mode 100644 index 00000000000..50e9ccb3c92 --- /dev/null +++ b/modules/container-k8s/src/main/jkube/dataverse-storage-pvc.yml @@ -0,0 +1,6 @@ +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Mi diff --git a/modules/container-k8s/src/main/jkube/dataverse-uploads-pvc.yaml b/modules/container-k8s/src/main/jkube/dataverse-uploads-pvc.yaml new file mode 100644 index 00000000000..50e9ccb3c92 --- /dev/null +++ b/modules/container-k8s/src/main/jkube/dataverse-uploads-pvc.yaml @@ -0,0 +1,6 @@ +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Mi diff --git a/modules/container-k8s/src/main/jkube/deps/postgres-deployment.yml b/modules/container-k8s/src/main/jkube/deps/postgres-deployment.yml new file mode 100644 index 00000000000..c5290982642 --- /dev/null +++ b/modules/container-k8s/src/main/jkube/deps/postgres-deployment.yml @@ -0,0 +1,31 @@ +spec: + replicas: 1 + strategy: + type: Recreate + template: + spec: + containers: + - name: postgres + image: postgres:13 + ports: + - containerPort: 5432 + env: + - name: POSTGRES_USER + value: dataverse + - name: POSTGRES_PASSWORD + value: supersecret + - name: PGDATA + value: /var/lib/postgresql/data/pgdata + volumeMounts: + - name: postgresql-persistent-storage + mountPath: /var/lib/postgresql/data + readinessProbe: + exec: + command: ["pg_isready"] + initialDelaySeconds: 5 + failureThreshold: 100 + periodSeconds: 5 + volumes: + - name: postgresql-persistent-storage + persistentVolumeClaim: + claimName: postgres \ No newline at end of file diff --git a/modules/container-k8s/src/main/jkube/deps/postgres-pvc.yml b/modules/container-k8s/src/main/jkube/deps/postgres-pvc.yml new file mode 100644 index 00000000000..9cefb651bd4 --- /dev/null +++ b/modules/container-k8s/src/main/jkube/deps/postgres-pvc.yml @@ -0,0 +1,6 @@ +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 300Mi diff --git a/modules/container-k8s/src/main/jkube/deps/postgres-svc.yml b/modules/container-k8s/src/main/jkube/deps/postgres-svc.yml new file mode 100644 index 00000000000..fc75438b31c --- /dev/null +++ b/modules/container-k8s/src/main/jkube/deps/postgres-svc.yml @@ -0,0 +1,5 @@ +spec: + ports: + - port: 5432 + targetPort: 5432 + protocol: TCP \ No newline at end of file diff --git a/modules/container-k8s/src/main/jkube/profiles.yml b/modules/container-k8s/src/main/jkube/profiles.yml new file mode 100644 index 00000000000..8443a9cf54c --- /dev/null +++ b/modules/container-k8s/src/main/jkube/profiles.yml @@ -0,0 +1,12 @@ +- name: deps + extends: default +- name: default + enricher: + excludes: + - jkube-volume-permission + - jkube-project-label +- name: security-hardening + enricher: + excludes: + - jkube-volume-permission + - jkube-project-label From b3321d4ad6760155672f67a95a4d9463eb5f3b1f Mon Sep 17 00:00:00 2001 From: Juan Pablo Tosca Villanueva Date: Fri, 9 Feb 2024 13:29:41 -0500 Subject: [PATCH 034/141] Add content to deaccession info message --- src/main/java/propertyFiles/Bundle.properties | 7 ++++--- src/main/webapp/dataset.xhtml | 7 ++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/propertyFiles/Bundle.properties b/src/main/java/propertyFiles/Bundle.properties index 157f2ecaf54..34e16e36eac 100644 --- a/src/main/java/propertyFiles/Bundle.properties +++ b/src/main/java/propertyFiles/Bundle.properties @@ -2002,7 +2002,8 @@ file.deleteFileDialog.immediate=The file will be deleted after you click on the file.deleteFileDialog.multiple.immediate=The file(s) will be deleted after you click on the Delete button. file.deleteFileDialog.header=Delete Files file.deleteFileDialog.failed.tip=Files will not be removed from previously published versions of the dataset. -file.deaccessionDialog.tip=Once you deaccession this dataset it will no longer be viewable by the public. +file.deaccessionDialog.tip.permanent=Deaccession is permanent. +file.deaccessionDialog.tip=This dataset will no longer be public and a tumbstone will display the reason for deaccessioning.
Please read the
documentation if you have any questions. file.deaccessionDialog.version=Version file.deaccessionDialog.reason.question1=Which version(s) do you want to deaccession? file.deaccessionDialog.reason.question2=What is the reason for deaccession? @@ -2016,8 +2017,8 @@ file.deaccessionDialog.reason.selectItem.other=Other (Please type reason in spac file.deaccessionDialog.enterInfo=Please enter additional information about the reason for deaccession. file.deaccessionDialog.leaveURL=If applicable, please leave a URL where this dataset can be accessed after deaccessioning. file.deaccessionDialog.leaveURL.watermark=Optional dataset site, http://... -file.deaccessionDialog.deaccession.tip=Are you sure you want to deaccession? The selected version(s) will no longer be viewable by the public. -file.deaccessionDialog.deaccessionDataset.tip=Are you sure you want to deaccession this dataset? It will no longer be viewable by the public. +file.deaccessionDialog.deaccession.tip=Are you sure you want to deaccession? This is permanent and the selected version(s) will no longer be viewable by the public. +file.deaccessionDialog.deaccessionDataset.tip=Are you sure you want to deaccession this dataset? This is permanent an it will no longer be viewable by the public. file.deaccessionDialog.dialog.selectVersion.error=Please select version(s) for deaccessioning. file.deaccessionDialog.dialog.reason.error=Please select reason for deaccessioning. file.deaccessionDialog.dialog.url.error=Please enter valid forwarding URL. diff --git a/src/main/webapp/dataset.xhtml b/src/main/webapp/dataset.xhtml index e50e68ec162..2afae295082 100644 --- a/src/main/webapp/dataset.xhtml +++ b/src/main/webapp/dataset.xhtml @@ -1221,7 +1221,12 @@ -

#{bundle['file.deaccessionDialog.tip']}

+
+   +


+ +

+
Date: Fri, 9 Feb 2024 17:12:24 -0500 Subject: [PATCH 035/141] #10286 add owner array to file api --- .../edu/harvard/iq/dataverse/api/Files.java | 17 ++++++++++------- .../iq/dataverse/util/json/JsonPrinter.java | 17 ++++++++++++++--- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Files.java b/src/main/java/edu/harvard/iq/dataverse/api/Files.java index 5d400ee1438..155d8953d15 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Files.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Files.java @@ -504,18 +504,21 @@ public Response updateFileMetadata(@Context ContainerRequestContext crc, @FormDa @GET @AuthRequired @Path("{id}/draft") - public Response getFileDataDraft(@Context ContainerRequestContext crc, @PathParam("id") String fileIdOrPersistentId, @Context UriInfo uriInfo, @Context HttpHeaders headers, @Context HttpServletResponse response) throws WrappedResponse, Exception { - return getFileDataResponse(getRequestUser(crc), fileIdOrPersistentId, uriInfo, headers, response, true); + public Response getFileDataDraft(@Context ContainerRequestContext crc, @PathParam("id") String fileIdOrPersistentId, @Context UriInfo uriInfo, @Context HttpHeaders headers, @Context HttpServletResponse response, @QueryParam("returnOwners") Boolean returnOwners) throws WrappedResponse, Exception { + Boolean includeOwners = returnOwners == null ? false : returnOwners; + return getFileDataResponse(getRequestUser(crc), fileIdOrPersistentId, uriInfo, headers, response, true, includeOwners); } @GET @AuthRequired @Path("{id}") - public Response getFileData(@Context ContainerRequestContext crc, @PathParam("id") String fileIdOrPersistentId, @Context UriInfo uriInfo, @Context HttpHeaders headers, @Context HttpServletResponse response) throws WrappedResponse, Exception { - return getFileDataResponse(getRequestUser(crc), fileIdOrPersistentId, uriInfo, headers, response, false); + public Response getFileData(@Context ContainerRequestContext crc, @PathParam("id") String fileIdOrPersistentId, @Context UriInfo uriInfo, @Context HttpHeaders headers, @Context HttpServletResponse response, @QueryParam("returnOwners") Boolean returnOwners) throws WrappedResponse, Exception { + Boolean includeOwners = returnOwners == null ? false : returnOwners; + System.out.print("includeOwners: " + includeOwners); + return getFileDataResponse(getRequestUser(crc), fileIdOrPersistentId, uriInfo, headers, response, false, includeOwners); } - private Response getFileDataResponse(User user, String fileIdOrPersistentId, UriInfo uriInfo, HttpHeaders headers, HttpServletResponse response, boolean draft ){ + private Response getFileDataResponse(User user, String fileIdOrPersistentId, UriInfo uriInfo, HttpHeaders headers, HttpServletResponse response, boolean draft, boolean includeOwners ){ DataverseRequest req; try { @@ -565,10 +568,10 @@ private Response getFileDataResponse(User user, String fileIdOrPersistentId, Uri MakeDataCountLoggingServiceBean.MakeDataCountEntry entry = new MakeDataCountLoggingServiceBean.MakeDataCountEntry(uriInfo, headers, dvRequestService, df); mdcLogService.logEntry(entry); } - + return Response.ok(Json.createObjectBuilder() .add("status", ApiConstants.STATUS_OK) - .add("data", json(fm)).build()) + .add("data", json(fm, includeOwners)).build()) .type(MediaType.APPLICATION_JSON) .build(); } diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index 7d9bede9a61..d88015145b3 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -639,8 +639,12 @@ public static JsonObjectBuilder json(DatasetFieldType fld) { return fieldsBld; } + + public static JsonObjectBuilder json(FileMetadata fmd){ + return json(fmd, false); + } - public static JsonObjectBuilder json(FileMetadata fmd) { + public static JsonObjectBuilder json(FileMetadata fmd, Boolean includeOwners) { return jsonObjectBuilder() // deprecated: .add("category", fmd.getCategory()) // TODO: uh, figure out what to do here... it's deprecated @@ -655,7 +659,7 @@ public static JsonObjectBuilder json(FileMetadata fmd) { .add("version", fmd.getVersion()) .add("datasetVersionId", fmd.getDatasetVersion().getId()) .add("categories", getFileCategories(fmd)) - .add("dataFile", JsonPrinter.json(fmd.getDataFile(), fmd, false)); + .add("dataFile", JsonPrinter.json(fmd.getDataFile(), fmd, false, includeOwners)); } public static JsonObjectBuilder json(AuxiliaryFile auxFile) { @@ -674,7 +678,11 @@ public static JsonObjectBuilder json(DataFile df) { return JsonPrinter.json(df, null, false); } - public static JsonObjectBuilder json(DataFile df, FileMetadata fileMetadata, boolean forExportDataProvider) { + public static JsonObjectBuilder json(DataFile df, FileMetadata fileMetadata, boolean forExportDataProvider){ + return json(df, fileMetadata, forExportDataProvider, false); + } + + public static JsonObjectBuilder json(DataFile df, FileMetadata fileMetadata, boolean forExportDataProvider, Boolean includeOwners) { // File names are no longer stored in the DataFile entity; // (they are instead in the FileMetadata (as "labels") - this way // the filename can change between versions... @@ -750,6 +758,9 @@ public static JsonObjectBuilder json(DataFile df, FileMetadata fileMetadata, boo ? JsonPrinter.jsonVarGroup(fileMetadata.getVarGroups()) : null); } + if (includeOwners){ + builder.add("ownerArray", getOwnersFromDvObject(df)); + } return builder; } From 43f61e6334c087648476737dfc7d32ff5bc16d1f Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Mon, 12 Feb 2024 13:29:34 -0500 Subject: [PATCH 036/141] #10286 add owner array to view dv --- .../java/edu/harvard/iq/dataverse/api/Dataverses.java | 6 ++++-- .../edu/harvard/iq/dataverse/util/json/JsonPrinter.java | 8 +++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java index 6c1bf42c02a..66aec38adfa 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java @@ -610,10 +610,12 @@ private Dataset parseDataset(String datasetJson) throws WrappedResponse { @GET @AuthRequired @Path("{identifier}") - public Response viewDataverse(@Context ContainerRequestContext crc, @PathParam("identifier") String idtf) { + public Response viewDataverse(@Context ContainerRequestContext crc, @PathParam("identifier") String idtf, @QueryParam("returnOwners") Boolean returnOwners) { + Boolean includeOwners = returnOwners == null ? false : returnOwners; return response(req -> ok( json(execCommand(new GetDataverseCommand(req, findDataverseOrDie(idtf))), - settingsService.isTrueForKey(SettingsServiceBean.Key.ExcludeEmailFromExport, false) + settingsService.isTrueForKey(SettingsServiceBean.Key.ExcludeEmailFromExport, false), + includeOwners )), getRequestUser(crc)); } diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index d88015145b3..6f750eaddac 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -258,11 +258,11 @@ public static JsonObjectBuilder json(Workflow wf){ } public static JsonObjectBuilder json(Dataverse dv) { - return json(dv, false); + return json(dv, false, false); } //TODO: Once we upgrade to Java EE 8 we can remove objects from the builder, and this email removal can be done in a better place. - public static JsonObjectBuilder json(Dataverse dv, Boolean hideEmail) { + public static JsonObjectBuilder json(Dataverse dv, Boolean hideEmail, Boolean includeOwners) { JsonObjectBuilder bld = jsonObjectBuilder() .add("id", dv.getId()) .add("alias", dv.getAlias()) @@ -271,7 +271,9 @@ public static JsonObjectBuilder json(Dataverse dv, Boolean hideEmail) { if(!hideEmail) { bld.add("dataverseContacts", JsonPrinter.json(dv.getDataverseContacts())); } - + if (includeOwners){ + bld.add("ownerArray", getOwnersFromDvObject(dv)); + } bld.add("permissionRoot", dv.isPermissionRoot()) .add("description", dv.getDescription()) .add("dataverseType", dv.getDataverseType().name()); From 1898c148512aec9943971f546c9dc7e53b537147 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Mon, 12 Feb 2024 15:39:10 -0500 Subject: [PATCH 037/141] #10286 add test for get ds api --- .../harvard/iq/dataverse/api/DatasetsIT.java | 28 +++++++++++++++++++ .../edu/harvard/iq/dataverse/api/UtilIT.java | 9 ++++++ 2 files changed, 37 insertions(+) diff --git a/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java b/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java index e1c4b901116..3703a0d39c3 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java @@ -1887,6 +1887,34 @@ public void testDeleteDatasetWhileFileIngesting() { .statusCode(FORBIDDEN.getStatusCode()); } + + @Test + public void testGetIncludeOwnerArray() { + + Response createUser = UtilIT.createRandomUser(); + createUser.then().assertThat() + .statusCode(OK.getStatusCode()); + String username = UtilIT.getUsernameFromResponse(createUser); + String apiToken = UtilIT.getApiTokenFromResponse(createUser); + + Response createDataverseResponse = UtilIT.createRandomDataverse(apiToken); + createDataverseResponse.prettyPrint(); + createDataverseResponse.then().assertThat() + .statusCode(CREATED.getStatusCode()); + String dataverseAlias = UtilIT.getAliasFromResponse(createDataverseResponse); + + Response createDatasetResponse = UtilIT.createRandomDatasetViaNativeApi(dataverseAlias, apiToken); + createDatasetResponse.prettyPrint(); + createDatasetResponse.then().assertThat() + .statusCode(CREATED.getStatusCode()); + Integer datasetId = JsonPath.from(createDatasetResponse.body().asString()).getInt("data.id"); + String persistentId = JsonPath.from(createDatasetResponse.body().asString()).getString("data.persistentId"); + logger.info("Dataset created with id " + datasetId + " and persistent id " + persistentId); + + Response getDatasetWithOwners = UtilIT.getDatasetWithOwners(persistentId, apiToken, true); + getDatasetWithOwners.prettyPrint(); + getDatasetWithOwners.then().assertThat().body("data.ownerArray[0].identifier", equalTo(dataverseAlias)); + } /** * In order for this test to pass you must have the Data Capture Module ( diff --git a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java index ec41248a65f..0598bb80ea6 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -1476,6 +1476,15 @@ static Response getDatasetVersion(String persistentId, String versionNumber, Str + persistentId + (excludeFiles ? "&excludeFiles=true" : "")); } + + static Response getDatasetWithOwners(String persistentId, String apiToken, boolean returnOwners) { + return given() + .header(API_TOKEN_HTTP_HEADER, apiToken) + .get("/api/datasets/:persistentId/" + + "?persistentId=" + + persistentId + + (returnOwners ? "&returnOwners=true" : "")); + } static Response getMetadataBlockFromDatasetVersion(String persistentId, String versionNumber, String metadataBlock, String apiToken) { return given() From 240e851c7ba43b5037097aa2f0e0e827f2564f12 Mon Sep 17 00:00:00 2001 From: Jim Myers Date: Tue, 13 Feb 2024 16:38:03 -0500 Subject: [PATCH 038/141] Ingest/Uningest from file page --- .../edu/harvard/iq/dataverse/FilePage.java | 112 ++++++++++++++++++ .../webapp/file-edit-button-fragment.xhtml | 16 +++ 2 files changed, 128 insertions(+) diff --git a/src/main/java/edu/harvard/iq/dataverse/FilePage.java b/src/main/java/edu/harvard/iq/dataverse/FilePage.java index 479c8a429c6..b6706acd4ff 100644 --- a/src/main/java/edu/harvard/iq/dataverse/FilePage.java +++ b/src/main/java/edu/harvard/iq/dataverse/FilePage.java @@ -475,6 +475,112 @@ public String restrictFile(boolean restricted) throws CommandException{ return returnToDraftVersion(); } + public String ingestFile() throws CommandException{ + + User u = session.getUser(); + if(!u.isAuthenticated() || !(permissionService.permissionsFor(u, file).contains(Permission.PublishDataset))) { + //Shouldn't happen (choice not displayed for users who don't have the right permission), but check anyway + logger.warning("User: " + u.getIdentifier() + " tried to ingest a file"); + JH.addMessage(FacesMessage.SEVERITY_WARN, BundleUtil.getStringFromBundle("file.ingest.cantIngestFileWarning")); + return null; + } + + DataFile dataFile = fileMetadata.getDataFile(); + editDataset = dataFile.getOwner(); + + if (dataFile.isTabularData()) { + JH.addMessage(FacesMessage.SEVERITY_WARN, BundleUtil.getStringFromBundle("file.ingest.alreadyIngestedWarning")); + return null; + } + + boolean ingestLock = dataset.isLockedFor(DatasetLock.Reason.Ingest); + + if (ingestLock) { + JH.addMessage(FacesMessage.SEVERITY_WARN, BundleUtil.getStringFromBundle("file.ingest.ingestInProgressWarning")); + return null; + } + + if (!FileUtil.canIngestAsTabular(dataFile)) { + JH.addMessage(FacesMessage.SEVERITY_WARN, BundleUtil.getStringFromBundle("file.ingest.cantIngestFileWarning")); + return null; + + } + + dataFile.SetIngestScheduled(); + + if (dataFile.getIngestRequest() == null) { + dataFile.setIngestRequest(new IngestRequest(dataFile)); + } + + dataFile.getIngestRequest().setForceTypeCheck(true); + + // update the datafile, to save the newIngest request in the database: + save(); + + // queue the data ingest job for asynchronous execution: + String status = ingestService.startIngestJobs(editDataset.getId(), new ArrayList<>(Arrays.asList(dataFile)), (AuthenticatedUser) session.getUser()); + + if (!StringUtil.isEmpty(status)) { + // This most likely indicates some sort of a problem (for example, + // the ingest job was not put on the JMS queue because of the size + // of the file). But we are still returning the OK status - because + // from the point of view of the API, it's a success - we have + // successfully gone through the process of trying to schedule the + // ingest job... + + logger.warning("Ingest Status for file: " + dataFile.getId() + " : " + status); + } + logger.info("File: " + dataFile.getId() + " ingest queued"); + + init(); + JsfHelper.addInfoMessage(BundleUtil.getStringFromBundle("file.ingest.ingestQueued")); + return returnToDraftVersion(); + } + + public String uningestFile() throws CommandException { + + if (!file.isTabularData()) { + if(file.isIngestProblem()) { + User u = session.getUser(); + if(!u.isAuthenticated() || !(permissionService.permissionsFor(u, file).contains(Permission.PublishDataset))) { + logger.warning("User: " + u.getIdentifier() + " tried to uningest a file"); + //Shouldn't happen (choice not displayed for users who don't have the right permission), but check anyway + JH.addMessage(FacesMessage.SEVERITY_WARN, BundleUtil.getStringFromBundle("file.ingest.cantUningestFileWarning")); + return null; + } + file.setIngestDone(); + file.setIngestReport(null); + } else { + JH.addMessage(FacesMessage.SEVERITY_WARN, BundleUtil.getStringFromBundle("file.ingest.cantUningestFileWarning")); + return null; + } + } else { + commandEngine.submit(new UningestFileCommand(dvRequestService.getDataverseRequest(), file)); + Long dataFileId = file.getId(); + file = datafileService.find(dataFileId); + } + editDataset = file.getOwner(); + if (editDataset.isReleased()) { + try { + ExportService instance = ExportService.getInstance(); + instance.exportAllFormats(editDataset); + + } catch (ExportException ex) { + // Something went wrong! + // Just like with indexing, a failure to export is not a fatal + // condition. We'll just log the error as a warning and keep + // going: + logger.log(Level.WARNING, "Uningest: Exception while exporting:{0}", ex.getMessage()); + } + } + save(); + //Refresh filemetadata with file title, etc. + init(); + JH.addMessage(FacesMessage.SEVERITY_INFO, BundleUtil.getStringFromBundle("file.uningest.complete")); + return returnToDraftVersion(); + } + + private List filesToBeDeleted = new ArrayList<>(); public String deleteFile() { @@ -948,6 +1054,12 @@ public boolean isPubliclyDownloadable() { return FileUtil.isPubliclyDownloadable(fileMetadata); } + public boolean isIngestable() { + DataFile f = fileMetadata.getDataFile(); + //Datafile is an ingestable type and hasn't been ingested yet or had an ingest fail + return (FileUtil.canIngestAsTabular(f)&&!(f.isTabularData() || f.isIngestProblem())); + } + private Boolean lockedFromEditsVar; private Boolean lockedFromDownloadVar; diff --git a/src/main/webapp/file-edit-button-fragment.xhtml b/src/main/webapp/file-edit-button-fragment.xhtml index 4dac1613266..e08de716cda 100644 --- a/src/main/webapp/file-edit-button-fragment.xhtml +++ b/src/main/webapp/file-edit-button-fragment.xhtml @@ -77,6 +77,22 @@ + + + +
  • + + + +
  • +
    + +
  • + + + +
  • +
    From fcdc24611d26889ba32fda351490c0ae657aef7e Mon Sep 17 00:00:00 2001 From: qqmyers Date: Tue, 13 Feb 2024 17:00:07 -0500 Subject: [PATCH 039/141] missing imports/@EJB --- src/main/java/edu/harvard/iq/dataverse/FilePage.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/FilePage.java b/src/main/java/edu/harvard/iq/dataverse/FilePage.java index b6706acd4ff..4e5843964e7 100644 --- a/src/main/java/edu/harvard/iq/dataverse/FilePage.java +++ b/src/main/java/edu/harvard/iq/dataverse/FilePage.java @@ -21,6 +21,7 @@ import edu.harvard.iq.dataverse.engine.command.impl.CreateNewDatasetCommand; import edu.harvard.iq.dataverse.engine.command.impl.PersistProvFreeFormCommand; import edu.harvard.iq.dataverse.engine.command.impl.RestrictFileCommand; +import edu.harvard.iq.dataverse.engine.command.impl.UningestFileCommand; import edu.harvard.iq.dataverse.engine.command.impl.UpdateDatasetVersionCommand; import edu.harvard.iq.dataverse.export.ExportService; import io.gdcc.spi.export.ExportException; @@ -28,6 +29,8 @@ import edu.harvard.iq.dataverse.externaltools.ExternalTool; import edu.harvard.iq.dataverse.externaltools.ExternalToolHandler; import edu.harvard.iq.dataverse.externaltools.ExternalToolServiceBean; +import edu.harvard.iq.dataverse.ingest.IngestRequest; +import edu.harvard.iq.dataverse.ingest.IngestServiceBean; import edu.harvard.iq.dataverse.makedatacount.MakeDataCountLoggingServiceBean; import edu.harvard.iq.dataverse.makedatacount.MakeDataCountLoggingServiceBean.MakeDataCountEntry; import edu.harvard.iq.dataverse.privateurl.PrivateUrlServiceBean; @@ -35,6 +38,8 @@ import edu.harvard.iq.dataverse.util.BundleUtil; import edu.harvard.iq.dataverse.util.FileUtil; import edu.harvard.iq.dataverse.util.JsfHelper; +import edu.harvard.iq.dataverse.util.StringUtil; + import static edu.harvard.iq.dataverse.util.JsfHelper.JH; import edu.harvard.iq.dataverse.util.SystemConfig; @@ -45,6 +50,7 @@ import java.util.Comparator; import java.util.List; import java.util.Set; +import java.util.logging.Level; import java.util.logging.Logger; import jakarta.ejb.EJB; import jakarta.ejb.EJBException; @@ -112,10 +118,10 @@ public class FilePage implements java.io.Serializable { GuestbookResponseServiceBean guestbookResponseService; @EJB AuthenticationServiceBean authService; - @EJB DatasetServiceBean datasetService; - + @EJB + IngestServiceBean ingestService; @EJB SystemConfig systemConfig; @@ -209,7 +215,7 @@ public String init() { // If this DatasetVersion is unpublished and permission is doesn't have permissions: // > Go to the Login page // - // Check permisisons + // Check permissions Boolean authorized = (fileMetadata.getDatasetVersion().isReleased()) || (!fileMetadata.getDatasetVersion().isReleased() && this.canViewUnpublishedDataset()); From 15ae19e36250e3a467452cfd41287df1cfe8bd3a Mon Sep 17 00:00:00 2001 From: qqmyers Date: Tue, 13 Feb 2024 17:00:28 -0500 Subject: [PATCH 040/141] Change command to publish perm --- .../dataverse/engine/command/impl/UningestFileCommand.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UningestFileCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UningestFileCommand.java index 3e85630dd59..e9791809cb2 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UningestFileCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UningestFileCommand.java @@ -33,7 +33,7 @@ * @author skraffmi * @author Leonid Andreev */ -@RequiredPermissions({}) +@RequiredPermissions(Permission.PublishDataset) public class UningestFileCommand extends AbstractVoidCommand { private static final Logger logger = Logger.getLogger(UningestFileCommand.class.getCanonicalName()); @@ -48,8 +48,8 @@ public UningestFileCommand(DataverseRequest aRequest, DataFile uningest) { protected void executeImpl(CommandContext ctxt) throws CommandException { // first check if user is a superuser - if ( (!(getUser() instanceof AuthenticatedUser) || !getUser().isSuperuser() ) ) { - throw new PermissionException("Uningest File can only be called by Superusers.", + if (!(getUser() instanceof AuthenticatedUser)) { + throw new PermissionException("Uningest File can only be called by User with the PublishDataset permission.", this, Collections.singleton(Permission.EditDataset), uningest); } From 262fb267a2025872d8f537e937ad31dc0a25a156 Mon Sep 17 00:00:00 2001 From: qqmyers Date: Tue, 13 Feb 2024 17:49:09 -0500 Subject: [PATCH 041/141] superuser only in command, add docs --- .../user/tabulardataingest/ingestprocess.rst | 20 ++++++++++++++++++- .../command/impl/UningestFileCommand.java | 10 +++++----- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/doc/sphinx-guides/source/user/tabulardataingest/ingestprocess.rst b/doc/sphinx-guides/source/user/tabulardataingest/ingestprocess.rst index 33ae9b555e6..9e82ff12b9b 100644 --- a/doc/sphinx-guides/source/user/tabulardataingest/ingestprocess.rst +++ b/doc/sphinx-guides/source/user/tabulardataingest/ingestprocess.rst @@ -32,7 +32,7 @@ format. (more info below) Tabular Data and Metadata -========================== +========================= Data vs. Metadata ----------------- @@ -56,3 +56,21 @@ the Dataverse Software was originally based on the `DDI Codebook `_ format. You can see an example of DDI output under the :ref:`data-variable-metadata-access` section of the :doc:`/api/dataaccess` section of the API Guide. + +Uningest and Reingest +===================== + +Ingest will only work for files whose content can be interpreted as a table. +Multi-sheets spreadsheets and CSV files with different number of entries per row are two examples where ingest will fail. +This is non-fatal. The Dataverse software will not produce a .tab version of the file and will show a warning to users +who can see the draft version of the dataset containing the file that will indicate why ingest failed. When the file is published as +part of the dataset, there will be no indication that ingest was attempted and failed. + +If the warning message is a concern, the Dataverse software includes both an API call (see the Files section of the :doc:`/api/native-api` guide) +and an Edit/Uningest menu option displayed on the file page, that allow a file to be Uningested. These are only available to superusers. +Uningest will remove the warning. Uningest can also be done for a file that was successfully ingested. +This will remove the .tab version of the file that was generated. + +If a file is a tabular format but was never ingested, .e.g. due to the ingest file size limit being lower in the past, or if ingest had failed, +e.g. in a prior Dataverse version, an reingest API (see the Files section of the :doc:`/api/native-api` guide) and a file page Edit/Reingest option +in the user interface allow ingest to be tried again. As with Uningest, this fucntionality is only available to superusers. diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UningestFileCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UningestFileCommand.java index e9791809cb2..ba04c4d7931 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UningestFileCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UningestFileCommand.java @@ -33,7 +33,7 @@ * @author skraffmi * @author Leonid Andreev */ -@RequiredPermissions(Permission.PublishDataset) +@RequiredPermissions({}) public class UningestFileCommand extends AbstractVoidCommand { private static final Logger logger = Logger.getLogger(UningestFileCommand.class.getCanonicalName()); @@ -47,10 +47,10 @@ public UningestFileCommand(DataverseRequest aRequest, DataFile uningest) { @Override protected void executeImpl(CommandContext ctxt) throws CommandException { - // first check if user is a superuser - if (!(getUser() instanceof AuthenticatedUser)) { - throw new PermissionException("Uningest File can only be called by User with the PublishDataset permission.", - this, Collections.singleton(Permission.EditDataset), uningest); + // first check if user is a superuser + if ((!(getUser() instanceof AuthenticatedUser) || !getUser().isSuperuser())) { + throw new PermissionException("Uningest File can only be called by Superusers.", this, + Collections.singleton(Permission.EditDataset), uningest); } // is this actually a tabular data file? From 130cfba92e9f3ced2e9497ba74b2f17b20bfec77 Mon Sep 17 00:00:00 2001 From: qqmyers Date: Tue, 13 Feb 2024 17:51:37 -0500 Subject: [PATCH 042/141] release note --- doc/release-notes/10318-uningest-and-reingest.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 doc/release-notes/10318-uningest-and-reingest.md diff --git a/doc/release-notes/10318-uningest-and-reingest.md b/doc/release-notes/10318-uningest-and-reingest.md new file mode 100644 index 00000000000..7465f934330 --- /dev/null +++ b/doc/release-notes/10318-uningest-and-reingest.md @@ -0,0 +1,2 @@ +New Uningest/Reingest options are available in the File Page Edit menu for superusers, allowing ingest errors to be cleared and for +ingest to be retried (e.g. after a Dataverse version update or if ingest size limits are changed). From 67d004fb5719f94389610227e070494f0d652ecd Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Tue, 13 Feb 2024 22:16:33 -0500 Subject: [PATCH 043/141] add redeploy tab for Netbeans #9590 --- .../source/container/dev-usage.rst | 58 ++++++++++++++++-- .../source/container/img/netbeans-compile.png | Bin 0 -> 99396 bytes .../source/container/img/netbeans-run.png | Bin 0 -> 124521 bytes .../container/img/netbeans-servers-common.png | Bin 0 -> 89185 bytes .../container/img/netbeans-servers-java.png | Bin 0 -> 68487 bytes .../source/developers/classic-dev-env.rst | 2 + 6 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 doc/sphinx-guides/source/container/img/netbeans-compile.png create mode 100644 doc/sphinx-guides/source/container/img/netbeans-run.png create mode 100644 doc/sphinx-guides/source/container/img/netbeans-servers-common.png create mode 100644 doc/sphinx-guides/source/container/img/netbeans-servers-java.png diff --git a/doc/sphinx-guides/source/container/dev-usage.rst b/doc/sphinx-guides/source/container/dev-usage.rst index 9fc9058eada..85b1b3e5f05 100644 --- a/doc/sphinx-guides/source/container/dev-usage.rst +++ b/doc/sphinx-guides/source/container/dev-usage.rst @@ -154,24 +154,29 @@ IDE-triggered re-deployments You have at least two options: -1. Use plugins for different IDEs by Payara to ease the burden of redeploying an application during development to a running Payara application server. +1. Use builtin features of IDEs or plugins for different IDEs by Payara to ease the burden of redeploying an application during development to a running Payara application server. Their guides contain `documentation on Payara IDE plugins `_. 2. Use a paid product like `JRebel `_. The main difference between the first and the second option is support for hot deploys of non-class files plus limitations in what the JVM HotswapAgent can do for you. Find more `details in a blog article by JRebel `_. -When opting for Payara tools, please follow these steps: +When opting for builtin features or Payara tools, please follow these steps: 1. | Download the Payara appserver to your machine, unzip and note the location for later. - | - See this guide for which version, in doubt lookup using + | - See :ref:`payara` for which version or run the following command | ``mvn help:evaluate -Dexpression=payara.version -q -DforceStdout`` - | - Can be downloaded from `Maven Central `_. + | - To download, see :ref:`payara` or try `Maven Central `_. 2. Install Payara tools plugin in your IDE: .. tabs:: + .. group-tab:: Netbeans + + This step is not necessary for Netbeans. The feature is builtin. + .. group-tab:: IntelliJ + **Requires IntelliJ Ultimate!** (Note that `free educational licenses `_ are available) @@ -180,6 +185,28 @@ When opting for Payara tools, please follow these steps: 3. Configure a connection to the application server: .. tabs:: + .. group-tab:: Netbeans + + Unzip Payara to ``/usr/local/payara6`` as explained in :ref:`install-payara-dev`. + + Launch Netbeans and click "Tools" and then "Servers". Click "Add Server" and select "Payara Server" and set the installation location to ``/usr/local/payara6``. Use the settings in the screenshot below. Most of the defaults are fine. + + Under "Common", the password should be "admin". Make sure "Enable Hot Deploy" is checked. + + .. image:: img/netbeans-servers-common.png + + Under "Java", change the debug port to 9009. + + .. image:: img/netbeans-servers-java.png + + Open the project properties (under "File"), navigate to "Compile" and make sure "Compile on Save" is checked. + + .. image:: img/netbeans-compile.png + + Under "Run", select "Payara Server" under "Server" and make sure "Deploy on Save" is checked. + + .. image:: img/netbeans-run.png + .. group-tab:: IntelliJ Create a new running configuration with a "Remote Payara". (Open dialog by clicking "Run", then "Edit Configurations") @@ -212,13 +239,32 @@ When opting for Payara tools, please follow these steps: .. image:: img/intellij-payara-config-server-behaviour.png 4. | Start all the containers. Follow the cheat sheet above, but take care to skip application deployment: - | - When using the Maven commands, append ``-Dapp.deploy.skip``. - | - When using Docker Compose, prepend the command with ``SKIP_DEPLOY=1``. + | - When using the Maven commands, append ``-Dapp.deploy.skip``. For example: + | ``mvn -Pct docker:run -Dapp.deploy.skip`` + | - When using Docker Compose, prepend the command with ``SKIP_DEPLOY=1``. For example: + | ``SKIP_DEPLOY=1 docker compose -f docker-compose-dev.yml up`` | - Note: the Admin Console can be reached at http://localhost:4848 or https://localhost:4949 5. To deploy the application to the running server, use the configured tools to deploy. Using the "Run" configuration only deploys and enables redeploys, while running "Debug" enables hot swapping of classes via JDWP. .. tabs:: + .. group-tab:: Netbeans + + Click "Debug" then "Debug Project". After some time, Dataverse will be deployed. + + Try making a code change, perhaps to ``Info.java``. + + Click "Debug" and then "Apply Code Changes". If the change was correctly applied, you should see output similar to this: + + .. code-block:: + + Classes to reload: + edu.harvard.iq.dataverse.api.Info + + Code updated + + Check to make sure the change is live by visiting, for example, http://localhost:8080/api/info/version + .. group-tab:: IntelliJ Choose "Run" or "Debug" in the toolbar. diff --git a/doc/sphinx-guides/source/container/img/netbeans-compile.png b/doc/sphinx-guides/source/container/img/netbeans-compile.png new file mode 100644 index 0000000000000000000000000000000000000000..e429695ccb01c0170ee612ef1e701aebb68029c7 GIT binary patch literal 99396 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 OK%OVP-KZym)BX!yWK!4w literal 0 HcmV?d00001 diff --git a/doc/sphinx-guides/source/container/img/netbeans-run.png b/doc/sphinx-guides/source/container/img/netbeans-run.png new file mode 100644 index 0000000000000000000000000000000000000000..00f8af23cc5a0292622ab9fb26d950f87becb3c6 GIT binary patch literal 124521 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%0D)CeV?U@;wm}A&9i(KwsMMG+v@8#o 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%0D)U3i?}Pw{|xb?=5# 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
    CB5t0Wn1;Ni>X3?ql)_CKU)bApArcg`9&>`yuXG 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
  • From 3d7f72a532841a1ce0a9635158b04a60ea080bf1 Mon Sep 17 00:00:00 2001 From: qqmyers Date: Wed, 14 Feb 2024 16:21:39 -0500 Subject: [PATCH 061/141] add uningest for a problem logic in api --- .../edu/harvard/iq/dataverse/api/Files.java | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Files.java b/src/main/java/edu/harvard/iq/dataverse/api/Files.java index 5d400ee1438..1f0e0801c68 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Files.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Files.java @@ -51,6 +51,7 @@ import edu.harvard.iq.dataverse.util.SystemConfig; import edu.harvard.iq.dataverse.util.URLTokenUtil; +import static edu.harvard.iq.dataverse.util.JsfHelper.JH; import static edu.harvard.iq.dataverse.util.json.JsonPrinter.json; import edu.harvard.iq.dataverse.util.json.JsonUtil; import edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder; @@ -65,6 +66,7 @@ import java.util.logging.Logger; import jakarta.ejb.EJB; import jakarta.ejb.EJBException; +import jakarta.faces.application.FacesMessage; import jakarta.inject.Inject; import jakarta.json.Json; import jakarta.json.JsonArray; @@ -637,7 +639,27 @@ public Response uningestDatafile(@Context ContainerRequestContext crc, @PathPara if (dataFile == null) { return error(Response.Status.NOT_FOUND, "File not found for given id."); } - + if (!dataFile.isTabularData()) { + // Ingest never succeeded, either there was a failure or this is not a tabular + // data file + // We allow anyone who can publish to uningest in order to clear a problem + if (dataFile.isIngestProblem()) { + try { + AuthenticatedUser au = getRequestAuthenticatedUserOrDie(crc); + if (!(permissionSvc.permissionsFor(au, dataFile).contains(Permission.PublishDataset))) { + return forbidden( + "Uningesting to remove an ingest problem can only be done by those who can publish the dataset"); + } + } catch (WrappedResponse wr) { + return wr.getResponse(); + } + dataFile.setIngestDone(); + dataFile.setIngestReport(null); + } else { + return error(Response.Status.BAD_REQUEST, + BundleUtil.getStringFromBundle("file.ingest.cantUningestFileWarning")); + } + } if (!dataFile.isTabularData()) { return error(Response.Status.BAD_REQUEST, "Cannot uningest non-tabular file."); } From 7de7f43c99d7f79a7a4a255e75bfa08506361a41 Mon Sep 17 00:00:00 2001 From: qqmyers Date: Wed, 14 Feb 2024 16:21:56 -0500 Subject: [PATCH 062/141] update docs --- .../source/user/tabulardataingest/ingestprocess.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/sphinx-guides/source/user/tabulardataingest/ingestprocess.rst b/doc/sphinx-guides/source/user/tabulardataingest/ingestprocess.rst index 4dce441de4a..418eb2206c8 100644 --- a/doc/sphinx-guides/source/user/tabulardataingest/ingestprocess.rst +++ b/doc/sphinx-guides/source/user/tabulardataingest/ingestprocess.rst @@ -67,9 +67,10 @@ who can see the draft version of the dataset containing the file that will indic part of the dataset, there will be no indication that ingest was attempted and failed. If the warning message is a concern, the Dataverse software includes both an API call (see :ref:`file-uningest` in the :doc:`/api/native-api` guide) -and an Edit/Uningest menu option displayed on the file page, that allow a file to be uningested. These are only available to superusers. -Uningest will remove the warning. Uningest can also be done for a file that was successfully ingested. -This will remove the .tab version of the file that was generated. +and an Edit/Uningest menu option displayed on the file page, that allow a file to be uningested by anone who can publish the dataset. + +Uningest will remove the warning. Uningest can also be done for a file that was successfully ingested. This is only available to superusers. +This will remove the variable-level metadata and the .tab version of the file that was generated. If a file is a tabular format but was never ingested, .e.g. due to the ingest file size limit being lower in the past, or if ingest had failed, e.g. in a prior Dataverse version, an reingest API (see :ref:`file-reingest` in the :doc:`/api/native-api` guide) and a file page Edit/Reingest option From 51fe60c095f52e26a6f1be7587c5323de7107993 Mon Sep 17 00:00:00 2001 From: qqmyers Date: Wed, 14 Feb 2024 16:26:50 -0500 Subject: [PATCH 063/141] fix logic --- .../edu/harvard/iq/dataverse/api/Files.java | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Files.java b/src/main/java/edu/harvard/iq/dataverse/api/Files.java index 1f0e0801c68..d48ae3247b5 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Files.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Files.java @@ -655,27 +655,24 @@ public Response uningestDatafile(@Context ContainerRequestContext crc, @PathPara } dataFile.setIngestDone(); dataFile.setIngestReport(null); + return ok("Datafile " + dataFile.getId() + " uningested."); } else { return error(Response.Status.BAD_REQUEST, - BundleUtil.getStringFromBundle("file.ingest.cantUningestFileWarning")); + BundleUtil.getStringFromBundle("Cannot uningest non-tabular file.")); + } + } else { + try { + DataverseRequest req = createDataverseRequest(getRequestUser(crc)); + execCommand(new UningestFileCommand(req, dataFile)); + Long dataFileId = dataFile.getId(); + dataFile = fileService.find(dataFileId); + Dataset theDataset = dataFile.getOwner(); + exportDatasetMetadata(settingsService, theDataset); + return ok("Datafile " + dataFileId + " uningested."); + } catch (WrappedResponse wr) { + return wr.getResponse(); } } - if (!dataFile.isTabularData()) { - return error(Response.Status.BAD_REQUEST, "Cannot uningest non-tabular file."); - } - - try { - DataverseRequest req = createDataverseRequest(getRequestUser(crc)); - execCommand(new UningestFileCommand(req, dataFile)); - Long dataFileId = dataFile.getId(); - dataFile = fileService.find(dataFileId); - Dataset theDataset = dataFile.getOwner(); - exportDatasetMetadata(settingsService, theDataset); - return ok("Datafile " + dataFileId + " uningested."); - } catch (WrappedResponse wr) { - return wr.getResponse(); - } - } // reingest attempts to queue an *existing* DataFile From 31d7cbcea224d253325f9baa3b4f4f1d8e802882 Mon Sep 17 00:00:00 2001 From: qqmyers Date: Wed, 14 Feb 2024 17:38:19 -0500 Subject: [PATCH 064/141] typo/merge issues --- src/main/webapp/file-edit-button-fragment.xhtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/webapp/file-edit-button-fragment.xhtml b/src/main/webapp/file-edit-button-fragment.xhtml index fd455521c98..30c3f6e7938 100644 --- a/src/main/webapp/file-edit-button-fragment.xhtml +++ b/src/main/webapp/file-edit-button-fragment.xhtml @@ -79,9 +79,9 @@ - +
  • - +
  • From 057d2c3c5d9a00b38354416dbaa70ee6637bbe43 Mon Sep 17 00:00:00 2001 From: qqmyers Date: Wed, 14 Feb 2024 17:49:28 -0500 Subject: [PATCH 065/141] missing save --- src/main/java/edu/harvard/iq/dataverse/api/Files.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Files.java b/src/main/java/edu/harvard/iq/dataverse/api/Files.java index d48ae3247b5..f735ecfdec8 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Files.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Files.java @@ -655,6 +655,7 @@ public Response uningestDatafile(@Context ContainerRequestContext crc, @PathPara } dataFile.setIngestDone(); dataFile.setIngestReport(null); + fileService.save(dataFile); return ok("Datafile " + dataFile.getId() + " uningested."); } else { return error(Response.Status.BAD_REQUEST, From beb5bf6847469ab9b41b3128837d5c9d4daddf24 Mon Sep 17 00:00:00 2001 From: qqmyers Date: Wed, 14 Feb 2024 17:55:59 -0500 Subject: [PATCH 066/141] tweak api doc --- doc/sphinx-guides/source/api/native-api.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index 8cfa5deb96c..1b04d7c9e12 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -2859,7 +2859,10 @@ The fully expanded example above (without environment variables) looks like this Uningest a File ~~~~~~~~~~~~~~~ -Reverse the tabular data ingest process performed on a file where ``ID`` is the database id or ``PERSISTENT_ID`` is the persistent id (DOI or Handle) of the file to process. Note that this requires "superuser" credentials. +Reverse the tabular data ingest process performed on a file where ``ID`` is the database id or ``PERSISTENT_ID`` is the persistent id (DOI or Handle) of the file to process. + +Note that this requires "superuser" credentials to undo a successful ingest and remove the variable-level metadata and .tab version of the file. +It can also be used by a user who can publish the dataset to clear the error from an unsuccessful ingest. A curl example using an ``ID``: From 00d418912d88e202a390a6c2d70d80efb0ec5bfc Mon Sep 17 00:00:00 2001 From: qqmyers Date: Wed, 14 Feb 2024 18:02:53 -0500 Subject: [PATCH 067/141] changelog, release note tweaks --- doc/release-notes/10318-uningest-and-reingest.md | 5 +++-- doc/sphinx-guides/source/api/changelog.rst | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/release-notes/10318-uningest-and-reingest.md b/doc/release-notes/10318-uningest-and-reingest.md index 7465f934330..9f6f81b4818 100644 --- a/doc/release-notes/10318-uningest-and-reingest.md +++ b/doc/release-notes/10318-uningest-and-reingest.md @@ -1,2 +1,3 @@ -New Uningest/Reingest options are available in the File Page Edit menu for superusers, allowing ingest errors to be cleared and for -ingest to be retried (e.g. after a Dataverse version update or if ingest size limits are changed). +New Uningest/Reingest options are available in the File Page Edit menu, allowing ingest errors to be cleared (by users who can published the associated dataset) +and (by suerpsuers) for a successful ingest to be undone or retried (e.g. after a Dataverse version update or if ingest size limits are changed). +The /api/files//uningest api also now allows users who can publish the dataset to undo an ingest failure. diff --git a/doc/sphinx-guides/source/api/changelog.rst b/doc/sphinx-guides/source/api/changelog.rst index d272086fa2e..99414550c4b 100644 --- a/doc/sphinx-guides/source/api/changelog.rst +++ b/doc/sphinx-guides/source/api/changelog.rst @@ -12,6 +12,7 @@ v6.2 - **/api/datasets/{id}/versions/{versionId}**: The includeFiles parameter has been renamed to excludeFiles. The default behavior remains the same, which is to include files. However, when excludeFiles is set to true, the files will be excluded. A bug that caused the API to only return a deaccessioned dataset if the user had edit privileges has been fixed. - **/api/datasets/{id}/versions**: The includeFiles parameter has been renamed to excludeFiles. The default behavior remains the same, which is to include files. However, when excludeFiles is set to true, the files will be excluded. +- **/api/files/$ID/uningest**: Can now be used by users with the ability to publish the dataset to undo a failed ingest. (Removing a successful ingest still requires being superuser) v6.1 ---- From 87b5a38bd5511a169f1ccae9d3bb966f2e3cb6b6 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Thu, 15 Feb 2024 17:01:59 -0500 Subject: [PATCH 068/141] typo #10318 --- .../source/user/tabulardataingest/ingestprocess.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/sphinx-guides/source/user/tabulardataingest/ingestprocess.rst b/doc/sphinx-guides/source/user/tabulardataingest/ingestprocess.rst index 418eb2206c8..1e481a54da6 100644 --- a/doc/sphinx-guides/source/user/tabulardataingest/ingestprocess.rst +++ b/doc/sphinx-guides/source/user/tabulardataingest/ingestprocess.rst @@ -67,7 +67,7 @@ who can see the draft version of the dataset containing the file that will indic part of the dataset, there will be no indication that ingest was attempted and failed. If the warning message is a concern, the Dataverse software includes both an API call (see :ref:`file-uningest` in the :doc:`/api/native-api` guide) -and an Edit/Uningest menu option displayed on the file page, that allow a file to be uningested by anone who can publish the dataset. +and an Edit/Uningest menu option displayed on the file page, that allow a file to be uningested by anyone who can publish the dataset. Uningest will remove the warning. Uningest can also be done for a file that was successfully ingested. This is only available to superusers. This will remove the variable-level metadata and the .tab version of the file that was generated. From 95ce492f221a5980729c6b26528feb1ac681c56b Mon Sep 17 00:00:00 2001 From: GPortas Date: Fri, 16 Feb 2024 10:38:56 +0000 Subject: [PATCH 069/141] Changed: includeDeaccessioned optional param in getLatestPublishedFileMetadata, and existing usages changed --- .../edu/harvard/iq/dataverse/DataFile.java | 8 +++-- .../edu/harvard/iq/dataverse/api/EditDDI.java | 2 +- .../edu/harvard/iq/dataverse/api/Files.java | 2 +- ...stractGetPublishedFileMetadataCommand.java | 31 +++++++++++++++++++ ...etDraftFileMetadataIfAvailableCommand.java | 4 +-- ...etLatestAccessibleFileMetadataCommand.java | 4 +-- ...GetLatestPublishedFileMetadataCommand.java | 19 +++++------- ...edFileMetadataByDatasetVersionCommand.java | 22 +++---------- .../MakeDataCountLoggingServiceBean.java | 2 +- 9 files changed, 56 insertions(+), 38 deletions(-) create mode 100644 src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractGetPublishedFileMetadataCommand.java diff --git a/src/main/java/edu/harvard/iq/dataverse/DataFile.java b/src/main/java/edu/harvard/iq/dataverse/DataFile.java index 818cade1eef..de13a83e204 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DataFile.java +++ b/src/main/java/edu/harvard/iq/dataverse/DataFile.java @@ -567,9 +567,13 @@ public FileMetadata getLatestFileMetadata() { return resultFileMetadata; } - public FileMetadata getLatestPublishedFileMetadata() throws UnsupportedOperationException { + public FileMetadata getLatestPublishedFileMetadata(boolean includeDeaccessioned) throws UnsupportedOperationException { FileMetadata resultFileMetadata = fileMetadatas.stream() - .filter(metadata -> !metadata.getDatasetVersion().getVersionState().equals(VersionState.DRAFT)) + .filter(metadata -> { + VersionState versionState = metadata.getDatasetVersion().getVersionState(); + return (!versionState.equals(VersionState.DRAFT) && + !(versionState.equals(VersionState.DEACCESSIONED) && !includeDeaccessioned)); + }) .reduce(null, this::getTheNewerFileMetadata); if (resultFileMetadata == null) { diff --git a/src/main/java/edu/harvard/iq/dataverse/api/EditDDI.java b/src/main/java/edu/harvard/iq/dataverse/api/EditDDI.java index 1b74ab5479e..d6aee0b7bfc 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/EditDDI.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/EditDDI.java @@ -124,7 +124,7 @@ public Response edit(@Context ContainerRequestContext crc, InputStream body, @Pa if (!latestVersion.isWorkingCopy()) { //for new draft version - FileMetadata latestFml = dataFile.getLatestPublishedFileMetadata(); + FileMetadata latestFml = dataFile.getLatestPublishedFileMetadata(true); boolean groupUpdate = newGroups(varGroupMap, latestFml); boolean varUpdate = varUpdates(mapVarToVarMet, latestFml, neededToUpdateVM, true); diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Files.java b/src/main/java/edu/harvard/iq/dataverse/api/Files.java index 55d65bae96b..b7494c5daec 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Files.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Files.java @@ -580,7 +580,7 @@ public Response getFileMetadata(@Context ContainerRequestContext crc, @PathParam return error(BAD_REQUEST, BundleUtil.getStringFromBundle("files.api.no.draft")); } } else { - fm = df.getLatestPublishedFileMetadata(); + fm = df.getLatestPublishedFileMetadata(false); MakeDataCountLoggingServiceBean.MakeDataCountEntry entry = new MakeDataCountLoggingServiceBean.MakeDataCountEntry(uriInfo, headers, dvRequestService, df); mdcLogService.logEntry(entry); } diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractGetPublishedFileMetadataCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractGetPublishedFileMetadataCommand.java new file mode 100644 index 00000000000..82d0ac3491b --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractGetPublishedFileMetadataCommand.java @@ -0,0 +1,31 @@ +package edu.harvard.iq.dataverse.engine.command.impl; + +import edu.harvard.iq.dataverse.DataFile; +import edu.harvard.iq.dataverse.Dataset; +import edu.harvard.iq.dataverse.DatasetVersion; +import edu.harvard.iq.dataverse.FileMetadata; +import edu.harvard.iq.dataverse.authorization.Permission; +import edu.harvard.iq.dataverse.engine.command.AbstractCommand; +import edu.harvard.iq.dataverse.engine.command.CommandContext; +import edu.harvard.iq.dataverse.engine.command.DataverseRequest; +import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; + +@RequiredPermissions({}) +abstract class AbstractGetPublishedFileMetadataCommand extends AbstractCommand { + protected final DataFile dataFile; + protected final boolean includeDeaccessioned; + + public AbstractGetPublishedFileMetadataCommand(DataverseRequest request, DataFile dataFile, boolean includeDeaccessioned) { + super(request, dataFile); + this.dataFile = dataFile; + this.includeDeaccessioned = includeDeaccessioned; + } + + protected boolean isDatasetVersionAccessible(DatasetVersion datasetVersion, Dataset ownerDataset, CommandContext ctxt) { + return datasetVersion.isReleased() || isDatasetVersionDeaccessionedAndAccessible(datasetVersion, ownerDataset, ctxt); + } + + private boolean isDatasetVersionDeaccessionedAndAccessible(DatasetVersion datasetVersion, Dataset ownerDataset, CommandContext ctxt) { + return includeDeaccessioned && datasetVersion.isDeaccessioned() && ctxt.permissions().requestOn(getRequest(), ownerDataset).has(Permission.EditDataset); + } +} diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDraftFileMetadataIfAvailableCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDraftFileMetadataIfAvailableCommand.java index e0f8ca1fcf8..8ed058d79f8 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDraftFileMetadataIfAvailableCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDraftFileMetadataIfAvailableCommand.java @@ -16,8 +16,8 @@ public class GetDraftFileMetadataIfAvailableCommand extends AbstractCommand { private final DataFile dataFile; - public GetDraftFileMetadataIfAvailableCommand(DataverseRequest aRequest, DataFile dataFile) { - super(aRequest, dataFile); + public GetDraftFileMetadataIfAvailableCommand(DataverseRequest request, DataFile dataFile) { + super(request, dataFile); this.dataFile = dataFile; } diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java index fa80b75c593..98913d63471 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java @@ -14,8 +14,8 @@ public class GetLatestAccessibleFileMetadataCommand extends AbstractCommand { - private final DataFile dataFile; - private final boolean includeDeaccessioned; +public class GetLatestPublishedFileMetadataCommand extends AbstractGetPublishedFileMetadataCommand { - public GetLatestPublishedFileMetadataCommand(DataverseRequest aRequest, DataFile dataFile, boolean includeDeaccessioned) { - super(aRequest, dataFile); - this.dataFile = dataFile; - this.includeDeaccessioned = includeDeaccessioned; + public GetLatestPublishedFileMetadataCommand(DataverseRequest request, DataFile dataFile, boolean includeDeaccessioned) { + super(request, dataFile, includeDeaccessioned); } @Override public FileMetadata execute(CommandContext ctxt) throws CommandException { try { - return dataFile.getLatestPublishedFileMetadata(); + FileMetadata fileMetadata = dataFile.getLatestPublishedFileMetadata(includeDeaccessioned); + if (isDatasetVersionAccessible(fileMetadata.getDatasetVersion(), dataFile.getOwner(), ctxt)) { + return fileMetadata; + } + return null; } catch (UnsupportedOperationException e) { return null; } diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetSpecificPublishedFileMetadataByDatasetVersionCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetSpecificPublishedFileMetadataByDatasetVersionCommand.java index 82350d3bd95..deffbfb57ee 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetSpecificPublishedFileMetadataByDatasetVersionCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetSpecificPublishedFileMetadataByDatasetVersionCommand.java @@ -1,29 +1,20 @@ package edu.harvard.iq.dataverse.engine.command.impl; import edu.harvard.iq.dataverse.DataFile; -import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.DatasetVersion; import edu.harvard.iq.dataverse.FileMetadata; -import edu.harvard.iq.dataverse.authorization.Permission; -import edu.harvard.iq.dataverse.engine.command.AbstractCommand; import edu.harvard.iq.dataverse.engine.command.CommandContext; import edu.harvard.iq.dataverse.engine.command.DataverseRequest; -import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; -@RequiredPermissions({}) -public class GetSpecificPublishedFileMetadataByDatasetVersionCommand extends AbstractCommand { +public class GetSpecificPublishedFileMetadataByDatasetVersionCommand extends AbstractGetPublishedFileMetadataCommand { private final long majorVersion; private final long minorVersion; - private final DataFile dataFile; - private final boolean includeDeaccessioned; - public GetSpecificPublishedFileMetadataByDatasetVersionCommand(DataverseRequest aRequest, DataFile dataFile, long majorVersion, long minorVersion, boolean includeDeaccessioned) { - super(aRequest, dataFile); - this.dataFile = dataFile; + public GetSpecificPublishedFileMetadataByDatasetVersionCommand(DataverseRequest request, DataFile dataFile, long majorVersion, long minorVersion, boolean includeDeaccessioned) { + super(request, dataFile, includeDeaccessioned); this.majorVersion = majorVersion; this.minorVersion = minorVersion; - this.includeDeaccessioned = includeDeaccessioned; } @Override @@ -36,13 +27,8 @@ public FileMetadata execute(CommandContext ctxt) throws CommandException { private boolean isRequestedVersionFileMetadata(FileMetadata fileMetadata, CommandContext ctxt) { DatasetVersion datasetVersion = fileMetadata.getDatasetVersion(); - Dataset ownerDataset = dataFile.getOwner(); - return (datasetVersion.isReleased() || isDatasetVersionDeaccessionedAndAccessible(datasetVersion, ownerDataset, ctxt)) + return isDatasetVersionAccessible(datasetVersion, dataFile.getOwner(), ctxt) && datasetVersion.getVersionNumber().equals(majorVersion) && datasetVersion.getMinorVersionNumber().equals(minorVersion); } - - private boolean isDatasetVersionDeaccessionedAndAccessible(DatasetVersion datasetVersion, Dataset ownerDataset, CommandContext ctxt) { - return includeDeaccessioned && datasetVersion.isDeaccessioned() && ctxt.permissions().requestOn(getRequest(), ownerDataset).has(Permission.EditDataset); - } } diff --git a/src/main/java/edu/harvard/iq/dataverse/makedatacount/MakeDataCountLoggingServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/makedatacount/MakeDataCountLoggingServiceBean.java index 5edf2fde0c3..a3f09d190ca 100644 --- a/src/main/java/edu/harvard/iq/dataverse/makedatacount/MakeDataCountLoggingServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/makedatacount/MakeDataCountLoggingServiceBean.java @@ -133,7 +133,7 @@ public MakeDataCountEntry(FacesContext fc, DataverseRequestServiceBean dvRequest //Exception thrown if no published metadata exists for DataFile //This is passed a DataFile to log the file downloaded. uriInfo and headers are passed in lieu of FacesContext public MakeDataCountEntry(UriInfo uriInfo, HttpHeaders headers, DataverseRequestServiceBean dvRequestService, DataFile df) throws UnsupportedOperationException{ - this(null, dvRequestService, df.getLatestPublishedFileMetadata().getDatasetVersion()); + this(null, dvRequestService, df.getLatestPublishedFileMetadata(false).getDatasetVersion()); if(uriInfo != null) { setRequestUrl(uriInfo.getRequestUri().toString()); From 61fa5719e73c7d3605268cca0fe4670cac9f4439 Mon Sep 17 00:00:00 2001 From: GPortas Date: Mon, 19 Feb 2024 01:00:36 +0000 Subject: [PATCH 070/141] Fixed: includeDeaccessioned wrong behavior in getFileInfo --- .../edu/harvard/iq/dataverse/DataFile.java | 12 +-- .../edu/harvard/iq/dataverse/api/EditDDI.java | 2 +- .../edu/harvard/iq/dataverse/api/Files.java | 2 +- ...GetLatestPublishedFileMetadataCommand.java | 16 ++-- .../MakeDataCountLoggingServiceBean.java | 2 +- .../edu/harvard/iq/dataverse/api/FilesIT.java | 84 +++++++++++++++---- .../edu/harvard/iq/dataverse/api/UtilIT.java | 5 ++ 7 files changed, 89 insertions(+), 34 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/DataFile.java b/src/main/java/edu/harvard/iq/dataverse/DataFile.java index de13a83e204..25ec40de845 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DataFile.java +++ b/src/main/java/edu/harvard/iq/dataverse/DataFile.java @@ -567,14 +567,10 @@ public FileMetadata getLatestFileMetadata() { return resultFileMetadata; } - public FileMetadata getLatestPublishedFileMetadata(boolean includeDeaccessioned) throws UnsupportedOperationException { + public FileMetadata getLatestPublishedFileMetadata() throws UnsupportedOperationException { FileMetadata resultFileMetadata = fileMetadatas.stream() - .filter(metadata -> { - VersionState versionState = metadata.getDatasetVersion().getVersionState(); - return (!versionState.equals(VersionState.DRAFT) && - !(versionState.equals(VersionState.DEACCESSIONED) && !includeDeaccessioned)); - }) - .reduce(null, this::getTheNewerFileMetadata); + .filter(metadata -> !metadata.getDatasetVersion().getVersionState().equals(VersionState.DRAFT)) + .reduce(null, DataFile::getTheNewerFileMetadata); if (resultFileMetadata == null) { throw new UnsupportedOperationException("No published metadata version for DataFile " + this.getId()); @@ -583,7 +579,7 @@ public FileMetadata getLatestPublishedFileMetadata(boolean includeDeaccessioned) return resultFileMetadata; } - private FileMetadata getTheNewerFileMetadata(FileMetadata current, FileMetadata candidate) { + public static FileMetadata getTheNewerFileMetadata(FileMetadata current, FileMetadata candidate) { if (current == null) { return candidate; } diff --git a/src/main/java/edu/harvard/iq/dataverse/api/EditDDI.java b/src/main/java/edu/harvard/iq/dataverse/api/EditDDI.java index d6aee0b7bfc..1b74ab5479e 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/EditDDI.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/EditDDI.java @@ -124,7 +124,7 @@ public Response edit(@Context ContainerRequestContext crc, InputStream body, @Pa if (!latestVersion.isWorkingCopy()) { //for new draft version - FileMetadata latestFml = dataFile.getLatestPublishedFileMetadata(true); + FileMetadata latestFml = dataFile.getLatestPublishedFileMetadata(); boolean groupUpdate = newGroups(varGroupMap, latestFml); boolean varUpdate = varUpdates(mapVarToVarMet, latestFml, neededToUpdateVM, true); diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Files.java b/src/main/java/edu/harvard/iq/dataverse/api/Files.java index b7494c5daec..55d65bae96b 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Files.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Files.java @@ -580,7 +580,7 @@ public Response getFileMetadata(@Context ContainerRequestContext crc, @PathParam return error(BAD_REQUEST, BundleUtil.getStringFromBundle("files.api.no.draft")); } } else { - fm = df.getLatestPublishedFileMetadata(false); + fm = df.getLatestPublishedFileMetadata(); MakeDataCountLoggingServiceBean.MakeDataCountEntry entry = new MakeDataCountLoggingServiceBean.MakeDataCountEntry(uriInfo, headers, dvRequestService, df); mdcLogService.logEntry(entry); } diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestPublishedFileMetadataCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestPublishedFileMetadataCommand.java index ea58cd4e7eb..7c07766748c 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestPublishedFileMetadataCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestPublishedFileMetadataCommand.java @@ -1,6 +1,7 @@ package edu.harvard.iq.dataverse.engine.command.impl; import edu.harvard.iq.dataverse.DataFile; +import edu.harvard.iq.dataverse.DatasetVersion; import edu.harvard.iq.dataverse.FileMetadata; import edu.harvard.iq.dataverse.engine.command.CommandContext; import edu.harvard.iq.dataverse.engine.command.DataverseRequest; @@ -14,14 +15,11 @@ public GetLatestPublishedFileMetadataCommand(DataverseRequest request, DataFile @Override public FileMetadata execute(CommandContext ctxt) throws CommandException { - try { - FileMetadata fileMetadata = dataFile.getLatestPublishedFileMetadata(includeDeaccessioned); - if (isDatasetVersionAccessible(fileMetadata.getDatasetVersion(), dataFile.getOwner(), ctxt)) { - return fileMetadata; - } - return null; - } catch (UnsupportedOperationException e) { - return null; - } + return dataFile.getFileMetadatas().stream().filter(fileMetadata -> { + DatasetVersion.VersionState versionState = fileMetadata.getDatasetVersion().getVersionState(); + return (!versionState.equals(DatasetVersion.VersionState.DRAFT) + && !(versionState.equals(DatasetVersion.VersionState.DEACCESSIONED) && !includeDeaccessioned) + && isDatasetVersionAccessible(fileMetadata.getDatasetVersion(), dataFile.getOwner(), ctxt)); + }).reduce(null, DataFile::getTheNewerFileMetadata); } } diff --git a/src/main/java/edu/harvard/iq/dataverse/makedatacount/MakeDataCountLoggingServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/makedatacount/MakeDataCountLoggingServiceBean.java index a3f09d190ca..5edf2fde0c3 100644 --- a/src/main/java/edu/harvard/iq/dataverse/makedatacount/MakeDataCountLoggingServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/makedatacount/MakeDataCountLoggingServiceBean.java @@ -133,7 +133,7 @@ public MakeDataCountEntry(FacesContext fc, DataverseRequestServiceBean dvRequest //Exception thrown if no published metadata exists for DataFile //This is passed a DataFile to log the file downloaded. uriInfo and headers are passed in lieu of FacesContext public MakeDataCountEntry(UriInfo uriInfo, HttpHeaders headers, DataverseRequestServiceBean dvRequestService, DataFile df) throws UnsupportedOperationException{ - this(null, dvRequestService, df.getLatestPublishedFileMetadata(false).getDatasetVersion()); + this(null, dvRequestService, df.getLatestPublishedFileMetadata().getDatasetVersion()); if(uriInfo != null) { setRequestUrl(uriInfo.getRequestUri().toString()); diff --git a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java index 4fb667d8955..4e1be85af56 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java @@ -1402,14 +1402,15 @@ public void testDataSizeInDataverse() throws InterruptedException { @Test public void testGetFileInfo() { Response createUser = UtilIT.createRandomUser(); - String username = UtilIT.getUsernameFromResponse(createUser); + String superUserUsername = UtilIT.getUsernameFromResponse(createUser); String superUserApiToken = UtilIT.getApiTokenFromResponse(createUser); - UtilIT.makeSuperUser(username); + UtilIT.makeSuperUser(superUserUsername); String dataverseAlias = createDataverseGetAlias(superUserApiToken); Integer datasetId = createDatasetGetId(dataverseAlias, superUserApiToken); createUser = UtilIT.createRandomUser(); - String apiTokenRegular = UtilIT.getApiTokenFromResponse(createUser); + String regularUsername = UtilIT.getUsernameFromResponse(createUser); + String regularApiToken = UtilIT.getApiTokenFromResponse(createUser); msg("Add a non-tabular file"); String pathToFile = "scripts/search/data/binary/trees.png"; @@ -1427,7 +1428,7 @@ public void testGetFileInfo() { .statusCode(OK.getStatusCode()); // Regular user should not get to see draft file data - getFileDataResponse = UtilIT.getFileData(dataFileId, apiTokenRegular); + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken); getFileDataResponse.then().assertThat() .statusCode(UNAUTHORIZED.getStatusCode()); @@ -1441,7 +1442,7 @@ public void testGetFileInfo() { .statusCode(OK.getStatusCode()); // Regular user should get to see published file data - getFileDataResponse = UtilIT.getFileData(dataFileId, apiTokenRegular); + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken); getFileDataResponse.then().assertThat() .statusCode(OK.getStatusCode()); @@ -1464,7 +1465,7 @@ public void testGetFileInfo() { .statusCode(OK.getStatusCode()); // Regular user should not get to see draft file data - getFileDataResponse = UtilIT.getFileData(dataFileId, apiTokenRegular, DS_VERSION_DRAFT); + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_DRAFT); getFileDataResponse.then().assertThat() .statusCode(UNAUTHORIZED.getStatusCode()); @@ -1481,13 +1482,13 @@ public void testGetFileInfo() { updateFileMetadataResponse.then().statusCode(OK.getStatusCode()); // Regular user should get to see latest published file data - getFileDataResponse = UtilIT.getFileData(dataFileId, apiTokenRegular, DS_VERSION_LATEST_PUBLISHED); + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST_PUBLISHED); getFileDataResponse.then().assertThat() .statusCode(OK.getStatusCode()) .body("data.label", equalTo(newFileNameFirstUpdate)); // Regular user should get to see latest published file data if latest is requested - getFileDataResponse = UtilIT.getFileData(dataFileId, apiTokenRegular, DS_VERSION_LATEST); + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST); getFileDataResponse.then().assertThat() .statusCode(OK.getStatusCode()) .body("data.label", equalTo(newFileNameFirstUpdate)); @@ -1504,25 +1505,80 @@ public void testGetFileInfo() { .statusCode(OK.getStatusCode()); // Regular user should get to see file data by specific version number - getFileDataResponse = UtilIT.getFileData(dataFileId, apiTokenRegular, "2.0"); + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, "2.0"); getFileDataResponse.then().assertThat() .statusCode(OK.getStatusCode()) .body("data.label", equalTo(newFileNameFirstUpdate)); - getFileDataResponse = UtilIT.getFileData(dataFileId, apiTokenRegular, "3.0"); + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, "3.0"); getFileDataResponse.then().assertThat() .statusCode(OK.getStatusCode()) .body("data.label", equalTo(newFileNameSecondUpdate)); + // The following tests cover cases where the dataset version is deaccessioned + Response deaccessionDatasetResponse = UtilIT.deaccessionDataset(datasetId, "3.0", "Test reason", null, superUserApiToken); + deaccessionDatasetResponse.then().assertThat().statusCode(OK.getStatusCode()); + + // Superuser should get to see file data if the latest version is deaccessioned filtering by latest and includeDeaccessioned is true + getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, DS_VERSION_LATEST, true); + getFileDataResponse.then().assertThat() + .body("data.label", equalTo(newFileNameSecondUpdate)) + .statusCode(OK.getStatusCode()); + + // Superuser should get to see version 2.0 file data if the latest version is deaccessioned filtering by latest and includeDeaccessioned is false + getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, DS_VERSION_LATEST, false); + getFileDataResponse.then().assertThat() + .body("data.label", equalTo(newFileNameFirstUpdate)) + .statusCode(OK.getStatusCode()); + + // Regular user should get to see version 2.0 file data if the latest version is deaccessioned filtering by latest and includeDeaccessioned is false + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST, true); + getFileDataResponse.then().assertThat() + .body("data.label", equalTo(newFileNameFirstUpdate)) + .statusCode(OK.getStatusCode()); + + // Update the file metadata + String newFileNameThirdUpdate = "trees_4.png"; + updateFileMetadata = Json.createObjectBuilder() + .add("label", newFileNameThirdUpdate); + updateFileMetadataResponse = UtilIT.updateFileMetadata(dataFileId, updateFileMetadata.build().toString(), superUserApiToken); + updateFileMetadataResponse.then().statusCode(OK.getStatusCode()); + + // Superuser should get to see draft file data if draft exists filtering by latest and includeDeaccessioned is true + getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, DS_VERSION_LATEST, true); + getFileDataResponse.then().assertThat() + .body("data.label", equalTo(newFileNameThirdUpdate)) + .statusCode(OK.getStatusCode()); + + // Regular user should get to see version 2.0 file data if the latest version is deaccessioned and draft exists filtering by latest and includeDeaccessioned is true + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST, true); + getFileDataResponse.then().assertThat() + .body("data.label", equalTo(newFileNameFirstUpdate)) + .statusCode(OK.getStatusCode()); + + // Publish dataset once again + publishDatasetResp = UtilIT.publishDatasetViaNativeApi(datasetId, "major", superUserApiToken); + publishDatasetResp.then().assertThat() + .statusCode(OK.getStatusCode()); + + // Regular user should get to see file data if the latest version is not deaccessioned filtering by latest and includeDeaccessioned is true + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST, true); + getFileDataResponse.then().assertThat() + .body("data.label", equalTo(newFileNameThirdUpdate)) + .statusCode(OK.getStatusCode()); + // Cleanup Response destroyDatasetResponse = UtilIT.destroyDataset(datasetId, superUserApiToken); - assertEquals(200, destroyDatasetResponse.getStatusCode()); + destroyDatasetResponse.then().assertThat().statusCode(OK.getStatusCode()); Response deleteDataverseResponse = UtilIT.deleteDataverse(dataverseAlias, superUserApiToken); - assertEquals(200, deleteDataverseResponse.getStatusCode()); + deleteDataverseResponse.then().assertThat().statusCode(OK.getStatusCode()); - Response deleteUserResponse = UtilIT.deleteUser(username); - assertEquals(200, deleteUserResponse.getStatusCode()); + Response deleteUserResponse = UtilIT.deleteUser(superUserUsername); + deleteUserResponse.then().assertThat().statusCode(OK.getStatusCode()); + + deleteUserResponse = UtilIT.deleteUser(regularUsername); + deleteUserResponse.then().assertThat().statusCode(OK.getStatusCode()); } @Test diff --git a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java index a3d894c7a52..a63d0521a24 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -1092,8 +1092,13 @@ static Response getFileData(String fileId, String apiToken) { } static Response getFileData(String fileId, String apiToken, String datasetVersionId) { + return getFileData(fileId, apiToken, datasetVersionId, false); + } + + static Response getFileData(String fileId, String apiToken, String datasetVersionId, boolean includeDeaccessioned) { return given() .header(API_TOKEN_HTTP_HEADER, apiToken) + .queryParam("includeDeaccessioned", includeDeaccessioned) .get("/api/files/" + fileId + "/versions/" + datasetVersionId); } From d0b745499bfcb8da33575eea66f6aedfa220d849 Mon Sep 17 00:00:00 2001 From: GPortas Date: Mon, 19 Feb 2024 10:00:09 +0000 Subject: [PATCH 071/141] Added: IT testGetFileInfo cases --- .../edu/harvard/iq/dataverse/api/FilesIT.java | 79 ++++++++++++++++++- 1 file changed, 75 insertions(+), 4 deletions(-) diff --git a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java index 4e1be85af56..ad86127e231 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java @@ -1420,9 +1420,10 @@ public void testGetFileInfo() { // Superuser should get to see draft file data String dataFileId = addResponse.getBody().jsonPath().getString("data.files[0].dataFile.id"); Response getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken); + String newFileName = "trees.png"; getFileDataResponse.then().assertThat() - .body("data.label", equalTo("trees.png")) - .body("data.dataFile.filename", equalTo("trees.png")) + .body("data.label", equalTo(newFileName)) + .body("data.dataFile.filename", equalTo(newFileName)) .body("data.dataFile.contentType", equalTo("image/png")) .body("data.dataFile.filesize", equalTo(8361)) .statusCode(OK.getStatusCode()); @@ -1444,7 +1445,8 @@ public void testGetFileInfo() { // Regular user should get to see published file data getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken); getFileDataResponse.then().assertThat() - .statusCode(OK.getStatusCode()); + .statusCode(OK.getStatusCode()) + .body("data.label", equalTo(newFileName)); // The following tests cover cases where a version ID is specified in the endpoint // Superuser should not get to see draft file data when no draft version exists @@ -1452,6 +1454,12 @@ public void testGetFileInfo() { getFileDataResponse.then().assertThat() .statusCode(NOT_FOUND.getStatusCode()); + // Regular user should get to see file data from specific version filtering by tag + getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, "1.0"); + getFileDataResponse.then().assertThat() + .statusCode(OK.getStatusCode()) + .body("data.label", equalTo(newFileName)); + // Update the file metadata String newFileNameFirstUpdate = "trees_2.png"; JsonObjectBuilder updateFileMetadata = Json.createObjectBuilder() @@ -1525,18 +1533,63 @@ public void testGetFileInfo() { .body("data.label", equalTo(newFileNameSecondUpdate)) .statusCode(OK.getStatusCode()); + // Superuser should get to see file data if the latest version is deaccessioned filtering by latest published and includeDeaccessioned is true + getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, DS_VERSION_LATEST_PUBLISHED, true); + getFileDataResponse.then().assertThat() + .body("data.label", equalTo(newFileNameSecondUpdate)) + .statusCode(OK.getStatusCode()); + // Superuser should get to see version 2.0 file data if the latest version is deaccessioned filtering by latest and includeDeaccessioned is false getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, DS_VERSION_LATEST, false); getFileDataResponse.then().assertThat() .body("data.label", equalTo(newFileNameFirstUpdate)) .statusCode(OK.getStatusCode()); - // Regular user should get to see version 2.0 file data if the latest version is deaccessioned filtering by latest and includeDeaccessioned is false + // Superuser should get to see version 2.0 file data if the latest version is deaccessioned filtering by latest published and includeDeaccessioned is false + getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, DS_VERSION_LATEST_PUBLISHED, false); + getFileDataResponse.then().assertThat() + .body("data.label", equalTo(newFileNameFirstUpdate)) + .statusCode(OK.getStatusCode()); + + // Superuser should get to see file data from specific deaccessioned version filtering by tag and includeDeaccessioned is true + getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, "3.0", true); + getFileDataResponse.then().assertThat() + .body("data.label", equalTo(newFileNameSecondUpdate)) + .statusCode(OK.getStatusCode()); + + // Superuser should not get to see file data from specific deaccessioned version filtering by tag and includeDeaccessioned is false + getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, "3.0", false); + getFileDataResponse.then().assertThat() + .statusCode(NOT_FOUND.getStatusCode()); + + // Regular user should get to see version 2.0 file data if the latest version is deaccessioned filtering by latest and includeDeaccessioned is true getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST, true); getFileDataResponse.then().assertThat() .body("data.label", equalTo(newFileNameFirstUpdate)) .statusCode(OK.getStatusCode()); + // Regular user should get to see version 2.0 file data if the latest version is deaccessioned filtering by latest published and includeDeaccessioned is true + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST_PUBLISHED, true); + getFileDataResponse.then().assertThat() + .body("data.label", equalTo(newFileNameFirstUpdate)) + .statusCode(OK.getStatusCode()); + + // Regular user should get to see version 2.0 file data if the latest version is deaccessioned filtering by latest published and includeDeaccessioned is false + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST_PUBLISHED, false); + getFileDataResponse.then().assertThat() + .body("data.label", equalTo(newFileNameFirstUpdate)) + .statusCode(OK.getStatusCode()); + + // Regular user should not get to see file data from specific deaccessioned version filtering by tag and includeDeaccessioned is true + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, "3.0", true); + getFileDataResponse.then().assertThat() + .statusCode(NOT_FOUND.getStatusCode()); + + // Regular user should not get to see file data from specific deaccessioned version filtering by tag and includeDeaccessioned is false + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, "3.0", false); + getFileDataResponse.then().assertThat() + .statusCode(NOT_FOUND.getStatusCode()); + // Update the file metadata String newFileNameThirdUpdate = "trees_4.png"; updateFileMetadata = Json.createObjectBuilder() @@ -1550,12 +1603,24 @@ public void testGetFileInfo() { .body("data.label", equalTo(newFileNameThirdUpdate)) .statusCode(OK.getStatusCode()); + // Superuser should get to see latest published file data if draft exists filtering by latest published and includeDeaccessioned is true + getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, DS_VERSION_LATEST_PUBLISHED, true); + getFileDataResponse.then().assertThat() + .body("data.label", equalTo(newFileNameSecondUpdate)) + .statusCode(OK.getStatusCode()); + // Regular user should get to see version 2.0 file data if the latest version is deaccessioned and draft exists filtering by latest and includeDeaccessioned is true getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST, true); getFileDataResponse.then().assertThat() .body("data.label", equalTo(newFileNameFirstUpdate)) .statusCode(OK.getStatusCode()); + // Regular user should get to see version 2.0 file data if the latest version is deaccessioned and draft exists filtering by latest published and includeDeaccessioned is true + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST_PUBLISHED, true); + getFileDataResponse.then().assertThat() + .body("data.label", equalTo(newFileNameFirstUpdate)) + .statusCode(OK.getStatusCode()); + // Publish dataset once again publishDatasetResp = UtilIT.publishDatasetViaNativeApi(datasetId, "major", superUserApiToken); publishDatasetResp.then().assertThat() @@ -1567,6 +1632,12 @@ public void testGetFileInfo() { .body("data.label", equalTo(newFileNameThirdUpdate)) .statusCode(OK.getStatusCode()); + // Regular user should get to see file data if the latest version is not deaccessioned filtering by latest published and includeDeaccessioned is true + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST_PUBLISHED, true); + getFileDataResponse.then().assertThat() + .body("data.label", equalTo(newFileNameThirdUpdate)) + .statusCode(OK.getStatusCode()); + // Cleanup Response destroyDatasetResponse = UtilIT.destroyDataset(datasetId, superUserApiToken); destroyDatasetResponse.then().assertThat().statusCode(OK.getStatusCode()); From a267adc66ceb02cd5864d7bf40d4637838c1c1d6 Mon Sep 17 00:00:00 2001 From: GPortas Date: Mon, 19 Feb 2024 10:38:32 +0000 Subject: [PATCH 072/141] Removed: commented code in json printer for DatasetVersion --- .../iq/dataverse/util/json/JsonPrinter.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index 2eaf6b64579..93e214159cf 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -356,9 +356,6 @@ public static JsonObjectBuilder json(DatasetVersion dsv, boolean includeFiles) { } public static JsonObjectBuilder json(DatasetVersion dsv, List anonymizedFieldTypeNamesList, boolean includeFiles) { - /* return json(dsv, null, includeFiles, null); - } - public static JsonObjectBuilder json(DatasetVersion dsv, List anonymizedFieldTypeNamesList, boolean includeFiles, Long numberOfFiles) {*/ Dataset dataset = dsv.getDataset(); JsonObjectBuilder bld = jsonObjectBuilder() .add("id", dsv.getId()).add("datasetId", dataset.getId()) @@ -374,8 +371,7 @@ public static JsonObjectBuilder json(DatasetVersion dsv, List anonymized .add("alternativePersistentId", dataset.getAlternativePersistentIdentifier()) .add("publicationDate", dataset.getPublicationDateFormattedYYYYMMDD()) .add("citationDate", dataset.getCitationDateFormattedYYYYMMDD()); - //.add("numberOfFiles", numberOfFiles); - + License license = DatasetUtil.getLicense(dsv); if (license != null) { bld.add("license", jsonLicense(dsv)); @@ -593,6 +589,18 @@ public static JsonObjectBuilder json(DatasetFieldType fld) { return fieldsBld; } + /* + + versionId: number +displayName: string +versionNumber: {majorNumber?: number, minorNumber?: number} +publishingStatus: string +citation: string +isLatest: boolean +isInReview: boolean +latestVersionPublishingStatus: string + */ + public static JsonObjectBuilder json(FileMetadata fmd) { return jsonObjectBuilder() // deprecated: .add("category", fmd.getCategory()) From ff2e86c19a232ac9821d045e284bb0f27bcd909b Mon Sep 17 00:00:00 2001 From: GPortas Date: Mon, 19 Feb 2024 11:38:03 +0000 Subject: [PATCH 073/141] Added: returnDatasetVersion optional parameter to getFileInfo API endpoint --- .../edu/harvard/iq/dataverse/api/Files.java | 14 +++--- .../iq/dataverse/util/json/JsonPrinter.java | 27 +++++++---- .../edu/harvard/iq/dataverse/api/FilesIT.java | 47 ++++++++++++------- .../edu/harvard/iq/dataverse/api/UtilIT.java | 5 +- 4 files changed, 59 insertions(+), 34 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Files.java b/src/main/java/edu/harvard/iq/dataverse/api/Files.java index fa8332c6138..d07950d5c37 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Files.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Files.java @@ -49,10 +49,7 @@ import jakarta.ejb.EJB; import jakarta.ejb.EJBException; import jakarta.inject.Inject; -import jakarta.json.Json; -import jakarta.json.JsonArray; -import jakarta.json.JsonString; -import jakarta.json.JsonValue; +import jakarta.json.*; import jakarta.json.stream.JsonParsingException; import jakarta.servlet.http.HttpServletResponse; import jakarta.ws.rs.*; @@ -489,9 +486,10 @@ public Response updateFileMetadata(@Context ContainerRequestContext crc, @FormDa public Response getFileData(@Context ContainerRequestContext crc, @PathParam("id") String fileIdOrPersistentId, @QueryParam("includeDeaccessioned") boolean includeDeaccessioned, + @QueryParam("returnDatasetVersion") boolean returnDatasetVersion, @Context UriInfo uriInfo, @Context HttpHeaders headers) { - return response( req -> getFileDataResponse(req, fileIdOrPersistentId, DS_VERSION_LATEST, includeDeaccessioned, uriInfo, headers), getRequestUser(crc)); + return response( req -> getFileDataResponse(req, fileIdOrPersistentId, DS_VERSION_LATEST, includeDeaccessioned, returnDatasetVersion, uriInfo, headers), getRequestUser(crc)); } @GET @@ -501,15 +499,17 @@ public Response getFileData(@Context ContainerRequestContext crc, @PathParam("id") String fileIdOrPersistentId, @PathParam("datasetVersionId") String datasetVersionId, @QueryParam("includeDeaccessioned") boolean includeDeaccessioned, + @QueryParam("returnDatasetVersion") boolean returnDatasetVersion, @Context UriInfo uriInfo, @Context HttpHeaders headers) { - return response( req -> getFileDataResponse(req, fileIdOrPersistentId, datasetVersionId, includeDeaccessioned, uriInfo, headers), getRequestUser(crc)); + return response( req -> getFileDataResponse(req, fileIdOrPersistentId, datasetVersionId, includeDeaccessioned, returnDatasetVersion, uriInfo, headers), getRequestUser(crc)); } private Response getFileDataResponse(final DataverseRequest req, String fileIdOrPersistentId, String datasetVersionId, boolean includeDeaccessioned, + boolean returnDatasetVersion, UriInfo uriInfo, HttpHeaders headers) throws WrappedResponse { final DataFile dataFile = execCommand(new GetDataFileCommand(req, findDataFileOrDie(fileIdOrPersistentId))); @@ -546,7 +546,7 @@ public Command handleLatestPublished() { return Response.ok(Json.createObjectBuilder() .add("status", ApiConstants.STATUS_OK) - .add("data", json(fileMetadata)).build()) + .add("data", json(fileMetadata, returnDatasetVersion)).build()) .type(MediaType.APPLICATION_JSON) .build(); } diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index 93e214159cf..df93727a666 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -602,28 +602,38 @@ public static JsonObjectBuilder json(DatasetFieldType fld) { */ public static JsonObjectBuilder json(FileMetadata fmd) { - return jsonObjectBuilder() + return json(fmd, false); + } + + public static JsonObjectBuilder json(FileMetadata fmd, boolean printDatasetVersion) { + NullSafeJsonBuilder builder = jsonObjectBuilder() // deprecated: .add("category", fmd.getCategory()) - // TODO: uh, figure out what to do here... it's deprecated - // in a sense that there's no longer the category field in the - // fileMetadata object; but there are now multiple, oneToMany file + // TODO: uh, figure out what to do here... it's deprecated + // in a sense that there's no longer the category field in the + // fileMetadata object; but there are now multiple, oneToMany file // categories - and we probably need to export them too!) -- L.A. 4.5 - // DONE: catgegories by name + // DONE: catgegories by name .add("description", fmd.getDescription()) .add("label", fmd.getLabel()) // "label" is the filename - .add("restricted", fmd.isRestricted()) + .add("restricted", fmd.isRestricted()) .add("directoryLabel", fmd.getDirectoryLabel()) .add("version", fmd.getVersion()) .add("datasetVersionId", fmd.getDatasetVersion().getId()) .add("categories", getFileCategories(fmd)) .add("dataFile", JsonPrinter.json(fmd.getDataFile(), fmd, false)); + + if (printDatasetVersion) { + builder.add("datasetVersion", json(fmd.getDatasetVersion(), false)); + } + + return builder; } - public static JsonObjectBuilder json(AuxiliaryFile auxFile) { + public static JsonObjectBuilder json(AuxiliaryFile auxFile) { return jsonObjectBuilder() .add("formatTag", auxFile.getFormatTag()) .add("formatVersion", auxFile.getFormatVersion()) // "label" is the filename - .add("origin", auxFile.getOrigin()) + .add("origin", auxFile.getOrigin()) .add("isPublic", auxFile.getIsPublic()) .add("type", auxFile.getType()) .add("contentType", auxFile.getContentType()) @@ -631,6 +641,7 @@ public static JsonObjectBuilder json(AuxiliaryFile auxFile) { .add("checksum", auxFile.getChecksum()) .add("dataFile", JsonPrinter.json(auxFile.getDataFile())); } + public static JsonObjectBuilder json(DataFile df) { return JsonPrinter.json(df, null, false); } diff --git a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java index d436b4129c4..125240b76b7 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java @@ -1530,65 +1530,65 @@ public void testGetFileInfo() { deaccessionDatasetResponse.then().assertThat().statusCode(OK.getStatusCode()); // Superuser should get to see file data if the latest version is deaccessioned filtering by latest and includeDeaccessioned is true - getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, DS_VERSION_LATEST, true); + getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, DS_VERSION_LATEST, true, false); getFileDataResponse.then().assertThat() .body("data.label", equalTo(newFileNameSecondUpdate)) .statusCode(OK.getStatusCode()); // Superuser should get to see file data if the latest version is deaccessioned filtering by latest published and includeDeaccessioned is true - getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, DS_VERSION_LATEST_PUBLISHED, true); + getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, DS_VERSION_LATEST_PUBLISHED, true, false); getFileDataResponse.then().assertThat() .body("data.label", equalTo(newFileNameSecondUpdate)) .statusCode(OK.getStatusCode()); // Superuser should get to see version 2.0 file data if the latest version is deaccessioned filtering by latest and includeDeaccessioned is false - getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, DS_VERSION_LATEST, false); + getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, DS_VERSION_LATEST, false, false); getFileDataResponse.then().assertThat() .body("data.label", equalTo(newFileNameFirstUpdate)) .statusCode(OK.getStatusCode()); // Superuser should get to see version 2.0 file data if the latest version is deaccessioned filtering by latest published and includeDeaccessioned is false - getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, DS_VERSION_LATEST_PUBLISHED, false); + getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, DS_VERSION_LATEST_PUBLISHED, false, false); getFileDataResponse.then().assertThat() .body("data.label", equalTo(newFileNameFirstUpdate)) .statusCode(OK.getStatusCode()); // Superuser should get to see file data from specific deaccessioned version filtering by tag and includeDeaccessioned is true - getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, "3.0", true); + getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, "3.0", true, false); getFileDataResponse.then().assertThat() .body("data.label", equalTo(newFileNameSecondUpdate)) .statusCode(OK.getStatusCode()); // Superuser should not get to see file data from specific deaccessioned version filtering by tag and includeDeaccessioned is false - getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, "3.0", false); + getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, "3.0", false, false); getFileDataResponse.then().assertThat() .statusCode(NOT_FOUND.getStatusCode()); // Regular user should get to see version 2.0 file data if the latest version is deaccessioned filtering by latest and includeDeaccessioned is true - getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST, true); + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST, true, false); getFileDataResponse.then().assertThat() .body("data.label", equalTo(newFileNameFirstUpdate)) .statusCode(OK.getStatusCode()); // Regular user should get to see version 2.0 file data if the latest version is deaccessioned filtering by latest published and includeDeaccessioned is true - getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST_PUBLISHED, true); + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST_PUBLISHED, true, false); getFileDataResponse.then().assertThat() .body("data.label", equalTo(newFileNameFirstUpdate)) .statusCode(OK.getStatusCode()); // Regular user should get to see version 2.0 file data if the latest version is deaccessioned filtering by latest published and includeDeaccessioned is false - getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST_PUBLISHED, false); + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST_PUBLISHED, false, false); getFileDataResponse.then().assertThat() .body("data.label", equalTo(newFileNameFirstUpdate)) .statusCode(OK.getStatusCode()); // Regular user should not get to see file data from specific deaccessioned version filtering by tag and includeDeaccessioned is true - getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, "3.0", true); + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, "3.0", true, false); getFileDataResponse.then().assertThat() .statusCode(NOT_FOUND.getStatusCode()); // Regular user should not get to see file data from specific deaccessioned version filtering by tag and includeDeaccessioned is false - getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, "3.0", false); + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, "3.0", false, false); getFileDataResponse.then().assertThat() .statusCode(NOT_FOUND.getStatusCode()); @@ -1600,25 +1600,25 @@ public void testGetFileInfo() { updateFileMetadataResponse.then().statusCode(OK.getStatusCode()); // Superuser should get to see draft file data if draft exists filtering by latest and includeDeaccessioned is true - getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, DS_VERSION_LATEST, true); + getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, DS_VERSION_LATEST, true, false); getFileDataResponse.then().assertThat() .body("data.label", equalTo(newFileNameThirdUpdate)) .statusCode(OK.getStatusCode()); // Superuser should get to see latest published file data if draft exists filtering by latest published and includeDeaccessioned is true - getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, DS_VERSION_LATEST_PUBLISHED, true); + getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, DS_VERSION_LATEST_PUBLISHED, true, false); getFileDataResponse.then().assertThat() .body("data.label", equalTo(newFileNameSecondUpdate)) .statusCode(OK.getStatusCode()); // Regular user should get to see version 2.0 file data if the latest version is deaccessioned and draft exists filtering by latest and includeDeaccessioned is true - getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST, true); + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST, true, false); getFileDataResponse.then().assertThat() .body("data.label", equalTo(newFileNameFirstUpdate)) .statusCode(OK.getStatusCode()); // Regular user should get to see version 2.0 file data if the latest version is deaccessioned and draft exists filtering by latest published and includeDeaccessioned is true - getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST_PUBLISHED, true); + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST_PUBLISHED, true, false); getFileDataResponse.then().assertThat() .body("data.label", equalTo(newFileNameFirstUpdate)) .statusCode(OK.getStatusCode()); @@ -1629,17 +1629,30 @@ public void testGetFileInfo() { .statusCode(OK.getStatusCode()); // Regular user should get to see file data if the latest version is not deaccessioned filtering by latest and includeDeaccessioned is true - getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST, true); + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST, true, false); getFileDataResponse.then().assertThat() .body("data.label", equalTo(newFileNameThirdUpdate)) .statusCode(OK.getStatusCode()); // Regular user should get to see file data if the latest version is not deaccessioned filtering by latest published and includeDeaccessioned is true - getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST_PUBLISHED, true); + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, DS_VERSION_LATEST_PUBLISHED, true, false); getFileDataResponse.then().assertThat() .body("data.label", equalTo(newFileNameThirdUpdate)) .statusCode(OK.getStatusCode()); + // The following tests cover cases where the user requests to include the dataset version information in the response + // User should get to see dataset version info in the response if returnDatasetVersion is true + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, "1.0", false, true); + getFileDataResponse.then().assertThat() + .body("data.datasetVersion.versionState", equalTo("RELEASED")) + .statusCode(OK.getStatusCode()); + + // User should not get to see dataset version info in the response if returnDatasetVersion is false + getFileDataResponse = UtilIT.getFileData(dataFileId, regularApiToken, "1.0", false, false); + getFileDataResponse.then().assertThat() + .body("data.datasetVersion", equalTo(null)) + .statusCode(OK.getStatusCode()); + // Cleanup Response destroyDatasetResponse = UtilIT.destroyDataset(datasetId, superUserApiToken); destroyDatasetResponse.then().assertThat().statusCode(OK.getStatusCode()); diff --git a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java index 410401514b1..9d728688f5f 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -1092,13 +1092,14 @@ static Response getFileData(String fileId, String apiToken) { } static Response getFileData(String fileId, String apiToken, String datasetVersionId) { - return getFileData(fileId, apiToken, datasetVersionId, false); + return getFileData(fileId, apiToken, datasetVersionId, false, false); } - static Response getFileData(String fileId, String apiToken, String datasetVersionId, boolean includeDeaccessioned) { + static Response getFileData(String fileId, String apiToken, String datasetVersionId, boolean includeDeaccessioned, boolean returnDatasetVersion) { return given() .header(API_TOKEN_HTTP_HEADER, apiToken) .queryParam("includeDeaccessioned", includeDeaccessioned) + .queryParam("returnDatasetVersion", returnDatasetVersion) .get("/api/files/" + fileId + "/versions/" + datasetVersionId); } From d4eedc2288f35a8be8ce25f8e48d20fac85aecdb Mon Sep 17 00:00:00 2001 From: GPortas Date: Mon, 19 Feb 2024 12:01:00 +0000 Subject: [PATCH 074/141] Added: extended docs for Get JSON Representation of a File --- doc/sphinx-guides/source/api/native-api.rst | 38 +++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index 4038ec4340d..3a0731d8c3f 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -2724,6 +2724,8 @@ Get JSON Representation of a File .. note:: Files can be accessed using persistent identifiers. This is done by passing the constant ``:persistentId`` where the numeric id of the file is expected, and then passing the actual persistent id as a query parameter with the name ``persistentId``. +This endpoint returns the file metadata present in the latest dataset version. + Example: Getting the file whose DOI is *10.5072/FK2/J8SJZB*: .. code-block:: bash @@ -2790,6 +2792,42 @@ The fully expanded example above (without environment variables) looks like this The file id can be extracted from the response retrieved from the API which uses the persistent identifier (``/api/datasets/:persistentId/?persistentId=$PERSISTENT_IDENTIFIER``). +By default, files from deaccessioned dataset versions are not included in the search. If no accessible dataset draft version exists, the search of the latest published file will ignore dataset deaccessioned versions unless ``includeDeaccessioned`` query parameter is set to ``true``. + +Usage example: + +.. code-block:: bash + + export SERVER_URL=https://demo.dataverse.org + export PERSISTENT_IDENTIFIER=doi:10.5072/FK2/J8SJZB + export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + + curl -H "X-Dataverse-key:$API_TOKEN" "$SERVER_URL/api/files/:persistentId/?persistentId=$PERSISTENT_IDENTIFIER&includeDeaccessioned=true" + +The fully expanded example above (without environment variables) looks like this: + +.. code-block:: bash + + curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" "https://demo.dataverse.org/api/files/:persistentId/?persistentId=doi:10.5072/FK2/J8SJZB&includeDeaccessioned=true" + +If you want to include the dataset version of the file in the response, there is an optional parameter for this called ``returnDatasetVersion`` whose default value is ``false``. + +Usage example: + +.. code-block:: bash + + export SERVER_URL=https://demo.dataverse.org + export PERSISTENT_IDENTIFIER=doi:10.5072/FK2/J8SJZB + export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + + curl -H "X-Dataverse-key:$API_TOKEN" "$SERVER_URL/api/files/:persistentId/?persistentId=$PERSISTENT_IDENTIFIER&returnDatasetVersion=true" + +The fully expanded example above (without environment variables) looks like this: + +.. code-block:: bash + + curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" "https://demo.dataverse.org/api/files/:persistentId/?persistentId=doi:10.5072/FK2/J8SJZB&returnDatasetVersion=true" + Adding Files ~~~~~~~~~~~~ From ab60747d339aeef63cb4100d4407deec30f7aef5 Mon Sep 17 00:00:00 2001 From: GPortas Date: Mon, 19 Feb 2024 12:36:34 +0000 Subject: [PATCH 075/141] Added: docs for Get JSON Representation of a File given a Dataset Version --- doc/sphinx-guides/source/api/native-api.rst | 64 +++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index 3a0731d8c3f..3d33be1ca45 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -2828,6 +2828,70 @@ The fully expanded example above (without environment variables) looks like this curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" "https://demo.dataverse.org/api/files/:persistentId/?persistentId=doi:10.5072/FK2/J8SJZB&returnDatasetVersion=true" +Get JSON Representation of a File given a Dataset Version +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: Files can be accessed using persistent identifiers. This is done by passing the constant ``:persistentId`` where the numeric id of the file is expected, and then passing the actual persistent id as a query parameter with the name ``persistentId``. + +This endpoint returns the file metadata present in the requested dataset version. To specify the dataset version, you can use ``:latest-published``, or ``:latest``, or ``:draft`` or ``1.0`` or any other style listed under :ref:`dataset-version-specifiers`. + +Example: Getting the file whose DOI is *10.5072/FK2/J8SJZB* present in the published dataset version ``1.0``: + +.. code-block:: bash + + export SERVER_URL=https://demo.dataverse.org + export PERSISTENT_IDENTIFIER=doi:10.5072/FK2/J8SJZB + export DATASET_VERSION=1.0 + export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + + curl -H "X-Dataverse-key:$API_TOKEN" "$SERVER_URL/api/files/:persistentId/versions/$DATASET_VERSION?persistentId=$PERSISTENT_IDENTIFIER" + +The fully expanded example above (without environment variables) looks like this: + +.. code-block:: bash + + curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" "https://demo.dataverse.org/api/files/:persistentId/versions/1.0?persistentId=doi:10.5072/FK2/J8SJZB" + +You may obtain a not found error depending on whether or not the specified version exists or you have permission to view it. + +By default, files from deaccessioned dataset versions are not included in the search unless ``includeDeaccessioned`` query parameter is set to ``true``. + +Usage example: + +.. code-block:: bash + + export SERVER_URL=https://demo.dataverse.org + export PERSISTENT_IDENTIFIER=doi:10.5072/FK2/J8SJZB + export DATASET_VERSION=:latest-published + export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + + curl -H "X-Dataverse-key:$API_TOKEN" "$SERVER_URL/api/files/:persistentId/versions/$DATASET_VERSION?persistentId=$PERSISTENT_IDENTIFIER&includeDeaccessioned=true" + +The fully expanded example above (without environment variables) looks like this: + +.. code-block:: bash + + curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" "https://demo.dataverse.org/api/files/:persistentId/versions/:latest-published?persistentId=doi:10.5072/FK2/J8SJZB&includeDeaccessioned=true" + +If you want to include the dataset version of the file in the response, there is an optional parameter for this called ``returnDatasetVersion`` whose default value is ``false``. + +Usage example: + +.. code-block:: bash + + export SERVER_URL=https://demo.dataverse.org + export PERSISTENT_IDENTIFIER=doi:10.5072/FK2/J8SJZB + export DATASET_VERSION=:draft + export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + + curl -H "X-Dataverse-key:$API_TOKEN" "$SERVER_URL/api/files/:persistentId/versions/$DATASET_VERSION?persistentId=$PERSISTENT_IDENTIFIER&returnDatasetVersion=true" + +The fully expanded example above (without environment variables) looks like this: + +.. code-block:: bash + + curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" "https://demo.dataverse.org/api/files/:persistentId/versions/:draft?persistentId=doi:10.5072/FK2/J8SJZB&returnDatasetVersion=true" + Adding Files ~~~~~~~~~~~~ From e5dbfa1510950bc8b0cb37bbf226cff0722938c8 Mon Sep 17 00:00:00 2001 From: GPortas Date: Mon, 19 Feb 2024 12:44:28 +0000 Subject: [PATCH 076/141] Added: release notes for #10280 --- doc/release-notes/10280-get-file-api-extension.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 doc/release-notes/10280-get-file-api-extension.md diff --git a/doc/release-notes/10280-get-file-api-extension.md b/doc/release-notes/10280-get-file-api-extension.md new file mode 100644 index 00000000000..fcca0afd78b --- /dev/null +++ b/doc/release-notes/10280-get-file-api-extension.md @@ -0,0 +1,8 @@ +The API endpoint `api/files/{id}` has been extended to support the following optional query parameters: + +- `includeDeaccessioned`: Indicates whether or not to consider deaccessioned dataset versions in the latest file search. (Default: `false`). +- `returnDatasetVersion`: Indicates whether or not to include the dataset version of the file in the response. (Default: `false`). + +A new endpoint `api/files/{id}/versions/{datasetVersionId}` has been created. This endpoint returns the file metadata present in the requested dataset version. To specify the dataset version, you can use ``:latest-published``, or ``:latest``, or ``:draft`` or ``1.0`` or any other available version identifier. + +The endpoint supports the `includeDeaccessioned` and `returnDatasetVersion` optional query parameters, as does the `api/files/{id}` endpoint. From ffd69e5cbf7f90f921e9d386c04fe3cfa062104e Mon Sep 17 00:00:00 2001 From: GPortas Date: Tue, 20 Feb 2024 12:59:48 +0000 Subject: [PATCH 077/141] Added: #10280 release note tweak --- doc/release-notes/10280-get-file-api-extension.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/release-notes/10280-get-file-api-extension.md b/doc/release-notes/10280-get-file-api-extension.md index fcca0afd78b..7ed70e93dc9 100644 --- a/doc/release-notes/10280-get-file-api-extension.md +++ b/doc/release-notes/10280-get-file-api-extension.md @@ -6,3 +6,5 @@ The API endpoint `api/files/{id}` has been extended to support the following opt A new endpoint `api/files/{id}/versions/{datasetVersionId}` has been created. This endpoint returns the file metadata present in the requested dataset version. To specify the dataset version, you can use ``:latest-published``, or ``:latest``, or ``:draft`` or ``1.0`` or any other available version identifier. The endpoint supports the `includeDeaccessioned` and `returnDatasetVersion` optional query parameters, as does the `api/files/{id}` endpoint. + +`api/files/{id}/draft` endpoint is no longer available in favor of the new endpoint `api/files/{id}/versions/{datasetVersionId}`, which can use the version identifier ``:draft`` (`api/files/{id}/versions/:draft`) to obtain the same result. From 2018c87acd9c86cd0131c5fcd8228ce4254ec488 Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Wed, 21 Feb 2024 10:50:36 +0100 Subject: [PATCH 078/141] style(ct): rename Maven skip deploy option To make SKIP_DEPLOY and the Maven property more alike, rename the Maven property to be "app.skipDeploy". --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index bf5bf16d423..aaa2b49eaae 100644 --- a/pom.xml +++ b/pom.xml @@ -916,7 +916,7 @@ gdcc/dataverse:${app.image.tag} unstable - false + false gdcc/base:${base.image.tag} unstable gdcc/configbaker:${conf.image.tag} @@ -929,7 +929,7 @@ ${postgresql.server.version} ${solr.version} dataverse - ${app.deploy.skip} + ${app.skipDeploy} From 626b2a87cad6a9e610c7a587bb5960997abb47cb Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Wed, 21 Feb 2024 10:54:13 +0100 Subject: [PATCH 079/141] doc(ct): rephrase and extend on running container dependencies for hot-reload - Make the description use tabs to be more aligned with the other tabs. - Include option as a tab to make IntelliJ run the compose commands for us --- .../source/container/dev-usage.rst | 49 +++++++++++++----- .../img/intellij-compose-add-new-config.png | Bin 0 -> 25929 bytes .../img/intellij-compose-add-run-payara.png | Bin 0 -> 14908 bytes .../container/img/intellij-compose-setup.png | Bin 0 -> 45986 bytes .../img/intellij-compose-sort-run-payara.png | Bin 0 -> 9725 bytes 5 files changed, 37 insertions(+), 12 deletions(-) create mode 100644 doc/sphinx-guides/source/container/img/intellij-compose-add-new-config.png create mode 100644 doc/sphinx-guides/source/container/img/intellij-compose-add-run-payara.png create mode 100644 doc/sphinx-guides/source/container/img/intellij-compose-setup.png create mode 100644 doc/sphinx-guides/source/container/img/intellij-compose-sort-run-payara.png diff --git a/doc/sphinx-guides/source/container/dev-usage.rst b/doc/sphinx-guides/source/container/dev-usage.rst index 6dbd0276cb3..a8e7efb7edc 100644 --- a/doc/sphinx-guides/source/container/dev-usage.rst +++ b/doc/sphinx-guides/source/container/dev-usage.rst @@ -144,15 +144,13 @@ Alternatives: Redeploying ----------- -Rebuilding and Running Images -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - The safest and most reliable way to redeploy code is to stop the running containers (with Ctrl-c if you started them in the foreground) and then build and run them again with ``mvn -Pct clean package docker:run``. +Safe, but also slowing down the development cycle a lot. -IDE-Triggered Redeployments -^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Hot Re-Deployments +^^^^^^^^^^^^^^^^^^ -Triggering redeployment using an IDE can greatly improve your feedback look when changing code. +Triggering redeployment of changes using an IDE can greatly improve your feedback loop when changing code. You have at least two options: @@ -237,12 +235,39 @@ To make use of builtin features or Payara tools (option 1), please follow these .. image:: img/intellij-payara-config-server-behaviour.png -#. | Start all the containers. Follow the cheat sheet above, but take care to skip application deployment: - | - When using the Maven commands, append ``-Dapp.deploy.skip``. For example: - | ``mvn -Pct docker:run -Dapp.deploy.skip`` - | - When using Docker Compose, prepend the command with ``SKIP_DEPLOY=1``. For example: - | ``SKIP_DEPLOY=1 docker compose -f docker-compose-dev.yml up`` - | - Note: the Admin Console can be reached at http://localhost:4848 or https://localhost:4949 +#. Start all the containers, but take care to skip application deployment. + + .. tabs:: + .. group-tab:: Maven + ``mvn -Pct docker:run -Dapp.skipDeploy`` + + Run above command in your terminal to start containers in foreground and skip deployment. + See cheat sheet above for more options. + Note that this command either assumes you built the :doc:`app-image` first or will download it from Docker Hub. + .. group-tab:: Compose + ``SKIP_DEPLOY=1 docker compose -f docker-compose-dev.yml up`` + + Run above command in your terminal to start containers in foreground and skip deployment. + See cheat sheet above for more options. + Note that this command either assumes you built the :doc:`app-image` first or will download it from Docker Hub. + .. group-tab:: IntelliJ + You can create a service configuration to automatically start services for you. + + **NOTE**: You might need to change the Docker Compose executable in your IDE settings to ``docker`` if you have no ``docker-compose`` bin. + + .. image:: img/intellij-compose-add-new-config.png + + Give your configuration a meaningful name, select the compose file to use (in this case the default one), add the environment variable ``SKIP_DEPLOY=1``, and optionally select the services to start. + + .. image:: img/intellij-compose-setup.png + + Now add this as dependent run configuration in your Payara Run Configuration you created before, in correct order: + + .. image:: img/intellij-compose-add-run-payara.png + .. image:: img/intellij-compose-sort-run-payara.png + + Note: the Admin Console can be reached at http://localhost:4848 or https://localhost:4949 + #. To deploy the application to the running server, use the configured tools to deploy. Using the "Run" configuration only deploys and enables redeploys, while running "Debug" enables hot swapping of classes via JDWP. diff --git a/doc/sphinx-guides/source/container/img/intellij-compose-add-new-config.png b/doc/sphinx-guides/source/container/img/intellij-compose-add-new-config.png new file mode 100644 index 0000000000000000000000000000000000000000..cec9bb357fea359ed18f3595c744cf50cc868845 GIT binary patch literal 25929 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%0AC|v>SpqtZ8=KY@W_J-0!nc1#*UWek5PJ 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%0D3=j^R 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 TxD@Q&C~yEdRoPl;^RWK|h`VSd literal 0 HcmV?d00001 diff --git a/doc/sphinx-guides/source/container/img/intellij-compose-add-run-payara.png b/doc/sphinx-guides/source/container/img/intellij-compose-add-run-payara.png new file mode 100644 index 0000000000000000000000000000000000000000..52a301f7ed58ff6f05ccd9ad99f5293d0e4143e1 GIT binary patch literal 14908 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 x^*z60>+Y4O4VHRNP9mxa|M&83yY84j}#Q=>6X( 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 CdnSkg literal 0 HcmV?d00001 From 0192758f335c9c493fc1cbe89c42ac2f46594ad3 Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Wed, 21 Feb 2024 18:19:41 +0100 Subject: [PATCH 080/141] doc(ct): add default admin credentials to base image docs --- doc/sphinx-guides/source/container/base-image.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/sphinx-guides/source/container/base-image.rst b/doc/sphinx-guides/source/container/base-image.rst index b43c201fe9f..c41250d48c5 100644 --- a/doc/sphinx-guides/source/container/base-image.rst +++ b/doc/sphinx-guides/source/container/base-image.rst @@ -361,6 +361,8 @@ Other Hints By default, ``domain1`` is enabled to use the ``G1GC`` garbage collector. +To access the Payara Admin Console or use the ``asadmin`` command, use username ``admin`` and password ``admin``. + For running a Java application within a Linux based container, the support for CGroups is essential. It has been included and activated by default since Java 8u192, Java 11 LTS and later. If you are interested in more details, you can read about those in a few places like https://developers.redhat.com/articles/2022/04/19/java-17-whats-new-openjdks-container-awareness, From c1612dbd4a5c057bb590c95679bd92c75b764cee Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Wed, 21 Feb 2024 18:20:29 +0100 Subject: [PATCH 081/141] style(ct): remove some typos and casing for dev usage docs --- doc/sphinx-guides/source/container/dev-usage.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/sphinx-guides/source/container/dev-usage.rst b/doc/sphinx-guides/source/container/dev-usage.rst index a8e7efb7edc..3c2b5934fe8 100644 --- a/doc/sphinx-guides/source/container/dev-usage.rst +++ b/doc/sphinx-guides/source/container/dev-usage.rst @@ -160,14 +160,14 @@ You have at least two options: The main differences between the first and the second options are support for hot deploys of non-class files and limitations in what the JVM HotswapAgent can do for you. Find more details in a `blog article by JRebel `_. -To make use of builtin features or Payara tools (option 1), please follow these steps: +To make use of builtin features or Payara IDE Tools (option 1), please follow these steps: #. | Download the version of Payara shown in :ref:`install-payara-dev` and unzip it to a reasonable location such as ``/usr/local/payara6``. | - Note that Payara can also be downloaded from `Maven Central `_. | - Note that another way to check the expected version of Payara is to run this command: | ``mvn help:evaluate -Dexpression=payara.version -q -DforceStdout`` -#. Install Payara tools plugin in your IDE: +#. Install Payara Tools plugin in your IDE: .. tabs:: .. group-tab:: Netbeans From bb8df95b752536af6ea374c8f73322b2f90f4881 Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Wed, 21 Feb 2024 18:20:46 +0100 Subject: [PATCH 082/141] fix(ct): make IntelliJ script less dependent - Remove Perl dependency for version number extraction - Rely on `docker cp` instead of mounting the filesystem --- scripts/intellij/cpwebapp.sh | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/scripts/intellij/cpwebapp.sh b/scripts/intellij/cpwebapp.sh index 6ecad367048..a823f8871ce 100755 --- a/scripts/intellij/cpwebapp.sh +++ b/scripts/intellij/cpwebapp.sh @@ -14,20 +14,21 @@ # https://www.jetbrains.com/help/idea/configuring-third-party-tools.html # -PROJECT_DIR=$1 -FILE_TO_COPY=$2 +set -eu + +PROJECT_DIR="$1" +FILE_TO_COPY="$2" RELATIVE_PATH="${FILE_TO_COPY#$PROJECT_DIR/}" # Check if RELATIVE_PATH starts with 'src/main/webapp', otherwise ignore -if [[ $RELATIVE_PATH == src/main/webapp* ]]; then - # Get current version. Any other way to do this? A simple VERSION file would help. - VERSION=`perl -ne 'print $1 if /(.*?)<\/revision>/' ./modules/dataverse-parent/pom.xml` - RELATIVE_PATH_WITHOUT_WEBAPP="${RELATIVE_PATH#src/main/webapp/}" - TARGET_DIR=./docker-dev-volumes/glassfish/applications/dataverse-$VERSION - TARGET_PATH="${TARGET_DIR}/${RELATIVE_PATH_WITHOUT_WEBAPP}" +if [[ "$RELATIVE_PATH" == "src/main/webapp"* ]]; then + # Extract version from POM, so we don't need to have Maven on the PATH + VERSION=$(grep -oPm1 "(?<=)[^<]+" "$PROJECT_DIR/modules/dataverse-parent/pom.xml") - mkdir -p "$(dirname "$TARGET_PATH")" - cp "$FILE_TO_COPY" "$TARGET_PATH" + # Construct the target path by cutting off the local prefix and prepend with in-container path + RELATIVE_PATH_WITHOUT_WEBAPP="${RELATIVE_PATH#src/main/webapp/}" + TARGET_PATH="/opt/payara/appserver/glassfish/domains/domain1/applications/dataverse-$VERSION/${RELATIVE_PATH_WITHOUT_WEBAPP}" - echo "File $FILE_TO_COPY copied to $TARGET_PATH" + # Copy file to container + docker cp "$FILE_TO_COPY" "dev_dataverse:$TARGET_PATH" fi From e9ff6bc2780da61d33226c53e7209528f827e33a Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Wed, 21 Feb 2024 18:36:39 +0100 Subject: [PATCH 083/141] doc(ct): add notes about IDE redeployment and add stub for non-code redeployment --- .../source/container/dev-usage.rst | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/doc/sphinx-guides/source/container/dev-usage.rst b/doc/sphinx-guides/source/container/dev-usage.rst index 3c2b5934fe8..aef262f30cf 100644 --- a/doc/sphinx-guides/source/container/dev-usage.rst +++ b/doc/sphinx-guides/source/container/dev-usage.rst @@ -147,11 +147,7 @@ Redeploying The safest and most reliable way to redeploy code is to stop the running containers (with Ctrl-c if you started them in the foreground) and then build and run them again with ``mvn -Pct clean package docker:run``. Safe, but also slowing down the development cycle a lot. -Hot Re-Deployments -^^^^^^^^^^^^^^^^^^ - Triggering redeployment of changes using an IDE can greatly improve your feedback loop when changing code. - You have at least two options: #. Use builtin features of IDEs or `IDE plugins from Payara `_. @@ -160,7 +156,13 @@ You have at least two options: The main differences between the first and the second options are support for hot deploys of non-class files and limitations in what the JVM HotswapAgent can do for you. Find more details in a `blog article by JRebel `_. -To make use of builtin features or Payara IDE Tools (option 1), please follow these steps: +IDE Triggered Code Re-Deployments +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To make use of builtin features or Payara IDE Tools (option 1), please follow steps below. +Note that using this method, you may redeploy a complete WAR or single methods. +Redeploying WARs supports swapping and adding classes and non-code materials, but is slower (still faster than rebuilding containers). +Hotswapping methods requires using JDWP (Debug Mode), but does not allow switching non-code material or adding classes. #. | Download the version of Payara shown in :ref:`install-payara-dev` and unzip it to a reasonable location such as ``/usr/local/payara6``. | - Note that Payara can also be downloaded from `Maven Central `_. @@ -312,6 +314,17 @@ To make use of builtin features or Payara IDE Tools (option 1), please follow th Note: in the background, the bootstrap job will wait for Dataverse to be deployed and responsive. When your IDE automatically opens the URL a newly deployed, not bootstrapped Dataverse application, it might take some more time and page refreshes until the job finishes. +IDE Triggered Non-Code Re-Deployments +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Either redeploy the WAR (see above), use JRebel or look into copying files into the exploded WAR within the running container. +The steps below describe options to enable the later in different IDEs. + +.. tabs:: + .. group-tab:: IntelliJ + TODO + + Using a Debugger ---------------- From 314e2ebf5f678a8cadfb925e0b1ea5c194019b8a Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Wed, 21 Feb 2024 16:18:55 -0500 Subject: [PATCH 084/141] #10286 changes from CR --- .../harvard/iq/dataverse/api/Datasets.java | 15 ++-- .../harvard/iq/dataverse/api/Dataverses.java | 2 +- .../edu/harvard/iq/dataverse/api/Files.java | 10 +-- .../iq/dataverse/util/json/JsonPrinter.java | 89 +++++++++++-------- .../harvard/iq/dataverse/api/DatasetsIT.java | 10 +-- .../iq/dataverse/api/DataversesIT.java | 2 +- .../edu/harvard/iq/dataverse/api/FilesIT.java | 2 +- 7 files changed, 70 insertions(+), 60 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java b/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java index d19c8bf3915..7d0141641fe 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java @@ -186,12 +186,11 @@ public interface DsVersionHandler { @GET @AuthRequired @Path("{id}") - public Response getDataset(@Context ContainerRequestContext crc, @PathParam("id") String id, @Context UriInfo uriInfo, @Context HttpHeaders headers, @Context HttpServletResponse response, @QueryParam("returnOwners") Boolean returnOwners) { + public Response getDataset(@Context ContainerRequestContext crc, @PathParam("id") String id, @Context UriInfo uriInfo, @Context HttpHeaders headers, @Context HttpServletResponse response, @QueryParam("returnOwners") boolean returnOwners) { return response( req -> { final Dataset retrieved = execCommand(new GetDatasetCommand(req, findDatasetOrDie(id))); final DatasetVersion latest = execCommand(new GetLatestAccessibleDatasetVersionCommand(req, retrieved)); - Boolean includeOwners = returnOwners == null ? false : returnOwners; - final JsonObjectBuilder jsonbuilder = json(retrieved, includeOwners); + final JsonObjectBuilder jsonbuilder = json(retrieved, returnOwners); //Report MDC if this is a released version (could be draft if user has access, or user may not have access at all and is not getting metadata beyond the minimum) if((latest != null) && latest.isReleased()) { MakeDataCountLoggingServiceBean.MakeDataCountEntry entry = new MakeDataCountEntry(uriInfo, headers, dvRequestService, retrieved); @@ -422,6 +421,7 @@ public Response getVersion(@Context ContainerRequestContext crc, @PathParam("versionId") String versionId, @QueryParam("excludeFiles") Boolean excludeFiles, @QueryParam("includeDeaccessioned") boolean includeDeaccessioned, + @QueryParam("returnOwners") boolean includeOwners, @Context UriInfo uriInfo, @Context HttpHeaders headers) { return response( req -> { @@ -440,7 +440,8 @@ public Response getVersion(@Context ContainerRequestContext crc, if (excludeFiles == null ? true : !excludeFiles) { dsv = datasetversionService.findDeep(dsv.getId()); } - return ok(json(dsv, excludeFiles == null ? true : !excludeFiles)); + System.out.print("returnOwners: " + includeOwners); + return ok(json(dsv, null, excludeFiles == null ? true : !excludeFiles, includeOwners)); }, getRequestUser(crc)); } @@ -4387,7 +4388,7 @@ public Response getDatasetSummaryFieldNames() { @GET @Path("privateUrlDatasetVersion/{privateUrlToken}") - public Response getPrivateUrlDatasetVersion(@PathParam("privateUrlToken") String privateUrlToken) { + public Response getPrivateUrlDatasetVersion(@PathParam("privateUrlToken") String privateUrlToken, @QueryParam("returnOwners") boolean returnOwners) { PrivateUrlUser privateUrlUser = privateUrlService.getPrivateUrlUserFromToken(privateUrlToken); if (privateUrlUser == null) { return notFound("Private URL user not found"); @@ -4404,9 +4405,9 @@ public Response getPrivateUrlDatasetVersion(@PathParam("privateUrlToken") String JsonObjectBuilder responseJson; if (isAnonymizedAccess) { List anonymizedFieldTypeNamesList = new ArrayList<>(Arrays.asList(anonymizedFieldTypeNames.split(",\\s"))); - responseJson = json(dsv, anonymizedFieldTypeNamesList, true); + responseJson = json(dsv, anonymizedFieldTypeNamesList, true, returnOwners); } else { - responseJson = json(dsv, true); + responseJson = json(dsv, null, true, returnOwners); } return ok(responseJson); } diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java index 66aec38adfa..3bcbfdd4d58 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java @@ -610,7 +610,7 @@ private Dataset parseDataset(String datasetJson) throws WrappedResponse { @GET @AuthRequired @Path("{identifier}") - public Response viewDataverse(@Context ContainerRequestContext crc, @PathParam("identifier") String idtf, @QueryParam("returnOwners") Boolean returnOwners) { + public Response getDataverse(@Context ContainerRequestContext crc, @PathParam("identifier") String idtf, @QueryParam("returnOwners") Boolean returnOwners) { Boolean includeOwners = returnOwners == null ? false : returnOwners; return response(req -> ok( json(execCommand(new GetDataverseCommand(req, findDataverseOrDie(idtf))), diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Files.java b/src/main/java/edu/harvard/iq/dataverse/api/Files.java index 13e459bc3e8..6efb4766dfa 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Files.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Files.java @@ -506,17 +506,15 @@ public Response updateFileMetadata(@Context ContainerRequestContext crc, @FormDa @GET @AuthRequired @Path("{id}/draft") - public Response getFileDataDraft(@Context ContainerRequestContext crc, @PathParam("id") String fileIdOrPersistentId, @Context UriInfo uriInfo, @Context HttpHeaders headers, @Context HttpServletResponse response, @QueryParam("returnOwners") Boolean returnOwners) throws WrappedResponse, Exception { - Boolean includeOwners = returnOwners == null ? false : returnOwners; - return getFileDataResponse(getRequestUser(crc), fileIdOrPersistentId, uriInfo, headers, response, true, includeOwners); + public Response getFileDataDraft(@Context ContainerRequestContext crc, @PathParam("id") String fileIdOrPersistentId, @Context UriInfo uriInfo, @Context HttpHeaders headers, @Context HttpServletResponse response, @QueryParam("returnOwners") boolean returnOwners) throws WrappedResponse, Exception { + return getFileDataResponse(getRequestUser(crc), fileIdOrPersistentId, uriInfo, headers, response, true, returnOwners); } @GET @AuthRequired @Path("{id}") - public Response getFileData(@Context ContainerRequestContext crc, @PathParam("id") String fileIdOrPersistentId, @Context UriInfo uriInfo, @Context HttpHeaders headers, @Context HttpServletResponse response, @QueryParam("returnOwners") Boolean returnOwners) throws WrappedResponse, Exception { - Boolean includeOwners = returnOwners == null ? false : returnOwners; - return getFileDataResponse(getRequestUser(crc), fileIdOrPersistentId, uriInfo, headers, response, false, includeOwners); + public Response getFileData(@Context ContainerRequestContext crc, @PathParam("id") String fileIdOrPersistentId, @Context UriInfo uriInfo, @Context HttpHeaders headers, @Context HttpServletResponse response, @QueryParam("returnOwners") boolean returnOwners) throws WrappedResponse, Exception { + return getFileDataResponse(getRequestUser(crc), fileIdOrPersistentId, uriInfo, headers, response, false, returnOwners); } private Response getFileDataResponse(User user, String fileIdOrPersistentId, UriInfo uriInfo, HttpHeaders headers, HttpServletResponse response, boolean draft, boolean includeOwners ){ diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index d64f77b3526..05dbc4d6079 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -272,7 +272,7 @@ public static JsonObjectBuilder json(Dataverse dv, Boolean hideEmail, Boolean in bld.add("dataverseContacts", JsonPrinter.json(dv.getDataverseContacts())); } if (includeOwners){ - bld.add("ownerArray", getOwnersFromDvObject(dv)); + bld.add("isPartOf", getOwnersFromDvObject(dv)); } bld.add("permissionRoot", dv.isPermissionRoot()) .add("description", dv.getDescription()) @@ -307,46 +307,58 @@ public static JsonArrayBuilder json(List dataverseContacts) { return jsonArrayOfContacts; } - public static JsonArrayBuilder getOwnersFromDvObject(DvObject dvObject) { - + public static JsonObjectBuilder getOwnersFromDvObject(DvObject dvObject){ + return getOwnersFromDvObject(dvObject, null); + } + + public static JsonObjectBuilder getOwnersFromDvObject(DvObject dvObject, DatasetVersion dsv) { List ownerList = new ArrayList(); dvObject = dvObject.getOwner(); // We're going to ignore the object itself + //Get "root" to top of list while (dvObject != null) { - ownerList.add(dvObject); + ownerList.add(0, dvObject); dvObject = dvObject.getOwner(); } + //then work "inside out" + JsonObjectBuilder saved = null; + for (DvObject dvo : ownerList) { + saved = addEmbeddedOwnerObject(dvo, saved, dsv); + } + return saved; + } + + private static JsonObjectBuilder addEmbeddedOwnerObject(DvObject dvo, JsonObjectBuilder isPartOf, DatasetVersion dsv ) { + JsonObjectBuilder ownerObject = jsonObjectBuilder(); + + if (dvo.isInstanceofDataverse()) { + ownerObject.add("type", "DATAVERSE"); + Dataverse in = (Dataverse) dvo; + ownerObject.add("identifier", in.getAlias()); + } + + if (dvo.isInstanceofDataset()) { + ownerObject.add("type", "DATASET"); + String versionString = ""; + if (dsv != null){ + versionString = dsv == null ? "" : "&version=" + dsv.getFriendlyVersionNumber(); + } + if (dvo.getGlobalId() != null) { + ownerObject.add("identifier", dvo.getGlobalId().asString() + versionString); + } else { + ownerObject.add("identifier", dvo.getId() ); + } + + } - JsonArrayBuilder jsonArrayOfOwners = Json.createArrayBuilder(); + ownerObject.add("displayName", dvo.getDisplayName()); - for (DvObject dvo : ownerList){ - JsonObjectBuilder ownerObject = jsonObjectBuilder(); - if (dvo.isInstanceofDataverse()){ - ownerObject.add("type", "DATAVERSE"); - } - if (dvo.isInstanceofDataset()){ - ownerObject.add("type", "DATASET"); - } - if (dvo.isInstanceofDataFile()){ - ownerObject.add("type", "DATAFILE"); - } - if (dvo.isInstanceofDataverse()){ - Dataverse in = (Dataverse) dvo; - ownerObject.add("identifier", in.getAlias()); - } - if (dvo.isInstanceofDataset() || dvo.isInstanceofDataFile() ){ - if (dvo.getIdentifier() != null){ - Dataset ds = (Dataset) dvo; - ownerObject.add("identifier", ds.getGlobalId().asString()); - } else { - ownerObject.add("identifier", dvo.getId()); - } - } - ownerObject.add("displayName", dvo.getDisplayName()); - jsonArrayOfOwners.add(ownerObject); + if (isPartOf != null) { + ownerObject.add("isPartOf", isPartOf); } - return jsonArrayOfOwners; + + return ownerObject; } - + public static JsonObjectBuilder json( DataverseTheme theme ) { final NullSafeJsonBuilder baseObject = jsonObjectBuilder() .add("id", theme.getId() ) @@ -388,7 +400,7 @@ public static JsonObjectBuilder json(Dataset ds, Boolean includeOwners) { bld.add("metadataLanguage", ds.getMetadataLanguage()); } if (includeOwners){ - bld.add("ownerArray", getOwnersFromDvObject(ds)); + bld.add("isPartOf", getOwnersFromDvObject(ds)); } return bld; } @@ -402,10 +414,10 @@ public static JsonObjectBuilder json(FileDetailsHolder ds) { } public static JsonObjectBuilder json(DatasetVersion dsv, boolean includeFiles) { - return json(dsv, null, includeFiles); + return json(dsv, null, includeFiles, false); } - public static JsonObjectBuilder json(DatasetVersion dsv, List anonymizedFieldTypeNamesList, boolean includeFiles) { + public static JsonObjectBuilder json(DatasetVersion dsv, List anonymizedFieldTypeNamesList, boolean includeFiles, boolean includeOwners) { /* return json(dsv, null, includeFiles, null); } public static JsonObjectBuilder json(DatasetVersion dsv, List anonymizedFieldTypeNamesList, boolean includeFiles, Long numberOfFiles) {*/ @@ -452,7 +464,10 @@ public static JsonObjectBuilder json(DatasetVersion dsv, List anonymized bld.add("metadataBlocks", (anonymizedFieldTypeNamesList != null) ? jsonByBlocks(dsv.getDatasetFields(), anonymizedFieldTypeNamesList) : jsonByBlocks(dsv.getDatasetFields()) - ); + ); + if(includeOwners){ + bld.add("isPartOf", getOwnersFromDvObject(dataset)); + } if (includeFiles) { bld.add("files", jsonFileMetadatas(dsv.getFileMetadatas())); } @@ -762,7 +777,7 @@ public static JsonObjectBuilder json(DataFile df, FileMetadata fileMetadata, boo : null); } if (includeOwners){ - builder.add("ownerArray", getOwnersFromDvObject(df)); + builder.add("isPartOf", getOwnersFromDvObject(df, fileMetadata.getDatasetVersion())); } return builder; } diff --git a/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java b/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java index f4e70e03d45..51fe52b5866 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java @@ -1889,7 +1889,7 @@ public void testDeleteDatasetWhileFileIngesting() { } @Test - public void testGetIncludeOwnerArray() { + public void testGetDatasetOwners() { Response createUser = UtilIT.createRandomUser(); createUser.then().assertThat() @@ -1913,7 +1913,7 @@ public void testGetIncludeOwnerArray() { Response getDatasetWithOwners = UtilIT.getDatasetWithOwners(persistentId, apiToken, true); getDatasetWithOwners.prettyPrint(); - getDatasetWithOwners.then().assertThat().body("data.ownerArray[0].identifier", equalTo(dataverseAlias)); + getDatasetWithOwners.then().assertThat().body("data.isPartOf.identifier", equalTo(dataverseAlias)); Response destroyDatasetResponse = UtilIT.destroyDataset(datasetId, apiToken); assertEquals(200, destroyDatasetResponse.getStatusCode()); @@ -1922,12 +1922,8 @@ public void testGetIncludeOwnerArray() { assertEquals(200, deleteDataverseResponse.getStatusCode()); Response deleteUserResponse = UtilIT.deleteUser(username); - assertEquals(200, deleteUserResponse.getStatusCode()); - + assertEquals(200, deleteUserResponse.getStatusCode()); } - - - /** * In order for this test to pass you must have the Data Capture Module ( diff --git a/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java index e41793a10d5..3330d11435a 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java @@ -170,7 +170,7 @@ public void testGetDataverseOwners() throws FileNotFoundException { Response getWithOwners = UtilIT.getDataverseWithOwners(level1a, apiToken, true); getWithOwners.prettyPrint(); - getWithOwners.then().assertThat().body("data.ownerArray[0].identifier", equalTo(first)); + getWithOwners.then().assertThat().body("data.isPartOf.identifier", equalTo(first)); } diff --git a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java index d69a3ac885c..fd72f22a140 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java @@ -1504,7 +1504,7 @@ public void testGetFileOwners() { .body("data.dataFile.filesize", equalTo(8361)) .statusCode(OK.getStatusCode()); - getFileDataResponse.then().assertThat().body("data.dataFile.ownerArray[0].identifier", equalTo(datasetPid)); + getFileDataResponse.then().assertThat().body("data.dataFile.isPartOf.identifier", equalTo(datasetPid)); // ------------------------- // Publish dataverse and dataset From c9cccaac56121bdfcc8f4bc2038fdf5de0b04794 Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Thu, 22 Feb 2024 07:38:45 +0100 Subject: [PATCH 085/141] docs(ct): remove configuration trigger step in IntelliJ Depending on the attachment configuration, the run configuration waits in blocking mode for more output from the container logs. The application would never be deployed, as the wait is indefinite. We need to run the compose step and the deploy step on their own. One appears in the services tab, the other in the run tab. --- .../source/container/dev-usage.rst | 6 +++--- .../img/intellij-compose-add-run-payara.png | Bin 14908 -> 0 bytes .../container/img/intellij-compose-run.png | Bin 0 -> 3080 bytes .../img/intellij-compose-sort-run-payara.png | Bin 9725 -> 0 bytes 4 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 doc/sphinx-guides/source/container/img/intellij-compose-add-run-payara.png create mode 100644 doc/sphinx-guides/source/container/img/intellij-compose-run.png delete mode 100644 doc/sphinx-guides/source/container/img/intellij-compose-sort-run-payara.png diff --git a/doc/sphinx-guides/source/container/dev-usage.rst b/doc/sphinx-guides/source/container/dev-usage.rst index aef262f30cf..d37b9f4763f 100644 --- a/doc/sphinx-guides/source/container/dev-usage.rst +++ b/doc/sphinx-guides/source/container/dev-usage.rst @@ -260,13 +260,13 @@ Hotswapping methods requires using JDWP (Debug Mode), but does not allow switchi .. image:: img/intellij-compose-add-new-config.png Give your configuration a meaningful name, select the compose file to use (in this case the default one), add the environment variable ``SKIP_DEPLOY=1``, and optionally select the services to start. + You might also want to change other options like attaching to containers to view the logs within the "Services" tab. .. image:: img/intellij-compose-setup.png - Now add this as dependent run configuration in your Payara Run Configuration you created before, in correct order: + Now run the configuration to prepare for deployment. - .. image:: img/intellij-compose-add-run-payara.png - .. image:: img/intellij-compose-sort-run-payara.png + .. image:: img/intellij-compose-run.png Note: the Admin Console can be reached at http://localhost:4848 or https://localhost:4949 diff --git a/doc/sphinx-guides/source/container/img/intellij-compose-add-run-payara.png b/doc/sphinx-guides/source/container/img/intellij-compose-add-run-payara.png deleted file mode 100644 index 52a301f7ed58ff6f05ccd9ad99f5293d0e4143e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14908 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 O571E6QK?dX6Zs$WY6r&v literal 0 HcmV?d00001 diff --git a/doc/sphinx-guides/source/container/img/intellij-compose-sort-run-payara.png b/doc/sphinx-guides/source/container/img/intellij-compose-sort-run-payara.png deleted file mode 100644 index 4efa1b0e925935eb58cb76654d6e89099047d959..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9725 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 CdnSkg From f3611a012773033e020c83230e3124df6351e195 Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Thu, 22 Feb 2024 07:40:29 +0100 Subject: [PATCH 086/141] chore(ct): move IntelliJ scripts to Docker folder This is very much Docker specific now and should be located within that folder. --- {scripts => docker/util}/intellij/cpwebapp.sh | 0 {scripts => docker/util}/intellij/watchers.xml | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {scripts => docker/util}/intellij/cpwebapp.sh (100%) rename {scripts => docker/util}/intellij/watchers.xml (100%) diff --git a/scripts/intellij/cpwebapp.sh b/docker/util/intellij/cpwebapp.sh similarity index 100% rename from scripts/intellij/cpwebapp.sh rename to docker/util/intellij/cpwebapp.sh diff --git a/scripts/intellij/watchers.xml b/docker/util/intellij/watchers.xml similarity index 100% rename from scripts/intellij/watchers.xml rename to docker/util/intellij/watchers.xml From 67ee8b7835bcdc0907083389bfa9d2fe1256680e Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Thu, 22 Feb 2024 07:55:38 +0100 Subject: [PATCH 087/141] docs(ct): add README for IntelliJ auto-copy save trigger --- docker/util/intellij/README.md | 13 +++++++++++++ docker/util/intellij/cpwebapp.sh | 11 ----------- 2 files changed, 13 insertions(+), 11 deletions(-) create mode 100644 docker/util/intellij/README.md diff --git a/docker/util/intellij/README.md b/docker/util/intellij/README.md new file mode 100644 index 00000000000..281d0e50ea6 --- /dev/null +++ b/docker/util/intellij/README.md @@ -0,0 +1,13 @@ +# IntelliJ Auto-Copy of Webapp Files + +When deploying the webapp via Payara Tools, you can use this tool to immediately copy changes to non-code files into the running deployment, instantly seeing changes in your browser. + +Note: as this relies on using a Bash shell script, it is pretty much limited to Mac and Linux. +Feel free to extend and provide a PowerShell equivalent! + +1. Install the [File Watcher plugin](https://plugins.jetbrains.com/plugin/7177-file-watchers) +2. Import the [watchers.xml](./watchers.xml) file at *File > Settings > Tools > File Watchers* +3. Once you have the deployment running (see Container Guides), editing files at `src/main/webapp` will be copied into the deployment after saving the edited file. + +Alternatively, you can add an External tool and trigger via menu or shortcut to do the copying manually: +https://www.jetbrains.com/help/idea/configuring-third-party-tools.html diff --git a/docker/util/intellij/cpwebapp.sh b/docker/util/intellij/cpwebapp.sh index a823f8871ce..0a59463f5aa 100755 --- a/docker/util/intellij/cpwebapp.sh +++ b/docker/util/intellij/cpwebapp.sh @@ -2,17 +2,6 @@ # # cpwebapp # -# Usage: -# -# Add a File watcher by importing watchers.xml into IntelliJ IDEA, and let it do the copying whenever you save a -# file under webapp. -# -# https://www.jetbrains.com/help/idea/settings-tools-file-watchers.html -# -# Alternatively, you can add an External tool and trigger via menu or shortcut to do the copying manually: -# -# https://www.jetbrains.com/help/idea/configuring-third-party-tools.html -# set -eu From fa61267a1de69527a504e846f5e97d7713bd166d Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Thu, 22 Feb 2024 07:56:22 +0100 Subject: [PATCH 088/141] fix(ct): properly quote var in expression Thank you, shellcheck! --- docker/util/intellij/cpwebapp.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/util/intellij/cpwebapp.sh b/docker/util/intellij/cpwebapp.sh index 0a59463f5aa..2d08fb1a873 100755 --- a/docker/util/intellij/cpwebapp.sh +++ b/docker/util/intellij/cpwebapp.sh @@ -7,7 +7,7 @@ set -eu PROJECT_DIR="$1" FILE_TO_COPY="$2" -RELATIVE_PATH="${FILE_TO_COPY#$PROJECT_DIR/}" +RELATIVE_PATH="${FILE_TO_COPY#"${PROJECT_DIR}/"}" # Check if RELATIVE_PATH starts with 'src/main/webapp', otherwise ignore if [[ "$RELATIVE_PATH" == "src/main/webapp"* ]]; then From d20785a97b392ce493dec84357973412d070d0b7 Mon Sep 17 00:00:00 2001 From: Oliver Bertuch Date: Thu, 22 Feb 2024 07:56:46 +0100 Subject: [PATCH 089/141] fix(ct): correct path in watchers.xml to shell script location --- docker/util/intellij/watchers.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/util/intellij/watchers.xml b/docker/util/intellij/watchers.xml index e118fea558f..4ccee125ec2 100644 --- a/docker/util/intellij/watchers.xml +++ b/docker/util/intellij/watchers.xml @@ -12,7 +12,7 @@ Q+ z8~-}reham}KN2RmT=cg)8hHq^ug)S{bf8dvNon7T-2&i88W}fV1MSc#$nsa4h|ED9O$Ziva~A((*T!N)5}rw zXxAUhe1#3K5KZFwtg!TR()&m4rp{E{j%fO`I;8$L#`3U$!yrt)kwq|y^vlD^VaInv z!c0CaCLd@xzLe|DC8{r7s?7|wqT^fr8gx20JtJ+t+_MtybDZv_2W_nm5SGtppk0*= z`Oe(bt$@JJ`OFo!3$CQ4LXX!!#e8Z3{!T4T?dPSEwV>4;p+Latv$Qql#)SefW@380 ze|igWvk$-s>izrn2lHRL+J-^^MYgtj9E_^*W@hwFXicl;AO^Ob&eH>^VyvcLW7&`N z>A3KEJEmb8Ja=KT{=Bm13ZTlFd)JKra-L!3y1s}sNXQE;UnCbyvp$%V6r^%o^$jha zG9S{gs1$-ll*1Kpz}o!4VDEJ&O5{Q?QslWdRITP!3^zxr3oX~d1h9S(F zY@b^q9W!#pyCyEYwEXU{BR-Wa)9+{^=?wA_au{$o`rY79ki#2!`7L*%)|v-u2QNN1 zRl{pejY>S-GN5+$I)O~XJ>(aZI%BdB9+R$_QBY^OM}8Uv9}~(d)J_HS!qEj!PF9JRPB_hrWLIVGr<2?6dRUn2Vf-P~09D^m3V;5X1mt zA}}EXp(T1V&ezWTn=f(4IAUd*jRp zNP$(#&kGOWnHs;GmLzT{NY`QDjw%}tU<>-__xCYOm?lV>$P<_$4!*m3Lgu&7H$<{0 zWo67)mc;*8R21Eoe5*c*BM=qlqxJMuUT-^A_nly{XNhlj89tCeLaa=7<#eCFFC2b^ zjHa}m6RvM7(!F;G^eATP%`oy*@)Q0N@IhMTq>UzBP}Fm1VFBTOTQL0G7eQl*A%Oa^ z$KDXSGP{mUCAE7Gm?|)xR(l3uz;lBcy+O+aMYFE5F)2QmeHDLO6dE8%-~lJ}!6Ax@ z*o*7n9opTUpAViIPG=?m&U9G_f0yD@1JP`u!QtW#!9>cFAObTx|W$yJeL(3-I0{gDmsEt{nLo}BKeW;>rse`n8!0b@Io#*YkP zE6M{ms3xJ^j4i$Yg3RYY{?Xr5S73OEfwpi{M~c?`)ztir}~hwtKx`4K~X3d+@avt$#Pv z0Har=oEBc5Ue4C6m)`fct5kZP2XHnlCKA9`5&5;jaPp7_?ATR>I-VM&M(nNF)?S3$ zVg`EOJ^X}#EkC$_vxLvq#5q=7$Z3=27wwfy8|`kT^4YwW8AHVrGUODL4JJU&hv5qk zkVFa}q9+WLG5rMPbg=eOpGb=EUi)5hryJR&Z$JXe4pwP|`ptN|BRFNqwM*?_o z8v|g4OGH@NJ`UiH?AriH!NjmV7b za^m$JkC|pm$rbwR<`B-^!}g_ZDpnNldaNHrGJwabBh0vmPHD0ZKw}E z(kG_yuj?-HT|XH9r*9y4GARDdYW^Vr|9$T%5*~kF4#tbfJ$_rgn<|GxV_EnT9& zPUH$eC9xCvd7=fA*cyI@zET8A`(dm^Yk>|aT&Dchfk``~>I`%}{p@$Jr2<%Amrbp~ zgGpVbeqDRLNcnq_*SDW}_e?#dIZQ|}oFWMX5IrIe$WX*qas@V=|7mRSY0O8e1sTIo z^FV92!^+W*Byf2~9$~}Vo`%3?Rl~@ynkq&K#IPc`G|N)+Aj&?GUhhqLiFj!BR78E& z`^!7xik#poYYc*BXY0xz;!rfpVr%u#tU@hu8RvhnIoMg|+fcGJO(}*iSaYraEHXWh zvHzNvRfWI}s!+mlAoCB(2B%9~^PFp|)qU`l2|K0)Yid+~@HHPUSk&G8P#)C1f`M9n zW@(qFpccPMr3H`H#N7lX-&)1EiYCRIdt|`EgG)omRAdJe+3sWT&D|d|{q0H-o{tOy zNnHr_rRj&=@!HRo8S3f#TM7Cs`UKA`DUks)A#=G(rNpqwQfNB@a**aLKlQAJPi*#w zgwf{OZtmhX3B{JH2woL?ty8QVYhf7RWw<*PM8{iPXg0(&*}@w;IM|8H+CEWie#-%s zO9K2qV%XlFwQcu$`1!CBWeax**{y1wEmI@zrQrBtf)*BnbR5)pn$|zMtqiTA#6Z9G z&3pXPwwOeb^r#UnA%f!7+jFL*G=5_GTr&>#)M$vWK6pb$4MU4`7nu!Jj=~wm#?pSu z;2+8cb4^-OS>_iO6Ggy*71XQ9a~#o*;R7cl?}Z&wVx_z6x=A6qSk%*kh%*;bCgjNE z2#`;Id9z^kF*K=9gzrnHl=g%X)z8W{#;0C!pG%}Gfsqh?P=bmC*RGfF&Wdmlu(&KK ziFZ;S>?r@FfXj>zYXzB3g}L62U92I5m)cEdzJ=oc%{C9S+?3MB6Pi~t$ue(M*hQ?& zGGedsmiN^d-6189=r=vXH~6m;2H31c!^ zldm6hn~G!DqYq;Gj#t1FoUP#?Q(h@kDDS z)psHk|LW7IAbQzmI4ZE+5IK z5gkJBl~F-PtdfHM;T{29fg*CJ-w@BxYhds)DwKAVJmFHeZWa{J@s78!6XSLhhC|fz z9IrdWM<~%!9B~hlqJ3L0*Z(YBn&n+*OVDp6JDx=qda&lTQZamqtvPWi^qo9kGVm9$ zZV{Plg_j0v5VJH;$Z%(kdkFgB4fU_LLjcuBm~O1bblclm`hEkkLOg#jOFjk#kHEk) zssKU!0GGc2m%{{h$RWq@4y9aE0MGgHZ0Xo)`9z9~!{X^KKkc{d(f50c`m|HWqo}2i zz=w*gj(fzbAD|(iPs$k2SJ=4#oN(6l($r|}bhr{ubGCMVJ@DZRqOF%1Yo!9_k1YoN zm)wsO0WaFzs*Fk9*vE7u|6Hrc7@od$>szAj#Eex7>#1eD6uD2#oF)1fwk1&!g^CcP z0ItH};D()WIA1^cUR?mw-U}z0?>rPEjGd$ zj)WW;6B3>T{*}B6O$s@wPbREvqZ6yT+a0qtUOJU3UNZ;kPHBAoD$m9j?|(%y1hq(j z_^{=4WP0@3--FDd7G;LUbqaooL13z4K8`Id_vzEfC6yx)H{FdF~z~PpeH3( z+A9}dKh{LZ9R~@>>ZM;;d)nJNTeUa)*2Q*!uMgK}5ufM`Eq^D=pO|mH&@7^wYA0y6 zn!^MUIhAmo3v=}|Vi8aeagjqB&=ah?C&fQD9fcm0N-^^G)cR1ek(8j)p`$ZP4$rUz zAh@7apnQ~I9mwce<=O&A^n?~i)8c|HL=*8WLoBWM(@@S5aDUFmzNEzo2DECi{aHHW z)m*0KGTIzG(>^|Vw&wUVDamcZU|Wik8 zMJdfw|7>+S^c)NvOEILnL`M1HVn?n9Pi<4A5fJ}vmkECI#dEe=NOSJY)Km}jgOp)W z{)UHbvc%IUNjSQ-;TE4SBJ-fq4v;x+z@SE97m4&PNVtwiMq-8c8v!0}i!UIkrR5g; z!&(Ri;C@VWGw7i2sAR)nuQmGWwT_o#i4|&D`U5LS79S$Mo_|ROwHQAo3(zGJFwDdg z;>apWv7;OO9J(*BSf3D+MGFim#P=}H!0V6B%_gh!@nLP5plk~roUKIXiIOKHG`;)6 zaK+F$(&l1?gZL3$>?**!)z}g&ylD7Dy?n-)8c6}vx;Z(D!VwHj4HfTQ(fl3oU?8~V zGaKzj0lOr~FfRYf%6Dz1VjGiRRUDzJ4AKyZF4Ty`jOkLjhQ^CX8W$CAb;4m zud!UfB_#ZmInTJf{H~AmDf239^utLy0pR{)?7b*H3;uG1YPR!WtEd271Y#23ZWlMa zt1K1Awbz^gZ^VxxN0trVp7{UoI>_o4tFJ-#A??1en zxZJGi<7xCPho`d8dz|qt&Cw=YhpXc}k%&cp_xDQ+v=_d9`crB3DZO4%h0ea=M{VjJ zY?T)YtZv-Pn*xgDh5sSgQt`{vDg7^A$Kc9!`CsSdRmkV@3lYaNx8rN#{zbb?eo#Z0 zEj7MrByqvdhzM%%AMm8K)U>~#21C%rRmFA?e*D5jRZ?0Rq4!A!FJ@>e_Ia#H-G3a` z8^5|TG@M<;yy^8u53>(rm#C` zErjrV+Ix30h>=h@5*7fxMPfzI*l-sFF7UoMPk4}z~P;)Q))o)91j*H!u z$!P+aef#}{VQgBGe-weUK9nSSvCrQIHX}m4XON`bu#NIO?xw}qlGW6}J` z{i?zz28JloeZFCBpys_ae-0_7f_-mV&mwpf|5qzhF(DZD5&HRr@X z?Xf;2^S&0l?nOE+X=i@83$eVRK_8~e7Lhr$F8$u(c11U}JrF~r)$WU4YBzPI{RM~9 z9P&+De7Dlv$$1z)#jowVSf$6cjMS$uxLkXJ;OY~Gn}>*(kJU0s0pd}+KJXd^L$^~4 z{*Y~3f~`dRw^j~yoHAVWfFRjFYO&X^J)Vc%Hyp#`!Cs{W=X8sf{WD5rZM+qPpa*v2 zR^RD4hn9r1$*J#0FNI<(7umzd*k|tV`T~6o$F;W>q1U}%Yi2`93MHJ~KBo8?Zr1uU zn}Kih_h3>Bq@u4G$iFhLTRo^q-xW5qKs=I*2tOTq%KR#L*U7ZVZVr4;*lBgJfzScS z6I}T)*e-+XB0tw%f(odb2DHIIPvGlM%=7tVd}<~OE?Ct~R8e+HE<@y9=i;l-ofQn+K( zSkA`no5(ov)Yhh{Ms`2S7x)~aZTi}B;eJ;_46r19G|26dp_9-5#&PWSDAs=HH+5FN zCVgu&Is-#=_#GcT{rVhEweYF<8FI$`$&xn*6pG#IDP(w{d|-fD_$09dgLU)t78y@Y z)UM#2Dtyg!yIR3!*&e!4gP#g0!V%VMv$I6v^ljSxA^%fGt;w(WYkRDB8mNTGGvEbU z8GM!HH6NJH%>7+MJ)09$)1mbCsmT@OeX7+Rq4X&{j}Ya0H`o%$;An>vqn3-AA)$=65m!Skyb^GPxwSJ7o zL+4uuW3xbDL`J;Pm(Iazt-KNm*SUhKLVfgrP$?S^J%Wddg7sNn zhvW?gLHv_DX(-0*0;P*({HW(USYFx&0^wo5U5Hc)vo?xfU^q%N@$E zOOjTjzN?n#XUJYYWd`)gunag9h&5ckawy(kpk?4FJHeS~HZ)p8Nuo!O#DoN9CA2aF z+m|7lBBq9fxZ|gExQQsS<{BTmQG)l2#p(uJ0W`47^w)h{lQ9Zbtskla4=9D{#>kes8o|J zfUMNnZDgZAmd<_dbaRS5{?Sp9%}Ag2QI7Gj{DfR#2>@9=h`qpi4LV^<@NN^3V!5spD;O-FIJ-E9C zcXxLQ?gV%DAdS0w({yt?|GoEn?zweO)vdRxKeSZan$KEmuJQcl7_|pSmD3FrB5x^Q zI^=em*6M*6i*+|3kjEBQ!?%@i8PJP>218 zq&Wqow=1vSLz-L{?|ub*S81H(KimFoyEqB{uCt9)4$MpzL#Aq;ASUL=PL4k)HqAu& z%uOuQIzH}689oyrw7}f_>#!fTnYl4xZA7$kD#qnbmfw<&&5&touzXcnM6e`bchG2!x?-Vg9%d%jIW8)zO@8mTgM;ySe8llRa)7kOt@8hIRH5yYBcLmWxH>7asy+ z&JJM;AP+*7gb`k)AGvZb^#Q@yG~I>!}QynJx5g`ViCz>>m46_%$@!a%vu{96mZTG{NJUBW5+3 zEx|^jDahoyU*pYWO+W!pbF86voVSj{_z{DY{;%NZa%wA1D=DAH<0702ZwLwgAU86% ziK6fC^(Xj?BVvF3VFdU4Y7Gx>XVMc;iqyLZCn*JK3OcIOPH#awea`f^UhI~C4(SQt zfLnyK@!iDUymcVW)$(1OVtZ9TrevR<+HHR)g1Wg@VGT~6q4r60ft;(9I1_yQ_lu@K zimdspl!U}#JPANt-<+BQbyq)klNUnk^h&0`8z3fP%TFG?{x$2x*}Kn$ahosY$9tJk zXTw1tzY)I%!3NsM_wPVT{S%jC$&EhttkESHKfai>FD;#<9v)-vB%W4ph6w4QP9H*MD(z7wV3aY4y_!E+pTf(putw?kVdnpEpJkYEw<2(QTsml811ZYf2zArw z-A_kAZJrCk{hzyo=Jw1;h*k-hCcjPck#F`ej<4;0qlj{2(9X*cGV zggqBP81}fAOXR1Q9GF$;iX162*_h~9VdE}IJR*>1q$a|$AjMnpVdb}no6543V8J%vd#?sOBXYhR z8TjYPqEw+Fzm%FE8F#dYF5_L%J}?%q@!+_NZdleiGQ?;2m^BxCoGv zQy-;!H!~_TqZni|oQFf)r6~aw*eaNIjpuklnaPD9=V4t0migMLy`R(z;{xIZ#Csz{ z3v$9zowN87Z4(QGpL2953V{d9iKeB@V=k>1qv&aZCD~z?hWmq$#e+<4^Pf&7Qfg#G z60IHfHxz#8B@C;ZMT9dU(kFjm^sUCo|XA$?dT)%js zJYC&OHOf83T)LX2w4JIuJl8~>TuOAj>AD7hY53U~WQ$OlY=uDywObiF{8)DJih&tU z8}GAe*PDV`Z`pZbmAu;^auYAkNGP~IV?}n|9K=GI3b;($4Q;!Ym!5o@N}!~&lPl@? zI47v{$b8xAc#P`QAaz(xj&KqnD@F;c;(1yR9>pkZqtryxM#z&Ha5&dc7>GpHUjoN~2Qc2E^nFeu+Os-tl z3w`+OY#Rpz-jv$6>O00ebxX*lC1*Y_$R4Z0UAy_O?oEEGMEd+4@#2@hzhfm}+fMRJ z@mH7D<~-cIX%zP zz1!PQd!=y~Bv4J&z8W#`?6~MKE7Pv%3GM?KPQ1#Gi@8D@B(fPJ8kXr3pjcC&01LI8 z;2{}9Dp7w?CKk zGBxZc3Pf7zeH-~}58^UeNPUQZ9?V3I1o?)%k{+{ov79dCK|td{R5t&yBbr-hO zAF)q7G0p_3YXYB=8PpMMl2GPTNSaRts%Oln%HeNbF*@6O;8dy%&EETr#cAt`mQDAb z%OFV@nyWfr)e;VKIKe)uAuAn|u6xedCq4B=PC+a#VLuHL7Rzj~6c~v;-hYWM9kP);LDmO~vJ&p41UJ=sy z#P$!}a2xoS&wo}H*KIc}^Qz*7bxr2g8$xTjc#C9xM#1>})GxkD)I$Syq1E2Q?xp1- za=d-yrFZ;JaNv=7{R`ZFs+Dt|*KOj(dGg`1R!w>M>t5!p7X~2Q>m# z=Myn)5=ijj0TK0hDY?%#!QZ>aHy+o1UQwkAscbbp*mKd9{HrU^n?k$hQZi-NFE`tz zPciKw$F&@!x!YQ|T6&TKY z#k(NQ*@Y4cMEq&*5YUw{fFF1HxJ`k*Ux$3kFozLXEviK;D*hJiw`dYCDfk*zR*7k^ zk|weF5{(~fuMiV6(|YSev>mLSS&rr2G_fy{nI6u6XbWUl_hi)3UL3GjO&@P;*@Efj zhh}EEV?_a9s=QLJr`FX5J_h==KtnoTC>4a;vs4KDLmqYyS+%?}rARMXZfVzfb8eED zndNeG1lqUwT!pU~D^WaejsnR|s_JLU6>LpjKf@+yTs@=YHn8ZsX+6Tp>wzc}pT#lg z<+h3sK$?)g?_65Cb7P;C?0;2hBx4olBHr>qQo@mqYp9sxbh))e8= z3B7wNx#@320P07b7<#27+0p_}C!CLQCeo8@uO~Eq?V~NgZO_fma&BDX2Vi0{YXrD( zbjXiYh#KwcE;-~MmS+hXQ`e^lbBcb8rYo7aCyhnDc~r6BTM52Dq(IC0v7TMUI+MB- zBcT!P@d4ljj6Q{iW~hdPq^Quoq#$-|rXFlyC-^DNGK)OFmIMP1ugYIhL(RMTvs~IZ z+Rw%9g!nTbxev14@@tJgp6G%xRBAPV$LAh4JiC0jDqojnX{n=Mf{ph+eK1K7aq?+s z411zxH&Y>om-EW4bb&!?$eoCHvc@Yjf#|VD*kfOWAKu7xzj=~Eu1Wk&sU?CF~c) zxT+%$Gkp77H!-IIa$VzhC)O*UNL2YCaQD+UkM`5x;Y@JZJtY*(YWQ7HWHXfr6yTk1r3&dFnlCg)^6ZlJ`e|H)YJg)NxfQAI8 zkjD{AHaCgjve&cyelZkr`$$tfiOsfTCd*l)CkwZ}3ld;qlXENi$f1$SdJhSgZGA*i zKjL!oGTOi7h@Jd#OTQTb*^IfK?xlQlz9^{M-VcxRJ0icxtffU^rR#d;6gC^J%Z50!l|126ga6zrPqebSUKx{88bW@ zy=2_~LhN}gO;nq;%uR(Yc9>UzQE+&fo%?G0j>i2WnQm)C46tv>?=IAcR~%WZ}Y zpoJ#E0Gk%TXEJSpA}x=_N^$7EP5eJ@Cv|DpwOl=`_Lf6+a^2%gFHhxK$73sI9~K*S zc#_wWx|iK3*=7)Ww3+Ze*9n%W&`3I3hDOXiwnGlgzAv&Qq%~zq(v^A?|DIaEU4lK3 z?@1YPoOZ=IK_eK(m?!AoOgpH5l^%&eYFLe0r3|7pX3J#FT+c`6-3Vf(H zgg;l=-~L8P{K{Y(tZO?wjZjvsZ0#RC!}SLU($5Kx0&f8tv*61l^TS_M4BF?U!GyNK zv9uJO;W6N{z{P(5LF;-X@p#1vWK7JI8CpJ0bVq)cg^`u!l&|p`v;04B3DH} zK3n%PxS8fVhXCe>kNZ)7CX+-@pW8AVcJq_JdNB(` z7!+Nl-IQ>?*5YuoP|h}<{ITn(r26n2fJO9H)S9SL!)CjAbn5B=d{k{?3b_!4{rVMY zU@S)t0Z*`s{XTW*M}+~mpKb2QlaQRIFWW~MRnqnYI|DPDK?%G-f%cP7Kas_OqEO5a)L%P6V;3fUAO%CmFrNt@ z$4|!uwAHB1H2z>7!X=_x9vo4Oir^Y2S6kNJuT0MAu!H7jS#nN7_Q$9Sp!tZ`rjLJw z8I9*$Zennpb`)0wEFG${v#h<#l67U*wNha|eFNfJWWA^q50VLcqQhC&XD^_p{-6=; zohqOIs4aWbPZ{JoF$4gtDRo8Z8v?tk{6aXQ_udb_L%+$FAVrc|{zX+jP~)gKT4VG4 z%2mvD-#5>jSQUUN()Cky__eE;BX61Wyc~y_{h_!f%7s}SOXF&8;!;wPeYM_QXxsQ= z>zMa(*LZqsFNOtZvF|XvPS*dV?#Ql7(h|qC*%OcbrPc<*Y?(YvD+CW!MhKJj1qY{{ zguk_&a*_BL6Zt-<8nrNPgD+zg56E$xF!Ehal!q|`p;y=9+$-J9{oWvmawvc|uoO@e zotq)o*DajZVuNB@gR7C$J^P^ah7$GY&gLgVlg!bB$TcmcCY*+S^g}-@@}|achd&j zE_5tkXD>y4wfoAVOJN>~)a3Q+k!5GrWXks_*3#w!r+pKq6;!*}k=fDMUr+8r^t^EG z*4@nT`qtAMh7~aywKmYamvuY0gkr>#peft6^4@fl@7(q!LY3=pF&BW>>R$2ANJFm` z>TY&f+N>vd^j`8lN{e7haQpTpMBC-!RF-*fLUjc4rsxxkI_bs#X#dxK5e2kS1m_kv zk?AA?evr~95U7KNS;I(F0GcPA1TunQ?8-4Yt}B%FIFXQ^V%noFOuH3D%#}+U-o8+{ z88lWZDm6*<@Jh|;j^Sm2+9)6&G(WOmk`vm?Ln7knNS!458f0I&e)YvzBpvF3LQ2E! zg>$r&*#uiJ+g{C&{AK(3Hx1R#r`s;Ux+}WNlW~?p4{u9!gth|U5QvHAIRzM^>z@Yp zy}oVZ<-Lfk$Wk4aJzSHENhNBluO!O0|5V+X?kk#%*t3`mFBNhI0lkPoQUB$zr>$Ow zUy>JZ;q8Gx_V>_RneE^k)b+MP#6&PEQby&$yl}yTAcw8VTVc!F+RB|9DZ`*Nh_b>% z_Z?f0-iSE&HmM`zGOTr8JA|Geick9R#UD)Sz{F*yqI^*_81?EO*S;MlcoZ*QIFohk zJHapvG&#hfl5wZZPuTT<;baJ!xNGX<-)}%ZOvEMC8m0!bKD+!ZHVdO%V!8FkG)kiR z?w+AGi0y)aj$T)P6z)(Z!vx=k*3!9&Gn`VJhP@E(m5V10nJax-;x&L{X)bMVK&KiL$J^P3;DF9k#J_!>Bh;X8-1T9E7&dKxfpLq-fN$J{~Sg z#ruinYYn9DV_pYeZVpmV7JmbKNH3OqLuAUn4$E6)xX!*+_m3vzPJ#FxCr~l!)(=qK zWwj>KXmz+&gLafpelgj!JQ@znlsv&E_&M3N7xTZFqT{tX`_^0rZrcqVdXn-d5?k14 zaNnO&*ObNzHwAxV@S%<=2A4P4ls^&Q`#a>sBr`KkMwS{ke8kc$B_ZFRG>rG(5vac* zCPhK9^AgnXaL>Vk;SGc&k`~KM40~T`Adj%spFNp`XsoIHs~hwbW|^f26hQCkN~x0Z zM$jnZ+mW}%iP&sPJksUgz}1htKV6dh9sFH&vp=j&Wd`MkUZ^MMKH-CZSFfm6@ z@jz=K(k%eGVVQqHLzez!$`C9gg{mDQoe(bvC8p4roprx9>7Q};R#3=^JiS6+`lspD zx*mSqD@tW);d+h<5UGmb_~%*Z__Pv*NQcGy>$e_g5{Y zA3FBEQhXbdO*){)?q3iH#)hN5IKGL{V8LXxfN;)qs(|-S3w-s0prT4;Qc_L)d z_LhP6O#0aRA$9VG9IZ9^AS>v<{7*;bfwNN>3|+SEflouQKKjYc<+r}0KJdor>Q*An z{nba-b9>DZVZ!P~B<7FKOo_v&i%xn5leWs~!W$!G0d&n?9xy!(+?>xs{~fpO7Wg=!xwB8z<7JAgYh&uk3WpsypF4r}KKt45_2w~TVlZZt%|qwX@@{j55KD$r+Lnb0W- z@K*vRAFKoaG<+x2b7fO?xRVfId$f;OFhM(;-0K$7n5A{aqVu&qUh7SLTN%5}b2Bbk zPrQhhFo;gtg!qpRU&28c%CDvdLV?z79~@@T68%D(jK-fv%i$XqAqf{j{?389g883E z>V&x%C@}3ciH#RgYubm2qI^GguN3Eedx#LK+1`fV z1sLIMaXq-Yv0(GgaQH{`ythj~uJOFk>-ILiY=cXU_#S&8$ARWcA{QzaPm%K<765sV z)O>sj8@|aZ&{Pgt+>@`vHOoXZb}IPw0fjDw%h}SL%2Th(SkVl-$Hs1dW>nDeC;O*A zGi(O$*Q{Df+B}1&v7}=t;l%vdLXHv^Z6#Knc*01w4J9d)8N1xS?Q6td@83CiACuH3 zC9mkGHW-fu3A}DCm6jBHEQ}@6uJjokeuAN)2#gyMck8{{-H;|ll>Kn zydKX=bUPlR2n171WpFiCf2%PyI$1zO`uIW(kvI|^XcJ%NJuWJFCCvi+`>#h8$TtL0 zVekRkAKtCbOHI=;6Qk1mioBB)-^0ev)tSfqk~b)?m(%njQur@jlZI4~HsMF^cV*>U zUO$GBrzK>XJlg2HKu1xg-rz7egGov9%8~fQ(OP)J`;3_dBKb)Iy1fG^QArmpL#%=# z_YR&Odmr0?g-L1HYZ=2W+!lMS)YR3`c`6PynnM=;jc9;FkL+ zDrVu+P-Ej)qN&cDrAcodr4~2{tFTkOb6|w1`|^jV?sCF=*e}by*cgGGlWPmns`W3@ zpF-ucCCB@7uhz5rO@JIl(`5+m-m*e05PNhW)u|<&&C{6+8qScRJ^KhJ+-2Y2(@=f} z2DB=RD(J^kn9UZBex;ghW#HzzZL(KWy;ygEa4=iB0ArcUVv5?-wV%xR|xyAsboCvCecH>63JC=<6%DxJ7?1ihY zFRq?$RSH%?uGkkDyNhlGg(VG8cCp1rPdYs+pV+Kupi%=-)usN zIIy*&yo02KOqH*`e4YQom7Te1t!%>4w1=+=ZQ{tHH-|QpSI7%wZf?jpcB27@H9^ZF zq3dfo@HZqedHL4V*oohK`&e({5!pub%BNnU|22x9AE2Y?N{3JbJpsAut4cRiIA^a; zUWcKD3GqsbDEGGEco*QY`|y-plI~vUW7YvV4i3!qOMB{PKiJugX3u{!&|{7E@|78| zDj(lEu4TV}z$;-4CwDv4KO+#%5Q^?TSdfB##1Yh5uVfjjM;R~~M(k9SIJuv6Ye=et zExC-~Sp*#jX-a&1k&1EL=jrahIt}nU5;K?7-TyRDbc%nvIFzF*9EzvIAfy^ zJLc(ALYJK`@0osTrVhlj`qQDH@xjM+6XUUi)srqu93NT2SG)-v<{KK0 zHIyY_{wh?$<3+3zqsy#SEg!!-;3o{c*VwKvRdk!-2~AtN8X9VJglF`1CIWMCR{*XL zZo2ejJ6t}|rA?SkP#Lr6N~oP%{K1bIOvl^oV2F3%=V4eb1dOmY#^_AE2rKZL@f~TM zt$yskstlbiRcGcuY+r|apccx*{isM8GM^`c(INjaKXtG6?MgU5UJxKU=;%YjNX<0L z)S^CDJ}qX1mWXH{CV_bAfyl@;6$6iIT6fCOXsZDH{h7jUm$f9?iFEG6n}J&SA4!vC zFW=^a{z^+;SU$Cvk`pXpBh4HI)4w0m;V*R1rLzjh z6~4_7aW9u{{?{Rs!e~Z&vZ=iVC*Xb1I<5w-hZAOc7~43S=9^-1mUhci576VgVX}FG z;S(I4R@-{^P7h&E2A%Ytj=0}5im<=x&F9~ILqC-T7qe#3uT1K%(Xe$ZV5Q_n4Pq{a z)wB_&;ah)(Sx(Rd^?M$+yhZt`d;NBnJEq7B%)*N^lbVwv*V#iq<-lg5VAQYC<1}9B z6JBp)UdfbcV@-SR>1uSC(KRq!d$0>MO>`^fxRl~{5wr)V998Yo`GOtTTjU(HMt!s1 zTgULiSGg-)qA&)LeV0#qUS@T*fFXp2m>u7=*DI%**`DUx%U*jsRKWh700AvV+Tc#; zx^sDhaRrlMc{2aWwv{!_#n zM+G|s+Sh~qzM!k#gXs4tjzcd?N9G_`0F@t-@(A9U5>xf>M~&pf%cqd+AflIxPtMR% zPyBT3_L(E+2UD6M{T>Tw@-y}=L)Y+j$cXFCmfE;tERCutG)>UE0l)L#ah^JOho$^g z6sb!5$Fq{M?%a&>bb?t-K}pZM^bXCZF^#BpCq|YHB?Qbu;CZA1&}w+qvGjmmgcETj zg1n!K-^+}e*E8A)MUk#KSEsjbQyf>v>^zAphsA8}Eu) z$Ww@w0kAikeDMa&^MZOavvJgi)nNB76t1(=Fkrl%<*9d{<+t&(rygpL?~_1JI|7e~ znlE})c&66F60}K-z+;K;1>ElHI!s+1r6r=b`)B_7R2mN5ycK6q^7wO8+;8|Pg*9xR zP&Mk;o6PgG7}fu-Mo>BZqed9_rDi0Hm_2K6X5ZlN3mU;GdYceu-VGlulc!`5CusIe zM0UVB@-+3ENV?P%d9M z5WsQ5o?}juD>*lis+D;z3kb=`kyaP`O7Qf>k=#F6zsoaN8mBV}+5V*3i?$z_NC&sw zBUUpX$2T~8)Zq4z}q)`W?Dztr?l9deN25~=NUL+(aM z&rTSX?c3Z5$R=yGrr_8OcM2QuT8puJGIViIrWaD{;k3<+43p4&vo`xi;N|+Yl||wc z?dRB|5c>w^uL#cnryP<+Fx=)}$ zgRyDK(!2hW8cNv!&hmWhxO80;0r0XP%ruKn7K4oaFrUS!@Xf*}3H;`xzkO1o9-Mbd z^TXOA8JHJm(WUdsRaZ$LBjx}Gf$$C}b!mcqk0!D~ibk#0oRP5(%AI43or zlyi($bC}^1R{>8ce(DUAcV5UejOm$)sF$k!5s@ClMAOjMqGA=IRfN;d;xeZeft*z+ z*(TJl=NUpWoKkl-y}S3sZMe1aMzX`)sqaVLaoZ-z_`hLiMA76ALF)Ml92_04o7qw@ zMI31M8~V>XrSzp#^*fVpbpY45Ey6$Ee$*kLY3UqnsC@W&2~BGI=iPm#(z1UIAfM2& z=KsYpLnWOSgunaTzi$68T1}sy>Qgnu`GRiyA<*rgi{h%E|Cnf!Auh(rRyV(GZ8kTC ztuR^8T|9nWV}5+rz1Zhg-Z<5OLecII0Bd1Z3veu=Eva+|oszR>1$(r;UEoe(Yb^z0 zpkhA3Tkw%X_D$_Zd`H^Le#%ErfHC!#mjpF_<>=;h4j|4Z*qxlT=aoRk{!&(RbUHyb zs4_?Mx5{#;mz_Obu@hQm;vHdP#(sUh|zI^UjquGbq z4gOr?JbB)Chrjyu&71eImfkX0l%vv@A-v-IS9`E@vA2dLginEFhlC+n;w$qR zFnxf=)2b(FL0wlBr7KJefQszfh6en`G)-R+GRKj9+1?|76iWkwtB&`G>pnCn4ORrG zj?0EQARk9oQJV0Dl1a0pY#{V*!*SK0F(0e`ruCy!ESWVxaUmF`&5(!uGK#7Gm1zD} z#!J6lpCwfu=Y(w%)j!9=7=-Iu)qeP-mkjs{eiK;xP-x4uvWWYy4b4p3A?8%J)xkAfta1 z1TsVlfs?U9+8uZ{i%D@F8Q|XYDRT?pak_Fw3W1`r#ACpN-&;rvhtW&Dd`NGgmIe~8 z5;YV0BX@%ctU|)7f0ZH+O12D_6CCFUQzfI-UMN;Xxqo>8$WYcBNypnzFnVl z#4k(Wu)ZD-5-~rl`@$$2puoqH4CbM|N2Cr@>CkBKUcDrmek}3+CXhNkM+m2WNiUVp16IE+sKPfG2}Zu(7(RVu9pvp(CXFkI6gNcl>}`Is+(9^EAqNjLLGPINwc7fP;{ zL8g@H$uYI`u|H_gepr|edjQK7`I!z!h`9@+KxiUYnl-;BQ(5U7=es(EpZV~$rylD! zH>#qY2~FN}Zw|jdA#f!Yl6QR3duXdYG-=zRzPPa8UtZQoG(f0pFyH`KZRwQB+1A_6Cu7){Ty}+RXkBinj#M`EeCl8LnVIXI(gA%$HH;VNw%X4y#w%^ zi26V4hu0K-LC;dX&OPU@Cq(YqGw2_%JKbVm}H|x`v!*=SRZSvQ&38_cwcy3`g|3zupvriP2eCUbznh!SqO;Z)-?iX%j

    O8cBKH;PQww?~k{r*m}PoS`@?Vm*2n?SG5`mQrJ}FXFdyHPyCxp>=i=ln8 z(G5LXQVv76T;TCk>As2<5AIXXnqxQa<#nvk`xSd{$Z9On1an82WQy53k1NbzPxp|0 z_+gFvQ3Y`a@}QNt`A>ptgong@*dk1<%wAg;3ME?nMo+XydT`LxlNAMmu_K-$4Qe<$ z*)k;sYD_IaDnjk;sjn-^XnwbFjsR1O z^i#swy8QBNRTAcXexML+8N&9)224Sgl!Q-Z!w)JH7JpV!({dqXT;uQqH^T|&lJBQQ zVQa_Di~4Q|i2(wQxp8q;$`0?NL9GV)L$o`7URfds4i$2%$0lB?pUlnNocrz`UB+vWWc53 zOP_gsVTu^@k7B!N=y*=Z0Uugj@WGJ>TUk68}lNwU`Sob;y!)#NES zGaL~mbV1i!_!Vo3Itv8mP&NcAAztzY&T_jH>cJfGrNN5Ewdf|yy+x)@3_Y3atT00m zckt-2F#R)4=Hn%_nhvBT7q@sy$V?X*3OVo8`%K>xQ}IV8RwSdME!e98?4l|s=!QDq zgmOlj%P|T_(ew@*=BV%;S%@znfh$lH8QP_A`EwJ zAeowIxm~cMJuG}WlV*YvtT*`ObuZtBxzW#Q;H%Xn)zng$bSKJYjaf#2bFv6scA9I; zJS{$a+P8;#GW;Wi?+G9##r=Mo%A^z3K5bsreSpfx>T4`eRay#g)0iAxJOx}!DB zTnx?=S?apAfTrG>KA8xI8j9aUp8TXFmYv50kXhOwWXBe+*-2_414A8EyQ0%7yk0}H zChSPo!BGS%vNg*Zq5mB{l})Ywi=J+7j^0poAKnly1AeBIV?HKI6G5#yUAtH&JLo81 z3kq}t?7P}^NEDAzxCVm6{q<%C>hcVIaDK)`=vd%Qq_cU%ODz?Jzg z6@H4hpK1gEJ>!xJZH}VDNPo^Ao-{dYvR!#v-9+hh{~<(|N9Y!HD*ODB-q|9I@IK_@ zC#X^BEv)i>`N}z)5c4Ngajt-qeOdIcYT3SvH+CSIk@{WRbH3kHXQZ3^ul5zs5BKXm zsLw69cM}%P#68)Y#HWdW@`yt^4loW~lnFAZ$r%p0{OLMzi2E9Ne$e8dQqks`T@v#U(|0QN_A!C-7gIeeICGgoR3HAW%r}Jz zpu@{4eP6t@H(Te4jQoKU>aRsNP=G_Ww)I05x7@l%=j;r-gVvmf|xyI z8U>#HJjd>xWFFP)(95L_YMVL62kCdq>+J8=T1c>=U zHuBbxz*;TQntY7SIvaO+wqP;3Cml*k(saJB-WD6H`_ip7iN2cswZ-Xw-V@K;b_s2> zj_Jc{y%}9i-Zu!D@jTQIS+>msjy?fpMyTUtd}lkuFUwyx7XVmVCA}6NEY>(m-%nD$@`Gf1h~j2yP&~ z*^3K(lJ+<0vq_j;sQ1xq`DlnzC3kK>I$_36otpSP)&whpB0mj>l9DlB$=Qm;c@xQe z@R%@3pTGZ_$6~P*_x|mKrd4x^+u>(S<6Y)Sdmpt@d)1z?8!He4$H`nI{2MmuEgWZC zLeE}sVc)|oy`M2oiN2QFM)x=Hc$uHq*J-2aX1o(;;%~W2ZD;EabNegiGrlKU@&h=t z1(#nkmacj+z2V*t3k;0dZKu|F=crQnIFvSJSi9IWK(C0~SZWk+4k+2sO_k$R70ue_ z3UD_X?>oU>frTpCyO7u}5L#@(A3`2T_G*S4dDn~xB3Uq6AS{Ken0PNTBE7h3gr^cV z&Y98v*kWYC4-t&3d-@d&kz+N_FflTWIj_~plyr~R6}c5gDOXF4-?ttlIbqrCr4uG* zZoW=aS%$|6?@{q~rR+B&t(`NUoWr8y%4kLF8k{!t;2$p~!5(2!O&42_Ooe!xg-9qd zB?hu5B8Lf_vQpPwu-Ex!bvGT0IrytpMU23h^A_PR%g-ph32?0tlgS$s0j!jK>!rkt zAs6qvdDcf_Hw}2}kKi#~`v=O=)(|<@kVaDTt6NSMR?i8w1#X{dYvGc%%NVVeTM%iX z`EutTH#Li&Zuq zbAx^`SlQ4%`w7*EG{pwR6(&Q`$xRzoaD|C*&SQiC>odV zsVLHCzvy%HA0X?Z3X>WKOxMD2J3&fHx&HY4xSK?Cp3Sxtzh5db4bDS0j6v{M>j(-4 zN|8LjyztpSUR@{;-{RjS@O1aqLpyLCZ+41 zC^817ENkMk325xxi z7jMH;qh1xk_~ROct(oa1$rD}hcQ86h@6OmK)7|f8)jXWxQ@pdxKY);C7XRH^u7GpD zki^xG7imu)s*O!=9+?f7ZeXU-r#aQ4{d)XQ9&3kgd^7}9aGx(LpLu&=d3wO}w5v_& zdm^7KGC^+vZDF;oKrm=^1$zWx#b^2U8@0F8z_xECH+ z36C7TBf@b^6p{7f&0_iHJrPhdeZ4p@wP%W>hEGtmUv2b<;Z-66HgxF|@CgY4T6bbk zEBNbfMwrvSyFT$-{p*pq2M?x?SS(k@G3HFVP9zx+*cAN!bcZJby)-Wrev-@qvF8-Vw z*qQ9j^MGPSV00nS8sYM1{>~~@RICG4efrT);~j5ks|7xNpt=epl1l`yx+Zu(Q8`V) zK~;d2PabahmxCDpEnS`GO&Vs~X^k0?cCPGrfZM#yZ7QW#^JtqN6=6}SfUPWgRdgU( zmWFm{qAh9o$emH#ZFO>nAAWE{iFGgdQg-hd5ou9N_D@VLaQZT!2W=bY3a27nRa{E1-xDOW?gm0u?w08_E0f7Z zu%mFk9X@M*i)X=Qz_EPDvPF7nTiQQWfktBrezKxy1AZ;W%Z$5P!=4OJpnJKf>v!0VT;gAQ?UmlKEA zrTXR%g09j?y>U$m)0=V+o}YF12Qn7-HXdQ%P`IA`dfEI>VJgv^Oy_XXjb`BtCv^MG zReGq@^8e)F9Fl+RWRGQ??i|W`gLdZ0z9guBdr@Vp`9`-85_O_8<(I1?-&|1l((vlI zu`qiFxFgahb$NqaUb(Eub4B8aYg0rP$MtV5Kk&ya=5(VTtVxipO$$%K+Bf4E)*$!? z3jQTj24KexEsv_A*Kh3*G#N3T=X%%(;>CMW>7%a{WrYpOimKPl3)-5`S96`_tz%dq zbwzeuc87KH=jrYc;@GYcHf!1s)LsUruw;g)D8py81+4;gL^ylxZr2Yw8dn=fk1Luk zLi8d}Ye0q^%YXb^M0oyMSW|s*fgb!P$((FM?dP-<>pt!QnePg==_gB@IVO3G=Ut&c7t!PP-1hRiWYL!fHwVIHn2IxIT`BfEd=m zkR5vH_psH(g#W$ZfL)7j`)PBR`fs}?mHZmyi;rlBA-daGK3qz#ixZuSJ z{Ye##-b=Dx2~72gj)UCSMx}+mMxW}@SO!937%&MF(gk8=?AZU=URN^js#D`qVjC%n z3?=su=XQ&UvRwSHK5i$!u@1RP*{&-ZqkwKZbU|Y1;XhFWf&9(bFMD@j)8(k5;HaZO zi@axak#UcK?MzNPt066&OgeawEhec$|C}kLx#%)Z)74y3xLnY0imPMwGVM+M-aB=YG{-8I-U8zZE~fI`J?77G(A}H_rf0jIFS)`<))=mvzCRjwKG#F7o7Kq9T>)_-eYKXD*?^XePw5Fd*WPB`tawlahXf8N_Q@J1+&MleY{3AV7v%G zXt-F380SJc`<@*31@-p*t~WR{V-S=6B}RfKo4^lWV)E@ezuhbekJMN4)VKV){zAvO z=*+dZLcPEsNi_-Q=xuy*K)m1j>gDoJpYVGiY`b?%OpMvgR+xp4skO3-3N%Bcpe_%_ zKSiUNf{QxlTQtEh`&XfZ=}Z|ryBY-~KZOq0i#)l^W>f-!B;f5q9xd*HCBxu>(Q7H_ zryXfD>%bQX1a?e5<+A~_gZ_eb=8+9 zGdN7kA9S!pVH$*AuV1vP;rrr7^&X*;usbxD7TD9smc&-E3{C6#=QYeb3?Kr`|)MYocYZ zH{#M3{Z4p_tx*g?`)=E%)@}z=OID6EGbo+4yiUa`{TdtLh<2ZuR)LSg=H`j%V@7@tj8}=IkjQOvB>1n zFG9V2FIY~yI!KZ6OYAS|#o(L(oZx&1cn%WK#9r8aiI{V`KeZn8Z%gH$!FW;%K_>zS24X2ti@ z_7|!KWeb8o+QM8Wt~sW!zkE$s)?Q?Bm*eOYF~cW$mG2Oe+D-4z6^r`z#%+GCgmR6U zu<)E2a_o#Q{u%G()qfEtYcTTGp?GUFT~+u+i&*m4+2^m79rnI*m}{BX^}Z&^=baUD zrja=fv+lK5hWd>Gjiew>Y~2{q`HA!{P|%!j$cN}v zjWe1q!^E;1jCKB}#`Fz3fGtomOt2Sor$fL^(Z$s=$rhY#x3w@?Ko&$Bo}+hK@wKHh z)E}p?CP#pSBV%s@-Qsjck;QrXA&FB_;0~n{f=uwyx4&7L+|v~#I{YH^XKjxipW7On zocQJYE+S>N%l@!cg2-Fk%VacyU~~Q2C5iI2&;cF z#JyHGjD<0T(MGf0=uAiD^oqkqZGiohHH*qF^E1iDU~6N!c9S{zz#hHj+G1kWdrCSP zDw_dp>AC$E$!T0U9(jTS;VPw!_j&`<%ow9 z=uySo=eRNO}zLqQ#@}EM)>GvP+ix^gu&V{}^Hyut*zZ-M!Wgr zuHfjk&yXcNcPTP5a#)_`SC~)l=UsT7SQJVUd0qCOc0t}VN3PJf5cXz8C?et? z9Ut7e!4xw}JI{;@V;I*ww|9&JV!s#MvgrY_qKvEA#Kh8KYMA6y)GcsyvH9%b)aMSf=aNPM|dql3khOB+?DaQ|N6 z9B@X%?1b(%8~EMck8TLI+oB~d&TM(by?ycROzjH9aSM%=_dn*CMagxt{ z73#*``)~@V>AV(g3uGAKu$oTtYue~u?`SJ81ZQX4bRip#)M89`-B^Dr=g*q`TJ~CR z_8Py_R+^xqChX+;rq*llHtK-0zYmMD#UQH`dtWuKDFJ=JPoy!n6m~qQT&qM-zS^Bu ztYO6P&PTCYCYnPAjnS;1UN$}NeV%gcR{P~B4Vy&AxC}5h8$mSYGm}mzp(4FpEyXPD zzSh=~q-RENOo2eQ?{p%<0+iV2L3 zltN|iOic09X#-q0kbCxq$M=uO7f;)GV04yrileno+Wt;KgJqTOrW842h@TQAN$?e1 zgfU>JGgd4ARu)w@C5ZErPBgB5 z;zg!K2dYex#7k1?uNB=!GPC7Cq4Z$>j@wkC0C(o`a%75d&Ie9Won z&}*EMVH=$1n<_LS@K%*|ltv({IuypbW8sg*ZY@xn3-4t&sbS6keC0+_hSrZTsf2^$ z`yIX@Db^x}`n7?KjZJ;INlJ`PP}JG;2mar0K&brkHMZmA^9Zx-6XbaaVe8Z$9=>v*3{nP21X?1vt znnH!P{JJl?QjH<`Q{xc5Z4ri6(x?`jN8973Ms)3aN!s1P^WFxzW0}}~WCfJL zU#@5uw9XH72ViMu5sL&b{jeFN#X4HLsj}>;3XUB`XUv4dsS@HaZrd#}d3Fu;Jmrk^ zn1Ugk#aL4(A-=+Yw@QTyiq>6F-}*yMkRwJb9>n2npeQthHj?mcc?M)ShI9|6my(g1Z7WGRGv$CHUAaa=Z+}|F8=@-Yskx zueY}l3Vi#)W|%Dm&INgjjm|wnRl!=-03Fe|{s|)i^4@gR$*l}hBD3M)Vg@y_dOzV` zUwr@7sm1-QXR8as-U#_EBRhh}4WZpO-a$fUGhs_t#=$9{lkxK6GwF|llQy~B3`>Ll z0Q9H2n!a1}p1R9XC0-bdTq=%jZT5GhYEG6Vt0pCi>x{Wc-SWk0J6+?5!eT&(9{;1Ks8aEIoAO7#eC!9RIqHq_+A8X#k;> zD%wE0oA=*X$W{;Le{^)FwjQs~I%$k^{JS@QK?cC_um7m;_WYsTw|`I6Ci^J&k6TD8 z_J4H?!L9Vy_axT^ho>B+}YJiyfaSD@o>4C6zvEYvWB z`7<;F6PN0Z8=fc{kmcn$f!Sj0p@*AC-eT-El1~0B?ve|o1jkcF=ls}u&f_qy(m{c_3gT4OG=F)uucb~G#w5>3_Q<-FAF z#3q|LG$%)jHgzqN(5_3|-D8p=GPJcRKB;uxyJ5_x!h@NdCbWGT4$&(Y1PY&3o4vsH zRK3r4D~v=@msE=i?k;i!Ss)&zpS$V>=JaKvii!Cb27rSjlXA1MmsgJvR0~V>`0tebWI~T=yWk#20yvlhQhy#0V2b-cR>Iv#VlF_H=Fg zytUT;ba~d0n-{yz&a;OG6iWU_s0 zh7?sTVpI00j9u4%-*}E#Sgd-&MEq{%mvKgiu6!GXH+0bZ|Gr064?CkczLsvyCi+-< z>#W(=&;ygHzo2U}_yl21G?J9{polcfBO#a)GXlM(hF65vF+N#`Q&0dF`JQeOXVR8H zJ4{WK;F}lJL^&&nE@hu@l+AD!WA5!W8r@sh*AWA-j#s}ur*k%aCau3P21?`rkZBTX+=l#7H|Ntc zm&aR)akrRGO^6ukPCCPw*2_Qb)dq}kDFyGu=AGj4E2(?7j5}Yw&4?k#h%WEp#;T^U zY@LBAqnOjM)i|Kb)Xw|+mkqztW&N|#AbEC0-*N3D($bO~Dlp31x%eMSTZ<3w(=Mcw z|DLMI349?9^3B1R(d1^{0i`3OpuX2KdnHcbcHrRhpZ@4v(8b)k~VE>^$SM*;ni@ z%D;w%OUiqtUbh(awUSh9elWZfwd3GWFBmSk#MHll8h_{!Xakm{c+VSSa4Xe5^REf} zup@a_L^&@?OLtKhJE8_H64%EJopF2X58KcB!PAY)V5kCZomtd;+jiZtqZzp z-JQoTR1&#Z38orG>g{wVT(q5jzT^#}c zIYoeH3sy8m-t=(WB+QHQ)7ZRID*j`5>8Yc3e!eIYPHgsR|}usO}IKcwjG}v&2n6$m2y~FkTR)} zAMj6H3qO`a8z>MH4u+6<fh4#CtTV0+7pO44-UlfTSx1pP)?? zLFQzt!%J=2;_<>MA}%T|7vn#Dpm!wH^8gB~i&yQDGeYylZPMFS;HLwMK! zPn9<(;$}v{cQS8myH*dwlWRRf!0#md+}0V_F|X;h=9pMNJ_%lb`XJ6ozr8AM?*!A; z9;%B#7+qkUxo6!wE%+^;Nsc;AKBNk-CIm z0%IPmFs+k(!5@jqHf$bq{^tUC3#_KDysnIb>7U&}&u#oIA5qiCE#WeUXh@qqe0G_u z#OG7}x>nzhm$2(&U!=HS*=7d5=G6u{nE|Z$T8A_&u zw_83_*LoBaZt=P;eMiK@I^AW?K2E%iG5U?Pr!O_fsBAE_-NFOjx98F^?Jd}7zQ?2s zN7a7Ob!%wur&WA0J6g$#{<4(5g(x`~|Mmh%dzvAh(ZcRm=Yjn<&Y1PB_`&-bxCc(u zFTZ&>5xcBFN&g@Qw9u@=e;gVnHG7NitTsIxqvwbejv41(m+D>zuk_TUY3Y9O@C9fI zntE03{7vodo!|EOAYW@-Z!I$OXnkSNM%1iT@XpXbQ~7S0+I{?VmOG-0=eUGyWfCP_wlP7*Bo|`d6Uwk&^;LCFFNI=bFs;uZ)2M z+M!R2+sEA<;0$8~3R#!)=5qS(oJ}QZXxUiA{jfHlMv4^oMcV6-bG^BfvVU0guYyq_ zR{4unW@`c}Z(~@+Uj^gi_>OBOd60^XhL_M@9c%$w(k^F3)5GTPmCTkC_W7a-IBtwq zPtLYKeO-Su0ML8uo7#pMbr$YQlbzYiugc$%6H@2*y7|lESko-Q2u)nK@(4dD8iN72 zMc>RHO9MAtbqDxxf=mAmyG zi5*lrD!jGkoSqMY!rg(ug*`86J z`<(kIj)n`FwdYS69u{^5q22%KkpV)Lu1s8hK@wE>X;3Y+aDOhZqQak_pAR!QGGa23 zqgSEd7}1b82T;^bgcc~Gy*)m-?}h%)iPfb4POP3=JTe;|^~&DlY?Te4YjJbBuwqG$ znRdQ$R^o~OtdwCO^<+gfj@e)1I0}XG6urZsPJIVuh0Ti|@&8O{QBwZ+pYB_0W z-@GMJq4CN4{*;QmSMW|;R8%h^VcEF$ZLRSi=lzLX+)E`bXo84lYTAL8J;7d@Q4A$& z+0CGNbt=Zc={sL%Z_u5W;OpanOM~@X#GlB{odFVH*H$SXdBKz=ls8yuxfyRO{n{jS z(ZP+AI^vC{vvpkrt!Z8b>;66HcNQYJpKzf{5P41AL1B(_>YA)}%V8C|PhT55N+a?e zH@je=1W?OP%nA}3n)yPN-tY44exoL6VFTSp=pqN$ zt$+jwf-RquxHzf0k^k2P6Uun9tJq8~x5{I-d0dFj{LpK2hZ(Gsd$}iyGiw=s?e2&v z?mk~@vs|MZYNPot%bPR`&3J8eJk*;Epe;Ar3Y{KLdwa!0ya+v)S2O=)e64JaP*p5_jP zaKal;NJ5^zC>{@;k$%}`?p3_PSNQTs4%=m{?0CdY(T!oUeYV$uj;vF(ebAx6yl}B8 z{ikhy0Q3Dl67J$rCyAd0I>LjE9pq|Mwf$=UYf@4Yn;%F^-}?*|razWsB$D~JoTcTv z*Khl@Q2Vu^se*yBkN*)yl7d%^%$;><9IWE)q`LYPs3tDBpQ+#y-s0-1eXDI!e9SH9 zv>Y3mD6n5^^#NVE4v&m@S{$!vjo2;PYOMP{*umIx(O&>BnLfIFpe&*sO}la+_Ip&m zzP|C1`Rgc|G~BAt^OL)~_YEK!5A?b6VCVPbYt{3MyaUqd@5&$tQDo+Hhv{-N0rR4` z0w9ACq=&Q669MgU#6Seuexhb57PH-yjih=49kj@&c(>4J09l@PlkR=m{HY)O+)hHY zAoM%y5{>>nXXlwmVmQ=_K))5jGqdrS0hlmWl8}GVEOVg*BM5f6N#E5pJ4-KJGTuNO zu+jqv31@$U9f^ml?OqQP@b0_WZ;@|20~L4&K^7bPO+JnHAlS>)SJ9FM8I5pYM^vzc z`ozZtg7@Blxq=Yh7UR}v7J13#U_)nTQd>17`DzyDM^7w`A@N?Ib~tin0#W5)SA4Aq zcAId7hq8wyF9svWEwWZqhSbaS_crh%=fv$U+E*N749R*Z&`E}q>DRT0=!~1aQMu%f; zEw~}Eq#xJJ%uF2u06<%;Cth*H^XyjKEA-l0+4TN;s)9$tW1hpK2l?7R;PO>T*-DvT z3n&0-^*IZryoA^?s^DEbAC8E2!zfrU!N`u|_9a^{cdES8Lll&D0DJh{o)XjruCQE& z$450ky>$S&PQQAuf$d&-Q%SlY$~TYT4rvCy3K-11wVci56&GoGb+{3OPrxT;*H#B_ zA1lm1vU1HmYGmhbAF?bcd|RRtlsUgIxYA*)sW}5n{k#az(gLDTTU7@_^on)iO_LV~ zD*O7524BXdJZmBsfA4X)4W8y!KD<7_bq&R&D_#$oe@bA@&;S#g%wjzx@LHiEzG-)I zt>r(tnYnn{Ie5HGHIUyK(3GrEOM$_Q=7Uw`KnzWiQvLx|PQqpOR&kr(&%Y-#h3HL%&+Kss2{^`CZ@#JX#gS z8$Sf&{O-sxHb3U3|mnLk`0&~b9N9&T5C^>$1nR3c0g=b5o3L@T0#*tUKE^ne?2@(QK0|(;Q z-_Ax0))OR3FE&el{xv6omPAKnU*<4y$c-Fn3162)yo&ktQh!iinZsdVkXji6w#fD@ zs6)6sT05_q%~iCxL!&PgPl9P&;jz-4BXi=?Xm$gUR=(wa3MDJyO>$Qd? zn$acMS%GG`lBrvY?DxJfo&l~DytOVU8M6)x^wt21d3 zpV`%!&B-A8q4n@i`>erx;1jsWhK?x}d9ayd5}R6~V#7mSID)dnrY$4&g=I6>`?oYs>CKR z_kH&H#p5hRMP{_t9n+`>-@EaJ_}4brR7Ih$5pqf%)cd(*xtS8O>~Y{k$gMEdqPQcu zVy9b`QtmVgD2M%w{ahlNOSdp zYiGNuUZy3`{mul*jc~t2oBio5?M1gt5D4>z2Vk@N0J?JVc^s*>Dvfxr&Z-PWe+1^q z!=NsMLouSA7C9@tS)Fqm#8*=M>HQHnBS#yZfNVbZYk490l9=p6=zsJY4As;0^jRe9 zur_YF6G_wUxQ91dA=C7pjhveT zftQ*I6vp1rO3|avw>A1~gd>U-Gr0hjGQ9LezK@sa6x26dtnDsCfN!-l)e)nyNyaTp z#doEa^Zg@Vl4-~`%o~l)J93P<6|sh~KQTud^FZ?wnsMR!7&gq!Mb+`phsugqeUTye zIxrml$$C?rUqIj*R?Te6hQkZk76`A`EVjkGXZuo-j`m8hjo6-2?q7@CVq1{G+h$dF0i^rt08Y ztnAB9u`+g+fOHE2Dfti+Hm+1Z=_sF)9^IkqIe3Q~Ahn;e%K1oloib`>7n3t6!B~31 zzgjPGpbxAB?LDNPr{>6*Im4DrG=&1^95FG0bT^rbfPmgC8*jNykSa6pOyIp9Td%;=$dWGVBa%3z_H zdx1;JeD2wG0=_X9;os(& zBN&4p%+hEwdV&gH!FfIRXG zf%ZLSI9n12NGwA#PDsf<6JB)pH1dVrEL=b`0YKuH`wNTJ#}Yi2%^Yis7tVA!6g)@t zoqoWd-{6<0hQa=MdYj?)K$#B*z}Uu;G9*7hWd5IE#m05Y%H3)|4rgFP?VSbg zp2B1Wo##)2eaDH10EDvl9CP6JWwhrLWe4@IAiw1chZn&lxe((|{t`z>IFxGch?SO> z3aGqlQ2eC7aA8p2{9w|4Z0+O&H1ODYe<9r=t4O;95N@QkdP?%1Uqlq>AROP}kLz8n zJarnxXb`p1P&2ogfbzk!1a*jFAV8 zwR=R3-v*p#xpaY+GY13={C+#JZ*nE(;|!{Rh^j)lBNa=z?5&aM#c(CpPp2(DtiC*U z9n6R}g9b;UCAnBgEnLU3M zQW)8XIcfc^chrIdsktEH7?T$%rWqLi0d$gHV*D?`gx??p@ZbCpid%06$bakw)vOSz{#<=UfCy1v71%JAo z%$3-wV4Byb^hokl9VHMUQc5V({ndIgMF!17~WYZh$c`9%-}RzeIuH{OwcDgzbDP7i&57WmFK@(+vYjV zFD%I!K|6+gWK1s|j->w{gpY~TUVl(GX1X(B26rOAJ6 zI5Vo6>!QK;?)YbkGyqP-jeHAYt@etm(HWa|Vq zWDCW*=ZD*)BZ5F+(7Ayg`LiHr#79J-oj+EHG#s3T13w17nM>hUgDgs3w`P*97a=$5 zeyA@4nb_+gCwx4Mw-akxz9W^NJ2UPDRYQS_(Y-aRPn~u9< zCCi6A?Fn~(u#Vmt~c|b1&4|PvI@bb%1>3ve| zzPM8M_N!zF+V#b+aRAIeKH$yQ(!RexdjOi85sn*liqJR1Ews2CT&_6KAFjRdK|zTr zuAhuBPft%3`W+GKb{yVAK?K!=EY7T`J|0xGeW{+k78N}GKzXA@E^U%k1!-a$*l zV7M|5;PKn$DLW>zm3~XTKJZI<*!nbaGucVvI1*_rOOe z4T43>RpW}^8x8TNZC2>rKt?nNYw{2D%>p2Vyi#kG|$>Xu}EJ4Bpz z4sp2nJSx}op8*vckN$~MS%@MU-|hD=zr?VzT7sJlAPH+`84InUe&W=b6vDOHr6>;59SUC~%V+kB|PJs&7s zE@uh+vP{6Re-(dTcGeD^rf5`B(_4b?7j5C2)N%2*7POjICKEL$wHcYH&lWCQ^g4{D# zVJp`=LU}6wv5PRl;-a+PhVuV+%7?ut#?0t4it8!6E)5YlcM%nn`uYsXN>U3z5f<>)hxH~9` z&wH&*rI6JHdb$zo(g}*_!ZG}d2;)$DY+TSc8jM4vfAv)CF|BVoK)Tp?WzzROb0gre zR7ywirw#u+fhP94HY0F*=}1g;$0UhaU92qbg2LDg?CHQuk=xvol(;;svCuMZPc1pO zib0D`sO+p~1QB?tnX*t$)kkK#(LXGFs0qZLPYer{s0Tf5MfpA>Nhmz$)a{3#TUbUj zdOG&N1v6w0P8#)knht9HZde};4r}|MJLW<1T+Bg}(S7(imhDO|klUAREcr=*(;3D*q z!W70#jkT8(RWS8Y4IU*$qMWD!R;9p1utr6qhcIPnNI-Mw`PQ#Fu&V}?#Kj!sixZ#@ zA}l5^%h6mT&VZXGO(%^Eu0U+r?n9#h+MS`BzSxkDaNybI>2c#{2e%2bS>oWD9q2#| z#)W+X<412*I7a*ad>S0)OVpH4D+PiR1>DMe&}RS^CTMsl2)BF__vKcFgy;pTxmA6c zX1806Ems-E*dWhQ7b9)xJ!y!VEAWD@@AD*HEaw+bn^;l{lGEq#j=6g|VD9X61%Mh1 z#+G`|E9jfAa&kD3IWe#oV)!pkgY8a82ya>qlLD)D&w=edH?jI(q84I{JHh2R#N>^I zw1N(Hiay`Ne+-H}>u!AXJ;q>bhoEpKL$gLWCO{!MdM9_{(Zsq~yT_B?y&~lo_Np_S ziLK<5!D}I(H)F989UQUwY?^Z}y#^3yVH#U#)G{n`>&6r)CtN6MN`k1YSyn;TD7z0R8y{~<3|KBR1su;5@;x^T3yFTPbT zYS-M=ra(}mE>>N1qj$%8BbE|GC(8ulKQWOJ;{Z5_eckC*^ed5Y4Qs<+fhQx7 z^(SJs>^uu)(Y^!Tn6g;BU@ zAyZJA&E6={Lj~PZsdF-?CMD-~b>mdao^ASG8o#4hIpcJ95K0SI!5y-l1MIc!Dff7hdn&;vW(dc0GE8V(booHtW?DdcF`T69_hbM@g5*gw*di zx;_=LZ}G~9b~z?_gZJ&VL*UhqP(%iU+P!*n=jl_aGoZQn8hn;3Jd!G`qF!yWCI~ts zfuRUo(O2Z2;WB?!*1Bs)p#k_uuDRq|cqE%WPCyG-a6CuPc|)$3V)-AD4#}>@eo=^D z?xbuY&H4|?qhk~wGGcYA7p(Wsd3$23cGSa^Mr(#tcFLR`brvG@OFi80b*?TqJswSi z69Y|77PGW{be1yiSP*BjW@WW^a&TIWJ^i0-oU5MTga9^tzoBUC0SN3BOk&Qk+x@xs z+nz!EVFf;+&I`WF!gISuMe#kn7ewQWb@uG~1Rbuz|1@#C2E4AvCk7pr&2BWwM4pj3}+0%xfzY!prU{zIVKlkU?ug~zJVN!=3v_#5O(cAKsH1!oH`AxW-bB!}U@B zz|R$t?|KwW#z+wtr-Ui$)lt{h31G_Jy(bkDIk*w<%vl{jJv|*gT^k=iJ-@LXJ?hC) zyeWD5_+)U=0e`NST|upCbI9MWvd7-v;qlIUs(Fab$YkB3_{o>}t5c8D=0{XT)cm#Y z19-j;U)t-d9IuQ8Liv{yo;SAI@z=YDxVj1X(lqt0C-ROURvF=HbKD%D20TQiJP(aZv5GL02& zA)2o4{$U;hYBg|_SUTEN3s;{`8%TZmSKrY`-KxS$Xt zCpRV^*>^Ba@6KG#9$-I6m)6a>rQ=sgltxGSyeMo$-Rg`JXggGBYNN}KxOZV@%aug! zrS(KB=ncXbWN9XFW9z3W6CfwL{)9MbncE4K}6lsRHO0^^OQoNOO zfDhj=OVo1Ci#$b4yEB)rJu%Tl!Nw;tR96Lkj>oD4v^HBqa| z&FRM!+{_ooRlX`Pn8uSxw>ey=!8W9HqWiTR08X0A_0yqfP?B@y_}XO8 z*wXBe*^&vqA4fUDjo>Hs487{|zlVQ_rBmi#s&utD1RigGhOI*%lj!WRLFew%jg!J& z@z6OGutFJ|a4_>&f{MTkSFNWW;0h^t1MrjNFqtS5=`&eA35TzClcbEJbadvJc<)=^ z(oP&(|Jw_I=T0K@^2_Da!BeU#bk4Z9&Dsqlo4G><`%6xxo{$;q#%?;yUg6vVUbsr` z;pdE%i#h&EBV+p=l5T~e zrRe(T{c_llIT+9WY0wEvE*Z;&kJ5ECQ{s8i@y9YFQK9heZTW`oNJF~A^->pu^Q`N= z@9QUJ@O7)y{7i*jbLc>>Uvezs*TKF|sy!M)Ui5W?K`Cn6?zYrchb$`d=OPaCWnP}l zonp6};byNUx~&nh9#mW9A8Q%4;mEYw9642UJwp_U>x@}j6Tt_X?TyDD#O=dg-~a5h zdkXbkE3P{(Kd<<9>gnf>Vhd*oxaTZaXzv?ME*~6BiraZ`rju~uBc%(wGg;IVQA^G} znDM?zU0!^-chq0om+|~hWzci04%DPFU+^`<> zJgX{=0@w)|2wuI4)CADTiWO7hLgo>_PFi|oE*%oNBQ!fV;b;-QCBg~u&dF>DOhg_e zhP?gu#oXCC{vmNck>%xi$6lTsoZ-=&(j8*A&NAfR7KUWwZuP=sa*tY=KpRVvTNHEEbcl=7^R2JxCn9 zlAT7(kdzoBI*lD`txL20kHoPHUN!M@t# z8~qij5Cf5G8@W!5-sU!KH-R(F@MSPjdFQ%p`x*ulV#8*)@|VM9mbV_1$%k-&n*B&3 z-N6-uj?3#fpH_D87)CH9Xw;?})I}MKCIA`6BiILx=Xd4_uKGym$ZHK_5eX97!NBla z%#Ux68DLHAes~`B&F;=a;24Xc++P01nZ#d>&cU6t;S)Kg z(|t~Iepi_)ii^pMSYnGOGtCMRH}!OxyH6O75FU%VJ8vAXBTb&6%zN^jA8k&E7h_qY zs@1;IqC1jlljW^DlA2{=15=5XnRo0CLY(nGnJaeXqQg8-AxbD!!5b*|mg72^(_~ux z^-xZBn@k!!&<dTjT*viSQEYknq_*Jrs_5X5j^fWGuU9c1f0(fW==L?zoLdWmCF5FLp|N zX_S9LVgCsJM9PXcUa}3bEe9Z|aBLvE{%0Xm#S(1DY)v41ZPgppL0|hYg39Ek<+kD= z9tLN4uv;?YX}irsB~Lg|7@qiOSbbQ7+;cYCc%itJ!eKFf!(lz!yy;?l>bXCjtw#|G zon(%V_aT_}n0W~3`wL{0XdX(1w*K%@5qMkJXhR29OFDO*6D1(WK9yWlm=$khQm zFf*Y)0 z**@}bY(fW#c?&i(rE(gfaU?sQV zN+9>M7%L;;NzQBeaNZ7qk(+B}a|V$vFF2C3d*LEZ>o{A?)0z7@zY*sKKG}7J<_8up z*Q}f-=?G+Gk2dRpylO}kIm?2KG?A-rN4kd7O`JGRC*M>TAVwfcLuSkN##-#Y@+M}% ziPb)>IIzqqu}T{EgpQfhgZcfhi2%?R(>t+}J1&iCeZl?F^yo2j zIK%Eh_%u0lTP~aMw4y|xPg4c;h(LSfgJHlvGE^&f@AErP3Pl}M?<}VIIfif60NQgS zfyZ0d{t~_2$}yx;Bt#xZKbW(xn)|8ISEbD}rFN#us4?TOlIzeE^ z^ibn^6PDfRnWMRCa!lR<4=m17tV&;WOjVA23i6R3WltTX(W|A5KDg=}30T%-1Ly{Y z6X2c4*t+yDCF7VR-bp5uJIP`7&xkb=S2x^Y>D*ojSk0rc)x=~MUP13~m;ZW3@qPkK zVPCn0yK@r7ZUacP+N%0)kFN>;I>$ZT;|4CvMSle%ew6|VR2U}R=B}TrC9HU6)@tS5 zONTDaE$Kg%D-jUUh<0t&Ak2}D^ogLaj;}w2s~}|y(uqIk96lDv8C*ZNx^O#+I(mQj z>!f#&gXh$Fue5oFkmKA^))27{mui^y$B=fdr3v{yj0Jf#Qaz@kQlx#FDgGI9S)?4J zkiP!>r%3}jI%JB4VEh)sF;E%)AB|_x}v$ z!+N^*G)5KpTrE!}MCzIP@AeX!!RRRf#R=Eqt|uPv?n&U=)Vm3lB3m2l!#fiOa}?K2 zJw%qhw)pO-HS?W6WUcwdy^Tap0q}m~%btH~qB-8L&T>7$6_ywWCkj#{Otsk=UMbkL z(Dqdt^tJu;ZEiZTJolw|C%en+^XuAMp^!HQ_Diq2 zc6*QC58AO@e&nv>eczsHzZNly|3(z*EQ^Y2_Hus)x_`Nd!e`I8yu37iby#byT;%H+ zqsDm+af&wW;pV|>s(70q6AEkC*XC^2?u^xvaGs`Na(hW$>ZKr5nOG-}u-lqFv zq45fpSm>K{OQ8k7gg>llJ?^?We|maKyFyNsx3HPdsWe5=3NpW60+ONu`~59pRKOgP zQnlmfC00rqt`|(g-4IINfZ5dqy+3TzGvvcxKFAn#S>6}*_Jwdv@FOLooNGr_q z;CS?gf>vBh0=y1T{6kAdYmW2&hEk@VqI`b$&)9E%S5RGa>nYDZ69IO*$fs9+Q4K!< z&Hy6%jZISpl>2_c$l^_%Z!MNm)&iOO*#zB5Ze#ze3IB$W>C+-NcwqK0-I z()Y!u2}J&@f9bY&L=VXK^fI#R>@|TA3UI|uj!i|Or)Gp2M;g={FDyu%&mFSaQ|*NH zu~>-n@cLukpiacT7VqjTbZdj*2H(0qqn|mGwS1EVJckl(j}2N#writ*R2x>_jWxz;d!<${>B$L{O4FkAV6K+f@q-a~lZ-rN@#%w+LDW_4WU$ zwO@M>cs?ZW(`!~beJz#JJm`71Fw)x#S3Wl!2w#oMz)ym;V`^O!tOEYRQNg}wM|Ev z^#OvX?de7k#M!-{b;iqK%rjyQhSl6K5>vt9x=qY8=27`Y-c-Ej>sm1tTiKK+;lop1 zm2fkfx8ydN;ao(%Ew?i#qfcxpI=;DEEnz1n9U0LMHKVyCouk`~smd@O7Dvg_NnxZ( z^4<3Gd$EeEhUz7Mx6;>4#^UoMfrl0)n_K7Z+N4QQCOK0vuJYsyK z)elk?8$4y&SG8MIq}nMi>1-F@#=Cn(V^_X7d0n5s*T~HKS}Tlses^B%5Y5A7A1n4y zzNi~E{;)uOv@n)6JUQviTx+5DHVAQ+YVgB<TGaCdhJ?(XjH?(VMLeLCM-d!KXbu6^tNxOJ;2e$YktoNqs`%rV9@Muq!jfqR@U z@5&voc?WmAGg1?D-Z#|N(cUU?eoM?XfdGG+gWBCl;}o`hidFzPC5(I3Y0A744cF?= zpr`(7>`kvKZqrGVL21cJgw_!T%y#1T-ElWWfolO6p8n8@?L#sFVda8b zzlt43W`qJ6l+$&418c1}0T445z}4g1XM0Ien!SZ^1r|76%}3Te0<6g<32WO5FEO)2 zaAB(XY)gbMUZt$wTRfF?dRsv9mtEH?{B)2W{b%oX>751Vl!ra{Gs)TXzNBH!rr*M# zjHC3dCJh#d%W;+YsYF>JEHAJA$3g<5tD!s;OpXUEFGi&8;%;43-up>R$?-ZvX?(WG z!;WyF+w-0yrtcP+e3_@HLk{e2~qYpg*e`7Da%C_aF8N2;i#1D(~^Ac>Yeq;(1R!&6F~C zI+ei<5M2{qnQm^zsGhcsRD*YWo=oG1%+$Ovpv=hWlu0pD`sBv~sjS2Rm)7lX@>%$g ztb;Bf+@zm^?Sjf>43=(n6n$C)N1M@^8A1|VIKnLlLN3rq>X9BP7=iWKb;e5@jP1ar z(rM!hxUmzB&(84C;mP45+`tydhE-Hhdl)9i`HeRKV?(Ql21O$qFictI-Tnq0+Z{Y@ z&_n1?n#PzKjw#9h6>8YWd3@r|;|Faq6bmD{##6C>M z)(_F$MQU}Wgm^Ha3bfaMWZVK!1w@}DFjD&}e~I0erizow7!Vjs1jb=*Hq)Eu5yZkbAv>J5r{)X-dJDq-Aelb=#`xLULMONA8 z!sD~WFNaa=7|D^pbYXZr&8mqNNzB4e8vhY(C!e2oB41mhigJ6c1Q;zgc7A2IL%;lT z)s?L-5wg*rnh;6xdJ@L>ltTxksIdkvB=&`C*{-Siv^oX$&rTM>SW zmR*}B_yyAcQB8r8R~4j9cETXPXm|Hi!>(Gs$2iM#A{=WHUE^Uv z!?l_CB;u_i`)fpjE!l|#U;nNh@p_`Ar$6i( z^TI^x#5?Hrz$&4N>5^skjX$b5EKh&u<&A=eJG| z*R4;m?RO(h)N~`lPmM$3atzJlPeBl5h#7be(gd)^F-)N1uLZUsUGK2)!Bcb9nDC61 zV2yG)Xr$*zLC8=8HOS(Y9F&)z9Cu&s|qpxLEc z5;C5<4*B;x{b2!tf#@DzJ|X0S{gLD$t^RtpP(mfYZHnW;zeAOZobdD}1{vKSG_g6X z-U&)evof?XHvW*7pHUP?Dv>lK={wA*O8y5jkIM)j54`z-^qD|_C($y5J-U>6E206F zV3RH%W7EkEr?sx=c!fArl8(OCGh+9%wuB5hnJLYstcFB!Bk{ffUJYhMcre87qBF)2 z*4oS&e=^;e+}3rb^lVD15+Rot(r~pt{L@@v-YF5Ux*y4j>_r3MwzH}?YQ+->%iDIv zbx};3voh0c^F#w`+!qBHlYA_oIenrs(A|uMKci{>1p%5whEJ>d->O@$pzmc;Sr0;r zl|mti`!@HIG8&LSn>Xc-!7lic%2g#k=2j#%0s=sbV&gu$=cBjF(! zqW3EMIfEi1=lQw(Ox7XYjPgHX>U%4iJVW!ZH*YhlC`N$S`y`>1(rCfL)NCk=fD&-}5XJ8WvrRB`ENY1+(3 z>I*1kUiNgeMjgY(?`ww?W|tp<)<5p;9SqL~JB;Q-l9HS4(6CaFA(<<({gkfnJ*jOq zI&`%gi_2b0cxdq5GqW-VCN+!)oniyOkQkohe==%Nm#cN!#)kNR{N%^CAVRU0hSzvL zDj#CLq*7qG+)oO|=dC{T4wq8BzMdfUm?v%^Gw-@Dg8O^m_@@~tU^QUYUHz8r|Lw!| z+%hs%yzJWSN$L!KA1an(VAA2_drEe`ClBfH+oF&9UA3_S17)Z)pS9^z#RkrB#L1M< zB_x*nFG64hnYS){etosFrY_M!%M1TEzHNhJ|3XOqzq_HHctT_$9clmd>L_x?zvAKl zj?s1^8TY>dcgX8KbW#rgq{43#P`hMPl=Fzky9BrV{ns^>|3<|rzmsQ6AYGiw!!g*- z3qxi|%D=AWX??d_s~ypMHFzz;LfcBGaF&F;t&d^3Tm}LG*V4FLbm))@-W*RT5tMED zC%q_X!48+cSK3e;h+TwL8iZ05MQ}R-x_53C{MO!0p=bp32hZ?)#izD> zn;`GbG*yAdrqDlNoHwu6B8>WfMz0auoz=Kp#`GKQ?s6R)v~5iOLA$cX{{YVREkW~| zvfV*soN2Cy%fr0wI(Src6gMW$gA()Sm*~p^bSZdYSvn_Wlbi+d2&ka>5y!VwQ%)OZ z&vvA%=`||pjQ03E==aI2*^pi{>}?g*ikHsoOO9!ND}DO|Ub#Hch|m0k1DVDbYs(^f zkS{1+_7fxW!sHK|ufG_UCB_!I)Jgqo|}CItt%EF;451`Q}H_ z^%a;vVV9-POrRF1ZA8F_*|~zv%*)|tFe8>q}8pV>9eY`quTgp^~WsVivcBp z+Be^qY(jPp7N?ji(x&|md`zm(ZY=9El`kR_EBro$6JMs(>N)2V21li#@n8|=k}J|_ zDFP|&4$VQYw@h~0pOt`^9JO!&pKO?Io4MO;+(7TJSGZx%=`;1W!m+A zoBFgb$5L#rTLl=!%^>*1i$>IZj&XOy$ueF)tuHx~YpN!0R_~AN)s=XbFv#3c2*A!L zhjy&%!1vMr89e{6N<#y-6W2DHG#7i4s;pw_p59v1klBg&)=ZlPgfFuAFFqz3itGRf z;IS`8k71e?>+IBPOJffxcTM)MzNtJwf&HZ6XYeC?)eUy|{`*5xZzR;g}yC#%^Mz4Y7+~tkcZucil#uFA6>^M-L(P_I3nDuMX_-<*__Ev-OGx(nD zl{i&FWE7GUnh-WO^ZuB_^&Jq~)$Xj5=Z{2?m!rg!Bi!MQoY{w*Tyf-t z*0d|RhHo7Uk@KrVc<;&b!+vl3J~k=z8|@FleNw5FKJT_-9UIwS`i@A~KQRx3(tS@x ze>OYiBZ-JW8KW|zbyRg?MG(?;VFk0l#M#yt*-xtUsLOFuufo-$+W%rq-zw*adN82n zT#Tz_Nuu#y8UE+2wl)XY?KLY&%D?l+$zgNfp7@i4W1g!siG=n_HQ~3l`EX+g`d5Ah z1%nXk$JAnE@)##+VS6T^H>(8s{bb${N#L{$_i!UmyNN368g~EWCa%%O5tj58vp|Pi zupcNeb?CYmIaCY&C3NOAVMF$=-f7X7D38OYC@zZ*L zmA@YiUpJ~bUOM|F_G}^gJ4=?{9AA;EC(!Vw6EvQHn67?>y=j-Id zx=wiJw6>v<2%G~W#JB<=z-E%JKwk)5Xkio(SYZtW#Gp~hKw7r%}(L}(gGxS zG}#YPVh?(cy#0O^zcwGeqHre^L%+~#PB?r@FfhPUW&?i;6t$W|?+6<~dd$7Q8g}^E zv7ce=Y~Q~Y4OhfBk@q-oHBk7}b`w{8X6yUG+DodYnjL67Zs-!FPrGCzA)s0L=CIOe z1#FG?rns+se7~jmBKy$!!;T}L_g*{ll7orwNn85Hx*O=vE&sC-ZD{UL6KV6vc{Lofyhe=qT8o?iy(!cgc6Uciqn5j)-T)h zyt57ZNwnYOCjw0;MnWXi-wG*|!onCA^?sHypH_rqM3{x&`Lm(s0>N&pV!J1kT)1mG z6pOIx4U#jih|b`)4IkJNJXSFzh}(^a$}RtCWo4XqJ8&|uk0$>R%EVxxn3A8_Dt5Ql zXg1o@z@ucS35%`bO^;~j7a(Y^{|>y25bcqix8{3!Y_k&`6YBWDS`&FrxP~9>JO=ne zfnllk$@UcE`XUgf#1U`2?6;Kb?y)cH^(YM=1TU=BRjTU&Te6=?dSNdIc(X=u(LBbP z{8V5j{>vF;Z)NKNWz5ImiECNAgw9ehX`#E7W3?nU(Wt8j!K7-?@joVhkfCU@kzQsB zX8_|$QB+j-`z~x^(WYu9YF>5T)#EJmYc@esJj?A&`I?l}o61xnG;tKlD1F|B%N^=G z$ftVf@uVG=PnqJrNMC-&Q7A^IHC1?fIDReTvzb@$qCc4A`n`13t~sQl0C7aTG~oXJ z^Y&D%5`=oD^1)t^?qs1tlFXjjo!>Psp~B%8^!mNysWyZ67sJIU*%!Bc8aO4oA0#(h z(8#pZ3p7DX_SCf=hm?zylh>uf6{79jHfD$PJIv+3VxwwL<%!u&=BZ}9l=bBH@B|V+ zr*p>1+I)YVf?uQ&Xn!cz5UAMOlmMREQh8FmdMm{jfvn$NWy0$=2J(04`q*OOH@9@w zYLLaLv0#0^U5+GNkI3vvwjd%hx;=eUZl}*F)S-SRi;ju;U7roq!r9!~_D_nJa%<3s z!4zb7-?nUsOEINt`m~2Hk44~)EOFe>Lx4OSP*jQK?)GJ%>jdVHYE$%CGBaVCC;XS2 zp4fCjGpk{SE(k4$mzvckliApNkKvu%Zm!d!GIF(cTI$ zg3tD3a_e)g)~u}MM;NWJv6{bNWgjPfrq85;LOz>jE*g;f^DMBS()8BcR{kf7#IYVY zJX8~?o*!o=$2*?W_a;}dKgoqCQjLMDA8EOt6eSBZO*sSKbSh)nAo-Ku71>2IkmB#O z?h{nARa~{@OYdtzO3ihof`HF${}gkW_61l{aw2n4mw5Z+IN~$?NAV6jI(Ma8htf_# zPFU$PiAk!c?(5WN=YqHNdTYLlz0UOe%CwGJU?H#le`WC;_?U_{I}}Tc3#NOQ^2S1rGVd;}JFwL7WRRcp@*Gp|$#koNPo58^ zC3h~D&Sv#Z>W!>^=qEdqWJ&x6{wmp8OpAj$es*lmRrxO2l;4X=Xbb+d)^ z0@QnF1hpaQ+gIL(ogXpf*nd>bTzOV8zBd6NjTUH~%+zRnIdk&o*zl+J!J%}>MIY&u zwnxZNi0(;g6Aa^7*qJpunsRGBk>2M(tjxS7_WQU7kMcM9E?Di>T1qB=-)9_ZdxP)) zP<>(&pzebjLjLZ#25)Xm=;iO{hBDKc(9D4~lqWM;dr&IO+0lZ48IirDb&l%0HyhXu z6y|KwNmLVdt2w>TYW@Rt!0ph{$uH4qb)Xy=nCKqD=T3~to6Y_`&}Ju88?G&I zZ$2_dUn8#010Vco%uNk@f}}CD*Y+8AzbLna5a+WTQ3Nd3PpTE$XhzI%aUWPn7MVJr zX#UUftMuG`k?6_VP@JyT0tZ-gx02uDW#is6_D}h>as9_Qe z>$vM*Rzje3+XB!TJe*qN8R01uLPs4wPZSfR?dWhM??c}3M7*)5>WwNtq!LZMMLM+& zm+!ww{U+#C-?%0^6rfk>Y2R4CEB`h)a2~Ult|&O_~FC1!P^Mx*dlu8+GdMOeTgmjM~K zF#CHRMIJCuuV&hUCBm7DBl2#MwC>IxS)T*ur2qZa9frNy)2ShHW5;M6#iqSO_DDEG zoUP60pf{drE&c6a-PatIPv`Q=GH>O*s!AX>?rUT99@u|NCUkonw^ z9iW&IA2ORBpB)d_@Uvkt#a^b`(%AHAl@NMh`Knp!;^M~p#KE#WKdg=C>VNhDz$(2DvnOYm~TRF}(!Lv`dkkRUbC1@8OEo?&;lE2%%|nNRy)syv4~c z2X_%2QrF1$D|JLm zwEADnL|$Px=)D`2pRP*_ka5x^OoCeBKidqhcj7;O!R^cViMYfn*xt8{X|mKz!qz68 zOv9F|bV^A7qaW2>Weaik?{1wjs0LJa0MRf5KUIS5JUT;S7FN5$7{*D;06@Lbn%deF zeowP%!wJk2=lqP843W+OF6?@;zzBh}gPb?gGKIIh1>!Cr_kyoNC8|AtU=+E;16c|* zTWztyj2aJedLD-@Wf74*Yh^5!EKZCJlHF6;G#Lo)YF?ahmtBHw)iwr;wxaw?so15H zHuzm$iFj!w!|or6QrRL{r3hts>UOpc^7;m>43_Q0l5=uo-3kow?nZmRI=w&UriojM zjrp)`oo}kSY}VVDmBK#Tn?Ja*C-H-wZ z;CMG<(Wgm;oGoVkx=cOYNi%nO{JqFaC!{eh+2j0uXdNfdAwz1h!1DV%1hf1EzRhI? zP0h}+x7H@Gq2kXS=cTLj;{mMyW*57o$5;?Cz%!BsLCs&S>I?I#$F^F zRVXmayXz%+rh~K6u;i5hzk}sBVkN!}ZyU)Yt3V~s@LP_*iKhuy5VPKL)0sZ67;j&h zbKzET;Wy_qj6_e{rlmQZ{kzIHn+IEb*H;o=1muS+Bv-p(d^?th+wm1qUS>NY0_mz4 z*GZ}Nd=>qU!2e9K^C}tp%j}~enoUK!FUAM!xizw_oa5%H7Wd)K!R}^9C3aS zU#VC7){uX0t+zUQkO0`nEKiKt{F;=v-a)UIL7h>&n^ZMv8z5D;VYtyCVd<=(7Em4<+04L z_A+bxixNZa>8kce9Ih~DI2RrH^86o{dgCLxwW;Ygwm{~;hfsQI7SHyZdFG|ZdE)>X z%n6!H0il=W^RxD&mj@cqQ@!0wE7CHf8)}@k`_QykB&h3#fCM*h33BZnzhv*Hdy}sx z@?2Kpf>&;-O1)@2f)$#N5(v1@d7^4xijUq@4PMZ+!5knUIfO2`v3`vh6PFttTx{Ia z%L$m|e@(|?$)syID{tH|n)|c;m%qE<44X$1Wjt@b44E`{wp;&3>ouK~fRbpZj9B=e zh5pSNWENwu{Y5n+6FaMnY$-!CR4N;(FJz$EL?%`%dX~;+pXyy&e(x4633$`~!X=ac zlmD1Dt%E}5M|5M^+3s*KQAeW>xE(zN?~lG$WjrcS9bkwDxTc#`CRJ>|jF7eohXARo zJKU#%iIp-MU#;Z-hyH<+5lh`3nQy#Paj8l6oNb3IvaMGfF~UbIkA^2e_6Ra}s~vZ7 z2t*3%?h`+?ER#Lw?n{r-eK>1owOWJmNlrEaxaeAiBxmOrMB^(bjEDwLwkjKZ`9dUb z_ojoLhPWSskIwJqM7xS?NvLYrg=0y@-=QJS&~bjp?qn)ATQ7o|pss23iam%%OU9NG zpI_d_V@X!9At`^tXO4~a4M&aLn`9JWWA1`ClWS6X=O$luIVTB#bvGi+kyT)$PF@li z2+vUqW8xD~lmr*c>52jJts7SWbA|YN6@n75ooyn=1)`!>}SzDv~vxUJWyy z%7(T-7&96OH!cRWbCb{3BPFO3JJ)V*q!0mxY~e^J8Sycv@GIZaa7nuoCCn1>qObqT z=|4Q`nf;<;Z!1+9?7Zr5rMQMB3q9wdbI4>3JUDEu;hAPiFaB|E&^VKk11|R8J*Veq z#euAsd}~!>V%wwt13mGwZz~L0rBL>XZBcs76wzys3dMgF1HR|R! zZ(U)yGRE<2p@Yt4#{Jp>j`-shNuLZ{S}fzfMrMJKh9pWtk(;B%m}J&lN@P}}9A~HO z2|u+Rjr;W{Z)<0tTu;xIWM`&y^UKzio@xwEO&91jdw1nJM+W`r40a-@bZH3M(bNtQ z_fGcP-;k&MDH4HEw#U@`8z}*m>U|9ch)tk7sP&ts7!PhbVX{<6vINVxaod0~5>-C# zYvSc2`Bb9;v0(9j#^Uim9`U~N*qC#vzsJaL)DmR142|_Py4B&XCS6Id2co9X#hx#bT zB!njSO{SoiVxb;X(6v+mEOS=$rH z!g*$IkGveFA1Kgl0QmA|Ewab)AqG9`cx7DlZBh@ZH|PPUkIw(*Dj;W}<~dV5&MP9Q zj@JtfKYu?gZVS$woE(p8C&bssONMW&ju3slGA-7!i4AXV=SLYOg)>*VYt#U5&VQ@$ zx1A1W?zVD~E6Hy_vEV%2UWo4*S867o`}MMM)>j;wjboxUGiBvgYEi0x^=`myvm5=< zBr^aE|0ZKIo5S>hR5u!JtJ^&_M2yu>h?C5yi%djB^g~2cw?5HvaI?M){j-&o71=+| zbsQn{dQ{Eg|4>BR4T=>-aOSBa3zizmT(?-X=%20WJ;ETehNSR+^0@v*nsDs36u~8t z^YEmxnXA+qj-umd-N0a_q(HhPREJIeO{_p>n~l~8+l)H81WHuXw|_BEkl!Phh2eE> zZf?vvU4q<>Cu5HSWxG-9-tpnYe<_(BZCVJ^!p3lD1L<|lOs4lAWhMR?*hj;@V zHJ;7BDPQo|B0cm-q}o>haoz@1SG3Mz3EV*b%U97@arQ{bkbFYdoIemdYAp6@K&n6e^i2F~s5J-S$ zh`ytUyPF&6X0-AcphQ!azY>Hu?F_3L$AhHs?WEPg^?vez9 zSEB0w12W>DYNFgzEOLB}Jcs%DWx#}$(RjlCUyDlo-y3|m+!V93Qyk9Ld-v|0=_W{) z-Eu{q`Qx4>YkMOcqNkytaJ5m4-8HLNq)40_O9cj|*-VbM7P8lRck>$x)iwjkGkdO> zF%oDEbpp*c*R7Wn%#Pq)hiGdK9*rE$CDbC8P`c)KoQj?UVKYKb-CP52=W&>9!Bin?njG z>-PE39CVGhuwc2uY&Z7{0akc8`*i2{_`97Qaz}?3tHoS!U8bPh;oe?;jhKD` zp*j-gz&hf)Kgz|(3FhoMuS=?G9S-cCr!7h0oE^!U3H=dz*f*aE{p} z7YdY0rJEK9Up_jX`vApg3TRnBw2lW7zm!(Qk@CJLi5%F;9`BmQUf^pYA;na3m&pE`BtsqDaW zL0g;RFYYfEqAETK(FTVrDR>yHkq#P<7ZSY=Jt@c7vY2T;_Y3t^w|yxNJN~D$YHMpo z{Iqj;nk2|{rH+e4G*Wl`L{1*Hz##rqvD}Rfo5M`gLT!5T_}ElLNHS+1x!RPB=F2{! zwm5(l^M;s#k0W%6Le++sLm(HT>tzHqt4fT}(@ip8K>xf_ij|PAjkndK(tWt;)fy${ zVHxyUI zQ@({V>6jN0OzNzJ^jHso)(SmU?qjzV7AdKbt)*#vb@`ioEkpNrz^_;o@o_peMZ@@@ zQc{$T?(QZ-GWi$Gw*O~9Qm1!ufWzf!i)M@)LOabT0Sc@79SAJB?nTb~Mk@X@_<6dg;D-&{zbpGkQ9X=^ z!mrvF6v!52Kg(Ugk&r0T$1%D*_00Ct0O-A5Uv3Hl1yLA>=hlmnt66!OeA~R5;L)}v zUbmIp2mB+yEld#OPBGH1i_5CL${+}#UJ#CkHxWolqWDmIoUr)JMeg0MQ0Fj7I=GHA z8pGCBYrv<#h27++^AZXX{<2IL<}oCBxn*!^izY0qQL!L#aZYw>z!g>=Nv%|3kFS2% z!IuxI)805VuV)~+yc;~i_$bD2aM80F!r=^g3xFnwJFWF)USt4ibBwRd#h$9OpPL&X z+xR<$`#%bPKRx7x-!KN)fy-}(!scu#%Uri8sxiz}^sI1JWdVVj z1_q;zk=}s2tp2@<1o(LJE4wA8g^s2GEz<$!9ReX!js!#h+!Q`fy2GDPEaQU=h9xb* z!=s=dP7MSF3+A--R&|;q$_pTT(w}st?PY_%)YX1*GkS{rTkDj1%RON(H+))NccS@W zndM{U6M@Ta|0HMPK5ZwM6@u^)p=B5lecu*CoUe$f;t%@6jE_)hNUhmyK%Ac$P*4+Y zHy~Pl3M+eTvDqtV!a$OkWzS_h!Nh&+9K{oX+gNd8uj_gEytwJjXBH|n7WIh^!&;+6*wg|2h>2EOByB@S2&R#k6^{zy9!GE)DBTlBCVEW1ifXjw)^rSK zH2Vw4ois2i^ox<$YHir59$9L?TZU5H(88{%^zAxfo=JFv!DXfSgU^hgiOkiE{U^Jm zsiC9xt+fU`F~rOk)Qa*oVf5OQIuxb`AvMCUhDPh64;0R^4! z|M5o&VS65ND50O^Z4u$erBzjtsz<-2svOp8o$f$Xcs$gPY;`a*A5HTQ6)&uuy}dO@ z_U)Q^LO*0I-d^z<7#lk|Sy@~2^R(9fJtKODyLcSr<|_e=x=omMP1d6Th2ef8I7kJ=JnVChDqt|4zv(7Jcp1e`o`P2u>lJgkcgLbU6eSr z<;$$t@^ET<0gUL6uium>I?97SUaTaLCx}Iy!=x?tt9~ep1sjGpd1B8N{(Nf%Vy`?m zSNiYefF91%4PFZkMxZnXY-RV1Z5i2Pm<4HgC$7gBiF>K33kpzf*U6bJd;mf{C6~d7 zml9Fr%%MS+$BFMgjgTBIm3|%<3jd{~QhVhulWz{F3rg*)wC3&Yp;M!OPf%cKT`|Re zeZQjo3RAo$Qh&CGUVf^!Lu2OYSb#DEI%zgPv466OL zK@ip>?{%i#garphdGZyyo`3PyG^r&L-ud3yxvj}eLoAbDA8PJLgH>>&+?rBmPer@h z4|cPwO>V3cZZ#&A8)9jP*1@C;5(5ikTym%x$B8!;*~ICg{aWA=%WM#AjpWL9Ds%!{ zx2SHukV~^S%G;{%L{TS>$oYe<9h^Yr6)Z?{by zL9Vbj$A!&NU}YR6^<+7;+#gAm|40rJ$8L(BA6u2T12OT}_?LtKWX4!P}=YXuwXM7AvNv82|THjAhhs_#TF`vfG5L?<=-2ho*5E8u97X1yK+awJQ! zY_71nIt0`YH>IkT!{;yixS`9wwkq1{o|&R1ofQVwUVa8>2!M03@yUc5d+Y!H>U5AK zPV!ysd5`zw6MkM~MUETQBl!adkDA$cl9qxi)%EH(M~vv;l>SQ#pkDlgWdD^}5jTm8 z=4Xg|ZJ#TZVth;m2Udx|qa=HRKEW?e{rfskyj$qc?ns;+{z0kt@2gDH0Y6pP1U1G- z-yG)%uA0EVnF`Jv07qS^dSn+U9J6iil-mEeE1MCUINA}tUl0ge)A`!VZG`;lO0ELd z{6vC{Tr4OmB1pPuEy!n1?@GpP=0*SEKG#IYCp;9CW^mOnSFQLioBV2jjUxE`o^_Jf zj)#KaIoh-T!NZk{sm*ng0@raKrXrJ$M#^Bd0*N0Sq&@axCgk?(HX^E@W zo_s}Mwl6Z zukIB?#|lWxJboi7x!Z%={Y?q|Q>%WTp9l_UudV?qaDUwG8M}fGoRl{VkLjEpr}*Z; zWy3KDm^|U+d_% zAy^z=GSe&WHr@u6Gwg~s^kGE5t=a&O@L`lIXrUMMZpPUK$(wrF5KOeVO8)3mH6mlq zCr^!tSS`ZM!LVCW6g;LgZL+6H1iRbURAXwk@o1H_#s}{wua9N+QBi`KSOSr>BN_$b zT-n#=yF*`JvglU7vE#L-Q}8#VdG{mDri^<$-87Px`kdsH&p6i{Ea@0AyoK|8V)J_! z7NT{>jbrcFCG3uwIt?z=FloGiN|Pg>^P(R|9;``HwV5PgsC5WWQ7n(%?9`U)5qCE+ z=DA`E+c~%%q6nj;PK;)8vLlr!$9$R-U$2VYgj*ZWt%SXq4(EE?a{`9)rg6lufY5JL z&IlW8gwT;*xBZ;>&lTYsUr#Swd{-zt$8i5}u9)uxm7=1dBctM; zwLNL)eD8&II9@~a_7*tI$Ci|oTyC{SO2JB*kT90$LB$QNEb!@3znp?`cjNSJcy}Xd zQSV>EErI#2_oIU35Dn!m=eJ1ri<7Nl5a8;3a#yOt=rWwEj0&E3tf(!LyLB`13`5d| z5cTjtNyWTsUB-Qgxu&prDU;*_xJn-3fcKMmJFfBoD(?5>X-IOlM1=7V=x9_AVE8Xd z>c&%D&&IVgF}#Upt&_cCkX2-oy5;s5(D+STQTf+V+rJU3Tw*_!?ae%Dllsm|rLQpm zj%KsDMuFrNfbmbTBF}h#vAIV5YXk^CVhAwJK+G+!7|8!IPJmS1QgeE+M4}-v4r|{g z1JpC_rZyzZnykR6hJ|ISM7xCQFDmt~A3!NuU8;wt$yyUu&E82r-bS2ZN|z7en+8m5 zVq$oKbepx%zlGK?-#K~M0u>C^ItZalNz`J`3^R9w%m3?r{H`{ClEj9WZC?4omL(WS z5Z8DKANK$A8E>Wz+)+6Uh=0vE4C zfJPAlf&O4hTiCB4danQkO}Qi@|I;VDn|MI^znVOCAipaY+Id@K%*KPpT3t4)5M?wx&0@eW7f;GK^Xn7 z4E>l28F37(YKC3Oys3D>I>XnWy`3R8Zlyv8PO2`Kr%=qiKDXRzT z-@8g&+gj-`tY0%Q%w8R@<2SWhkogigE-vMwZ*wfe^pAThzs6O%mvv@H_xZrN*ol9# z767ABOz4_Lx2&jsGMyZPZ)BuwVFERzq^8SEEkI z8*DxL^V-_jaoTg=PTzCfyy%B<>BThf1s1td?%?3R84$2j`Q?D!6Es#A(icQzo)e20 zen3%k?4?p<7MusZ{;C=ekL)Qx(cYEa*T+}Gg~N}G8c$l=X6Gxcf?njkCg!MDhQiaL zBRkx)Qt|FckB}$;cn7V;yjx-PnE4Ut*b?ydlSCviWq%Z+0w_^E+hnN&cq3U~Qrb_r zf%3n?@;+g=f8n(P^JdJ_NaQ%Qy`Wo}wI$36#B%ODcQt4KEx)Z6R)7t^5$Nn8CJlw{ zfaV<%0x_s*nX5i@?!>XhQEuyM@lt7LC;1`XOII9IJ(4)zf^Bd{E2E3I;63KYlUJ7V zh{=V_;9)fX?yf%yi?t^~mmyJdHnOnUGHDCp*p7Uc9gq0zX&lCU|Db6g+kBgsbuSFQ zo5ZV=_wK`p;YMd=$7`-K)RSeBq6s}me6HNqmZ_eId(E`pg@5NrAdxxJ%7&(&wpN$N?zv2A2Wkfi1IGwd^o? zUs)z9?`(yO)pPKunxWLCZu~0gdzZ|Z<{NnV>uSh|`8_wY(?W)HD|N!5x9lzFimy{> zR%Xh8nc6!K6J8fsme+%tyZv-9JSecE8 zJ`tW_Mohq3D7SI12;E_Zo3|*cC1s6!{*!`aNXzRyNGkHo-m#!(pnDR3E8~1V!%Is^ zp}n-r_1eMX=)=YA`J=r0^6Rw4#%nw3uyWL>=!DKonXLhDbuvkX(_>k(3C97wD2&zC zIt74O#Js2K_>sla;gdbTz<@wuP~~BbE64&AT^{fHrufUZ-?fNE@JCcwDs(^rBlLAOH(x5t*)ag7FU3h?1r#v`hwdSm&E#?PMzlivOi-3oUZ z8DtfGlouMsVw;mL`WUf;p#6|^qEjxLQ7*LKz`-tXLo9@z{#=j6IZ7Fovlr zx~8gYG16FRZKg0p0yI#eMcNBU!uu%Pu1M}cS77-OHUH`M-r6f4(r-yB@Yx?W<#_%_ zzg&Vu2+~%oCBK1c{5d^el_xY9$DsJdxAn3D8ES6Ux9z2!;F&uaJKk>B2bmsmIwqP@ z{MK+j5K1=QHBP(8^pe-=Gh4M%qpeziq|f-!0OEIx$r|UreW=gEaLLEZKl<|}3`k#Y z*Np^ZHFE6on=K0o`tNC3KP^nvyr~^mfxT(CKGx_xIo%WFr?4>&)-bWhZP2Ce(2(gT zrcJe|5xJwk$-1S$8jAhuyeI8-Yasl^EsIQqd&6a5 z(Oc$>BVwA&djkvZqY_9asybe@Yf0x9aW74$UQFzZr{GE1mdIZPTba@s90^D1m#+8w zSrX;f?e?=Bb}$jx-PP85;?yWLXA6DP*D!mp*AxkT9XHGRmVWe7DtxPxe5z|oZ58{nTjPez1?ROjE4N@% zGq#bcD997}<}C)b-L#g;skMK1o}a zKs_R3)brfwW<*LL)~u9krh>fO;G$L_8qmCoMzTIF(Wz)BVT>&Tn@3(&p&+222a-9@saF#B-toxBKUXgPV@PLUgc%Es3o$YUrc!{FR}xRw?w z7D!=VC;y5|t1AKW=|hyFYB<7N^%gw*?pb;vbmX#V0d+UaPy>E7JW6VoYZM<3!M9>#uk?e(F&tFN2Ih~7G<#<0>aQ1(rl_o?}_IojX&=Ah8&u89V9^p}F)4FIgR{M$nZ?{-MKc^wfD=)zpu(tMFR zu1S>MJHV%X5y#GOPc6>E9{H?|Q#C}b^@=uI|66kB8^et%V_?_trI4BiY?5ZmU>(2^ z7u1bE2UutgKDrUy(ApF3nC@ZA`_x3V(%18=pyU>7yY%Y5gz-k`l+Vo%Upl=4-)l@PEf&Y*u?yFlH`U8Q3v^Tg&*(K>^5xx3c;NM4r`TLL zBp?+)9?KBX>R707Z0bdKb@00D``4Ifxsn=++Ylb-sljed@}0bia%D0{R%hCyM{e_e z_p&smhtHumR|NU;gYuv?r2Cgj+%8(3c?I1aGKsz9@J^-tk32-hmQ zeW^cgyLm&(H_bLT>%aV*uKnuL>tk&LJ=lpS=vR$2Ug7R`-a&(j@!J+0*CC^-bYB@)IPEFgcUUrYNLE27JhuO;iYw z8=j&8g2=tI23{e{}ET#@9J)^JMs6ZJlLURPDR=!2m%*5s;9Q zE@_Y&QbJ0)QyK*+2?uacK)R$PC8WED0isTM| zbsYDKV|`iox~|`Oo-pDa=s^gW(SO>Ov=p(eq#+AHj?#Sib>ucG5wHl8U%#K(an73N zU1<}X>1CU}n^d1tiV@^qMbPYlUAXkRB<^PUh_-|cT6Un_>TG_T ziRR7GT^rl%P*7JGDH9iDBzt{Nu;QG^VFA?y4HAKSuX&7go2!dnycUpwUM6<0{WKTH zUFd5@FAkSek#}x9=w^Ag5mOedkwerj^47w&Uof82^zI1vY?o}R{l0~rMTTaUL4NvZ zh%~k@nCe(i@z!nzMCH9>==6*1mnr2E2p#&kQ^aF)--=6^8;cupr3E65BK~XJC(M3j z=@(g>Un>=t5>CIkQdKBR=F%%7!afHtYB?rzs`VdUNAfrxk$u<{2el=KXc6uUe8X zb+Ou-?WD+sVa-uCxhj!&RDO(Lca_Pe7+gk?^vt-S3;`b}?*b2kKvzFASt%9%L*x0K z>hxvl(>|SP^Bi95G6Yv#_&(nF?o?zt?U}@&kWp#ikPNhnkNSErt0{`aSnf`Be75+H z7id}t8ns{yQ|?oqYkA8U@!|#EH!zxAJ)w?`EAqF&)vw+3YRgRdT~7unH|_cIrV8NW z*qbZN@A`G5cINX4B#ag}3aX@J;*#q(bD~LH>`eJgbydn&z1^QHBtJG%NpZL_o@VOg z2<&4g;gMC*jaJF!WXJY!y@}v_V3dDvnaXF3+P?g`B6%p=l*ga&^g)eYWl>%}QPUC- z=;!4r2@i~`5*~U#-iB@{QERQ9#*G`IE3roYRVDHO+f0}9Ja>Cq z;v&8O>H3@^1aA|LJ9Jt5OG#0CO?x=UBGsPjrq|_J73Q&XPbsqYXVI92gid6EMNg z5ynpi*wz=Sb;W`zDgGD#kl=9sRyH_p)kAi)?=x}ar)%eZHh1Y~6)qLSF$T>fC8 z;vBQJ{Pc94l{ZIUs!#o0Cct;6g}L)zWJ`T zO!NzTdheInfR=BD&rgBL;HjcN)7^lFzs2+1d_U6oE<1aGK!cxLjt<{0lJM~<-Y4mS zxB>J+8nS_gLa3{4cg$E|_%tU9+JZo|4%|Zp1ybdP#PXh!7Xz1lmIAL_s9y5#N>ZWK z*cXF|eJ_U|2VKLcza<1F;THeU!m_Bs*_|jtFUinS#kc`(N2T+CNq?pxgb&QeUy-z6 zp2I;ZvXO7}biB+Hv#R(b%Tw^phMF0VEWOW6qbHO`$$5HCrxM#;0UBPFGD}wa-Klrh zZ?e)i-wdd_nFX)9bXC*)S!?Oy8WLVRGr{Z3-tcrS1-O?S+QhNY zKwAPrtJ{$1ar^k?G3M@tze_)3P))XyzJQ?iyJ7PIV-^M)_Mi}qUE_l^s_B((qwv6JSF+_ zU@k#7`QnL84k%<>nG;(%6eK;EpN#tumyEE6b_pc}OOyTurE8hco@~#@UwU`^BHvcb zXz9_29^=QF%QcTHfIf4`Mt+Hre|M5jtvp+DyPk8T7(RWr@D@x8HYy4;pcl5StFsD# zYyguh$*c&uv~$AO&S9%1t+XShZEa;cwr}>B9ULT|*KVdinf~UyBeIr~LrI+*u2Ojs z>`P^0DC-$=PJ0W1uaLCrATgR}bxj+5%-C-Jdu7)@$=|vaJ=?;{mWu6TqRdKchc+q; zlk}x82OdEhBy;yNrP{Za?!FO(_e{mrEK*AWf_T@ZV5COmq_MWS=M%vf3o5-M{z_`PQ;c_SQ zmY|=<_mn*Qrg0i1Z)Z5(G3VTU3Vr)i;p?(0NR{Zy;1krIdmjg3N`g{4+^AfQxMl1* zPeUe#?BzfN!Rw?njDBKZ@3nDkO-y~4O&kZRR1x5<>)<8lr4JiynhUm@1Dab{YY&Jjh zR(r^}9P;cd3KVteF-I(&G#6tpby{SeL>WphBjRo(^)ld~w_cX@qS<9cMGrm86!OLI zd7E5wZC<{rkG|HW^<-8g2yhU5X{6XD3O${UFU!-gshYhiSQ315EX)lz~otcHJ% z5f*cq=&o_F@e|>nRqYd5N?ea?ziU~bvngre?rgRzd|t=| zZ+@nB`&naU^xmJ62>`e&AU~cU7{JRr(6lGbYn^AewDAV(;8R#5;LC@OZQ}2s5VZYEDz@E^|LPh(7%% zk@!7~bjLcv@XCtEM6ANg5O{r^M8m={SMJyPmlP|gPPJ0Wdg1>RV$Kdlr+Bm^mvigX z;9@W;HA6$?uDo{7PoHUWpKU8;?C(fg>lKOHKCMIA0m(>x;EKJB5v;5B#r~7&qjBAC za^Bui?r|;96xB1-BK>naR`rA@tBYq#wP5*KM^RDN71plnOIXDzF4cYU%(&V&qo(Q2 zMB$EC_UK?Fc{g6WvR6l|!NsDDEP2MQSXSJGQWu&up}o$*M|?YJxu7#V=x>x23U$Kj z9x3WL?nVZ_^ed2yu>R0UH&I3?T527TBtUX~zO(x=+{;XbL6V}cKa)dkF2zO+-l1Nz$Nwadn}1W)6FC8Uzs$@Xme9~rl@{|_S3f!OEfbdtEQ@NPB_ zpR%o&G1o2sWm6@#-OF8M6JK&fLZ`QGTdy6?uk^;%d{Zbj zZ(>|csejIkEuGN1Lj~Y;qB0qhY%&++*ebbKM{=dlyj?AY$%&}N-o6y+s?a_@V(kLF zqMr)Zs4e($Q4c6es!we^N>B62LWh6dHen4h$|+RcfKULNm>`Dm&*5eq{7xia+oz8{SMih6aCNgH}uVEc3Uny1=;XuT;pUh6o6Vhcs1{ zjHqaVzD=9;E@V%iRy@@I@e0V)9SV-ZG(WLNhC9V|20cmaTq00t{y24eHz?rZJ?WDx zM*p%`oh`=U_vK=MeElO7TeL zMS&+bn2^vcx#*6(?qpU{&Bg8*%Fx4Oe<^TQXMVSO(eR@nKdj&Nsj`8CDSBWG3UJ{i z?g~znc*HGyRpN~~rmWihkuUJSPh8emEOE?xURJzyoH@eU86K#c2lt7fZkEp+jhOebpMs7X+4k}PQPU+ifk4fHeMq|u>!jZ` zquhcWZ-Bt;C-MkM!==@Sld>b{Weycy(kc90BX-B|_jkTEYG}a}-KKM|6TOhgS(|BO z8onKfy5Y%Jc%Y-}tQ7w!H?J}ILN81wyuRBolpwl5tJb-9lzn?zgj9E+VH2Hr;bUqN zKUU0oZ;6*rz|ZES)Nm&|E5w@Dek>#2_z{1`9p7J-dE?z?c(DK9UScC9rW0@Tu1ay! zpd1u%roh2U`#Fq6<;)x+*2vBESKyi1^^4+DSjl3T8PC<=*IuWMg%_$ir`UCjRX4Ge2FhtJN3$3SFP9 z%C@^^ZPklT#*a>|h=c&&1ey|kZ2JS2}cDkHT(UXqu&jB?hhZdswCL{t-9Fe^TQkZnmxXG^67hZC*E^3dI? zfT?S%V;_e=be^7-0=wad48q+16N~v$?oDEb7uWDf@PBLtki4@IxJGhdZVVDb#_&-n z&%Ig}4@B270lANH?Ax1yBl#@@LG`aR+rMVpUa+Y2a)^7dm105%To@rCi*YOI@4q$) z;eQn^M)5Ca4AJAk%g5)iHO557Vj|y|Tlta3?!3-^?@#-BVW_%C>6kTKd>?Xa=DwPi z^J&9daqwH_#;9h_UUfCm2;aHpGvDz#pU|sQ0?woCIg_P~BSiC{-YxBTIw0&_c<6FJ zq25^?VZnd+k{uURkA-&E9MP{k0d0|lHF++liaN8s@BLZVYu|d-X8$++GTV1HzcI+3 ziH2$ifBscKn;ImOAv*Wv@1B$pzJ)bj%=^Z|{6LS{i3Tqiu`)<(xb9hKyTRZcr$VLl z1g+FlI$VyhT1_0kO)<|~^=A~ahLTM_?#sRx_1M&&Z*tQCLMC%=X#N=)8Bs5T+XT-Y zs5)Gv>Rn`E2l;BH?+{mV?RHNmxyO)w=1M$NUpYMOk-mE98xsC^ad^;V9Yvh)bQDhu zCGYzBNmtB)P#C)0|6Zz56o6u{BKwjjCV;ioY%oEveuPc#jz zDdWJerJ*sV>0)Tm*7?Z~pBR$C!wO&^6Q|ovpl!X z2YEmr=C=zbt)&$eBVoHbnEiMs6r|L35`5{5ZwqEA;K(ui3zp3zG;>0qS<5qfsfOHc z_%$=bRgRjeUj;rpkVyL%?11ulCMJp8Re#_to|%npUeEg1pzZVhay9sTp)sT5@H$i9mg=Mgm0mx>4C6)dk4YPr zL>2!3VoQ1lYScbkIAGBzTdWxDAI;pqJ2uz-PW7BQy{qSvP;ia7HMcB(Ur_yjLm8}X z#_X=s;_*#Q8}}L7+`*ng_(iX#+JDZzqf} Date: Thu, 22 Feb 2024 14:44:51 +0000 Subject: [PATCH 092/141] Removed: temporal comment --- .../harvard/iq/dataverse/util/json/JsonPrinter.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index df93727a666..c6d655c78eb 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -589,18 +589,6 @@ public static JsonObjectBuilder json(DatasetFieldType fld) { return fieldsBld; } - /* - - versionId: number -displayName: string -versionNumber: {majorNumber?: number, minorNumber?: number} -publishingStatus: string -citation: string -isLatest: boolean -isInReview: boolean -latestVersionPublishingStatus: string - */ - public static JsonObjectBuilder json(FileMetadata fmd) { return json(fmd, false); } From 28799497eddb8d16c5ec7674115db26085283b71 Mon Sep 17 00:00:00 2001 From: GPortas Date: Thu, 22 Feb 2024 14:49:11 +0000 Subject: [PATCH 093/141] Removed: duplicated check in GetLatestPublishedFileMetadataCommand --- .../command/impl/GetLatestPublishedFileMetadataCommand.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestPublishedFileMetadataCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestPublishedFileMetadataCommand.java index 7c07766748c..aee1bc27718 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestPublishedFileMetadataCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestPublishedFileMetadataCommand.java @@ -18,7 +18,6 @@ public FileMetadata execute(CommandContext ctxt) throws CommandException { return dataFile.getFileMetadatas().stream().filter(fileMetadata -> { DatasetVersion.VersionState versionState = fileMetadata.getDatasetVersion().getVersionState(); return (!versionState.equals(DatasetVersion.VersionState.DRAFT) - && !(versionState.equals(DatasetVersion.VersionState.DEACCESSIONED) && !includeDeaccessioned) && isDatasetVersionAccessible(fileMetadata.getDatasetVersion(), dataFile.getOwner(), ctxt)); }).reduce(null, DataFile::getTheNewerFileMetadata); } From 78d7283c39ec8554918bd70907ceebc7647c0387 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Thu, 22 Feb 2024 10:05:31 -0500 Subject: [PATCH 094/141] #10286 minor cleanup --- .../java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index 05dbc4d6079..d9c48e94930 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -346,8 +346,7 @@ private static JsonObjectBuilder addEmbeddedOwnerObject(DvObject dvo, JsonObject ownerObject.add("identifier", dvo.getGlobalId().asString() + versionString); } else { ownerObject.add("identifier", dvo.getId() ); - } - + } } ownerObject.add("displayName", dvo.getDisplayName()); From a752ba77e6fcabfd5a37651a92faa176e1a31bcd Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Thu, 22 Feb 2024 10:38:09 -0500 Subject: [PATCH 095/141] #10286 separate version from identifier --- .../iq/dataverse/util/json/JsonPrinter.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index d9c48e94930..f3a756940f9 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -338,15 +338,15 @@ private static JsonObjectBuilder addEmbeddedOwnerObject(DvObject dvo, JsonObject if (dvo.isInstanceofDataset()) { ownerObject.add("type", "DATASET"); - String versionString = ""; - if (dsv != null){ - versionString = dsv == null ? "" : "&version=" + dsv.getFriendlyVersionNumber(); - } if (dvo.getGlobalId() != null) { - ownerObject.add("identifier", dvo.getGlobalId().asString() + versionString); + ownerObject.add("identifier", dvo.getGlobalId().asString()); } else { - ownerObject.add("identifier", dvo.getId() ); - } + ownerObject.add("identifier", dvo.getId()); + } + String versionString = dsv == null ? "" : dsv.getFriendlyVersionNumber(); + if (!versionString.isEmpty()){ + ownerObject.add("version", dvo.getId()); + } } ownerObject.add("displayName", dvo.getDisplayName()); From 951077f6e7921b5da7019c3e36868e919c2e6f20 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Thu, 22 Feb 2024 13:35:05 -0500 Subject: [PATCH 096/141] #10286 fix copy paste error --- .../java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index f3a756940f9..941c04dd4eb 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -345,7 +345,7 @@ private static JsonObjectBuilder addEmbeddedOwnerObject(DvObject dvo, JsonObject } String versionString = dsv == null ? "" : dsv.getFriendlyVersionNumber(); if (!versionString.isEmpty()){ - ownerObject.add("version", dvo.getId()); + ownerObject.add("version", versionString); } } From 7a430bf8c3671876447efc1ae74581aadc2516d4 Mon Sep 17 00:00:00 2001 From: GPortas Date: Fri, 23 Feb 2024 09:09:43 +0000 Subject: [PATCH 097/141] Changed: docs to point out that files may not have PIDs --- doc/sphinx-guides/source/api/native-api.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index 3d33be1ca45..3c00d8c991f 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -2722,7 +2722,7 @@ Files Get JSON Representation of a File ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. note:: Files can be accessed using persistent identifiers. This is done by passing the constant ``:persistentId`` where the numeric id of the file is expected, and then passing the actual persistent id as a query parameter with the name ``persistentId``. +.. note:: When a file has been assigned a persistent identifier, it can be used in the API. This is done by passing the constant ``:persistentId`` where the numeric id of the file is expected, and then passing the actual persistent id as a query parameter with the name ``persistentId``. This endpoint returns the file metadata present in the latest dataset version. @@ -2831,7 +2831,7 @@ The fully expanded example above (without environment variables) looks like this Get JSON Representation of a File given a Dataset Version ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. note:: Files can be accessed using persistent identifiers. This is done by passing the constant ``:persistentId`` where the numeric id of the file is expected, and then passing the actual persistent id as a query parameter with the name ``persistentId``. +.. note:: When a file has been assigned a persistent identifier, it can be used in the API. This is done by passing the constant ``:persistentId`` where the numeric id of the file is expected, and then passing the actual persistent id as a query parameter with the name ``persistentId``. This endpoint returns the file metadata present in the requested dataset version. To specify the dataset version, you can use ``:latest-published``, or ``:latest``, or ``:draft`` or ``1.0`` or any other style listed under :ref:`dataset-version-specifiers`. From 470318968e3449c43964b6f9503bfcd9e257f1c5 Mon Sep 17 00:00:00 2001 From: GPortas Date: Fri, 23 Feb 2024 09:30:17 +0000 Subject: [PATCH 098/141] Refactor: new dataFile.getDraftFileMetadata() method to avoid extra command call in GetLatestAccessibleFileMetadataCommand --- src/main/java/edu/harvard/iq/dataverse/DataFile.java | 8 ++++++++ .../impl/GetDraftFileMetadataIfAvailableCommand.java | 6 +----- .../impl/GetLatestAccessibleFileMetadataCommand.java | 4 +--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/DataFile.java b/src/main/java/edu/harvard/iq/dataverse/DataFile.java index 25ec40de845..53cdff31cc2 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DataFile.java +++ b/src/main/java/edu/harvard/iq/dataverse/DataFile.java @@ -545,6 +545,14 @@ public void setDescription(String description) { fmd.setDescription(description); } } + + public FileMetadata getDraftFileMetadata() { + FileMetadata latestFileMetadata = getLatestFileMetadata(); + if (latestFileMetadata.getDatasetVersion().isDraft()) { + return latestFileMetadata; + } + return null; + } public FileMetadata getFileMetadata() { return getLatestFileMetadata(); diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDraftFileMetadataIfAvailableCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDraftFileMetadataIfAvailableCommand.java index 8ed058d79f8..1d83f0dd1f4 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDraftFileMetadataIfAvailableCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetDraftFileMetadataIfAvailableCommand.java @@ -23,10 +23,6 @@ public GetDraftFileMetadataIfAvailableCommand(DataverseRequest request, DataFile @Override public FileMetadata execute(CommandContext ctxt) throws CommandException { - FileMetadata latestFileMetadata = dataFile.getLatestFileMetadata(); - if (latestFileMetadata.getDatasetVersion().isDraft()) { - return latestFileMetadata; - } - return null; + return dataFile.getDraftFileMetadata(); } } diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java index 98913d63471..b6c0fb9c427 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java @@ -25,9 +25,7 @@ public FileMetadata execute(CommandContext ctxt) throws CommandException { FileMetadata fileMetadata = null; if (ctxt.permissions().requestOn(getRequest(), dataFile.getOwner()).has(Permission.ViewUnpublishedDataset)) { - fileMetadata = ctxt.engine().submit( - new GetDraftFileMetadataIfAvailableCommand(getRequest(), dataFile) - ); + fileMetadata = dataFile.getDraftFileMetadata(); } if (fileMetadata == null) { From f49a48ab234c4750994cadd25b451a8b08e6cd1c Mon Sep 17 00:00:00 2001 From: GPortas Date: Fri, 23 Feb 2024 09:36:14 +0000 Subject: [PATCH 099/141] Refactor: new AbstractGetPublishedFileMetadataCommand.getLatestPublishedFileMetadata method to avoid extra command call in GetLatestAccessibleFileMetadataCommand --- .../AbstractGetPublishedFileMetadataCommand.java | 8 ++++++++ .../GetLatestAccessibleFileMetadataCommand.java | 15 +++------------ .../GetLatestPublishedFileMetadataCommand.java | 7 +------ 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractGetPublishedFileMetadataCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractGetPublishedFileMetadataCommand.java index 82d0ac3491b..4fef2c27efb 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractGetPublishedFileMetadataCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractGetPublishedFileMetadataCommand.java @@ -21,6 +21,14 @@ public AbstractGetPublishedFileMetadataCommand(DataverseRequest request, DataFil this.includeDeaccessioned = includeDeaccessioned; } + protected FileMetadata getLatestPublishedFileMetadata(CommandContext ctxt) { + return dataFile.getFileMetadatas().stream().filter(fileMetadata -> { + DatasetVersion.VersionState versionState = fileMetadata.getDatasetVersion().getVersionState(); + return (!versionState.equals(DatasetVersion.VersionState.DRAFT) + && isDatasetVersionAccessible(fileMetadata.getDatasetVersion(), dataFile.getOwner(), ctxt)); + }).reduce(null, DataFile::getTheNewerFileMetadata); + } + protected boolean isDatasetVersionAccessible(DatasetVersion datasetVersion, Dataset ownerDataset, CommandContext ctxt) { return datasetVersion.isReleased() || isDatasetVersionDeaccessionedAndAccessible(datasetVersion, ownerDataset, ctxt); } diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java index b6c0fb9c427..05f3c73bde0 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java @@ -3,21 +3,14 @@ import edu.harvard.iq.dataverse.DataFile; import edu.harvard.iq.dataverse.FileMetadata; import edu.harvard.iq.dataverse.authorization.Permission; -import edu.harvard.iq.dataverse.engine.command.AbstractCommand; import edu.harvard.iq.dataverse.engine.command.CommandContext; import edu.harvard.iq.dataverse.engine.command.DataverseRequest; -import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; -@RequiredPermissions({}) -public class GetLatestAccessibleFileMetadataCommand extends AbstractCommand { - private final DataFile dataFile; - private final boolean includeDeaccessioned; +public class GetLatestAccessibleFileMetadataCommand extends AbstractGetPublishedFileMetadataCommand { public GetLatestAccessibleFileMetadataCommand(DataverseRequest request, DataFile dataFile, boolean includeDeaccessioned) { - super(request, dataFile); - this.dataFile = dataFile; - this.includeDeaccessioned = includeDeaccessioned; + super(request, dataFile, includeDeaccessioned); } @Override @@ -29,9 +22,7 @@ public FileMetadata execute(CommandContext ctxt) throws CommandException { } if (fileMetadata == null) { - fileMetadata = ctxt.engine().submit( - new GetLatestPublishedFileMetadataCommand(getRequest(), dataFile, includeDeaccessioned) - ); + fileMetadata = getLatestPublishedFileMetadata(ctxt); } return fileMetadata; diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestPublishedFileMetadataCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestPublishedFileMetadataCommand.java index aee1bc27718..fc13dba1a34 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestPublishedFileMetadataCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestPublishedFileMetadataCommand.java @@ -1,7 +1,6 @@ package edu.harvard.iq.dataverse.engine.command.impl; import edu.harvard.iq.dataverse.DataFile; -import edu.harvard.iq.dataverse.DatasetVersion; import edu.harvard.iq.dataverse.FileMetadata; import edu.harvard.iq.dataverse.engine.command.CommandContext; import edu.harvard.iq.dataverse.engine.command.DataverseRequest; @@ -15,10 +14,6 @@ public GetLatestPublishedFileMetadataCommand(DataverseRequest request, DataFile @Override public FileMetadata execute(CommandContext ctxt) throws CommandException { - return dataFile.getFileMetadatas().stream().filter(fileMetadata -> { - DatasetVersion.VersionState versionState = fileMetadata.getDatasetVersion().getVersionState(); - return (!versionState.equals(DatasetVersion.VersionState.DRAFT) - && isDatasetVersionAccessible(fileMetadata.getDatasetVersion(), dataFile.getOwner(), ctxt)); - }).reduce(null, DataFile::getTheNewerFileMetadata); + return getLatestPublishedFileMetadata(ctxt); } } From c0ba4c7d03fc41bf80f3a5d25dc4c76102d4a693 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Fri, 23 Feb 2024 14:05:53 -0500 Subject: [PATCH 100/141] improve release note #9590 --- doc/release-notes/9590-faster-redeploy.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/release-notes/9590-faster-redeploy.md b/doc/release-notes/9590-faster-redeploy.md index caaa688bf58..ed903849444 100644 --- a/doc/release-notes/9590-faster-redeploy.md +++ b/doc/release-notes/9590-faster-redeploy.md @@ -1,3 +1,5 @@ -In the Container Guide, documentation for developers on how to quickly redeploy code has been improved for IntelliJ and Netbeans is now covered. +In the Container Guide, documentation for developers on how to quickly redeploy code has been added for Netbeans and improved for IntelliJ. Also in the context of containers, a new option to skip deployment has been added and the war file is now consistently named "dataverse.war" rather than having a version in the filename, such as "dataverse-6.1.war". This predictability makes tooling easier. + +Finally, an option to create tabs in the guides using [Sphinx Tabs](https://sphinx-tabs.readthedocs.io) has been added. (You can see the tabs in action in the "dev usage" page of the Container Guide.) To continue building the guides, you will need to install this new dependency by re-running `pip install -r requirements.txt`. \ No newline at end of file From e153914646ad15a870fdc9a4eb16f8d79c8a951b Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Fri, 23 Feb 2024 14:42:16 -0500 Subject: [PATCH 101/141] various doc tweaks #9590 --- doc/sphinx-guides/source/admin/metadatacustomization.rst | 2 +- doc/sphinx-guides/source/developers/coding-style.rst | 2 +- doc/sphinx-guides/source/developers/dev-environment.rst | 6 +++--- doc/sphinx-guides/source/developers/fontcustom.rst | 2 +- doc/sphinx-guides/source/developers/testing.rst | 2 +- doc/sphinx-guides/source/developers/tips.rst | 6 +++--- doc/sphinx-guides/source/developers/tools.rst | 9 +++++++-- doc/sphinx-guides/source/developers/troubleshooting.rst | 2 +- 8 files changed, 18 insertions(+), 13 deletions(-) diff --git a/doc/sphinx-guides/source/admin/metadatacustomization.rst b/doc/sphinx-guides/source/admin/metadatacustomization.rst index 78eadd9b2ce..66911aa0ad1 100644 --- a/doc/sphinx-guides/source/admin/metadatacustomization.rst +++ b/doc/sphinx-guides/source/admin/metadatacustomization.rst @@ -413,7 +413,7 @@ Setting Up a Dev Environment for Testing You have several options for setting up a dev environment for testing metadata block changes: -- Docker: See :doc:`/container/index`. +- Docker: See :doc:`/container/running/metadata-blocks` in the Container Guide. - AWS deployment: See the :doc:`/developers/deployment` section of the Developer Guide. - Full dev environment: See the :doc:`/developers/dev-environment` section of the Developer Guide. diff --git a/doc/sphinx-guides/source/developers/coding-style.rst b/doc/sphinx-guides/source/developers/coding-style.rst index 0c00f611a7f..c6c4b309963 100755 --- a/doc/sphinx-guides/source/developers/coding-style.rst +++ b/doc/sphinx-guides/source/developers/coding-style.rst @@ -57,7 +57,7 @@ Place curly braces according to the style below, which is an example you can see Format Code You Changed with Netbeans ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -As you probably gathered from the :doc:`dev-environment` section, IQSS has standardized on Netbeans. It is much appreciated when you format your code (but only the code you touched!) using the out-of-the-box Netbeans configuration. If you have created an entirely new Java class, you can just click Source -> Format. If you are adjusting code in an existing class, highlight the code you changed and then click Source -> Format. Keeping the "diff" in your pull requests small makes them easier to code review. +IQSS has standardized on Netbeans. It is much appreciated when you format your code (but only the code you touched!) using the out-of-the-box Netbeans configuration. If you have created an entirely new Java class, you can just click Source -> Format. If you are adjusting code in an existing class, highlight the code you changed and then click Source -> Format. Keeping the "diff" in your pull requests small makes them easier to code review. Checking Your Formatting With Checkstyle ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/sphinx-guides/source/developers/dev-environment.rst b/doc/sphinx-guides/source/developers/dev-environment.rst index 1301994cc82..2837f901d5e 100755 --- a/doc/sphinx-guides/source/developers/dev-environment.rst +++ b/doc/sphinx-guides/source/developers/dev-environment.rst @@ -71,10 +71,10 @@ After some time you should be able to log in: - username: dataverseAdmin - password: admin1 -More Information ----------------- +Next Steps +---------- -See also the :doc:`/container/dev-usage` section of the Container Guide. +See the :doc:`/container/dev-usage` section of the Container Guide for tips on fast redeployment, viewing logs, and more. Getting Help ------------ diff --git a/doc/sphinx-guides/source/developers/fontcustom.rst b/doc/sphinx-guides/source/developers/fontcustom.rst index 2a94b0ffc0b..edcda1e69ab 100755 --- a/doc/sphinx-guides/source/developers/fontcustom.rst +++ b/doc/sphinx-guides/source/developers/fontcustom.rst @@ -35,7 +35,7 @@ RVM is a good way to install a specific version of Ruby: https://rvm.io Install Dependencies and Font Custom Gem ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The brew commands below assume you are on a Mac. See :doc:`dev-environment` for more on ``brew``. +The brew commands below assume you are on a Mac. .. code-block:: bash diff --git a/doc/sphinx-guides/source/developers/testing.rst b/doc/sphinx-guides/source/developers/testing.rst index 24e14ade932..f56160dd498 100755 --- a/doc/sphinx-guides/source/developers/testing.rst +++ b/doc/sphinx-guides/source/developers/testing.rst @@ -273,7 +273,7 @@ Remember, it’s only a test (and it's not graded)! Some guidelines to bear in m - If you need to test an optional service (S3, etc.), add it to our docker compose file. See :doc:`/container/dev-usage`. - Just as with any development, if you’re stuck: ask for help! -To execute existing integration tests on your local Dataverse installation, a helpful command line tool to use is `Maven `_. You should have Maven installed as per the `Development Environment `_ guide, but if not it’s easily done via Homebrew: ``brew install maven``. +To execute existing integration tests on your local Dataverse installation from the command line, use Maven. You should have Maven installed as per :doc:`dev-environment`, but if not it's easily done via Homebrew: ``brew install maven``. Once installed, you may run commands with ``mvn [options] [] []``. diff --git a/doc/sphinx-guides/source/developers/tips.rst b/doc/sphinx-guides/source/developers/tips.rst index 764434d1896..1df618d8297 100755 --- a/doc/sphinx-guides/source/developers/tips.rst +++ b/doc/sphinx-guides/source/developers/tips.rst @@ -2,7 +2,7 @@ Tips ==== -If you just followed the steps in :doc:`dev-environment` for the first time, you will need to get set up to deploy code to your app server. Below you'll find other tips as well. +If you just followed the steps in :doc:`classic-dev-env` for the first time, you will need to get set up to deploy code to your app server. Below you'll find other tips as well. .. contents:: |toctitle| :local: @@ -10,7 +10,7 @@ If you just followed the steps in :doc:`dev-environment` for the first time, you Iterating on Code and Redeploying --------------------------------- -When you followed the steps in the :doc:`dev-environment` section, the war file was deployed to Payara by the Dataverse Software installation script. That's fine but once you're ready to make a change to the code you will need to get comfortable with undeploying and redeploying code (a war file) to Payara. +When you followed the steps in the :doc:`classic-dev-env` section, the war file was deployed to Payara by the Dataverse Software installation script. That's fine but once you're ready to make a change to the code you will need to get comfortable with undeploying and redeploying code (a war file) to Payara. It's certainly possible to manage deployment and undeployment of the war file via the command line using the ``asadmin`` command that ships with Payara (that's what the Dataverse Software installation script uses and the steps are documented below), but we recommend getting set up with an IDE such as Netbeans to manage deployment for you. @@ -99,7 +99,7 @@ With over 100 tables, the Dataverse Software PostgreSQL database ("dvndb") can b pgAdmin ~~~~~~~~ -Back in the :doc:`dev-environment` section, we had you install pgAdmin, which can help you explore the tables and execute SQL commands. It's also listed in the :doc:`tools` section. +Back in the :doc:`classic-dev-env` section, we had you install pgAdmin, which can help you explore the tables and execute SQL commands. It's also listed in the :doc:`tools` section. SchemaSpy ~~~~~~~~~ diff --git a/doc/sphinx-guides/source/developers/tools.rst b/doc/sphinx-guides/source/developers/tools.rst index 9d2740fab6a..79fccb8188e 100755 --- a/doc/sphinx-guides/source/developers/tools.rst +++ b/doc/sphinx-guides/source/developers/tools.rst @@ -2,11 +2,16 @@ Tools ===== -These are handy tools for your :doc:`/developers/dev-environment/`. +These are handy tools for your :doc:`dev-environment`. .. contents:: |toctitle| :local: +Tools for Faster Deployment ++++++++++++++++++++++++++++ + +See :ref:`ide-trigger-code-deploy` in the Container Guide. + Netbeans Connector Chrome Extension +++++++++++++++++++++++++++++++++++ @@ -18,7 +23,7 @@ Unfortunately, while the Netbeans Connector Chrome Extension used to "just work" pgAdmin +++++++ -You probably installed pgAdmin when following the steps in the :doc:`dev-environment` section but if not, you can download it from https://www.pgadmin.org +You may have installed pgAdmin when following the steps in the :doc:`classic-dev-env` section but if not, you can download it from https://www.pgadmin.org Maven +++++ diff --git a/doc/sphinx-guides/source/developers/troubleshooting.rst b/doc/sphinx-guides/source/developers/troubleshooting.rst index 832785f9860..8075f75dbdf 100755 --- a/doc/sphinx-guides/source/developers/troubleshooting.rst +++ b/doc/sphinx-guides/source/developers/troubleshooting.rst @@ -2,7 +2,7 @@ Troubleshooting =============== -Over in the :doc:`dev-environment` section we described the "happy path" of when everything goes right as you set up your Dataverse Software development environment. Here are some common problems and solutions for when things go wrong. +Over in the :doc:`classic-dev-env` section we described the "happy path" of when everything goes right as you set up your Dataverse Software development environment. Here are some common problems and solutions for when things go wrong. .. contents:: |toctitle| :local: From d27e7d37128b634811189830e7ca72d1a8a456e8 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Fri, 23 Feb 2024 14:50:50 -0500 Subject: [PATCH 102/141] remove next/prev from dev guide Maintaining these links is a maintenance burden. They should be added programatically across all the guides instead. --- doc/sphinx-guides/source/developers/classic-dev-env.rst | 4 ---- doc/sphinx-guides/source/developers/coding-style.rst | 4 ---- doc/sphinx-guides/source/developers/containers.rst | 4 ---- doc/sphinx-guides/source/developers/debugging.rst | 4 ---- doc/sphinx-guides/source/developers/dependencies.rst | 4 ---- doc/sphinx-guides/source/developers/deployment.rst | 5 ----- doc/sphinx-guides/source/developers/documentation.rst | 4 ---- doc/sphinx-guides/source/developers/geospatial.rst | 4 ---- doc/sphinx-guides/source/developers/intro.rst | 4 ---- doc/sphinx-guides/source/developers/making-releases.rst | 4 ---- doc/sphinx-guides/source/developers/remote-users.rst | 4 ---- doc/sphinx-guides/source/developers/selinux.rst | 4 ---- .../source/developers/sql-upgrade-scripts.rst | 4 ---- doc/sphinx-guides/source/developers/testing.rst | 4 ---- doc/sphinx-guides/source/developers/tips.rst | 4 ---- doc/sphinx-guides/source/developers/tools.rst | 7 ------- doc/sphinx-guides/source/developers/troubleshooting.rst | 4 ---- doc/sphinx-guides/source/developers/unf/index.rst | 4 ---- doc/sphinx-guides/source/developers/version-control.rst | 4 ---- 19 files changed, 80 deletions(-) diff --git a/doc/sphinx-guides/source/developers/classic-dev-env.rst b/doc/sphinx-guides/source/developers/classic-dev-env.rst index 015ba43644d..6978f389e01 100755 --- a/doc/sphinx-guides/source/developers/classic-dev-env.rst +++ b/doc/sphinx-guides/source/developers/classic-dev-env.rst @@ -262,7 +262,3 @@ Next Steps If you can log in to the Dataverse installation, great! If not, please see the :doc:`troubleshooting` section. For further assistance, please see "Getting Help" in the :doc:`intro` section. You're almost ready to start hacking on code. Now that the installer script has you up and running, you need to continue on to the :doc:`tips` section to get set up to deploy code from your IDE or the command line. - ----- - -Previous: :doc:`intro` | Next: :doc:`tips` diff --git a/doc/sphinx-guides/source/developers/coding-style.rst b/doc/sphinx-guides/source/developers/coding-style.rst index c6c4b309963..9da7836bbf4 100755 --- a/doc/sphinx-guides/source/developers/coding-style.rst +++ b/doc/sphinx-guides/source/developers/coding-style.rst @@ -131,7 +131,3 @@ Bike Shedding What color should the `bike shed `_ be? :) Come debate with us about coding style in this Google doc that has public comments enabled: https://docs.google.com/document/d/1KTd3FpM1BI3HlBofaZjMmBiQEJtFf11jiiGpQeJzy7A/edit?usp=sharing - ----- - -Previous: :doc:`debugging` | Next: :doc:`deployment` diff --git a/doc/sphinx-guides/source/developers/containers.rst b/doc/sphinx-guides/source/developers/containers.rst index 175b178b455..ed477ccefea 100755 --- a/doc/sphinx-guides/source/developers/containers.rst +++ b/doc/sphinx-guides/source/developers/containers.rst @@ -29,7 +29,3 @@ Using Containers for Reproducible Research ------------------------------------------ Please see :ref:`research-code` in the User Guide for this related topic. - ----- - -Previous: :doc:`deployment` | Next: :doc:`making-releases` diff --git a/doc/sphinx-guides/source/developers/debugging.rst b/doc/sphinx-guides/source/developers/debugging.rst index 50e8901b1ff..ffee6764b7f 100644 --- a/doc/sphinx-guides/source/developers/debugging.rst +++ b/doc/sphinx-guides/source/developers/debugging.rst @@ -63,7 +63,3 @@ to maintain your settings more easily for different environments. .. _Jakarta Server Faces 3.0 Spec: https://jakarta.ee/specifications/faces/3.0/jakarta-faces-3.0.html#a6088 .. _PrimeFaces Configuration Docs: https://primefaces.github.io/primefaces/11_0_0/#/gettingstarted/configuration - ----- - -Previous: :doc:`documentation` | Next: :doc:`coding-style` diff --git a/doc/sphinx-guides/source/developers/dependencies.rst b/doc/sphinx-guides/source/developers/dependencies.rst index 0208c49f90a..26880374f23 100644 --- a/doc/sphinx-guides/source/developers/dependencies.rst +++ b/doc/sphinx-guides/source/developers/dependencies.rst @@ -444,7 +444,3 @@ The codebase is structured like this: .. [#f1] Modern IDEs import your Maven POM and offer import autocompletion for classes based on direct dependencies in the model. You might end up using legacy or repackaged classes because of a wrong scope. .. [#f2] This is going to bite back in modern IDEs when importing classes from transitive dependencies by "autocompletion accident". - ----- - -Previous: :doc:`documentation` | Next: :doc:`debugging` diff --git a/doc/sphinx-guides/source/developers/deployment.rst b/doc/sphinx-guides/source/developers/deployment.rst index 045b0d0abbc..75ad2fa33fb 100755 --- a/doc/sphinx-guides/source/developers/deployment.rst +++ b/doc/sphinx-guides/source/developers/deployment.rst @@ -146,8 +146,3 @@ To Update Datafile Location to your-s3-bucket, Assuming no ``file://`` Prefix WHERE id IN (SELECT o.id FROM dvobject o, dataset s WHERE o.dtype = 'DataFile' AND s.id = o.owner_id AND s.harvestingclient_id IS null AND o.storageidentifier NOT LIKE '%://%'); - - ----- - -Previous: :doc:`coding-style` | Next: :doc:`containers` diff --git a/doc/sphinx-guides/source/developers/documentation.rst b/doc/sphinx-guides/source/developers/documentation.rst index 4ec011f2b24..a4b8c027445 100755 --- a/doc/sphinx-guides/source/developers/documentation.rst +++ b/doc/sphinx-guides/source/developers/documentation.rst @@ -159,7 +159,3 @@ A few notes about the command above: Also, as of this writing we have enabled PDF builds from the "develop" branch. You download the PDF from http://preview.guides.gdcc.io/_/downloads/en/develop/pdf/ If you would like to help improve the PDF version of the guides, please get in touch! Please see :ref:`getting-help-developers` for ways to contact the developer community. - ----- - -Previous: :doc:`testing` | Next: :doc:`dependencies` diff --git a/doc/sphinx-guides/source/developers/geospatial.rst b/doc/sphinx-guides/source/developers/geospatial.rst index 9744438bf5d..0570e993d10 100644 --- a/doc/sphinx-guides/source/developers/geospatial.rst +++ b/doc/sphinx-guides/source/developers/geospatial.rst @@ -81,7 +81,3 @@ For two "final" shapefile sets, ``bicycles.zip`` and ``subway_line.zip``, a new - Mimetype: ``application/zipped-shapefile`` - Mimetype Label: "Shapefile as ZIP Archive" - ----- - -Previous: :doc:`unf/index` | Next: :doc:`remote-users` diff --git a/doc/sphinx-guides/source/developers/intro.rst b/doc/sphinx-guides/source/developers/intro.rst index ce05670977a..350968012d8 100755 --- a/doc/sphinx-guides/source/developers/intro.rst +++ b/doc/sphinx-guides/source/developers/intro.rst @@ -75,7 +75,3 @@ As a developer, you also may be interested in these projects related to Datavers - Third party apps - make use of Dataverse installation APIs: :doc:`/api/apps` - chat.dataverse.org - chat interface for Dataverse Project users and developers: https://github.com/IQSS/chat.dataverse.org - [Your project here] :) - ----- - -Next: :doc:`dev-environment` diff --git a/doc/sphinx-guides/source/developers/making-releases.rst b/doc/sphinx-guides/source/developers/making-releases.rst index 18ae34ee656..e7a59910e56 100755 --- a/doc/sphinx-guides/source/developers/making-releases.rst +++ b/doc/sphinx-guides/source/developers/making-releases.rst @@ -230,7 +230,3 @@ We've merged the hotfix into the "master" branch but now we need the fixes (and Because of the hotfix version, any SQL scripts in "develop" should be renamed (from "5.11.0" to "5.11.1" for example). To read more about our naming conventions for SQL scripts, see :doc:`sql-upgrade-scripts`. Please note that version bumps and SQL script renaming both require all open pull requests to be updated with the latest from the "develop" branch so you might want to add any SQL script renaming to the hotfix branch before you put it through QA to be merged with develop. This way, open pull requests only need to be updated once. - ----- - -Previous: :doc:`containers` | Next: :doc:`tools` diff --git a/doc/sphinx-guides/source/developers/remote-users.rst b/doc/sphinx-guides/source/developers/remote-users.rst index 484abe9ccf0..38b3edab772 100755 --- a/doc/sphinx-guides/source/developers/remote-users.rst +++ b/doc/sphinx-guides/source/developers/remote-users.rst @@ -75,7 +75,3 @@ In case you want to stop and remove the Keycloak container, just run the other a ``./rm-keycloak.sh`` Note: the Keycloak admin to login at the admin console is ``kcadmin:kcpassword`` - ----- - -Previous: :doc:`unf/index` | Next: :doc:`geospatial` diff --git a/doc/sphinx-guides/source/developers/selinux.rst b/doc/sphinx-guides/source/developers/selinux.rst index dcbf3ee594f..ca41ab82d25 100644 --- a/doc/sphinx-guides/source/developers/selinux.rst +++ b/doc/sphinx-guides/source/developers/selinux.rst @@ -109,7 +109,3 @@ Once your updated SELinux rules are in place, try logging in with Shibboleth aga Keep iterating until it works and then create a pull request based on your updated file. Good luck! Many thanks to Bill Horka from IQSS for his assistance in explaining how to construct a SELinux Type Enforcement (TE) file! - ----- - -Previous: :doc:`geospatial` diff --git a/doc/sphinx-guides/source/developers/sql-upgrade-scripts.rst b/doc/sphinx-guides/source/developers/sql-upgrade-scripts.rst index 4689aeec0f2..6ac3fdcb3d6 100644 --- a/doc/sphinx-guides/source/developers/sql-upgrade-scripts.rst +++ b/doc/sphinx-guides/source/developers/sql-upgrade-scripts.rst @@ -43,7 +43,3 @@ Renaming SQL Upgrade Scripts Please note that if you need to rename your script (because a new version of the Dataverse Software was released, for example), you will see the error "FlywayException: Validate failed: Detected applied migration not resolved locally" when you attempt to deploy and deployment will fail. To resolve this problem, delete the old migration from the ``flyway_schema_history`` table and attempt to redeploy. - ----- - -Previous: :doc:`version-control` | Next: :doc:`testing` diff --git a/doc/sphinx-guides/source/developers/testing.rst b/doc/sphinx-guides/source/developers/testing.rst index f56160dd498..2ea85913d42 100755 --- a/doc/sphinx-guides/source/developers/testing.rst +++ b/doc/sphinx-guides/source/developers/testing.rst @@ -555,7 +555,3 @@ Future Work on Accessibility Testing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Using https://github.com/GlobalDataverseCommunityConsortium/dataverse-ansible and hooks available from accessibility testing tools, automate the running of accessibility tools on PRs so that developers will receive quicker feedback on proposed code changes that reduce the accessibility of the application. - ----- - -Previous: :doc:`sql-upgrade-scripts` | Next: :doc:`documentation` diff --git a/doc/sphinx-guides/source/developers/tips.rst b/doc/sphinx-guides/source/developers/tips.rst index 1df618d8297..839ae3aa19d 100755 --- a/doc/sphinx-guides/source/developers/tips.rst +++ b/doc/sphinx-guides/source/developers/tips.rst @@ -239,7 +239,3 @@ with the following code in ``SettingsWrapper.java``: A more serious example would be direct calls to PermissionServiceBean methods used in render logic expressions. This is something that has happened and caused some problems in real life. A simple permission service lookup (for example, whether a user is authorized to create a dataset in the current dataverse) can easily take 15 database queries. Repeated multiple times, this can quickly become a measurable delay in rendering the page. PermissionsWrapper must be used exclusively for any such lookups from JSF pages. See also :doc:`performance`. - ----- - -Previous: :doc:`dev-environment` | Next: :doc:`troubleshooting` diff --git a/doc/sphinx-guides/source/developers/tools.rst b/doc/sphinx-guides/source/developers/tools.rst index 79fccb8188e..9b3e38232e8 100755 --- a/doc/sphinx-guides/source/developers/tools.rst +++ b/doc/sphinx-guides/source/developers/tools.rst @@ -266,10 +266,3 @@ We can see that the first ``FGC`` resulted in reducing the ``"O"`` by almost 7GB etc. ... It is clearly growing - so now we can conclude that indeed something there is using memory in a way that's not recoverable, and this is a clear problem. - - - - ----- - -Previous: :doc:`making-releases` | Next: :doc:`unf/index` diff --git a/doc/sphinx-guides/source/developers/troubleshooting.rst b/doc/sphinx-guides/source/developers/troubleshooting.rst index 8075f75dbdf..2c437ca8b2e 100755 --- a/doc/sphinx-guides/source/developers/troubleshooting.rst +++ b/doc/sphinx-guides/source/developers/troubleshooting.rst @@ -110,7 +110,3 @@ If you are seeing ``Response code: 400, [url] domain of URL is not allowed`` it' ``./asadmin delete-jvm-options '-Ddataverse.siteUrl=http\://localhost\:8080'`` ``./asadmin create-jvm-options '-Ddataverse.siteUrl=http\://demo.dataverse.org'`` - ----- - -Previous: :doc:`tips` | Next: :doc:`version-control` diff --git a/doc/sphinx-guides/source/developers/unf/index.rst b/doc/sphinx-guides/source/developers/unf/index.rst index 856de209e82..596bb0cf3bf 100644 --- a/doc/sphinx-guides/source/developers/unf/index.rst +++ b/doc/sphinx-guides/source/developers/unf/index.rst @@ -37,7 +37,3 @@ Learn more: Micah Altman and Gary King. 2007. “A Proposed Standard for the Sch unf-v3 unf-v5 unf-v6 - ----- - -Previous: :doc:`/developers/tools` | Next: :doc:`/developers/remote-users` diff --git a/doc/sphinx-guides/source/developers/version-control.rst b/doc/sphinx-guides/source/developers/version-control.rst index 85ae62f59a6..c5669d02e77 100644 --- a/doc/sphinx-guides/source/developers/version-control.rst +++ b/doc/sphinx-guides/source/developers/version-control.rst @@ -286,7 +286,3 @@ GitHub documents how to make changes to a fork at https://help.github.com/articl vim path/to/file.txt git commit git push OdumInstitute 4709-postgresql_96 - ----- - -Previous: :doc:`troubleshooting` | Next: :doc:`sql-upgrade-scripts` From fe166f74182b8465903020a210720cbd09837f05 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Fri, 23 Feb 2024 15:22:03 -0500 Subject: [PATCH 103/141] typo #9590 --- doc/sphinx-guides/source/container/dev-usage.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/sphinx-guides/source/container/dev-usage.rst b/doc/sphinx-guides/source/container/dev-usage.rst index 43291d8baca..be4eda5da44 100644 --- a/doc/sphinx-guides/source/container/dev-usage.rst +++ b/doc/sphinx-guides/source/container/dev-usage.rst @@ -331,7 +331,7 @@ The steps below describe options to enable the later in different IDEs. This imitates the Netbeans builtin function to copy changes to files under ``src/main/webapp`` into a destination folder. It is different in the way that it will copy the files into the running container deployment without using a bind mount. - 1. Install the `File Watcher plugin `_ + 1. Install the `File Watchers plugin `_ 2. Import the :download:`watchers.xml <../../../../docker/util/intellij/watchers.xml>` file at *File > Settings > Tools > File Watchers* 3. Once you have the deployment running (see above), editing files under ``src/main/webapp`` will be copied into the container after saving the edited file. Note: by default, IDE auto-saves will not trigger the copy. From 9d438a17247a9f3bd1b8b868a79f0fcddf9e0edc Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Fri, 23 Feb 2024 15:46:53 -0500 Subject: [PATCH 104/141] Revert "feat(k8s): initial commit of new module" This reverts commit 8547dbf4222597dc48c83f45104bb9165dcce843. --- modules/container-k8s/pom.xml | 59 --------------- .../src/main/jkube/dataverse-datasets-pvc.yml | 6 -- .../src/main/jkube/dataverse-deployment.yaml | 72 ------------------- .../src/main/jkube/dataverse-docroot-pvc.yml | 6 -- .../src/main/jkube/dataverse-storage-pvc.yml | 6 -- .../src/main/jkube/dataverse-uploads-pvc.yaml | 6 -- .../main/jkube/deps/postgres-deployment.yml | 31 -------- .../src/main/jkube/deps/postgres-pvc.yml | 6 -- .../src/main/jkube/deps/postgres-svc.yml | 5 -- .../container-k8s/src/main/jkube/profiles.yml | 12 ---- 10 files changed, 209 deletions(-) delete mode 100644 modules/container-k8s/pom.xml delete mode 100644 modules/container-k8s/src/main/jkube/dataverse-datasets-pvc.yml delete mode 100644 modules/container-k8s/src/main/jkube/dataverse-deployment.yaml delete mode 100644 modules/container-k8s/src/main/jkube/dataverse-docroot-pvc.yml delete mode 100644 modules/container-k8s/src/main/jkube/dataverse-storage-pvc.yml delete mode 100644 modules/container-k8s/src/main/jkube/dataverse-uploads-pvc.yaml delete mode 100644 modules/container-k8s/src/main/jkube/deps/postgres-deployment.yml delete mode 100644 modules/container-k8s/src/main/jkube/deps/postgres-pvc.yml delete mode 100644 modules/container-k8s/src/main/jkube/deps/postgres-svc.yml delete mode 100644 modules/container-k8s/src/main/jkube/profiles.yml diff --git a/modules/container-k8s/pom.xml b/modules/container-k8s/pom.xml deleted file mode 100644 index 470abb753ae..00000000000 --- a/modules/container-k8s/pom.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - 4.0.0 - - - edu.harvard.iq - dataverse-parent - ${revision} - ../dataverse-parent - - - io.gdcc - container-k8s - ${packaging.type} - Container Kubernetes Materials - This module provides resources to run Dataverse on OpenShift or plain Kubernetes - - - - poikilotherm - Oliver Bertuch - github@bertuch.eu - Europe/Berlin - - maintainer - - - - - - - - pom - - - - - ct - - true - dataverse-k8s - - - - - - org.eclipse.jkube - kubernetes-maven-plugin - 1.16.0 - - - - - - - - - \ No newline at end of file diff --git a/modules/container-k8s/src/main/jkube/dataverse-datasets-pvc.yml b/modules/container-k8s/src/main/jkube/dataverse-datasets-pvc.yml deleted file mode 100644 index 50e9ccb3c92..00000000000 --- a/modules/container-k8s/src/main/jkube/dataverse-datasets-pvc.yml +++ /dev/null @@ -1,6 +0,0 @@ -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 100Mi diff --git a/modules/container-k8s/src/main/jkube/dataverse-deployment.yaml b/modules/container-k8s/src/main/jkube/dataverse-deployment.yaml deleted file mode 100644 index 5d1ed67f635..00000000000 --- a/modules/container-k8s/src/main/jkube/dataverse-deployment.yaml +++ /dev/null @@ -1,72 +0,0 @@ -spec: - replicas: 1 - template: - spec: - containers: - - name: dataverse - image: ghcr.io/gdcc/dataverse:openshift-poc - imagePullPolicy: Always - resources: - requests: - memory: "1Gi" - limits: - memory: "2Gi" - ports: - - containerPort: 8080 - readinessProbe: - httpGet: - path: /api/info/version - port: 8080 - #args: - # - bash - # - -c - # - "ls -laZ /opt/payara/config; touch /opt/payara/config/test" - env: - - name: DATAVERSE_DB_HOST - value: postgres - - name: DATAVERSE_DB_USER - value: dataverse - - name: DATAVERSE_DB_PASSWORD - value: supersecret - volumeMounts: - - name: storage - mountPath: /dv - - name: datasets - mountPath: /dv/store - - name: docroot - mountPath: /dv/docroot - - name: uploads - mountPath: /dv/uploads - - name: config - mountPath: /opt/payara/config - - name: dvtemp - mountPath: /dv/temp - - name: tmp - mountPath: /tmp - - name: heapdumps - mountPath: /dumps - - name: bootstrap - image: ghcr.io/gdcc/configbaker:openshift-poc - restartPolicy: Never - args: ["bootstrap.sh", "-u", "http://localhost:8080", "-t", "3m", "dev"] - volumes: - - name: storage - persistentVolumeClaim: - claimName: dataverse-storage - - name: datasets - persistentVolumeClaim: - claimName: dataverse-datasets - - name: docroot - persistentVolumeClaim: - claimName: dataverse-docroot - - name: uploads - persistentVolumeClaim: - claimName: dataverse-uploads - - name: config - emptyDir: {} - - name: dvtemp - emptyDir: {} - - name: tmp - emptyDir: {} - - name: heapdumps - emptyDir: {} \ No newline at end of file diff --git a/modules/container-k8s/src/main/jkube/dataverse-docroot-pvc.yml b/modules/container-k8s/src/main/jkube/dataverse-docroot-pvc.yml deleted file mode 100644 index 50e9ccb3c92..00000000000 --- a/modules/container-k8s/src/main/jkube/dataverse-docroot-pvc.yml +++ /dev/null @@ -1,6 +0,0 @@ -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 100Mi diff --git a/modules/container-k8s/src/main/jkube/dataverse-storage-pvc.yml b/modules/container-k8s/src/main/jkube/dataverse-storage-pvc.yml deleted file mode 100644 index 50e9ccb3c92..00000000000 --- a/modules/container-k8s/src/main/jkube/dataverse-storage-pvc.yml +++ /dev/null @@ -1,6 +0,0 @@ -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 100Mi diff --git a/modules/container-k8s/src/main/jkube/dataverse-uploads-pvc.yaml b/modules/container-k8s/src/main/jkube/dataverse-uploads-pvc.yaml deleted file mode 100644 index 50e9ccb3c92..00000000000 --- a/modules/container-k8s/src/main/jkube/dataverse-uploads-pvc.yaml +++ /dev/null @@ -1,6 +0,0 @@ -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 100Mi diff --git a/modules/container-k8s/src/main/jkube/deps/postgres-deployment.yml b/modules/container-k8s/src/main/jkube/deps/postgres-deployment.yml deleted file mode 100644 index c5290982642..00000000000 --- a/modules/container-k8s/src/main/jkube/deps/postgres-deployment.yml +++ /dev/null @@ -1,31 +0,0 @@ -spec: - replicas: 1 - strategy: - type: Recreate - template: - spec: - containers: - - name: postgres - image: postgres:13 - ports: - - containerPort: 5432 - env: - - name: POSTGRES_USER - value: dataverse - - name: POSTGRES_PASSWORD - value: supersecret - - name: PGDATA - value: /var/lib/postgresql/data/pgdata - volumeMounts: - - name: postgresql-persistent-storage - mountPath: /var/lib/postgresql/data - readinessProbe: - exec: - command: ["pg_isready"] - initialDelaySeconds: 5 - failureThreshold: 100 - periodSeconds: 5 - volumes: - - name: postgresql-persistent-storage - persistentVolumeClaim: - claimName: postgres \ No newline at end of file diff --git a/modules/container-k8s/src/main/jkube/deps/postgres-pvc.yml b/modules/container-k8s/src/main/jkube/deps/postgres-pvc.yml deleted file mode 100644 index 9cefb651bd4..00000000000 --- a/modules/container-k8s/src/main/jkube/deps/postgres-pvc.yml +++ /dev/null @@ -1,6 +0,0 @@ -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 300Mi diff --git a/modules/container-k8s/src/main/jkube/deps/postgres-svc.yml b/modules/container-k8s/src/main/jkube/deps/postgres-svc.yml deleted file mode 100644 index fc75438b31c..00000000000 --- a/modules/container-k8s/src/main/jkube/deps/postgres-svc.yml +++ /dev/null @@ -1,5 +0,0 @@ -spec: - ports: - - port: 5432 - targetPort: 5432 - protocol: TCP \ No newline at end of file diff --git a/modules/container-k8s/src/main/jkube/profiles.yml b/modules/container-k8s/src/main/jkube/profiles.yml deleted file mode 100644 index 8443a9cf54c..00000000000 --- a/modules/container-k8s/src/main/jkube/profiles.yml +++ /dev/null @@ -1,12 +0,0 @@ -- name: deps - extends: default -- name: default - enricher: - excludes: - - jkube-volume-permission - - jkube-project-label -- name: security-hardening - enricher: - excludes: - - jkube-volume-permission - - jkube-project-label From 4709cd068f1db31e514f520f6f4eac8ba30e9b1a Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Fri, 23 Feb 2024 16:54:40 -0500 Subject: [PATCH 105/141] #10286 merge cleanup --- .../harvard/iq/dataverse/util/json/JsonPrinter.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index 6b28dfb0050..202b23a331d 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -657,25 +657,26 @@ public static JsonObjectBuilder json(DatasetFieldType fld) { } public static JsonObjectBuilder json(FileMetadata fmd){ - return json(fmd, false); + return json(fmd, false, false); } - public static JsonObjectBuilder json(FileMetadata fmd, Boolean includeOwners) { - return jsonObjectBuilder() + public static JsonObjectBuilder json(FileMetadata fmd, boolean includeOwners, boolean printDatasetVersion) { + JsonObjectBuilder builder = jsonObjectBuilder(); + // deprecated: .add("category", fmd.getCategory()) // TODO: uh, figure out what to do here... it's deprecated // in a sense that there's no longer the category field in the // fileMetadata object; but there are now multiple, oneToMany file // categories - and we probably need to export them too!) -- L.A. 4.5 // DONE: catgegories by name - .add("description", fmd.getDescription()) + builder.add("description", fmd.getDescription()) .add("label", fmd.getLabel()) // "label" is the filename .add("restricted", fmd.isRestricted()) .add("directoryLabel", fmd.getDirectoryLabel()) .add("version", fmd.getVersion()) .add("datasetVersionId", fmd.getDatasetVersion().getId()) .add("categories", getFileCategories(fmd)) - .add("dataFile", JsonPrinter.json(fmd.getDataFile(), fmd, false)); + .add("dataFile", JsonPrinter.json(fmd.getDataFile(), fmd, false, includeOwners)); if (printDatasetVersion) { builder.add("datasetVersion", json(fmd.getDatasetVersion(), false)); From 4789d2e8bb0acefb1a531eeef5b4f86a9eceac5c Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Mon, 26 Feb 2024 11:43:20 -0500 Subject: [PATCH 106/141] #10286 more merge fixes --- src/main/java/edu/harvard/iq/dataverse/api/Files.java | 10 +++++++--- .../harvard/iq/dataverse/util/json/JsonPrinter.java | 4 ++++ .../java/edu/harvard/iq/dataverse/api/FilesIT.java | 4 ++-- .../iq/dataverse/util/json/JsonPrinterTest.java | 2 ++ 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Files.java b/src/main/java/edu/harvard/iq/dataverse/api/Files.java index a522a4de8b1..c5ac468d1b1 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Files.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Files.java @@ -487,9 +487,10 @@ public Response getFileData(@Context ContainerRequestContext crc, @PathParam("id") String fileIdOrPersistentId, @QueryParam("includeDeaccessioned") boolean includeDeaccessioned, @QueryParam("returnDatasetVersion") boolean returnDatasetVersion, + @QueryParam("returnOwners") boolean returnOwners, @Context UriInfo uriInfo, @Context HttpHeaders headers) { - return response( req -> getFileDataResponse(req, fileIdOrPersistentId, DS_VERSION_LATEST, includeDeaccessioned, returnDatasetVersion, uriInfo, headers), getRequestUser(crc)); + return response( req -> getFileDataResponse(req, fileIdOrPersistentId, DS_VERSION_LATEST, includeDeaccessioned, returnDatasetVersion, returnOwners, uriInfo, headers), getRequestUser(crc)); } @GET @@ -500,9 +501,10 @@ public Response getFileData(@Context ContainerRequestContext crc, @PathParam("datasetVersionId") String datasetVersionId, @QueryParam("includeDeaccessioned") boolean includeDeaccessioned, @QueryParam("returnDatasetVersion") boolean returnDatasetVersion, + @QueryParam("returnOwners") boolean returnOwners, @Context UriInfo uriInfo, @Context HttpHeaders headers) { - return response( req -> getFileDataResponse(req, fileIdOrPersistentId, datasetVersionId, includeDeaccessioned, returnDatasetVersion, uriInfo, headers), getRequestUser(crc)); + return response( req -> getFileDataResponse(req, fileIdOrPersistentId, datasetVersionId, includeDeaccessioned, returnDatasetVersion, returnOwners, uriInfo, headers), getRequestUser(crc)); } private Response getFileDataResponse(final DataverseRequest req, @@ -510,6 +512,7 @@ private Response getFileDataResponse(final DataverseRequest req, String datasetVersionId, boolean includeDeaccessioned, boolean returnDatasetVersion, + boolean returnOwners, UriInfo uriInfo, HttpHeaders headers) throws WrappedResponse { final DataFile dataFile = execCommand(new GetDataFileCommand(req, findDataFileOrDie(fileIdOrPersistentId))); @@ -546,10 +549,11 @@ public Command handleLatestPublished() { return Response.ok(Json.createObjectBuilder() .add("status", ApiConstants.STATUS_OK) - .add("data", json(fm, includeOwners)).build()) + .add("data", json(fileMetadata, returnOwners, returnDatasetVersion)).build()) .type(MediaType.APPLICATION_JSON) .build(); } + @GET @AuthRequired diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index 202b23a331d..873e3721493 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -681,6 +681,10 @@ public static JsonObjectBuilder json(FileMetadata fmd, boolean includeOwners, bo if (printDatasetVersion) { builder.add("datasetVersion", json(fmd.getDatasetVersion(), false)); } + + if (includeOwners){ + builder.add("isPartOf", getOwnersFromDvObject(fmd.getDataFile(), fmd.getDatasetVersion())); + } return builder; } diff --git a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java index fd54defae85..e09177bad70 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java @@ -1676,7 +1676,7 @@ public void testGetFileOwners() { String dataverseAlias = createDataverseGetAlias(apiToken); - Response createDatasetResponse = UtilIT.createRandomDatasetViaNativeApi(dataverseAlias, apiToken); + Response createDatasetResponse = UtilIT.createRandomDatasetViaNativeApi(dataverseAlias, apiToken); createDatasetResponse.prettyPrint(); Integer datasetId = JsonPath.from(createDatasetResponse.body().asString()).getInt("data.id"); @@ -1704,7 +1704,7 @@ public void testGetFileOwners() { .body("data.dataFile.filesize", equalTo(8361)) .statusCode(OK.getStatusCode()); - getFileDataResponse.then().assertThat().body("data.dataFile.isPartOf.identifier", equalTo(datasetPid)); + getFileDataResponse.then().assertThat().body("data.dataFile.isPartOf.identifier", equalTo(datasetPid)); // ------------------------- // Publish dataverse and dataset diff --git a/src/test/java/edu/harvard/iq/dataverse/util/json/JsonPrinterTest.java b/src/test/java/edu/harvard/iq/dataverse/util/json/JsonPrinterTest.java index 88f6a5bdbce..11da71e1980 100644 --- a/src/test/java/edu/harvard/iq/dataverse/util/json/JsonPrinterTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/util/json/JsonPrinterTest.java @@ -158,8 +158,10 @@ public void testGetFileCategories() { emb.setDateAvailable(LocalDate.parse("2021-12-03")); emb.setReason("Some reason"); dataFile.setEmbargo(emb); + dsVersion.setId(Long.MIN_VALUE); fmd.setDatasetVersion(dsVersion); fmd.setDataFile(dataFile); + fmd.setVersion(Long.MIN_VALUE); List fileCategories = new ArrayList<>(); DataFileCategory dataFileCategory = new DataFileCategory(); dataFileCategory.setName("Data"); From 6a4af1579fa12ecfe4d79845b51f277042571cec Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Mon, 26 Feb 2024 14:53:05 -0500 Subject: [PATCH 107/141] #10286 prevent double owner array; fix test --- .../harvard/iq/dataverse/util/json/JsonPrinter.java | 11 +++-------- .../java/edu/harvard/iq/dataverse/api/FilesIT.java | 2 +- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index 873e3721493..5ee05aeb2a1 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -339,10 +339,9 @@ private static JsonObjectBuilder addEmbeddedOwnerObject(DvObject dvo, JsonObject if (dvo.isInstanceofDataset()) { ownerObject.add("type", "DATASET"); if (dvo.getGlobalId() != null) { - ownerObject.add("identifier", dvo.getGlobalId().asString()); - } else { - ownerObject.add("identifier", dvo.getId()); + ownerObject.add("persistentIdentifier", dvo.getGlobalId().asString()); } + ownerObject.add("identifier", dvo.getId()); String versionString = dsv == null ? "" : dsv.getFriendlyVersionNumber(); if (!versionString.isEmpty()){ ownerObject.add("version", versionString); @@ -420,7 +419,7 @@ public static JsonObjectBuilder json(DatasetVersion dsv, List anonymized /* return json(dsv, null, includeFiles, null); } public static JsonObjectBuilder json(DatasetVersion dsv, List anonymizedFieldTypeNamesList, boolean includeFiles, Long numberOfFiles) {*/ - Dataset dataset = dsv.getDataset(); + Dataset dataset = dsv.getDataset(); JsonObjectBuilder bld = jsonObjectBuilder() .add("id", dsv.getId()).add("datasetId", dataset.getId()) .add("datasetPersistentId", dataset.getGlobalId().asString()) @@ -681,10 +680,6 @@ public static JsonObjectBuilder json(FileMetadata fmd, boolean includeOwners, bo if (printDatasetVersion) { builder.add("datasetVersion", json(fmd.getDatasetVersion(), false)); } - - if (includeOwners){ - builder.add("isPartOf", getOwnersFromDvObject(fmd.getDataFile(), fmd.getDatasetVersion())); - } return builder; } diff --git a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java index e09177bad70..f001580508c 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java @@ -1704,7 +1704,7 @@ public void testGetFileOwners() { .body("data.dataFile.filesize", equalTo(8361)) .statusCode(OK.getStatusCode()); - getFileDataResponse.then().assertThat().body("data.dataFile.isPartOf.identifier", equalTo(datasetPid)); + getFileDataResponse.then().assertThat().body("data.dataFile.isPartOf.identifier", equalTo(datasetId)); // ------------------------- // Publish dataverse and dataset From 14a817c866455d90851def63a811d706bf56b0f5 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Mon, 26 Feb 2024 15:27:54 -0500 Subject: [PATCH 108/141] #10286 add release note --- doc/release-notes/10286-return-owner-added-to-get-apis.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 doc/release-notes/10286-return-owner-added-to-get-apis.md diff --git a/doc/release-notes/10286-return-owner-added-to-get-apis.md b/doc/release-notes/10286-return-owner-added-to-get-apis.md new file mode 100644 index 00000000000..b0aba92f537 --- /dev/null +++ b/doc/release-notes/10286-return-owner-added-to-get-apis.md @@ -0,0 +1,5 @@ +The API endpoints for getting datasets, Dataverse collections, and datafiles have been extended to support the following optional 'returnOwners' query parameter. + +Including the parameter and setting it to true will add a hierarchy showing which dataset and dataverse collection(s) the object is part of to the json object returned. + + From a34d1ecc13c192f3fcba7796f1e30cd0121006d8 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Mon, 26 Feb 2024 16:07:39 -0500 Subject: [PATCH 109/141] Update native-api.rst --- doc/sphinx-guides/source/api/native-api.rst | 43 +++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index 3c00d8c991f..d2af542f326 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -88,6 +88,14 @@ The fully expanded example above (without environment variables) looks like this curl "https://demo.dataverse.org/api/dataverses/root" +If you want to include the Dataverse collections that this collection is part of, you must set ``returnOwners`` query parameter to ``true``. + +Usage example: + +.. code-block:: bash + + curl "https://demo.dataverse.org/api/dataverses/root?returnOwners=true" + To view an unpublished Dataverse collection: .. code-block:: bash @@ -910,6 +918,14 @@ The fully expanded example above (without environment variables) looks like this The dataset id can be extracted from the response retrieved from the API which uses the persistent identifier (``/api/datasets/:persistentId/?persistentId=$PERSISTENT_IDENTIFIER``). +If you want to include the Dataverse collections that this dataset is part of, you must set ``returnOwners`` query parameter to ``true``. + +Usage example: + +.. code-block:: bash + + curl "https://demo.dataverse.org/api/datasets/24?returnOwners=true" + List Versions of a Dataset ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1016,6 +1032,14 @@ Usage example: curl "https://demo.dataverse.org/api/datasets/24/versions/1.0?includeDeaccessioned=true" +If you want to include the Dataverse collections that this dataset version is part of, you must set ``returnOwners`` query parameter to ``true``. + +Usage example: + +.. code-block:: bash + + curl "https://demo.dataverse.org/api/datasets/24versions/1.0?returnOwners=true" + .. _export-dataset-metadata-api: Export Metadata of a Dataset in Various Formats @@ -2892,6 +2916,25 @@ The fully expanded example above (without environment variables) looks like this curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" "https://demo.dataverse.org/api/files/:persistentId/versions/:draft?persistentId=doi:10.5072/FK2/J8SJZB&returnDatasetVersion=true" +If you want to include the dataset and collections that the is part of in the response, there is an optional parameter for this called ``returnOwners`` whose default value is ``false``. + +Usage example: + +.. code-block:: bash + + export SERVER_URL=https://demo.dataverse.org + export PERSISTENT_IDENTIFIER=doi:10.5072/FK2/J8SJZB + export DATASET_VERSION=:draft + export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + + curl -H "X-Dataverse-key:$API_TOKEN" "$SERVER_URL/api/files/:persistentId/versions/$DATASET_VERSION?persistentId=$PERSISTENT_IDENTIFIER&returnOwners=true" + +The fully expanded example above (without environment variables) looks like this: + +.. code-block:: bash + + curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" "https://demo.dataverse.org/api/files/:persistentId/versions/:draft?persistentId=doi:10.5072/FK2/J8SJZB&returnOwners=true" + Adding Files ~~~~~~~~~~~~ From 3751638054e386b4a95151f21ef2a935b20d6faa Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Mon, 26 Feb 2024 16:09:16 -0500 Subject: [PATCH 110/141] #10286 remove debug code --- src/main/java/edu/harvard/iq/dataverse/api/Datasets.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java b/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java index 7d0141641fe..f82d7adaecd 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java @@ -440,7 +440,6 @@ public Response getVersion(@Context ContainerRequestContext crc, if (excludeFiles == null ? true : !excludeFiles) { dsv = datasetversionService.findDeep(dsv.getId()); } - System.out.print("returnOwners: " + includeOwners); return ok(json(dsv, null, excludeFiles == null ? true : !excludeFiles, includeOwners)); }, getRequestUser(crc)); } From 6b7058ae9a9fd4dd3b606c67385f4b70a6b95ceb Mon Sep 17 00:00:00 2001 From: Vera Clemens Date: Tue, 27 Feb 2024 10:35:22 +0100 Subject: [PATCH 111/141] fix: do not allow users to assign permissions that they don't have themselves --- .../engine/command/impl/AssignRoleCommand.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AssignRoleCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AssignRoleCommand.java index 5577d541012..e4edb973cd9 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AssignRoleCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AssignRoleCommand.java @@ -19,6 +19,7 @@ import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.engine.command.exception.IllegalCommandException; import java.util.Collections; +import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -75,9 +76,19 @@ public RoleAssignment execute(CommandContext ctxt) throws CommandException { @Override public Map> getRequiredPermissions() { // for data file check permission on owning dataset - return Collections.singletonMap("", - defPoint instanceof Dataverse ? Collections.singleton(Permission.ManageDataversePermissions) - : defPoint instanceof Dataset ? Collections.singleton(Permission.ManageDatasetPermissions) : Collections.singleton(Permission.ManageFilePermissions)); + Set requiredPermissions = new HashSet(); + + if (defPoint instanceof Dataverse) { + requiredPermissions.add(Permission.ManageDataversePermissions); + } else if (defPoint instanceof Dataset) { + requiredPermissions.add(Permission.ManageDatasetPermissions); + } else { + requiredPermissions.add(Permission.ManageFilePermissions); + } + + requiredPermissions.addAll(role.permissions()); + + return Collections.singletonMap("", requiredPermissions); } @Override From aeb487ea7a3c6228687320f2acd700b255db90b3 Mon Sep 17 00:00:00 2001 From: Vera Clemens Date: Tue, 27 Feb 2024 10:35:44 +0100 Subject: [PATCH 112/141] test: do not allow users to assign permissions that they don't have themselves --- .../harvard/iq/dataverse/api/DatasetsIT.java | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java b/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java index e1c4b901116..310bc2e5851 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java @@ -1670,6 +1670,26 @@ public void testAddRoles(){ giveRandoPermission = UtilIT.grantRoleOnDataset(datasetPersistentId, "fileDownloader", "@" + randomUsername, apiToken); giveRandoPermission.prettyPrint(); assertEquals(200, giveRandoPermission.getStatusCode()); + + // Create another random user to become curator: + + Response createCuratorUser = UtilIT.createRandomUser(); + createCuratorUser.prettyPrint(); + String curatorUsername = UtilIT.getUsernameFromResponse(createCuratorUser); + String curatorUserApiToken = UtilIT.getApiTokenFromResponse(createCuratorUser); + + Response giveCuratorPermission = UtilIT.grantRoleOnDataset(datasetPersistentId, "curator", "@" + curatorUsername, apiToken); + giveCuratorPermission.prettyPrint(); + assertEquals(200, giveCuratorPermission.getStatusCode()); + + // Test if privilege escalation is possible: curator should not be able to assign admin rights + Response giveTooMuchPermission = UtilIT.grantRoleOnDataset(datasetPersistentId, "admin", "@" + curatorUsername, curatorUserApiToken); + giveTooMuchPermission.prettyPrint(); + assertEquals(401, giveTooMuchPermission.getStatusCode()); + + giveTooMuchPermission = UtilIT.grantRoleOnDataset(datasetPersistentId, "admin", "@" + randomUsername, curatorUserApiToken); + giveTooMuchPermission.prettyPrint(); + assertEquals(401, giveTooMuchPermission.getStatusCode()); String idToDelete = JsonPath.from(giveRandoPermission.getBody().asString()).getString("data.id"); @@ -1692,7 +1712,7 @@ public void testAddRoles(){ deleteGrantedAccess.prettyPrint(); assertEquals(200, deleteGrantedAccess.getStatusCode()); - Response deleteDatasetResponse = UtilIT.deleteDatasetViaNativeApi(datasetId, apiToken); + Response deleteDatasetResponse = UtilIT.deleteDatasetViaNativeApi(datasetId, apiToken); deleteDatasetResponse.prettyPrint(); assertEquals(200, deleteDatasetResponse.getStatusCode()); @@ -1703,6 +1723,14 @@ public void testAddRoles(){ Response deleteUserResponse = UtilIT.deleteUser(username); deleteUserResponse.prettyPrint(); assertEquals(200, deleteUserResponse.getStatusCode()); + + deleteUserResponse = UtilIT.deleteUser(randomUsername); + deleteUserResponse.prettyPrint(); + assertEquals(200, deleteUserResponse.getStatusCode()); + + deleteUserResponse = UtilIT.deleteUser(curatorUsername); + deleteUserResponse.prettyPrint(); + assertEquals(200, deleteUserResponse.getStatusCode()); } From c0c247e8cd7b6ddcec88b45a0b9fa425badea12f Mon Sep 17 00:00:00 2001 From: Vera Clemens Date: Tue, 27 Feb 2024 13:49:47 +0100 Subject: [PATCH 113/141] docs: update User Guide + add release note for IQSS#10342 --- .../10342-assign-roles-without-privilege-escalation.md | 1 + doc/sphinx-guides/source/user/dataset-management.rst | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 doc/release-notes/10342-assign-roles-without-privilege-escalation.md diff --git a/doc/release-notes/10342-assign-roles-without-privilege-escalation.md b/doc/release-notes/10342-assign-roles-without-privilege-escalation.md new file mode 100644 index 00000000000..a4ef743f50d --- /dev/null +++ b/doc/release-notes/10342-assign-roles-without-privilege-escalation.md @@ -0,0 +1 @@ +The permissions required to assign a role have been fixed. It is no longer possible to assign a role that includes permissions that the assigning user doesn't have. \ No newline at end of file diff --git a/doc/sphinx-guides/source/user/dataset-management.rst b/doc/sphinx-guides/source/user/dataset-management.rst index 708113f9a99..d3faf479deb 100755 --- a/doc/sphinx-guides/source/user/dataset-management.rst +++ b/doc/sphinx-guides/source/user/dataset-management.rst @@ -566,7 +566,7 @@ This is where you will enable a particular Guestbook for your dataset, which is Roles & Permissions =================== -Dataverse installation user accounts can be granted roles that define which actions they are allowed to take on specific Dataverse collections, datasets, and/or files. Each role comes with a set of permissions, which define the specific actions that users may take. +Dataverse installation user accounts can be granted roles that define which actions they are allowed to take on specific Dataverse collections, datasets, and/or files. Each role comes with a set of permissions, which define the specific actions that users may take. It is not possible to grant a role that comes with a permission that the granting user themselves does not have. Roles and permissions may also be granted to groups. Groups can be defined as a set of Dataverse user accounts, a collection of IP addresses (e.g. all users of a library's computers), or a collection of all users who log in using a particular institutional login (e.g. everyone who logs in with a particular university's account credentials). From 34c0f6762f08e50cff641ac14f31538df147aeb1 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Tue, 27 Feb 2024 09:22:23 -0500 Subject: [PATCH 114/141] #10286 code cleanup --- .../harvard/iq/dataverse/api/Datasets.java | 4 +-- .../harvard/iq/dataverse/api/Dataverses.java | 5 ++-- .../iq/dataverse/util/json/JsonPrinter.java | 25 ++++++++----------- 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java b/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java index f82d7adaecd..04af43931cb 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java @@ -421,7 +421,7 @@ public Response getVersion(@Context ContainerRequestContext crc, @PathParam("versionId") String versionId, @QueryParam("excludeFiles") Boolean excludeFiles, @QueryParam("includeDeaccessioned") boolean includeDeaccessioned, - @QueryParam("returnOwners") boolean includeOwners, + @QueryParam("returnOwners") boolean returnOwners, @Context UriInfo uriInfo, @Context HttpHeaders headers) { return response( req -> { @@ -440,7 +440,7 @@ public Response getVersion(@Context ContainerRequestContext crc, if (excludeFiles == null ? true : !excludeFiles) { dsv = datasetversionService.findDeep(dsv.getId()); } - return ok(json(dsv, null, excludeFiles == null ? true : !excludeFiles, includeOwners)); + return ok(json(dsv, null, excludeFiles == null ? true : !excludeFiles, returnOwners)); }, getRequestUser(crc)); } diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java index 3bcbfdd4d58..88c6c85802d 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java @@ -610,12 +610,11 @@ private Dataset parseDataset(String datasetJson) throws WrappedResponse { @GET @AuthRequired @Path("{identifier}") - public Response getDataverse(@Context ContainerRequestContext crc, @PathParam("identifier") String idtf, @QueryParam("returnOwners") Boolean returnOwners) { - Boolean includeOwners = returnOwners == null ? false : returnOwners; + public Response getDataverse(@Context ContainerRequestContext crc, @PathParam("identifier") String idtf, @QueryParam("returnOwners") boolean returnOwners) { return response(req -> ok( json(execCommand(new GetDataverseCommand(req, findDataverseOrDie(idtf))), settingsService.isTrueForKey(SettingsServiceBean.Key.ExcludeEmailFromExport, false), - includeOwners + returnOwners )), getRequestUser(crc)); } diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index 5ee05aeb2a1..d9f19f1e94e 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -262,7 +262,7 @@ public static JsonObjectBuilder json(Dataverse dv) { } //TODO: Once we upgrade to Java EE 8 we can remove objects from the builder, and this email removal can be done in a better place. - public static JsonObjectBuilder json(Dataverse dv, Boolean hideEmail, Boolean includeOwners) { + public static JsonObjectBuilder json(Dataverse dv, Boolean hideEmail, Boolean returnOwners) { JsonObjectBuilder bld = jsonObjectBuilder() .add("id", dv.getId()) .add("alias", dv.getAlias()) @@ -271,7 +271,7 @@ public static JsonObjectBuilder json(Dataverse dv, Boolean hideEmail, Boolean in if(!hideEmail) { bld.add("dataverseContacts", JsonPrinter.json(dv.getDataverseContacts())); } - if (includeOwners){ + if (returnOwners){ bld.add("isPartOf", getOwnersFromDvObject(dv)); } bld.add("permissionRoot", dv.isPermissionRoot()) @@ -384,7 +384,7 @@ public static JsonObjectBuilder json(Dataset ds){ return json(ds, false); } - public static JsonObjectBuilder json(Dataset ds, Boolean includeOwners) { + public static JsonObjectBuilder json(Dataset ds, Boolean returnOwners) { JsonObjectBuilder bld = jsonObjectBuilder() .add("id", ds.getId()) .add("identifier", ds.getIdentifier()) @@ -397,7 +397,7 @@ public static JsonObjectBuilder json(Dataset ds, Boolean includeOwners) { if (DvObjectContainer.isMetadataLanguageSet(ds.getMetadataLanguage())) { bld.add("metadataLanguage", ds.getMetadataLanguage()); } - if (includeOwners){ + if (returnOwners){ bld.add("isPartOf", getOwnersFromDvObject(ds)); } return bld; @@ -415,11 +415,8 @@ public static JsonObjectBuilder json(DatasetVersion dsv, boolean includeFiles) { return json(dsv, null, includeFiles, false); } - public static JsonObjectBuilder json(DatasetVersion dsv, List anonymizedFieldTypeNamesList, boolean includeFiles, boolean includeOwners) { - /* return json(dsv, null, includeFiles, null); - } - public static JsonObjectBuilder json(DatasetVersion dsv, List anonymizedFieldTypeNamesList, boolean includeFiles, Long numberOfFiles) {*/ - Dataset dataset = dsv.getDataset(); + public static JsonObjectBuilder json(DatasetVersion dsv, List anonymizedFieldTypeNamesList, boolean includeFiles, boolean returnOwners) { + Dataset dataset = dsv.getDataset(); JsonObjectBuilder bld = jsonObjectBuilder() .add("id", dsv.getId()).add("datasetId", dataset.getId()) .add("datasetPersistentId", dataset.getGlobalId().asString()) @@ -462,7 +459,7 @@ public static JsonObjectBuilder json(DatasetVersion dsv, List anonymized jsonByBlocks(dsv.getDatasetFields(), anonymizedFieldTypeNamesList) : jsonByBlocks(dsv.getDatasetFields()) ); - if(includeOwners){ + if(returnOwners){ bld.add("isPartOf", getOwnersFromDvObject(dataset)); } if (includeFiles) { @@ -659,7 +656,7 @@ public static JsonObjectBuilder json(FileMetadata fmd){ return json(fmd, false, false); } - public static JsonObjectBuilder json(FileMetadata fmd, boolean includeOwners, boolean printDatasetVersion) { + public static JsonObjectBuilder json(FileMetadata fmd, boolean returnOwners, boolean printDatasetVersion) { JsonObjectBuilder builder = jsonObjectBuilder(); // deprecated: .add("category", fmd.getCategory()) @@ -675,7 +672,7 @@ public static JsonObjectBuilder json(FileMetadata fmd, boolean includeOwners, bo .add("version", fmd.getVersion()) .add("datasetVersionId", fmd.getDatasetVersion().getId()) .add("categories", getFileCategories(fmd)) - .add("dataFile", JsonPrinter.json(fmd.getDataFile(), fmd, false, includeOwners)); + .add("dataFile", JsonPrinter.json(fmd.getDataFile(), fmd, false, returnOwners)); if (printDatasetVersion) { builder.add("datasetVersion", json(fmd.getDatasetVersion(), false)); @@ -705,7 +702,7 @@ public static JsonObjectBuilder json(DataFile df, FileMetadata fileMetadata, boo return json(df, fileMetadata, forExportDataProvider, false); } - public static JsonObjectBuilder json(DataFile df, FileMetadata fileMetadata, boolean forExportDataProvider, Boolean includeOwners) { + public static JsonObjectBuilder json(DataFile df, FileMetadata fileMetadata, boolean forExportDataProvider, boolean returnOwners) { // File names are no longer stored in the DataFile entity; // (they are instead in the FileMetadata (as "labels") - this way // the filename can change between versions... @@ -781,7 +778,7 @@ public static JsonObjectBuilder json(DataFile df, FileMetadata fileMetadata, boo ? JsonPrinter.jsonVarGroup(fileMetadata.getVarGroups()) : null); } - if (includeOwners){ + if (returnOwners){ builder.add("isPartOf", getOwnersFromDvObject(df, fileMetadata.getDatasetVersion())); } return builder; From ae132a3837fe4dc3eccd58f3965682d9faf930b3 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Tue, 27 Feb 2024 09:24:46 -0500 Subject: [PATCH 115/141] Revert "Update native-api.rst" This reverts commit a34d1ecc13c192f3fcba7796f1e30cd0121006d8. --- doc/sphinx-guides/source/api/native-api.rst | 43 --------------------- 1 file changed, 43 deletions(-) diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index d2af542f326..3c00d8c991f 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -88,14 +88,6 @@ The fully expanded example above (without environment variables) looks like this curl "https://demo.dataverse.org/api/dataverses/root" -If you want to include the Dataverse collections that this collection is part of, you must set ``returnOwners`` query parameter to ``true``. - -Usage example: - -.. code-block:: bash - - curl "https://demo.dataverse.org/api/dataverses/root?returnOwners=true" - To view an unpublished Dataverse collection: .. code-block:: bash @@ -918,14 +910,6 @@ The fully expanded example above (without environment variables) looks like this The dataset id can be extracted from the response retrieved from the API which uses the persistent identifier (``/api/datasets/:persistentId/?persistentId=$PERSISTENT_IDENTIFIER``). -If you want to include the Dataverse collections that this dataset is part of, you must set ``returnOwners`` query parameter to ``true``. - -Usage example: - -.. code-block:: bash - - curl "https://demo.dataverse.org/api/datasets/24?returnOwners=true" - List Versions of a Dataset ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1032,14 +1016,6 @@ Usage example: curl "https://demo.dataverse.org/api/datasets/24/versions/1.0?includeDeaccessioned=true" -If you want to include the Dataverse collections that this dataset version is part of, you must set ``returnOwners`` query parameter to ``true``. - -Usage example: - -.. code-block:: bash - - curl "https://demo.dataverse.org/api/datasets/24versions/1.0?returnOwners=true" - .. _export-dataset-metadata-api: Export Metadata of a Dataset in Various Formats @@ -2916,25 +2892,6 @@ The fully expanded example above (without environment variables) looks like this curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" "https://demo.dataverse.org/api/files/:persistentId/versions/:draft?persistentId=doi:10.5072/FK2/J8SJZB&returnDatasetVersion=true" -If you want to include the dataset and collections that the is part of in the response, there is an optional parameter for this called ``returnOwners`` whose default value is ``false``. - -Usage example: - -.. code-block:: bash - - export SERVER_URL=https://demo.dataverse.org - export PERSISTENT_IDENTIFIER=doi:10.5072/FK2/J8SJZB - export DATASET_VERSION=:draft - export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - - curl -H "X-Dataverse-key:$API_TOKEN" "$SERVER_URL/api/files/:persistentId/versions/$DATASET_VERSION?persistentId=$PERSISTENT_IDENTIFIER&returnOwners=true" - -The fully expanded example above (without environment variables) looks like this: - -.. code-block:: bash - - curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" "https://demo.dataverse.org/api/files/:persistentId/versions/:draft?persistentId=doi:10.5072/FK2/J8SJZB&returnOwners=true" - Adding Files ~~~~~~~~~~~~ From da7773241a30643e4b71b9d9f86df26e0d4c450e Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Tue, 27 Feb 2024 09:55:40 -0500 Subject: [PATCH 116/141] #10286 one more test --- src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java index f001580508c..7150b32c2b0 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java @@ -1705,6 +1705,7 @@ public void testGetFileOwners() { .statusCode(OK.getStatusCode()); getFileDataResponse.then().assertThat().body("data.dataFile.isPartOf.identifier", equalTo(datasetId)); + getFileDataResponse.then().assertThat().body("data.dataFile.isPartOf.persistentIdentifier", equalTo(datasetPid)); // ------------------------- // Publish dataverse and dataset From 9790d23504b150f1e8002ac7b55911e01aafa981 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Tue, 27 Feb 2024 11:42:53 -0500 Subject: [PATCH 117/141] Update native-api.rst --- doc/sphinx-guides/source/api/native-api.rst | 54 +++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index 3c00d8c991f..ca36e906545 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -88,6 +88,14 @@ The fully expanded example above (without environment variables) looks like this curl "https://demo.dataverse.org/api/dataverses/root" +If you want to include the Dataverse collections that this collection is part of, you must set ``returnOwners`` query parameter to ``true``. + +Usage example: + +.. code-block:: bash + + curl "https://demo.dataverse.org/api/dataverses/root?returnOwners=true" + To view an unpublished Dataverse collection: .. code-block:: bash @@ -910,6 +918,14 @@ The fully expanded example above (without environment variables) looks like this The dataset id can be extracted from the response retrieved from the API which uses the persistent identifier (``/api/datasets/:persistentId/?persistentId=$PERSISTENT_IDENTIFIER``). +If you want to include the Dataverse collections that this dataset is part of, you must set ``returnOwners`` query parameter to ``true``. + +Usage example: + +.. code-block:: bash + + curl "https://demo.dataverse.org/api/datasets/24?returnOwners=true" + List Versions of a Dataset ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1016,6 +1032,14 @@ Usage example: curl "https://demo.dataverse.org/api/datasets/24/versions/1.0?includeDeaccessioned=true" +If you want to include the Dataverse collections that this dataset version is part of, you must set ``returnOwners`` query parameter to ``true``. + +Usage example: + +.. code-block:: bash + + curl "https://demo.dataverse.org/api/datasets/24/versions/1.0?returnOwners=true" + .. _export-dataset-metadata-api: Export Metadata of a Dataset in Various Formats @@ -2585,6 +2609,15 @@ Get Dataset By Private URL Token curl "$SERVER_URL/api/datasets/privateUrlDatasetVersion/$PRIVATE_URL_TOKEN" +If you want to include the Dataverse collections that this dataset is part of, you must set ``returnOwners`` query parameter to ``true``. + +Usage example: + +.. code-block:: bash + + curl "https://demo.dataverse.org/api/datasets/privateUrlDatasetVersion/a56444bc-7697-4711-8964-e0577f055fd2?returnOwners=true" + + .. _get-citation: Get Citation @@ -2892,6 +2925,27 @@ The fully expanded example above (without environment variables) looks like this curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" "https://demo.dataverse.org/api/files/:persistentId/versions/:draft?persistentId=doi:10.5072/FK2/J8SJZB&returnDatasetVersion=true" +If you want to include the dataset and collections that the file is part of in the response, there is an optional parameter for this called ``returnOwners`` whose default value is ``false``. + +Usage example: + +.. code-block:: bash + + export SERVER_URL=https://demo.dataverse.org + export PERSISTENT_IDENTIFIER=doi:10.5072/FK2/J8SJZB + export DATASET_VERSION=:draft + export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + + curl -H "X-Dataverse-key:$API_TOKEN" "$SERVER_URL/api/files/:persistentId/versions/$DATASET_VERSION?persistentId=$PERSISTENT_IDENTIFIER&returnOwners=true" + +The fully expanded example above (without environment variables) looks like this: + +.. code-block:: bash + + curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" "https://demo.dataverse.org/api/files/:persistentId/versions/:draft?persistentId=doi:10.5072/FK2/J8SJZB&returnOwners=true" + + + Adding Files ~~~~~~~~~~~~ From 5760149b5527ebd351acca0b71757d8a4c8540bb Mon Sep 17 00:00:00 2001 From: qqmyers Date: Wed, 28 Feb 2024 16:26:55 -0500 Subject: [PATCH 118/141] typo --- doc/release-notes/10318-uningest-and-reingest.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/release-notes/10318-uningest-and-reingest.md b/doc/release-notes/10318-uningest-and-reingest.md index 9f6f81b4818..80ca6be57ea 100644 --- a/doc/release-notes/10318-uningest-and-reingest.md +++ b/doc/release-notes/10318-uningest-and-reingest.md @@ -1,3 +1,3 @@ New Uningest/Reingest options are available in the File Page Edit menu, allowing ingest errors to be cleared (by users who can published the associated dataset) -and (by suerpsuers) for a successful ingest to be undone or retried (e.g. after a Dataverse version update or if ingest size limits are changed). +and (by superusers) for a successful ingest to be undone or retried (e.g. after a Dataverse version update or if ingest size limits are changed). The /api/files//uningest api also now allows users who can publish the dataset to undo an ingest failure. From b62c12369955ec2425d3ff23219e0cac75d5d189 Mon Sep 17 00:00:00 2001 From: luddaniel <83018819+luddaniel@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:57:57 +0100 Subject: [PATCH 119/141] Make licenses searchable and facetable (#10204) * #9060 #7482 License of dataset and datafile are now indexed, searchable in API and filterable in GUI facets * #9060 #7482 Fix NullPointer possible case and IndexServiceBeanTest issues * #9060 #7482 Adding release note * #9060 #7482 review + added i18n on license facet --------- Co-authored-by: jeromeroucou --- conf/solr/9.3.0/schema.xml | 2 + ...482-make-licenses-searchable-faceatable.md | 6 +++ .../iq/dataverse/mydata/MyDataFinder.java | 2 +- .../iq/dataverse/search/IndexServiceBean.java | 15 ++++++- .../iq/dataverse/search/SearchFields.java | 2 + .../search/SearchIncludeFragment.java | 6 +++ .../dataverse/search/SearchServiceBean.java | 43 +++++++++++++------ .../java/propertyFiles/License.properties | 2 + .../staticSearchFields.properties | 1 + 9 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 doc/release-notes/9060-7482-make-licenses-searchable-faceatable.md diff --git a/conf/solr/9.3.0/schema.xml b/conf/solr/9.3.0/schema.xml index 3711ffeddba..f60a83f55f3 100644 --- a/conf/solr/9.3.0/schema.xml +++ b/conf/solr/9.3.0/schema.xml @@ -229,6 +229,8 @@ + + 6.2023.8 - 42.6.0 + 42.7.2 9.3.0 1.12.290 26.30.0 From c90595c5025955de7362ff0b30711f61877332ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:12:39 -0500 Subject: [PATCH 125/141] Bump org.apache.commons:commons-compress from 1.21 to 1.26.0 in /modules/dataverse-parent (#10332) * Bump org.apache.commons:commons-compress in /modules/dataverse-parent Bumps org.apache.commons:commons-compress from 1.21 to 1.26.0. --- updated-dependencies: - dependency-name: org.apache.commons:commons-compress dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Update commons-io commons-compress 1.26.0 uses a class introduced in commons-io 2.12 --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: qqmyers --- modules/dataverse-parent/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/dataverse-parent/pom.xml b/modules/dataverse-parent/pom.xml index bfefe3347fa..fd176c2fd80 100644 --- a/modules/dataverse-parent/pom.xml +++ b/modules/dataverse-parent/pom.xml @@ -157,10 +157,10 @@ 8.0.0 1.7.35 - 2.11.0 + 2.15.1 1.2 3.12.0 - 1.21 + 1.26.0 4.5.13 4.4.14 From 7706e586523adbe52d21c2c2bfc4c9c3994f65b4 Mon Sep 17 00:00:00 2001 From: Jan Range Date: Fri, 1 Mar 2024 08:33:48 +0100 Subject: [PATCH 126/141] add direct upload ref to `getting-started` --- doc/sphinx-guides/source/api/getting-started.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/sphinx-guides/source/api/getting-started.rst b/doc/sphinx-guides/source/api/getting-started.rst index a50f12d1381..fefe19bfb4e 100644 --- a/doc/sphinx-guides/source/api/getting-started.rst +++ b/doc/sphinx-guides/source/api/getting-started.rst @@ -86,7 +86,7 @@ See :ref:`create-dataset-command`. Uploading Files ~~~~~~~~~~~~~~~ -See :ref:`add-file-api`. +See :ref:`add-file-api`. In addition, when a Dataverse installation is configured to use S3 storage with direct upload enabled, there is API support to send a file directly to S3. This facilitates an efficient method to upload big files, but is more complex. The procedure is described in the :doc:`/developers/s3-direct-upload-api` guide. Publishing a Dataverse Collection ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 24de891582cdab7c4bf629ab671d3112f5f723cb Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Fri, 1 Mar 2024 06:05:30 -0500 Subject: [PATCH 127/141] use the term section and mention when switching guides #10347 --- doc/sphinx-guides/source/api/getting-started.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/sphinx-guides/source/api/getting-started.rst b/doc/sphinx-guides/source/api/getting-started.rst index fefe19bfb4e..c12fb01a269 100644 --- a/doc/sphinx-guides/source/api/getting-started.rst +++ b/doc/sphinx-guides/source/api/getting-started.rst @@ -86,7 +86,7 @@ See :ref:`create-dataset-command`. Uploading Files ~~~~~~~~~~~~~~~ -See :ref:`add-file-api`. In addition, when a Dataverse installation is configured to use S3 storage with direct upload enabled, there is API support to send a file directly to S3. This facilitates an efficient method to upload big files, but is more complex. The procedure is described in the :doc:`/developers/s3-direct-upload-api` guide. +See :ref:`add-file-api`. In addition, when a Dataverse installation is configured to use S3 storage with direct upload enabled, there is API support to send a file directly to S3. This facilitates an efficient method to upload big files, but is more complex. The procedure is described in the :doc:`/developers/s3-direct-upload-api` section of the Developer Guide. Publishing a Dataverse Collection ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 950b5fbdd9fd823f2d286830d7658fa1e8776a17 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Fri, 1 Mar 2024 06:11:09 -0500 Subject: [PATCH 128/141] add toc, overview heading, title case for all headings #10347 --- .../source/developers/s3-direct-upload-api.rst | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/doc/sphinx-guides/source/developers/s3-direct-upload-api.rst b/doc/sphinx-guides/source/developers/s3-direct-upload-api.rst index d7f270a4e38..1cb9ae9e6db 100644 --- a/doc/sphinx-guides/source/developers/s3-direct-upload-api.rst +++ b/doc/sphinx-guides/source/developers/s3-direct-upload-api.rst @@ -3,6 +3,12 @@ Direct DataFile Upload/Replace API The direct Datafile Upload API is used internally to support direct upload of files to S3 storage and by tools such as the DVUploader. +.. contents:: |toctitle| + :local: + +Overview +-------- + Direct upload involves a series of three activities, each involving interacting with the server for a Dataverse installation: * Requesting initiation of a transfer from the server @@ -91,7 +97,7 @@ If the client is unable to complete the multipart upload, it should call the abo .. _direct-add-to-dataset-api: -Adding the Uploaded file to the Dataset +Adding the Uploaded File to the Dataset --------------------------------------- Once the file exists in the s3 bucket, a final API call is needed to add it to the Dataset. This call is the same call used to upload a file to a Dataverse installation but, rather than sending the file bytes, additional metadata is added using the "jsonData" parameter. @@ -119,7 +125,7 @@ The allowed checksum algorithms are defined by the edu.harvard.iq.dataverse.Data Note that this API call can be used independently of the others, e.g. supporting use cases in which the file already exists in S3/has been uploaded via some out-of-band method. Enabling out-of-band uploads is described at :ref:`file-storage` in the Configuration Guide. With current S3 stores the object identifier must be in the correct bucket for the store, include the PID authority/identifier of the parent dataset, and be guaranteed unique, and the supplied storage identifier must be prefaced with the store identifier used in the Dataverse installation, as with the internally generated examples above. -To add multiple Uploaded Files to the Dataset +To Add Multiple Uploaded Files to the Dataset --------------------------------------------- Once the files exists in the s3 bucket, a final API call is needed to add all the files to the Dataset. In this API call, additional metadata is added using the "jsonData" parameter. @@ -150,8 +156,7 @@ The allowed checksum algorithms are defined by the edu.harvard.iq.dataverse.Data Note that this API call can be used independently of the others, e.g. supporting use cases in which the files already exists in S3/has been uploaded via some out-of-band method. Enabling out-of-band uploads is described at :ref:`file-storage` in the Configuration Guide. With current S3 stores the object identifier must be in the correct bucket for the store, include the PID authority/identifier of the parent dataset, and be guaranteed unique, and the supplied storage identifier must be prefaced with the store identifier used in the Dataverse installation, as with the internally generated examples above. - -Replacing an existing file in the Dataset +Replacing an Existing File in the Dataset ----------------------------------------- Once the file exists in the s3 bucket, a final API call is needed to register it as a replacement of an existing file. This call is the same call used to replace a file to a Dataverse installation but, rather than sending the file bytes, additional metadata is added using the "jsonData" parameter. @@ -180,7 +185,7 @@ Note that the API call does not validate that the file matches the hash value su Note that this API call can be used independently of the others, e.g. supporting use cases in which the file already exists in S3/has been uploaded via some out-of-band method. Enabling out-of-band uploads is described at :ref:`file-storage` in the Configuration Guide. With current S3 stores the object identifier must be in the correct bucket for the store, include the PID authority/identifier of the parent dataset, and be guaranteed unique, and the supplied storage identifier must be prefaced with the store identifier used in the Dataverse installation, as with the internally generated examples above. -Replacing multiple existing files in the Dataset +Replacing Multiple Existing Files in the Dataset ------------------------------------------------ Once the replacement files exist in the s3 bucket, a final API call is needed to register them as replacements for existing files. In this API call, additional metadata is added using the "jsonData" parameter. From 4c36dc6e2c8afc103453738cf861c5671812d841 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Fri, 1 Mar 2024 10:44:14 -0500 Subject: [PATCH 129/141] fix link to Flyway naming The old link goes to generic documentation. The new link shows the conventions on how Flyway files need to be named. --- doc/sphinx-guides/source/developers/sql-upgrade-scripts.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/sphinx-guides/source/developers/sql-upgrade-scripts.rst b/doc/sphinx-guides/source/developers/sql-upgrade-scripts.rst index 6ac3fdcb3d6..32c465524b0 100644 --- a/doc/sphinx-guides/source/developers/sql-upgrade-scripts.rst +++ b/doc/sphinx-guides/source/developers/sql-upgrade-scripts.rst @@ -28,7 +28,7 @@ How to Create a SQL Upgrade Script We assume you have already read the :doc:`version-control` section and have been keeping your feature branch up to date with the "develop" branch. -Create a new file called something like ``V4.11.0.1__5565-sanitize-directory-labels.sql`` in the ``src/main/resources/db/migration`` directory. Use a version like "4.11.0.1" in the example above where the previously released version was 4.11, ensuring that the version number is unique. Note that this is not the version that you expect the code changes to be included in (4.12 in this example). When the previously released version is a patch version (e.g. 5.10.1), use "5.10.1.1" for the first SQL script version (rather than "5.10.1.0.1"). For the "description" you should the name of your branch, which should include the GitHub issue you are working on, as in the example above. To read more about Flyway file naming conventions, see https://flywaydb.org/documentation/migrations#naming +Create a new file called something like ``V4.11.0.1__5565-sanitize-directory-labels.sql`` in the ``src/main/resources/db/migration`` directory. Use a version like "4.11.0.1" in the example above where the previously released version was 4.11, ensuring that the version number is unique. Note that this is not the version that you expect the code changes to be included in (4.12 in this example). When the previously released version is a patch version (e.g. 5.10.1), use "5.10.1.1" for the first SQL script version (rather than "5.10.1.0.1"). For the "description" you should the name of your branch, which should include the GitHub issue you are working on, as in the example above. To read more about Flyway file naming conventions, see https://documentation.red-gate.com/fd/migrations-184127470.html The SQL migration script you wrote will be part of the war file and executed when the war file is deployed. To see a history of Flyway database migrations that have been applied, look at the ``flyway_schema_history`` table. From d7f1468a36799c30d8f497f6a8b16902481d3e5a Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Fri, 1 Mar 2024 13:29:50 -0500 Subject: [PATCH 130/141] link to project board from README #9157 Otherwise, it's hard to find. --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 831dbfed5ff..651d0352dec 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Dataverse® Dataverse is an [open source][] software platform for sharing, finding, citing, and preserving research data (developed by the [Dataverse team](https://dataverse.org/about) at the [Institute for Quantitative Social Science](https://iq.harvard.edu/) and the [Dataverse community][]). -[dataverse.org][] is our home on the web and shows a map of Dataverse installations around the world, a list of [features][], [integrations][] that have been made possible through [REST APIs][], our development [roadmap][], and more. +[dataverse.org][] is our home on the web and shows a map of Dataverse installations around the world, a list of [features][], [integrations][] that have been made possible through [REST APIs][], our [project board][], our development [roadmap][], and more. We maintain a demo site at [demo.dataverse.org][] which you are welcome to use for testing and evaluating Dataverse. @@ -29,6 +29,7 @@ Dataverse is a trademark of President and Fellows of Harvard College and is regi [Installation Guide]: https://guides.dataverse.org/en/latest/installation/index.html [latest release]: https://github.com/IQSS/dataverse/releases [features]: https://dataverse.org/software-features +[project board]: https://github.com/orgs/IQSS/projects/34 [roadmap]: https://www.iq.harvard.edu/roadmap-dataverse-project [integrations]: https://dataverse.org/integrations [REST APIs]: https://guides.dataverse.org/en/latest/api/index.html From aa9c6b0625a43f9b6c193026324631be5afd6b3b Mon Sep 17 00:00:00 2001 From: Alexis Guanche <74431162+Saixel@users.noreply.github.com> Date: Fri, 1 Mar 2024 19:26:45 +0000 Subject: [PATCH 131/141] Add .qpj and .qmd Extensions to Shapefile Handling #8134 (#10305) * Added qpj and qmd extensions to handle shapefiles * Include .qpj and .qmd in Shapefile Ingest Documentation #8134 * Add release note for .qpj and .qmd shapefile support * Update doc/release-notes/8134-add-qpj-qmd-extensions.md Co-authored-by: Philip Durbin * Add test for .qpj and .qmd file handling in ShapefileHandler --------- Co-authored-by: Philip Durbin --- .../8134-add-qpj-qmd-extensions.md | 3 ++ .../source/developers/geospatial.rst | 2 +- .../iq/dataverse/util/ShapefileHandler.java | 2 +- .../util/shapefile/ShapefileHandlerTest.java | 37 +++++++++++++++++-- 4 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 doc/release-notes/8134-add-qpj-qmd-extensions.md diff --git a/doc/release-notes/8134-add-qpj-qmd-extensions.md b/doc/release-notes/8134-add-qpj-qmd-extensions.md new file mode 100644 index 00000000000..65f4485354b --- /dev/null +++ b/doc/release-notes/8134-add-qpj-qmd-extensions.md @@ -0,0 +1,3 @@ +Add .qpj and .qmd Extensions to Shapefile Handling + +- Support for `.qpj` and `.qmd` files in shapefile uploads has been introduced, ensuring that these files are properly recognized and handled as part of geospatial datasets in Dataverse. diff --git a/doc/sphinx-guides/source/developers/geospatial.rst b/doc/sphinx-guides/source/developers/geospatial.rst index 0570e993d10..48d300524c2 100644 --- a/doc/sphinx-guides/source/developers/geospatial.rst +++ b/doc/sphinx-guides/source/developers/geospatial.rst @@ -34,7 +34,7 @@ For example: Upon recognition of the four required files, the Dataverse installation will group them as well as any other relevant files into a shapefile set. Files with these extensions will be included in the shapefile set: - Required: ``.shp``, ``.shx``, ``.dbf``, ``.prj`` -- Optional: ``.sbn``, ``.sbx``, ``.fbn``, ``.fbx``, ``.ain``, ``.aih``, ``.ixs``, ``.mxs``, ``.atx``, ``.cpg``, ``shp.xml`` +- Optional: ``.sbn``, ``.sbx``, ``.fbn``, ``.fbx``, ``.ain``, ``.aih``, ``.ixs``, ``.mxs``, ``.atx``, ``.cpg``, ``.qpj``, ``.qmd``, ``shp.xml`` Then the Dataverse installation creates a new ``.zip`` with mimetype as a shapefile. The shapefile set will persist as this new ``.zip``. diff --git a/src/main/java/edu/harvard/iq/dataverse/util/ShapefileHandler.java b/src/main/java/edu/harvard/iq/dataverse/util/ShapefileHandler.java index 3af562882f3..9786fda4217 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/ShapefileHandler.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/ShapefileHandler.java @@ -72,7 +72,7 @@ public class ShapefileHandler{ public final static List SHAPEFILE_MANDATORY_EXTENSIONS = Arrays.asList("shp", "shx", "dbf", "prj"); public final static String SHP_XML_EXTENSION = "shp.xml"; public final static String BLANK_EXTENSION = "__PLACEHOLDER-FOR-BLANK-EXTENSION__"; - public final static List SHAPEFILE_ALL_EXTENSIONS = Arrays.asList("shp", "shx", "dbf", "prj", "sbn", "sbx", "fbn", "fbx", "ain", "aih", "ixs", "mxs", "atx", "cpg", SHP_XML_EXTENSION); + public final static List SHAPEFILE_ALL_EXTENSIONS = Arrays.asList("shp", "shx", "dbf", "prj", "sbn", "sbx", "fbn", "fbx", "ain", "aih", "ixs", "mxs", "atx", "cpg", "qpj", "qmd", SHP_XML_EXTENSION); public boolean DEBUG = false; diff --git a/src/test/java/edu/harvard/iq/dataverse/util/shapefile/ShapefileHandlerTest.java b/src/test/java/edu/harvard/iq/dataverse/util/shapefile/ShapefileHandlerTest.java index b93028b6365..f0e538616b2 100644 --- a/src/test/java/edu/harvard/iq/dataverse/util/shapefile/ShapefileHandlerTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/util/shapefile/ShapefileHandlerTest.java @@ -144,9 +144,40 @@ public void testCreateZippedNonShapefile() throws IOException{ msg("Passed!"); } - - - + + + @Test + public void testShapefileWithQpjAndQmd() throws IOException { + msgt("(4) testShapefileWithQpjAndQmd"); + + // Create mock files for the new extensions + List fileNames = Arrays.asList("testShape.shp", "testShape.shx", "testShape.dbf", "testShape.prj", "testShape.qpj", "testShape.qmd"); + + // Create a zip file with these files + File zipFile = createAndZipFiles(fileNames, "testShapeWithNewExtensions.zip"); + + // Pass the zip to the ShapefileHandler + ShapefileHandler shpHandler = new ShapefileHandler(new FileInputStream(zipFile)); + shpHandler.DEBUG = true; + + // Check if it is recognized as a shapefile + assertTrue(shpHandler.containsShapefile(), "The zip should contain a shapefile with the new extensions"); + + // Get file groups map and verify presence + Map> fileGroups = shpHandler.getFileGroups(); + assertFalse(fileGroups.isEmpty(), "The file groups map should not be empty"); + + // Ensure the specific extensions are present + assertTrue(fileGroups.containsKey("testShape"), "The file group should contain the key 'testShape'"); + assertTrue(fileGroups.get("testShape").containsAll(Arrays.asList("shp", "shx", "dbf", "prj", "qpj", "qmd")), "The file group should include the new extensions .qpj and .qmd"); + + // Delete the test zip file + zipFile.delete(); + + msg("Test passed successfully!"); + } + + @Test public void testZippedTwoShapefiles() throws IOException{ msgt("(2) testZippedTwoShapefiles"); From 891e4217a30c701304d22fa9b79bdd88612765e4 Mon Sep 17 00:00:00 2001 From: Steven Ferey Date: Fri, 1 Mar 2024 21:38:32 +0100 Subject: [PATCH 132/141] 10177 api metrics add user accounts number (#10260) * #10177 API Metrics : add user accounts number * #10177 correction of installation word --- ...17-api-metrics-add-user-accounts-number.md | 3 + doc/sphinx-guides/source/api/metrics.rst | 14 ++- .../edu/harvard/iq/dataverse/api/Metrics.java | 92 +++++++++++++++++++ .../dataverse/metrics/MetricsServiceBean.java | 48 ++++++++++ .../harvard/iq/dataverse/api/MetricsIT.java | 83 ++++++++++++++++- .../edu/harvard/iq/dataverse/api/UtilIT.java | 30 +++++- 6 files changed, 259 insertions(+), 11 deletions(-) create mode 100644 doc/release-notes/10117-api-metrics-add-user-accounts-number.md diff --git a/doc/release-notes/10117-api-metrics-add-user-accounts-number.md b/doc/release-notes/10117-api-metrics-add-user-accounts-number.md new file mode 100644 index 00000000000..566815d6e5e --- /dev/null +++ b/doc/release-notes/10117-api-metrics-add-user-accounts-number.md @@ -0,0 +1,3 @@ +### New Accounts Metrics API + +Users can retrieve new types of metrics related to user accounts. The new capabilities are [described](https://guides.dataverse.org/en/6.2/api/metrics.html) in the guides. \ No newline at end of file diff --git a/doc/sphinx-guides/source/api/metrics.rst b/doc/sphinx-guides/source/api/metrics.rst index 613671e49d1..14402096650 100755 --- a/doc/sphinx-guides/source/api/metrics.rst +++ b/doc/sphinx-guides/source/api/metrics.rst @@ -1,7 +1,7 @@ Metrics API =========== -The Metrics API provides counts of downloads, datasets created, files uploaded, and more, as described below. The Dataverse Software also includes aggregate counts of Make Data Count metrics (described in the :doc:`/admin/make-data-count` section of the Admin Guide and available per-Dataset through the :doc:`/api/native-api`). A table of all the endpoints is listed below. +The Metrics API provides counts of downloads, datasets created, files uploaded, user accounts created, and more, as described below. The Dataverse Software also includes aggregate counts of Make Data Count metrics (described in the :doc:`/admin/make-data-count` section of the Admin Guide and available per-Dataset through the :doc:`/api/native-api`). A table of all the endpoints is listed below. .. contents:: |toctitle| :local: @@ -21,7 +21,7 @@ The Metrics API includes several categories of endpoints that provide different * Form: GET https://$SERVER/api/info/metrics/$type - * where ``$type`` can be set, for example, to ``dataverses`` (Dataverse collections), ``datasets``, ``files`` or ``downloads``. + * where ``$type`` can be set, for example, to ``dataverses`` (Dataverse collections), ``datasets``, ``files``, ``downloads`` or ``accounts``. * Example: ``curl https://demo.dataverse.org/api/info/metrics/downloads`` @@ -31,7 +31,7 @@ The Metrics API includes several categories of endpoints that provide different * Form: GET https://$SERVER/api/info/metrics/$type/toMonth/$YYYY-DD - * where ``$type`` can be set, for example, to ``dataverses`` (Dataverse collections), ``datasets``, ``files`` or ``downloads``. + * where ``$type`` can be set, for example, to ``dataverses`` (Dataverse collections), ``datasets``, ``files``, ``downloads`` or ``accounts``. * Example: ``curl https://demo.dataverse.org/api/info/metrics/dataverses/toMonth/2018-01`` @@ -41,7 +41,7 @@ The Metrics API includes several categories of endpoints that provide different * Form: GET https://$SERVER/api/info/metrics/$type/pastDays/$days - * where ``$type`` can be set, for example, to ``dataverses`` (Dataverse collections), ``datasets``, ``files`` or ``downloads``. + * where ``$type`` can be set, for example, to ``dataverses`` (Dataverse collections), ``datasets``, ``files``, ``downloads`` or ``accounts``. * Example: ``curl https://demo.dataverse.org/api/info/metrics/datasets/pastDays/30`` @@ -51,7 +51,7 @@ The Metrics API includes several categories of endpoints that provide different * Form: GET https://$SERVER/api/info/metrics/$type/monthly - * where ``$type`` can be set, for example, to ``dataverses`` (Dataverse collections), ``datasets``, ``files`` or ``downloads``. + * where ``$type`` can be set, for example, to ``dataverses`` (Dataverse collections), ``datasets``, ``files``, ``downloads`` or ``accounts``. * Example: ``curl https://demo.dataverse.org/api/info/metrics/downloads/monthly`` @@ -163,6 +163,10 @@ The following table lists the available metrics endpoints (not including the Mak /api/info/metrics/uniquefiledownloads/toMonth/{yyyy-MM},"count by id, pid","json, csv",collection subtree,published,y,cumulative up to month specified,unique download counts per file id to the specified month. PIDs are also included in output if they exist /api/info/metrics/tree,"id, ownerId, alias, depth, name, children",json,collection subtree,published,y,"tree of dataverses starting at the root or a specified parentAlias with their id, owner id, alias, name, a computed depth, and array of children dataverses","underlying code can also include draft dataverses, this is not currently accessible via api, depth starts at 0" /api/info/metrics/tree/toMonth/{yyyy-MM},"id, ownerId, alias, depth, name, children",json,collection subtree,published,y,"tree of dataverses in existence as of specified date starting at the root or a specified parentAlias with their id, owner id, alias, name, a computed depth, and array of children dataverses","underlying code can also include draft dataverses, this is not currently accessible via api, depth starts at 0" + /api/info/metrics/accounts,count,json,Dataverse installation,all,y,as of now/totals, + /api/info/metrics/accounts/toMonth/{yyyy-MM},count,json,Dataverse installation,all,y,cumulative up to month specified, + /api/info/metrics/accounts/pastDays/{n},count,json,Dataverse installation,all,y,aggregate count for past n days, + /api/info/metrics/accounts/monthly,"date, count","json, csv",Dataverse installation,all,y,monthly cumulative timeseries from first date of first entry to now, Related API Endpoints --------------------- diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Metrics.java b/src/main/java/edu/harvard/iq/dataverse/api/Metrics.java index 7bb2570334b..452e5df9f9a 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Metrics.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Metrics.java @@ -547,6 +547,98 @@ public Response getDownloadsPastDays(@Context UriInfo uriInfo, @PathParam("days" return ok(jsonObj); } + /** Accounts */ + + @GET + @Path("accounts") + public Response getAccountsAllTime(@Context UriInfo uriInfo) { + return getAccountsToMonth(uriInfo, MetricsUtil.getCurrentMonth()); + } + + @GET + @Path("accounts/toMonth/{yyyymm}") + public Response getAccountsToMonth(@Context UriInfo uriInfo, @PathParam("yyyymm") String yyyymm) { + + try { + errorIfUnrecongizedQueryParamPassed(uriInfo, new String[] { }); + } catch (IllegalArgumentException ia) { + return error(BAD_REQUEST, ia.getLocalizedMessage()); + } + + String metricName = "accountsToMonth"; + String sanitizedyyyymm = MetricsUtil.sanitizeYearMonthUserInput(yyyymm); + JsonObject jsonObj = MetricsUtil.stringToJsonObject(metricsSvc.returnUnexpiredCacheMonthly(metricName, sanitizedyyyymm, null, null)); + + if (null == jsonObj) { // run query and save + Long count; + try { + count = metricsSvc.accountsToMonth(sanitizedyyyymm); + } catch (ParseException e) { + return error(BAD_REQUEST, "Unable to parse supplied date: " + e.getLocalizedMessage()); + } + jsonObj = MetricsUtil.countToJson(count).build(); + metricsSvc.save(new Metric(metricName, sanitizedyyyymm, null, null, jsonObj.toString())); + } + + return ok(jsonObj); + } + + @GET + @Path("accounts/pastDays/{days}") + public Response getAccountsPastDays(@Context UriInfo uriInfo, @PathParam("days") int days) { + + try { + errorIfUnrecongizedQueryParamPassed(uriInfo, new String[] { }); + } catch (IllegalArgumentException ia) { + return error(BAD_REQUEST, ia.getLocalizedMessage()); + } + + String metricName = "accountsPastDays"; + + if (days < 1) { + return error(BAD_REQUEST, "Invalid parameter for number of days."); + } + + JsonObject jsonObj = MetricsUtil.stringToJsonObject(metricsSvc.returnUnexpiredCacheDayBased(metricName, String.valueOf(days), null, null)); + + if (null == jsonObj) { // run query and save + Long count = metricsSvc.accountsPastDays(days); + jsonObj = MetricsUtil.countToJson(count).build(); + metricsSvc.save(new Metric(metricName, String.valueOf(days), null, null, jsonObj.toString())); + } + + return ok(jsonObj); + } + + @GET + @Path("accounts/monthly") + @Produces("text/csv, application/json") + public Response getAccountsTimeSeries(@Context Request req, @Context UriInfo uriInfo) { + + try { + errorIfUnrecongizedQueryParamPassed(uriInfo, new String[] { }); + } catch (IllegalArgumentException ia) { + return error(BAD_REQUEST, ia.getLocalizedMessage()); + } + + String metricName = "accounts"; + JsonArray jsonArray = MetricsUtil.stringToJsonArray(metricsSvc.returnUnexpiredCacheAllTime(metricName, null, null)); + + if (null == jsonArray) { // run query and save + // Only handling published right now + jsonArray = metricsSvc.accountsTimeSeries(); + metricsSvc.save(new Metric(metricName, null, null, null, jsonArray.toString())); + } + + MediaType requestedType = getVariant(req, MediaType.valueOf(FileUtil.MIME_TYPE_CSV), MediaType.APPLICATION_JSON_TYPE); + if ((requestedType != null) && (requestedType.equals(MediaType.APPLICATION_JSON_TYPE))) { + return ok(jsonArray); + } + return ok(FileUtil.jsonArrayOfObjectsToCSV(jsonArray, MetricsUtil.DATE, MetricsUtil.COUNT), MediaType.valueOf(FileUtil.MIME_TYPE_CSV), "accounts.timeseries.csv"); + } + + /** MakeDataCount */ + @GET @Path("makeDataCount/{metric}") public Response getMakeDataCountMetricCurrentMonth(@Context UriInfo uriInfo, @PathParam("metric") String metricSupplied, @QueryParam("country") String country, @QueryParam("parentAlias") String parentAlias) { diff --git a/src/main/java/edu/harvard/iq/dataverse/metrics/MetricsServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/metrics/MetricsServiceBean.java index 1b5619c53e0..a74474efa15 100644 --- a/src/main/java/edu/harvard/iq/dataverse/metrics/MetricsServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/metrics/MetricsServiceBean.java @@ -572,6 +572,54 @@ public JsonArray uniqueDatasetDownloads(String yyyymm, Dataverse d) { } + //Accounts + + /* + * + * @param yyyymm Month in YYYY-MM format. + */ + public long accountsToMonth(String yyyymm) throws ParseException { + Query query = em.createNativeQuery("" + + "select count(authenticateduser.id)\n" + + "from authenticateduser\n" + + "where authenticateduser.createdtime is not null\n" + + "and date_trunc('month', createdtime) <= to_date('" + yyyymm + "','YYYY-MM');" + ); + logger.log(Level.FINE, "Metric query: {0}", query); + + return (long) query.getSingleResult(); + } + + /* + * + * @param days interval since the current date to list + * the number of user accounts created + */ + public long accountsPastDays(int days) { + Query query = em.createNativeQuery("" + + "select count(id)\n" + + "from authenticateduser\n" + + "where authenticateduser.createdtime is not null\n" + + "and authenticateduser.createdtime > current_date - interval '" + days + "' day;" + ); + logger.log(Level.FINE, "Metric query: {0}", query); + + return (long) query.getSingleResult(); + } + + public JsonArray accountsTimeSeries() { + Query query = em.createNativeQuery("" + + "select distinct to_char(au.createdtime, 'YYYY-MM'), count(id)\n" + + "from authenticateduser as au\n" + + "where au.createdtime is not null\n" + + "group by to_char(au.createdtime, 'YYYY-MM')\n" + + "order by to_char(au.createdtime, 'YYYY-MM');"); + + logger.log(Level.FINE, "Metric query: {0}", query); + List results = query.getResultList(); + return MetricsUtil.timeSeriesToJson(results); + } + //MDC diff --git a/src/test/java/edu/harvard/iq/dataverse/api/MetricsIT.java b/src/test/java/edu/harvard/iq/dataverse/api/MetricsIT.java index e3328eefb4a..a8f7afc1cb0 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/MetricsIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/MetricsIT.java @@ -1,16 +1,18 @@ package edu.harvard.iq.dataverse.api; -import io.restassured.RestAssured; -import io.restassured.response.Response; -import edu.harvard.iq.dataverse.metrics.MetricsUtil; import static jakarta.ws.rs.core.Response.Status.BAD_REQUEST; import static jakarta.ws.rs.core.Response.Status.OK; -import org.junit.jupiter.api.AfterAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; +import edu.harvard.iq.dataverse.metrics.MetricsUtil; +import edu.harvard.iq.dataverse.util.FileUtil; +import io.restassured.RestAssured; +import io.restassured.response.Response; +import jakarta.ws.rs.core.MediaType; //TODO: These tests are fairly flawed as they don't actually add data to compare on. //To improve these tests we should try adding data and see if the number DOESN'T @@ -120,6 +122,54 @@ public void testGetDownloadsToMonth() { response.then().assertThat() .statusCode(BAD_REQUEST.getStatusCode()); } + + @Test + public void testGetAccountsToMonth() { + String thismonth = MetricsUtil.getCurrentMonth(); + + Response response = UtilIT.metricsAccountsToMonth(thismonth, null); + String precache = response.prettyPrint(); + response.then().assertThat() + .statusCode(OK.getStatusCode()); + + //Run each query twice and compare results to tests caching + response = UtilIT.metricsAccountsToMonth(thismonth, null); + String postcache = response.prettyPrint(); + response.then().assertThat() + .statusCode(OK.getStatusCode()); + + assertEquals(precache, postcache); + + //Test error when passing extra query params + response = UtilIT.metricsAccountsToMonth(thismonth, "dataLocation=local"); + response.then().assertThat() + .statusCode(BAD_REQUEST.getStatusCode()); + } + + @Test + public void testGetAccountsTimeSeries() { + Response response = UtilIT.metricsAccountsTimeSeries(MediaType.APPLICATION_JSON, null); + String precache = response.prettyPrint(); + response.then().assertThat() + .statusCode(OK.getStatusCode()); + + //Run each query twice and compare results to tests caching + response = UtilIT.metricsAccountsTimeSeries(MediaType.APPLICATION_JSON, null); + String postcache = response.prettyPrint(); + response.then().assertThat() + .statusCode(OK.getStatusCode()); + + assertEquals(precache, postcache); + + response = UtilIT.metricsAccountsTimeSeries(FileUtil.MIME_TYPE_CSV, null); + response.then().assertThat() + .statusCode(OK.getStatusCode()); + + //Test error when passing extra query params + response = UtilIT.metricsAccountsTimeSeries(MediaType.APPLICATION_JSON, "dataLocation=local"); + response.then().assertThat() + .statusCode(BAD_REQUEST.getStatusCode()); + } @Test @@ -214,6 +264,29 @@ public void testGetDownloadsPastDays() { response.then().assertThat() .statusCode(BAD_REQUEST.getStatusCode()); } + + @Test + public void testGetAccountsPastDays() { + String days = "30"; + + Response response = UtilIT.metricsAccountsPastDays(days, null); + String precache = response.prettyPrint(); + response.then().assertThat() + .statusCode(OK.getStatusCode()); + + //Run each query twice and compare results to tests caching + response = UtilIT.metricsAccountsPastDays(days, null); + String postcache = response.prettyPrint(); + response.then().assertThat() + .statusCode(OK.getStatusCode()); + + assertEquals(precache, postcache); + + //Test error when passing extra query params + response = UtilIT.metricsAccountsPastDays(days, "dataLocation=local"); + response.then().assertThat() + .statusCode(BAD_REQUEST.getStatusCode()); + } @Test diff --git a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java index 246700474a9..080ca0c43e9 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -48,7 +48,7 @@ import edu.harvard.iq.dataverse.util.StringUtil; import java.util.Collections; -import static org.junit.jupiter.api.Assertions.assertEquals; + import static org.junit.jupiter.api.Assertions.*; public class UtilIT { @@ -2564,6 +2564,25 @@ static Response metricsDownloadsToMonth(String yyyymm, String queryParams) { RequestSpecification requestSpecification = given(); return requestSpecification.get("/api/info/metrics/downloads/toMonth" + optionalYyyyMm + optionalQueryParams); } + + static Response metricsAccountsToMonth(String yyyymm, String queryParams) { + String optionalQueryParams = ""; + if (queryParams != null) { + optionalQueryParams = "?" + queryParams; + } + RequestSpecification requestSpecification = given(); + return requestSpecification.get("/api/info/metrics/accounts/toMonth/" + yyyymm + optionalQueryParams); + } + + static Response metricsAccountsTimeSeries(String mediaType, String queryParams) { + String optionalQueryParams = ""; + if (queryParams != null) { + optionalQueryParams = "?" + queryParams; + } + RequestSpecification requestSpecification = given(); + requestSpecification.contentType(mediaType); + return requestSpecification.get("/api/info/metrics/accounts/monthly" + optionalQueryParams); + } static Response metricsDataversesPastDays(String days, String queryParams) { String optionalQueryParams = ""; @@ -2601,6 +2620,15 @@ static Response metricsDownloadsPastDays(String days, String queryParams) { return requestSpecification.get("/api/info/metrics/downloads/pastDays/" + days + optionalQueryParams); } + static Response metricsAccountsPastDays(String days, String queryParams) { + String optionalQueryParams = ""; + if (queryParams != null) { + optionalQueryParams = "?" + queryParams; + } + RequestSpecification requestSpecification = given(); + return requestSpecification.get("/api/info/metrics/accounts/pastDays/" + days + optionalQueryParams); + } + static Response metricsDataversesByCategory(String queryParams) { String optionalQueryParams = ""; if (queryParams != null) { From 0390b385af7030a413e3ebd3ac960a2238e978ff Mon Sep 17 00:00:00 2001 From: qqmyers Date: Mon, 4 Mar 2024 19:38:32 -0600 Subject: [PATCH 133/141] OIDC state algorithm update (#10275) * security enhancement * add missing params * change doFinal per https://gist.github.com/patrickfav/7e28d4eb4bf500f7ee8012c4a0cf7bbf * add iv to encrypted value * Update src/main/java/edu/harvard/iq/dataverse/util/StringUtil.java Co-authored-by: Oliver Bertuch --------- Co-authored-by: Oliver Bertuch --- .../harvard/iq/dataverse/util/StringUtil.java | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/util/StringUtil.java b/src/main/java/edu/harvard/iq/dataverse/util/StringUtil.java index 33c87563104..137ae21d793 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/StringUtil.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/StringUtil.java @@ -2,9 +2,13 @@ import edu.harvard.iq.dataverse.authorization.providers.oauth2.OAuth2LoginBackingBean; import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; @@ -19,6 +23,7 @@ import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.lang3.StringUtils; @@ -117,6 +122,10 @@ public static List htmlArray2textArray(List htmlArray) { return cleanTextArray; } + private final static SecureRandom secureRandom = new SecureRandom(); + // 12 bytes is recommended by GCM spec + private final static int GCM_IV_LENGTH = 12; + /** * Generates an AES-encrypted version of the string. Resultant string is URL safe. * @param value The value to encrypt. @@ -124,19 +133,26 @@ public static List htmlArray2textArray(List htmlArray) { * @return encrypted string, URL-safe. */ public static String encrypt(String value, String password ) { + byte[] baseBytes = value.getBytes(); try { - Cipher aes = Cipher.getInstance("AES"); + byte[] iv = new byte[GCM_IV_LENGTH]; //NEVER REUSE THIS IV WITH SAME KEY + secureRandom.nextBytes(iv); + Cipher aes = Cipher.getInstance("AES/GCM/NoPadding"); final SecretKeySpec secretKeySpec = generateKeyFromString(password); - aes.init(Cipher.ENCRYPT_MODE, secretKeySpec); + GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv); + aes.init(Cipher.ENCRYPT_MODE, secretKeySpec, parameterSpec); byte[] encrypted = aes.doFinal(baseBytes); - String base64ed = new String(Base64.getEncoder().encode(encrypted)); + ByteBuffer byteBuffer = ByteBuffer.allocate(iv.length + encrypted.length); + byteBuffer.put(iv); + byteBuffer.put(encrypted); + String base64ed = new String(Base64.getEncoder().encode(byteBuffer.array())); return base64ed.replaceAll("\\+", ".") .replaceAll("=", "-") .replaceAll("/", "_"); } catch ( InvalidKeyException | NoSuchAlgorithmException | BadPaddingException - | IllegalBlockSizeException | NoSuchPaddingException | UnsupportedEncodingException ex) { + | IllegalBlockSizeException | NoSuchPaddingException | UnsupportedEncodingException | InvalidAlgorithmParameterException ex) { Logger.getLogger(OAuth2LoginBackingBean.class.getName()).log(Level.SEVERE, null, ex); throw new RuntimeException(ex); } @@ -149,13 +165,15 @@ public static String decrypt(String value, String password ) { byte[] baseBytes = Base64.getDecoder().decode(base64); try { - Cipher aes = Cipher.getInstance("AES"); - aes.init( Cipher.DECRYPT_MODE, generateKeyFromString(password)); - byte[] decrypted = aes.doFinal(baseBytes); + Cipher aes = Cipher.getInstance("AES/GCM/NoPadding"); + //use first 12 bytes for iv + AlgorithmParameterSpec gcmIv = new GCMParameterSpec(128, baseBytes, 0, GCM_IV_LENGTH); + aes.init( Cipher.DECRYPT_MODE, generateKeyFromString(password),gcmIv); + byte[] decrypted = aes.doFinal(baseBytes,GCM_IV_LENGTH, baseBytes.length - GCM_IV_LENGTH); return new String(decrypted); } catch ( InvalidKeyException | NoSuchAlgorithmException | BadPaddingException - | IllegalBlockSizeException | NoSuchPaddingException | UnsupportedEncodingException ex) { + | IllegalBlockSizeException | NoSuchPaddingException | UnsupportedEncodingException | InvalidAlgorithmParameterException ex) { Logger.getLogger(OAuth2LoginBackingBean.class.getName()).log(Level.SEVERE, null, ex); throw new RuntimeException(ex); } From 44ce6a19c72c7c4c3c156e44fa56de5d89613106 Mon Sep 17 00:00:00 2001 From: qqmyers Date: Wed, 6 Mar 2024 08:06:55 -0600 Subject: [PATCH 134/141] IQSS/3623 - Multiple PID Provider support (#10234) * Switch to per-pid-provider settings * partial refactor towards non-bean providers * ~auto refactor name/package, remove bean status * remove Util class * rename * add factories for all, fix providers, etc. * unmanaged providers * add getters * add name to cnstr, add cnstr for unmanaged, add auth/shoulder checks * update permalinks, add separator setting * no arg constructor * add unmanaged providers * check canManagePid instead * replace getBean(), compiles except for tests * update tests, comment out ones that are TBD * add clear method for testing * bugs - remove dup authority, fix name, add auth/sep/shoulder tests * make managed/excluded lists optional * fix name in generated pids * move setup to berforeall, add test of second permaprovider * provider name->id * adding label, more name->id * providerName->providerId * add factory map, lookups, add factory, perma parsing tests * first datacite parsing test/fix id in pid * rename class * move auth/shoulder check to lower level method * fix ids, fix managed list optional in fake * add effective pid generator logic * add effective pid generator tests * fix param order * fix perma handling of managed/excluded entries * add managed/excluded tests, cleanup * update pidprovider discovery to get effective one when necessary * replace all refs to global protocol/auth/shoulder settings xcept one keeping the new PidProviderFactoryBean.getDefaultPidGenerator() for now as a possible way to stay ~backward comaptible All the rest - tried to find the appropriate PidProvider to supply the values * first UI for setting Pid generator * typo * flyway script to add pid spec column * @AutoService and public class for loader discovery * minor cleanup/refactor * verify protocol/auth are set/match the provider plus cleanup * only call getGlobalId() when one should exist * force all calls to create identifier to set protocol/auth as well * move template to match refactor * require superuser to change PidProvider * cleanup * check can create method * make fake provider create file pids * typo - fix UI * return default instead of null for UI * unrelated - logic fix * partial support for legacy config - FAKE and DatCite - for testing * cleanup * style fail * fix test - don't reset list of providers * allow old aliases * reverse logic in datacite legacy creator, add null check * fix lookups, update test, test DataCite legacy * missing if! * disable obsolete test * updated docs * add test urls as default * cleanup -remove unused imports * unrelated link fix * fix for #10251 - sync terms popup required code * API calls for getting provider info and changing PID Generators * api docs * change level for entries to fix build error * typo in refs * fix indents * more bad refs * support for legacy hdl, perma, ezid * new packages for everyone! (refactor) * unused imports * fix cut/paste issues * add deprecation info * Apply suggestions from code review Co-authored-by: Oliver Bertuch * reorg/update imports * revert 2e41b9e * deprecate old settings * Change error handling and warnings per review * Add testing for a valid PID generator as a config test * formatting, switch if /else logic per review * add deprecation * move pid provider's dir setting to spi scope * change flyway name, tweak release note, delete unused test class * temporary flyway change * use new settings in install * Revert "temporary flyway change" This reverts commit 7106ef68e7ba203b2de8f06b7fbc0777d9138318. * fix rest api setting * handle spaces in the pidproviders setting * add note in Harvard setup * refactoring/cleaning DataCite provider, drop cache * moving XmlMetadataTemplate to doi package * missing import * move xml file to match package * minor fixes, make getPidStatus visible in test * disabled test of DPI lifecycle * update installer/docs to not talk about a partial DataCite test setup * remove legacy setting * indent issue * missing ) * fix setting name * remove obsolete settings * add defaults * add valid fake pid setup for docker * also adding pid config to the -dev yml * Update docker-compose-dev.yml Co-authored-by: Steven Winship <39765413+stevenwinship@users.noreply.github.com> * Update docker/compose/demo/compose.yml Co-authored-by: Steven Winship <39765413+stevenwinship@users.noreply.github.com> * Update docker-compose-dev.yml Co-authored-by: Steven Winship <39765413+stevenwinship@users.noreply.github.com> * Update docker/compose/demo/compose.yml Co-authored-by: Steven Winship <39765413+stevenwinship@users.noreply.github.com> --------- Co-authored-by: Oliver Bertuch Co-authored-by: qqmye Co-authored-by: Steven Winship <39765413+stevenwinship@users.noreply.github.com> --- doc/release-notes/3623-multipid.md | 37 + doc/sphinx-guides/source/api/native-api.rst | 100 +++ .../source/developers/deployment.rst | 2 +- .../source/installation/config.rst | 467 ++++++++++-- docker-compose-dev.yml | 6 + docker/compose/demo/compose.yml | 6 + scripts/api/setup-all.sh | 4 - scripts/api/setup-optional-harvard.sh | 1 + scripts/deploy/phoenix.dataverse.org/post | 1 - scripts/dev/dev-rebuild.sh | 3 - scripts/dev/docker-final-setup.sh | 3 - scripts/installer/as-setup.sh | 15 +- scripts/installer/install.py | 13 +- .../AbstractGlobalIdServiceBean.java | 700 ----------------- .../dataverse/DOIDataCiteRegisterCache.java | 90 --- .../dataverse/DOIDataCiteRegisterService.java | 707 ------------------ .../iq/dataverse/DOIDataCiteServiceBean.java | 248 ------ .../harvard/iq/dataverse/DOIServiceBean.java | 78 -- .../harvard/iq/dataverse/DataCitation.java | 5 +- .../iq/dataverse/DataFileServiceBean.java | 5 +- .../edu/harvard/iq/dataverse/Dataset.java | 1 + .../edu/harvard/iq/dataverse/DatasetPage.java | 35 +- .../iq/dataverse/DatasetServiceBean.java | 79 +- .../harvard/iq/dataverse/DataversePage.java | 31 +- .../iq/dataverse/DvObjectContainer.java | 84 ++- .../iq/dataverse/DvObjectServiceBean.java | 23 +- .../iq/dataverse/EditDatafilesPage.java | 3 - .../iq/dataverse/EjbDataverseEngine.java | 42 +- .../edu/harvard/iq/dataverse/GlobalId.java | 10 +- .../iq/dataverse/S3PackageImporter.java | 23 +- .../harvard/iq/dataverse/SettingsWrapper.java | 24 - .../edu/harvard/iq/dataverse/api/Admin.java | 97 +-- .../harvard/iq/dataverse/api/Datasets.java | 83 ++ .../harvard/iq/dataverse/api/Dataverses.java | 17 +- .../harvard/iq/dataverse/api/LDNInbox.java | 16 +- .../iq/dataverse/api/MakeDataCountApi.java | 14 +- .../edu/harvard/iq/dataverse/api/Pids.java | 37 + .../CollectionDepositManagerImpl.java | 15 +- .../api/imports/ImportGenericServiceBean.java | 34 +- .../api/imports/ImportServiceBean.java | 5 +- .../importer/filesystem/FileRecordWriter.java | 21 +- .../engine/command/CommandContext.java | 16 +- .../impl/AbstractCreateDatasetCommand.java | 14 +- .../command/impl/AbstractDatasetCommand.java | 17 +- .../impl/AbstractSubmitToArchiveCommand.java | 2 +- .../command/impl/CreateNewDatasetCommand.java | 31 +- .../command/impl/DeleteDataFileCommand.java | 21 +- .../engine/command/impl/DeletePidCommand.java | 21 +- .../command/impl/DestroyDatasetCommand.java | 26 +- .../FinalizeDatasetPublicationCommand.java | 96 ++- .../impl/GrantSuperuserStatusCommand.java | 2 +- .../command/impl/ImportDatasetCommand.java | 10 +- .../command/impl/PublishDatasetCommand.java | 24 +- .../command/impl/RegisterDvObjectCommand.java | 68 +- .../command/impl/ReservePidCommand.java | 10 +- .../impl/RevokeSuperuserStatusCommand.java | 2 +- .../impl/UpdateDatasetTargetURLCommand.java | 10 +- .../UpdateDvObjectPIDMetadataCommand.java | 23 +- .../export/InternalExportDataProvider.java | 3 +- .../export/openaire/OpenAireExportUtil.java | 8 +- .../pidproviders/AbstractPidProvider.java | 550 ++++++++++++++ .../PermaLinkPidProviderServiceBean.java | 160 ---- .../iq/dataverse/pidproviders/PidHelper.java | 43 -- .../PidProvider.java} | 115 ++- .../pidproviders/PidProviderFactory.java | 8 + .../pidproviders/PidProviderFactoryBean.java | 251 +++++++ .../iq/dataverse/pidproviders/PidUtil.java | 118 ++- .../pidproviders/doi/AbstractDOIProvider.java | 123 +++ .../UnmanagedDOIProvider.java} | 28 +- .../pidproviders/doi/XmlMetadataTemplate.java | 314 ++++++++ .../datacite/DOIDataCiteRegisterService.java | 222 ++++++ .../doi/datacite/DataCiteDOIProvider.java | 319 ++++++++ .../doi/datacite/DataCiteProviderFactory.java | 43 ++ .../doi/datacite}/DataCiteRESTfullClient.java | 23 +- .../doi/ezid/EZIdDOIProvider.java} | 51 +- .../doi/ezid/EZIdProviderFactory.java | 42 ++ .../fake/FakeDOIProvider.java} | 30 +- .../doi/fake/FakeProviderFactory.java | 38 + .../handle/HandlePidProvider.java} | 96 ++- .../handle/HandleProviderFactory.java | 45 ++ .../UnmanagedHandlePidProvider.java} | 49 +- .../perma/PermaLinkPidProvider.java | 201 +++++ .../perma/PermaLinkProviderFactory.java | 43 ++ .../perma/UnmanagedPermaLinkPidProvider.java | 114 +++ .../settings/ConfigCheckService.java | 18 +- .../iq/dataverse/settings/JvmSettings.java | 100 ++- .../settings/SettingsServiceBean.java | 78 +- .../iq/dataverse/util/SystemConfig.java | 30 +- .../iq/dataverse/util/json/JSONLDUtil.java | 4 +- .../iq/dataverse/util/json/JsonParser.java | 4 +- .../workflow/WorkflowServiceBean.java | 18 +- src/main/java/propertyFiles/Bundle.properties | 2 + .../META-INF/microprofile-config.properties | 11 - .../V6.1.0.4__3623-multiple-pid-providers.sql | 2 + .../doi}/datacite_metadata_template.xml | 0 src/main/webapp/dataset.xhtml | 2 +- src/main/webapp/dataverse.xhtml | 13 + .../harvard/iq/dataverse/GlobalIdTest.java | 8 +- .../PersistentIdentifierServiceBeanTest.java | 139 ---- .../harvard/iq/dataverse/api/DatasetsIT.java | 4 + .../dataaccess/GlobusOverlayAccessIOTest.java | 6 +- .../dataaccess/RemoteOverlayAccessIOTest.java | 4 +- .../dataverse/engine/TestCommandContext.java | 25 +- .../export/OpenAireExportUtilTest.java | 9 +- .../ExternalToolHandlerTest.java | 4 +- .../ExternalToolServiceBeanTest.java | 4 +- .../iq/dataverse/globus/GlobusUtilTest.java | 6 +- .../dataverse/pidproviders/PidUtilTest.java | 435 ++++++++++- .../doi/datacite/DataCiteProviderTest.java | 187 +++++ .../search/IndexServiceBeanTest.java | 3 +- .../dataverse/settings/JvmSettingsTest.java | 17 +- .../iq/dataverse/sitemap/SiteMapUtilTest.java | 10 +- .../iq/dataverse/util/UrlTokenUtilTest.java | 4 +- 113 files changed, 4605 insertions(+), 3157 deletions(-) create mode 100644 doc/release-notes/3623-multipid.md delete mode 100644 src/main/java/edu/harvard/iq/dataverse/AbstractGlobalIdServiceBean.java delete mode 100644 src/main/java/edu/harvard/iq/dataverse/DOIDataCiteRegisterCache.java delete mode 100644 src/main/java/edu/harvard/iq/dataverse/DOIDataCiteRegisterService.java delete mode 100644 src/main/java/edu/harvard/iq/dataverse/DOIDataCiteServiceBean.java delete mode 100644 src/main/java/edu/harvard/iq/dataverse/DOIServiceBean.java create mode 100644 src/main/java/edu/harvard/iq/dataverse/pidproviders/AbstractPidProvider.java delete mode 100644 src/main/java/edu/harvard/iq/dataverse/pidproviders/PermaLinkPidProviderServiceBean.java delete mode 100644 src/main/java/edu/harvard/iq/dataverse/pidproviders/PidHelper.java rename src/main/java/edu/harvard/iq/dataverse/{GlobalIdServiceBean.java => pidproviders/PidProvider.java} (56%) create mode 100644 src/main/java/edu/harvard/iq/dataverse/pidproviders/PidProviderFactory.java create mode 100644 src/main/java/edu/harvard/iq/dataverse/pidproviders/PidProviderFactoryBean.java create mode 100644 src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/AbstractDOIProvider.java rename src/main/java/edu/harvard/iq/dataverse/pidproviders/{UnmanagedDOIServiceBean.java => doi/UnmanagedDOIProvider.java} (73%) create mode 100644 src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/XmlMetadataTemplate.java create mode 100644 src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DOIDataCiteRegisterService.java create mode 100644 src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DataCiteDOIProvider.java create mode 100644 src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DataCiteProviderFactory.java rename src/main/java/edu/harvard/iq/dataverse/{ => pidproviders/doi/datacite}/DataCiteRESTfullClient.java (92%) rename src/main/java/edu/harvard/iq/dataverse/{DOIEZIdServiceBean.java => pidproviders/doi/ezid/EZIdDOIProvider.java} (89%) create mode 100644 src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/ezid/EZIdProviderFactory.java rename src/main/java/edu/harvard/iq/dataverse/pidproviders/{FakePidProviderServiceBean.java => doi/fake/FakeDOIProvider.java} (59%) create mode 100644 src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/fake/FakeProviderFactory.java rename src/main/java/edu/harvard/iq/dataverse/{HandlenetServiceBean.java => pidproviders/handle/HandlePidProvider.java} (87%) create mode 100644 src/main/java/edu/harvard/iq/dataverse/pidproviders/handle/HandleProviderFactory.java rename src/main/java/edu/harvard/iq/dataverse/pidproviders/{UnmanagedHandlenetServiceBean.java => handle/UnmanagedHandlePidProvider.java} (61%) create mode 100644 src/main/java/edu/harvard/iq/dataverse/pidproviders/perma/PermaLinkPidProvider.java create mode 100644 src/main/java/edu/harvard/iq/dataverse/pidproviders/perma/PermaLinkProviderFactory.java create mode 100644 src/main/java/edu/harvard/iq/dataverse/pidproviders/perma/UnmanagedPermaLinkPidProvider.java create mode 100644 src/main/resources/db/migration/V6.1.0.4__3623-multiple-pid-providers.sql rename src/main/resources/edu/harvard/iq/dataverse/{ => pidproviders/doi}/datacite_metadata_template.xml (100%) delete mode 100644 src/test/java/edu/harvard/iq/dataverse/PersistentIdentifierServiceBeanTest.java create mode 100644 src/test/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DataCiteProviderTest.java diff --git a/doc/release-notes/3623-multipid.md b/doc/release-notes/3623-multipid.md new file mode 100644 index 00000000000..8c13eb1aec6 --- /dev/null +++ b/doc/release-notes/3623-multipid.md @@ -0,0 +1,37 @@ +This release adds support for using multiple PID (DOI, Handle, PermalLink) providers, multiple PID provider accounts +(managing a given protocol, authority,separator, shoulder combination), assigning PID provider accounts to specific collections, +and supporting transferred PIDs (where a PID is managed by an account when it's authority, separator, and/or shoulder don't match +the combination where the account can mint new PIDs). It also adds the ability for additional provider services beyond the existing +DataCite, EZId, Handle, and PermaLink providers to be dynamically added as separate jar files. + +These changes require per-provider settings rather than the global PID settings previously supported. While backward compatibility +for installations using a single PID Provider account is provided, updating to use the new microprofile settings is highly recommended +and will be required in a future version. + +New microprofile settings (where * indicates a provider id indicating which provider the setting is for): + +dataverse.pid.providers +dataverse.pid.default-provider +dataverse.pid.*.type +dataverse.pid.*.label +dataverse.pid.*.authority +dataverse.pid.*.shoulder +dataverse.pid.*.identifier-generation-style +dataverse.pid.*.datafile-pid-format +dataverse.pid.*.managed-list +dataverse.pid.*.excluded-list +dataverse.pid.*.datacite.mds-api-url +dataverse.pid.*.datacite.rest-api-url +dataverse.pid.*.datacite.username +dataverse.pid.*.datacite.password +dataverse.pid.*.ezid.api-url +dataverse.pid.*.ezid.username +dataverse.pid.*.ezid.password +dataverse.pid.*.permalink.base-url +dataverse.pid.*.permalink.separator +dataverse.pid.*.handlenet.index +dataverse.pid.*.handlenet.independent-service +dataverse.pid.*.handlenet.auth-handle +dataverse.pid.*.handlenet.key.path +dataverse.pid.*.handlenet.key.passphrase +dataverse.spi.pidproviders.directory diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index 1e61e78aa45..7f048f96eb9 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -2747,6 +2747,56 @@ The fully expanded example above (without environment variables) looks like this curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" "https://demo.dataverse.org/api/datasets/24/versions/1.0/canDownloadAtLeastOneFile" +.. _dataset-pid-generator: + +Configure The PID Generator a Dataset Uses (If Enabled) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Dataverse can be configured to use multiple PID Providers (see the :ref:`pids-configuration` section for more information). +When there are multiple PID Providers and File PIDs are enabled, it is possible to set which provider will be used to generate (mint) those PIDs. +While it usually makes sense to use the same PID Provider that manages the dataset PID, there are cases, specifically if the PID Provider for the dataset PID cannot generate +other PIDs with the same authority/shoulder, etc. as in the dataset PID, where another Provider is needed. Dataverse has a set of API calls to see what PID provider will be +used to generate datafile PIDs and, as a superuser, to change it (to a new one or back to a default). + +To see the current choice for this dataset: + +.. code-block:: bash + + export SERVER_URL=https://demo.dataverse.org + export PERSISTENT_IDENTIFIER=doi:10.5072/FK2/YD5QDG + + curl "$SERVER_URL/api/datasets/:persistentId/pidGenerator?persistentId=$PERSISTENT_IDENTIFIER" + +The response will be the id of the PID Provider that will be used. Details of that provider's configration can be obtained via the :ref:`pids-providers-api`. + +To set the behavior for this dataset: + +.. code-block:: bash + + export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + export SERVER_URL=https://demo.dataverse.org + export PERSISTENT_IDENTIFIER=doi:10.5072/FK2/YD5QDG + export GENERATOR_ID=perma1 + + curl -X PUT -H "X-Dataverse-key:$API_TOKEN" -H Content-type:application/json -d $GENERATOR_ID "$SERVER_URL/api/datasets/:persistentId/pidGenerator?persistentId=$PERSISTENT_IDENTIFIER" + + +The PID Provider id used must be one of the those configured - see :ref:`pids-providers-api`. +The return status code may be 200/OK, 401/403 if an api key is not sent or the user is not a superuser, or 404 if the dataset or PID provider are not found. +Note that using a PIDProvider that generates DEPENDENT datafile PIDs that doesn't share the dataset PID's protocol/authority/separator/shoulder is not supported. (INDEPENDENT should be used in this case see the :ref:`pids-configuration` section for more information). + +The API can also be used to reset the dataset to use the default/inherited value: + +.. code-block:: bash + + export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + export SERVER_URL=https://demo.dataverse.org + export PERSISTENT_IDENTIFIER=doi:10.5072/FK2/YD5QDG + + curl -X DELETE -H "X-Dataverse-key:$API_TOKEN" -H Content-type:application/json "$SERVER_URL/api/datasets/:persistentId/pidGenerator?persistentId=$PERSISTENT_IDENTIFIER" + +The default will always be the same provider as for the dataset PID if that provider can generate new PIDs, and will be the PID Provider set for the collection or the global default otherwise. + Files ----- @@ -4809,6 +4859,56 @@ The fully expanded example above (without environment variables) looks like this curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X DELETE "https://demo.dataverse.org/api/pids/:persistentId/delete?persistentId=doi:10.70122/FK2/9BXT5O" +.. _pids-providers-api: + +Get Information about Configured PID Providers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Dataverse can be configured with one or more PID Providers that it uses to create new PIDs and manage existing ones. +This API call returns a JSONObject listing the configured providers and details about the protocol/authority/separator/shoulder they manage, +along with information about about how new dataset and datafile PIDs are generated. See the :ref:`pids-configuration` section for more information. + +.. note:: See :ref:`curl-examples-and-environment-variables` if you are unfamiliar with the use of export below. + +.. code-block:: bash + + export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + export SERVER_URL=https://demo.dataverse.org + + curl -H "X-Dataverse-key:$API_TOKEN" "$SERVER_URL/api/pids/providers" + +The fully expanded example above (without environment variables) looks like this: + +.. code-block:: bash + + curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" "https://demo.dataverse.org/api/pids/providers" + +Get the id of the PID Provider Managing a Given PID +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Dataverse can be configured with one or more PID Providers that it uses to create new PIDs and manage existing ones. +This API call returns the string id of the PID Provider than manages a given PID. See the :ref:`pids-configuration` section for more information. +Delete PID (this is only possible for PIDs that are in the "draft" state) and within a Dataverse installation, set ``globalidcreatetime`` to null and ``identifierregistered`` to false. A superuser API token is required. + +.. note:: See :ref:`curl-examples-and-environment-variables` if you are unfamiliar with the use of export below. + +.. code-block:: bash + + export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + export SERVER_URL=https://demo.dataverse.org + export PID=doi:10.70122/FK2/9BXT5O + + curl -H "X-Dataverse-key:$API_TOKEN" "$SERVER_URL/api/pids/providers/$PID" + +The fully expanded example above (without environment variables) looks like this: + +.. code-block:: bash + + curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" "https://demo.dataverse.org/api/pids/providers/doi:10.70122/FK2/9BXT5O" + +If the PID is not managed by Dataverse, this call will report if the PID is recognized as a valid PID for a given protocol (doi, hdl, or perma) + or will return a 400/Bad Request response if it is not. + .. _admin: diff --git a/doc/sphinx-guides/source/developers/deployment.rst b/doc/sphinx-guides/source/developers/deployment.rst index 75ad2fa33fb..678e29f4079 100755 --- a/doc/sphinx-guides/source/developers/deployment.rst +++ b/doc/sphinx-guides/source/developers/deployment.rst @@ -114,7 +114,7 @@ Please note that while the script should work well on new-ish branches, older br Migrating Datafiles from Local Storage to S3 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -A number of pilot Dataverse installations start on local storage, then administrators are tasked with migrating datafiles into S3 or similar object stores. The files may be copied with a command-line utility such as `s3cmd`. You will want to retain the local file hierarchy, keeping the authority (for example: 10.5072) at the bucket "root." +A number of pilot Dataverse installations start on local storage, then administrators are tasked with migrating datafiles into S3 or similar object stores. The files may be copied with a command-line utility such as `s3cmd `_. You will want to retain the local file hierarchy, keeping the authority (for example: 10.5072) at the bucket "root." The below example queries may assist with updating dataset and datafile locations in the Dataverse installation's PostgresQL database. Depending on the initial version of the Dataverse Software and subsequent upgrade path, Datafile storage identifiers may or may not include a ``file://`` prefix, so you'll want to catch both cases. diff --git a/doc/sphinx-guides/source/installation/config.rst b/doc/sphinx-guides/source/installation/config.rst index c233e594fa7..2baa2827250 100644 --- a/doc/sphinx-guides/source/installation/config.rst +++ b/doc/sphinx-guides/source/installation/config.rst @@ -178,56 +178,383 @@ Persistent Identifiers and Publishing Datasets Persistent identifiers (PIDs) are a required and integral part of the Dataverse Software. They provide a URL that is guaranteed to resolve to the datasets or files they represent. The Dataverse Software currently supports creating -identifiers using one of several PID providers. The most appropriate PIDs for public data are DOIs (provided by +identifiers using any of several PID types. The most appropriate PIDs for public data are DOIs (e.g., provided by DataCite or EZID) and Handles. Dataverse also supports PermaLinks which could be useful for intranet or catalog use cases. A DOI provider called "FAKE" is recommended only for testing and development purposes. +Dataverse can be configured with one or more PID providers, each of which can mint and manage PIDs with a given protocol +(e.g., doi, handle, permalink) using a specific service provider/account (e.g. with DataCite, EZId, or HandleNet) +to manage an authority/shoulder combination, aka a "prefix" (PermaLinks also support custom separator characters as part of the prefix), +along with an optional list of individual PIDs (with different authority/shoulders) than can be managed with that account. + Testing PID Providers +++++++++++++++++++++ -By default, the installer configures the DataCite test service as the registration provider. DataCite requires that you -register for a test account, configured with your own prefix (please contact support@datacite.org). +By default, the installer configures the Fake DOI provider as the registration provider. Unlike other DOI Providers, the Fake Provider does not involve any +external resolution service and is not appropriate for use beyond development and testing. You may wish instead to test with +PermaLinks or with a DataCite test account (which uses DataCite's test infrastructure and will help assure your Dataverse instance can make network connections to DataCite. +DataCite requires that you register for a test account, which will have a username, password and your own prefix (please contact support@datacite.org for a test account. +You may wish to `contact the GDCC `_ instead - GDCC is able to provide DataCite accounts with a group discount and can also provide test accounts.). Once you receive the login name, password, and prefix for the account, -configure the credentials via :ref:`dataverse.pid.datacite.username` and -:ref:`dataverse.pid.datacite.password`, then restart Payara. - -Configure the prefix via the API (where it is referred to as :ref:`:Authority`): +configure the credentials as described below. -``curl -X PUT -d 10.xxxx http://localhost:8080/api/admin/settings/:Authority`` +Alternately, you may wish to configure other providers for testing: -.. TIP:: - This testing section is oriented around DataCite but other PID Providers can be tested as well. - - EZID is available to University of California scholars and researchers. Testing can be done using the authority 10.5072 and shoulder FK2 with the "apitest" account (contact EZID for credentials) or an institutional account. Configuration in Dataverse is then analogous to using DataCite. - - The PermaLink and FAKE DOI providers do not involve an external account. See :ref:`permalinks` and (for the FAKE DOI provider) the :doc:`/developers/dev-environment` section of the Developer Guide. + - The PermaLink provider, like the FAKE DOI provider, does not involve an external account. + Unlike the Fake DOI provider, the PermaLink provider creates PIDs that begin with "perma:", making it clearer that they are not DOIs, + and that do resolve to the local dataset/file page in Dataverse, making them useful for some production use cases. See :ref:`permalinks` and (for the FAKE DOI provider) the :doc:`/developers/dev-environment` section of the Developer Guide. + +Provider-specific configuration is described below. -Once all is configured, you will be able to publish datasets and files, but **the persistent identifiers will not be citable**, -and they will only resolve from the DataCite test environment (and then only if the Dataverse installation from which -you published them is accessible - DOIs minted from your laptop will not resolve). Note that any datasets or files -created using the test configuration cannot be directly migrated and would need to be created again once a valid DOI -namespace is configured. +Once all is configured, you will be able to publish datasets and files, but **the persistent identifiers will not be citable** +as they, with the exception of PermaLinks, will not redirect to your dataset page in Dataverse. -One you are done testing, to properly configure persistent identifiers for a production installation, an account and associated namespace must be -acquired for a fee from a DOI or HDL provider. **DataCite** (https://www.datacite.org) is the recommended DOI provider +Note that any datasets or files created using a test configuration cannot be directly migrated to a production PID provider +and would need to be created again once a valid PID Provider(s) are configured. + +One you are done testing, to properly configure persistent identifiers for a production installation, an account and associated namespace (e.g. authority/shoulder) must be +acquired for a fee from a DOI or HDL provider. (As noted above, PermaLinks May be appropriate for intranet and catalog uses cases.) +**DataCite** (https://www.datacite.org) is the recommended DOI provider (see https://dataversecommunity.global for more on joining DataCite through the Global Dataverse Community Consortium) but **EZID** (http://ezid.cdlib.org) is an option for the University of California according to https://www.cdlib.org/cdlinfo/2017/08/04/ezid-doi-service-is-evolving/ . **Handle.Net** (https://www.handle.net) is the HDL provider. -Once you have your DOI or Handle account credentials and a namespace, configure your Dataverse installation -using the JVM options and database settings below. +Once you have your DOI or Handle account credentials and a prefix, configure your Dataverse installation +using the settings below. + + +Configuring PID Providers ++++++++++++++++++++++++++ + +There are two required global settings to configure PID providers - the list of ids of providers and which one of those should be the default. +Per-provider settings are also required - some that are common to all types and some type specific. All of these settings are defined +to be compatible with the MicroProfile specification which means that + +1. Any of these settings can be set via system properties (see :ref:`jvm-options` for how to do this), environment variables, or other + MicroProfile Config mechanisms supported by the app server. + `See Payara docs for supported sources `_. +2. Remember to protect your secrets. For passwords, use an environment variable (bare minimum), a password alias named the same + as the key (OK) or use the `"dir config source" of Payara `_ (best). + + Alias creation example: + + .. code-block:: shell + + echo "AS_ADMIN_ALIASPASSWORD=changeme" > /tmp/p.txt + asadmin create-password-alias --passwordfile /tmp/p.txt dataverse.pid.datacite1.datacite.password + rm /tmp/p.txt + +3. Environment variables follow the key, replacing any dot, colon, dash, etc. into an underscore "_" and all uppercase + letters. Example: ``dataverse.pid.default-provider`` -> ``DATAVERSE_PID_DEFAULT_PROVIDER`` + +Global Settings +^^^^^^^^^^^^^^^ + +The following three global settings are required to configure PID Providers in the Dataverse software: + +.. _dataverse.pid.providers: + +dataverse.pid.providers +^^^^^^^^^^^^^^^^^^^^^^^ + +A comma-separated list of the ids of the PID providers to use. IDs should be simple unique text strings, e.g. datacite1, perma1, etc. +IDs are used to scope the provider-specific settings but are not directly visible to users. + +.. _dataverse.pid.default-provider: + +dataverse.pid.default-provider +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ID of the default PID provider to use. + +.. _dataverse.spi.pidproviders.directory: + +dataverse.spi.pidproviders.directory +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The path to the directory where JAR files containing additional types of PID Providers can be added. +Dataverse includes providers that support DOIs (DataCite, EZId, or FAKE), Handles, and PermaLinks. +PID provider jar files added to this directory can replace any of these or add new PID Providers. + +Per-Provider Settings +^^^^^^^^^^^^^^^^^^^^^ + +Each Provider listed by id in the dataverse.pid.providers setting must be configured with the following common settings and any settings that are specific to the provider type. + +.. _dataverse.pid.*.type: + +dataverse.pid.*.type +^^^^^^^^^^^^^^^^^^^^ + +The Provider type, currently one of ``datacite``, ``ezid``, ``FAKE``, ``hdl``, or ``perma``. The type defines which protocol a service supports (DOI, Handle, or PermaLink) and, for DOI Providers, which +DOI service is used. + +.. _dataverse.pid.*.label: + +dataverse.pid.*.label +^^^^^^^^^^^^^^^^^^^^^ + +A human-readable label for the provider + +.. _dataverse.pid.*.authority: + +dataverse.pid.*.authority +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. _dataverse.pid.*.shoulder: + +dataverse.pid.*.shoulder +^^^^^^^^^^^^^^^^^^^^^^^^ + +In general, PIDs are of the form ``:/*`` where ``*`` is the portion unique to an individual PID. PID Providers must define +the authority and shoulder (with the protocol defined by the ``dataverse.pid.*.type`` setting) that defines the set of existing PIDs they can manage and the prefix they can use when minting new PIDs. +(Often an account with a PID service provider will be limited to using a single authority/shoulder. If your PID service provider account allows more than one combination that you wish to use in Dataverse, configure multiple PID Provider, one for each combination.) + +.. _dataverse.pid.*.identifier-generation-style: + +dataverse.pid.*.identifier-generation-style +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +By default, Pid Providers in Dataverse generate a random 6 character string, +pre-pended by the Shoulder if set, to use as the identifier for a Dataset. +Set this to ``storedProcGenerated`` to generate instead a custom *unique* +identifier (again pre-pended by the Shoulder if set) through a database +stored procedure or function (the assumed default setting is ``randomString``). +When using the ``storedProcGenerated`` setting, a stored procedure or function must be created in +the database. + +As a first example, the script below (downloadable +:download:`here `) produces +sequential numerical values. You may need to make some changes to suit your +system setup, see the comments for more information: + +.. literalinclude:: ../_static/util/createsequence.sql + :language: plpgsql + +As a second example, the script below (downloadable +:download:`here `) produces +sequential 8 character identifiers from a base36 representation of current +timestamp. + +.. literalinclude:: ../_static/util/identifier_from_timestamp.sql + :language: plpgsql + +Note that the SQL in these examples scripts is Postgres-specific. +If necessary, it can be reimplemented in any other SQL flavor - the standard +JPA code in the application simply expects the database to have a saved +function ("stored procedure") named ``generateIdentifierFromStoredProcedure()`` +returning a single ``varchar`` argument. + +Please note that this setting interacts with the ``dataverse.pid.*.datafile-pid-format`` +setting below to determine how datafile identifiers are generated. + + +.. _dataverse.pid.*.datafile-pid-format: + +dataverse.pid.*.datafile-pid-format +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This setting controls the way that the "identifier" component of a file's +persistent identifier (PID) relates to the PID of its "parent" dataset - for a give PID Provider. + +By default the identifier for a file is dependent on its parent dataset. +For example, if the identifier of a dataset is "TJCLKP", the identifier for +a file within that dataset will consist of the parent dataset's identifier +followed by a slash ("/"), followed by a random 6 character string, +yielding "TJCLKP/MLGWJO". Identifiers in this format are what you should +expect if you leave ``dataverse.pid.*.datafile-pid-format`` undefined or set it to +``DEPENDENT`` and have not changed the ``dataverse.pid.*.identifier-generation-style`` +setting from its default. + +Alternatively, the identifier for File PIDs can be configured to be +independent of Dataset PIDs using the setting ``INDEPENDENT``. +In this case, file PIDs will not contain the PIDs of their parent datasets, +and their PIDs will be generated the exact same way that datasets' PIDs are, +based on the ``dataverse.pid.*.identifier-generation-style`` setting described above +(random 6 character strings or custom unique identifiers through a stored +procedure, pre-pended by any shoulder). + +The chart below shows examples from each possible combination of parameters +from the two settings. ``dataverse.pid.*.identifier-generation-style`` can be either +``randomString`` (the default) or ``storedProcGenerated`` and +``dataverse.pid.*.datafile-pid-format`` can be either ``DEPENDENT`` (the default) or +``INDEPENDENT``. In the examples below the "identifier" for the dataset is +"TJCLKP" for ``randomString`` and "100001" for ``storedProcGenerated`` (when +using sequential numerical values, as described in +:ref:`dataverse.pid.*.identifier-generation-style` above), or "krby26qt" for +``storedProcGenerated`` (when using base36 timestamps, as described in +:ref:`dataverse.pid.*.identifier-generation-style` above). + ++-----------------+---------------+----------------------+---------------------+ +| | randomString | storedProcGenerated | storedProcGenerated | +| | | | | +| | | (sequential numbers) | (base36 timestamps) | ++=================+===============+======================+=====================+ +| **DEPENDENT** | TJCLKP/MLGWJO | 100001/1 | krby26qt/1 | ++-----------------+---------------+----------------------+---------------------+ +| **INDEPENDENT** | MLGWJO | 100002 | krby27pz | ++-----------------+---------------+----------------------+---------------------+ + +As seen above, in cases where ``dataverse.pid.*.identifier-generation-style`` is set to +``storedProcGenerated`` and ``dataverse.pid.*.datafile-pid-format`` is set to ``DEPENDENT``, +each file within a dataset will be assigned a number *within* that dataset +starting with "1". + +Otherwise, if ``dataverse.pid.*.datafile-pid-format`` is set to ``INDEPENDENT``, each file +within the dataset is assigned with a new PID which is the next available +identifier provided from the database stored procedure. In our example: +"100002" when using sequential numbers or "krby27pz" when using base36 +timestamps. + +.. _dataverse.pid.*.managed-list: + +dataverse.pid.*.managed-list +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. _dataverse.pid.*.excluded-list: + +dataverse.pid.*.excluded-list +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +With at least some PID services, it is possible for the authority(permission) to manage specific individual PIDs +to be transferred between accounts. To handle these cases, the individual PIDs, written in the +standard format, e.g. doi:10.5072/FK2ABCDEF can be added to the comma-separated ``managed`` or ``excluded`` list +for a given provider. For entries on the ``managed- list``, Dataverse will assume this PID +Provider/account can update the metadata and landing URL for the PID at the service provider +(even though it does not match the provider's authority/shoulder settings). Conversely, +Dataverse will assume that PIDs on the ``excluded-list`` cannot be managed/updated by this provider +(even though they match the provider's authority/shoulder settings). These settings are optional +with the default assumption that these lists are empty. + +.. _dataverse.pid.*.datacite: + +DataCite-specific Settings +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +dataverse.pid.*.datacite.mds-api-url +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +dataverse.pid.*.datacite.rest-api-url +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +dataverse.pid.*.datacite.username +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +dataverse.pid.*.datacite.password +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +PID Providers of type ``datacite`` require four additional parameters that define how the provider connects to DataCite. +DataCite has two APIs that are used in Dataverse: + +The base URL of the `DataCite MDS API `_, +used to mint and manage DOIs. Current valid values for ``dataverse.pid.*.datacite.mds-api-url`` are "https://mds.datacite.org" (production) and "https://mds.test.datacite.org" (testing, the default). + +The `DataCite REST API `_ is also used - :ref:`PIDs API ` information retrieval and :doc:`/admin/make-data-count`. +Current valid values for ``dataverse.pid.*.datacite.rest-api-url`` are "https://api.datacite.org" (production) and "https://api.test.datacite.org" (testing, the default). + +DataCite uses `HTTP Basic authentication `_ +for `Fabrica `_ and their APIs. You need to provide +the same credentials (``username``, ``password``) to Dataverse software to mint and manage DOIs for you. +As noted above, you should use one of the more secure options for setting the password. + + +.. _dataverse.pid.*.ezid: + +EZId-specific Settings +^^^^^^^^^^^^^^^^^^^^^^ + +dataverse.pid.*.ezid.api-url +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +dataverse.pid.*.ezid.username +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +dataverse.pid.*.ezid.password +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Note that use of `EZId `_ is limited primarily to University of California institutions. If you have an EZId account, +you will need to configure the ``api-url`` and your account ``username`` and ``password``. As above, you should use one of the more secure +options for setting the password. + +.. _dataverse.pid.*.permalink: + +PermaLink-specific Settings +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +dataverse.pid.*.permalink.base-url +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +dataverse.pid.*.permalink.separator +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +PermaLinks are a simple PID option intended for intranet and catalog use cases. They can be used without an external service or +be configured with the ``base-url`` of a resolution service. PermaLinks also allow a custom ``separator`` to be used. (Note: when using multiple +PermaLink providers, you should avoid ambiguous authority/separator/shoulder combinations that would result in the same overall prefix.) + +.. _dataverse.pid.*.handlenet: + +Handle-specific Settings +^^^^^^^^^^^^^^^^^^^^^^^^ + +dataverse.pid.*.handlenet.index +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +dataverse.pid.*.handlenet.independent-service +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +dataverse.pid.*.handlenet.auth-handle +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +dataverse.pid.*.handlenet.key +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +dataverse.pid.*.handlenet.path +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +dataverse.pid.*.handlenet.passphrase +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Note: If you are **minting your own handles** and plan to set up your own handle service, please refer to `Handle.Net documentation `_. + +Configure your Handle.net ``index`` to be used registering new persistent +identifiers. Defaults to ``300``. + +Indices are used to separate concerns within the Handle system. To add data to +an index, authentication is mandatory. See also chapter 1.4 "Authentication" of +the `Handle.Net Technical Documentation `__ + +Handle.Net servers use a public key authentication method where the public key +is stored in a handle itself and the matching private key is provided from this +file. Typically, the absolute path ends like ``handle/svr_1/admpriv.bin``. +The key file may (and should) be encrypted with a passphrase (used for +encryption with AES-128). See +also chapter 1.4 "Authentication" of the `Handle.Net Technical Documentation +`__ + +Provide an absolute ``key.path`` to a private key file authenticating requests to your +Handle.Net server. + +Provide a ``key.passphrase`` to decrypt the private key file at ``dataverse.pid.*.handlenet.key.path``. + +Set ``independent-service`` to true if you want to use a Handle service which is setup to work 'independently' (No communication with the Global Handle Registry). +By default this setting is false. + +Set ``auth-handle`` to / to be used on a global handle service when the public key is NOT stored in the default handle. +This setting is optional. If the public key is, for instance, stored in handle: ``21.T12996/USER01``, ``auth-handle`` should be set to this value. + .. _pids-doi-configuration: -Configuring Your Dataverse Installation for DOIs -++++++++++++++++++++++++++++++++++++++++++++++++ +Backward-compatibility for Single PID Provider Installations +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -As explained above, by default your Dataverse installation attempts to register DOIs for each -dataset and file under a test authority. You must apply for your own credentials. +While using the PID Provider configuration settings described above is recommended, Dataverse installations +only using a single PID Provider can use the settings below instead. In general, these legacy settings mirror +those above except for not including a PID Provider id. -Here are the configuration options for DOIs: +Configuring Your Dataverse Installation for a Single DOI Provider +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Here are the configuration options for DOIs.: **JVM Options for DataCite:** @@ -257,8 +584,8 @@ this provider. .. _pids-handle-configuration: -Configuring Your Dataverse Installation for Handles -+++++++++++++++++++++++++++++++++++++++++++++++++++ +Configuring Your Dataverse Installation for a Single Handle Provider +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Here are the configuration options for handles. Most notably, you need to change the ``:Protocol`` setting, as it defaults to DOI usage. @@ -282,12 +609,8 @@ Note: If you are **minting your own handles** and plan to set up your own handle .. _permalinks: -Configuring Your Dataverse Installation for PermaLinks -++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -PermaLinks are a simple mechanism to provide persistent URLs for datasets and datafiles (if configured) that does not involve an external service providing metadata-based search services. -They are potentially appropriate for Intranet use cases as well as in cases where Dataverse is being used as a catalog or holding duplicate copies of datasets where the authoritative copy already has a DOI or Handle. -PermaLinks use the protocol "perma" (versus "doi" or "handle") and do not use a "/" character as a separator between the authority and shoulder. It is recommended to choose an alphanumeric value for authority that does not resemble that of DOIs (which are primarily numeric and start with "10." as in "10.5072") to avoid PermaLinks being mistaken for DOIs. +Configuring Your Dataverse Installation for a Single PermaLink Provider +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Here are the configuration options for PermaLinks: @@ -2114,8 +2437,8 @@ For limiting the size (in bytes) of thumbnail images generated from files. The d .. _dataverse.pid.datacite.mds-api-url: -dataverse.pid.datacite.mds-api-url -++++++++++++++++++++++++++++++++++ +Legacy Single PID Provider: dataverse.pid.datacite.mds-api-url +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Configure the base URL of the `DataCite MDS API `_, used to mint and manage DOIs. Valid values are "https://mds.datacite.org" and "https://mds.test.datacite.org" @@ -2148,8 +2471,8 @@ Without setting an option, always defaults to testing API endpoint. .. _dataverse.pid.datacite.rest-api-url: -dataverse.pid.datacite.rest-api-url -+++++++++++++++++++++++++++++++++++ +Legacy Single PID Provider: dataverse.pid.datacite.rest-api-url ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Configure the base URL endpoint of the `DataCite REST API `_, used for :ref:`PIDs API ` information retrieval and :doc:`/admin/make-data-count`. @@ -2176,8 +2499,8 @@ you can issue the following command: .. _dataverse.pid.datacite.username: -dataverse.pid.datacite.username -+++++++++++++++++++++++++++++++ +Legacy Single PID Provider: dataverse.pid.datacite.username ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ DataCite uses `HTTP Basic authentication `_ for `Fabrica `_ and their APIs. You need to provide @@ -2198,8 +2521,8 @@ Once you have a username from DataCite, you can enter it like this: .. _dataverse.pid.datacite.password: -dataverse.pid.datacite.password -+++++++++++++++++++++++++++++++ +Legacy Single PID Provider: dataverse.pid.datacite.password ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Once you have a password from your provider, you should create a password alias. This avoids storing it in clear text, although you could use a JVM option `to reference @@ -2225,8 +2548,8 @@ To manage these, read up on `Payara docs about password aliases `. @@ -2247,8 +2570,8 @@ and re-add it. .. _dataverse.pid.handlenet.key.passphrase: -dataverse.pid.handlenet.key.passphrase -++++++++++++++++++++++++++++++++++++++ +Legacy Single PID Provider: dataverse.pid.handlenet.key.passphrase +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Related to :ref:`Handle.Net PID provider usage `. @@ -2268,8 +2591,8 @@ the old JVM option and the wrapped password alias, then recreate as shown for .. _dataverse.pid.handlenet.index: -dataverse.pid.handlenet.index -+++++++++++++++++++++++++++++ +Legacy Single PID Provider: dataverse.pid.handlenet.index ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Related to :ref:`Handle.Net PID provider usage `. @@ -2287,8 +2610,8 @@ re-add it. .. _dataverse.pid.permalink.base-url: -dataverse.pid.permalink.base-url -++++++++++++++++++++++++++++++++ +Legacy Single PID Provider: dataverse.pid.permalink.base-url +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ When using :ref:`PermaLinks `, this setting can be used to configure an external resolver. Dataverse will associate a PermaLink PID with the URL: ``/citation?persistentId=perma:``. The default value is your Dataverse site URL, which will result in PermaLinks correctly resolving to the appropriate dataset page. @@ -2309,8 +2632,8 @@ variable ``DATAVERSE_PID_PERMALINK_BASE_URL``. This setting was formerly known a .. _dataverse.pid.ezid.api-url: -dataverse.pid.ezid.api-url -++++++++++++++++++++++++++ +Legacy Single PID Provider: dataverse.pid.ezid.api-url +++++++++++++++++++++++++++++++++++++++++++++++++++++++ The EZID DOI provider is likely not an option if you are `not associated with California Digital Library (CDL) or Purdue University @@ -2324,8 +2647,8 @@ variable ``DATAVERSE_PID_EZID_API_URL``. This setting was formerly known as .. _dataverse.pid.ezid.username: -dataverse.pid.ezid.username -+++++++++++++++++++++++++++ +Legacy Single PID Provider: dataverse.pid.ezid.username ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ The EZID DOI provider is likely not an option if you are `not associated with California Digital Library (CDL) or Purdue University @@ -2342,8 +2665,8 @@ should delete and re-add it. .. _dataverse.pid.ezid.password: -dataverse.pid.ezid.password -+++++++++++++++++++++++++++ +Legacy Single PID Provider: dataverse.pid.ezid.password ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ The EZID DOI provider is likely not an option if you are `not associated with California Digital Library (CDL) or Purdue University @@ -2805,8 +3128,8 @@ By default the footer says "Copyright © [YYYY]" but you can add text after the .. _:DoiProvider: -:DoiProvider -++++++++++++ +Legacy Single PID Provider: :DoiProvider +++++++++++++++++++++++++++++++++++++++++ As of this writing "DataCite" and "EZID" are the only valid options for production installations. Developers using Dataverse Software 4.10+ are welcome to use the keyword "FAKE" to configure a non-production installation with an @@ -2826,8 +3149,8 @@ JVM options: .. _:Protocol: -:Protocol -+++++++++ +Legacy Single PID Provider: :Protocol ++++++++++++++++++++++++++++++++++++++ As of this writing "doi","hdl", and "perma" are the only valid option for the protocol for a persistent ID. @@ -2835,8 +3158,8 @@ As of this writing "doi","hdl", and "perma" are the only valid option for the pr .. _:Authority: -:Authority -++++++++++ +Legacy Single PID Provider: :Authority +++++++++++++++++++++++++++++++++++++++ Use the authority assigned to you by your DoiProvider or HandleProvider, or your choice if using PermaLinks. @@ -2846,8 +3169,8 @@ Please note that a DOI or Handle authority cannot have a slash ("/") in it (slas .. _:Shoulder: -:Shoulder -+++++++++ +Legacy Single PID Provider: :Shoulder ++++++++++++++++++++++++++++++++++++++ The shoulder is used with DOIs and PermaLinks. Out of the box, the shoulder is set to "FK2/" but this is for testing only! When you apply for your DOI authority/namespace, you may have been assigned a shoulder. The following is only an example and a trailing slash is optional. @@ -2855,8 +3178,8 @@ The shoulder is used with DOIs and PermaLinks. Out of the box, the shoulder is s .. _:IdentifierGenerationStyle: -:IdentifierGenerationStyle -++++++++++++++++++++++++++ +Legacy Single PID Provider: :IdentifierGenerationStyle +++++++++++++++++++++++++++++++++++++++++++++++++++++++ By default, the Dataverse Software generates a random 6 character string, pre-pended by the Shoulder if set, to use as the identifier for a Dataset. @@ -2894,8 +3217,8 @@ more details. .. _:DataFilePIDFormat: -:DataFilePIDFormat -++++++++++++++++++ +Legacy Single PID Provider: :DataFilePIDFormat +++++++++++++++++++++++++++++++++++++++++++++++ This setting controls the way that the "identifier" component of a file's persistent identifier (PID) relates to the PID of its "parent" dataset. @@ -2985,8 +3308,8 @@ When :AllowEnablingFilePIDsPerCollection is true, setting File PIDs to be enable .. _:IndependentHandleService: -:IndependentHandleService -+++++++++++++++++++++++++ +Legacy Single PID Provider: :IndependentHandleService ++++++++++++++++++++++++++++++++++++++++++++++++++++++ Specific for Handle PIDs. Set this setting to true if you want to use a Handle service which is setup to work 'independently' (No communication with the Global Handle Registry). By default this setting is absent and the Dataverse Software assumes it to be false. @@ -2995,8 +3318,8 @@ By default this setting is absent and the Dataverse Software assumes it to be fa .. _:HandleAuthHandle: -:HandleAuthHandle -+++++++++++++++++ +Legacy Single PID Provider: :HandleAuthHandle ++++++++++++++++++++++++++++++++++++++++++++++ Specific for Handle PIDs. Set this setting to / to be used on a global handle service when the public key is NOT stored in the default handle. By default this setting is absent and the Dataverse Software assumes it to be not set. If the public key for instance is stored in handle: 21.T12996/USER01. diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index 42702bff155..ae0aa2bdf76 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -48,6 +48,12 @@ services: -Ddataverse.files.minio1.download-redirect=false -Ddataverse.files.minio1.access-key=4cc355_k3y -Ddataverse.files.minio1.secret-key=s3cr3t_4cc355_k3y + -Ddataverse.pid.providers=fake + -Ddataverse.pid.default-provider=fake + -Ddataverse.pid.fake.type=FAKE + -Ddataverse.pid.fake.label=FakeDOIProvider + -Ddataverse.pid.fake.authority=10.5072 + -Ddataverse.pid.fake.shoulder=FK2/ ports: - "8080:8080" # HTTP (Dataverse Application) - "4949:4848" # HTTPS (Payara Admin Console) diff --git a/docker/compose/demo/compose.yml b/docker/compose/demo/compose.yml index a262f43006a..e4bcc9778d7 100644 --- a/docker/compose/demo/compose.yml +++ b/docker/compose/demo/compose.yml @@ -18,6 +18,12 @@ services: -Ddataverse.files.file1.type=file -Ddataverse.files.file1.label=Filesystem -Ddataverse.files.file1.directory=${STORAGE_DIR}/store + -Ddataverse.pid.providers=fake + -Ddataverse.pid.default-provider=fake + -Ddataverse.pid.fake.type=FAKE + -Ddataverse.pid.fake.label=FakeDOIProvider + -Ddataverse.pid.fake.authority=10.5072 + -Ddataverse.pid.fake.shoulder=FK2/ ports: - "8080:8080" # HTTP (Dataverse Application) - "4848:4848" # HTTP (Payara Admin Console) diff --git a/scripts/api/setup-all.sh b/scripts/api/setup-all.sh index e247caa72b5..5ddd9a35fdc 100755 --- a/scripts/api/setup-all.sh +++ b/scripts/api/setup-all.sh @@ -57,10 +57,6 @@ echo "- Allow internal signup" curl -X PUT -d yes "${DATAVERSE_URL}/api/admin/settings/:AllowSignUp" curl -X PUT -d "/dataverseuser.xhtml?editMode=CREATE" "${DATAVERSE_URL}/api/admin/settings/:SignUpUrl" -curl -X PUT -d doi "${DATAVERSE_URL}/api/admin/settings/:Protocol" -curl -X PUT -d 10.5072 "${DATAVERSE_URL}/api/admin/settings/:Authority" -curl -X PUT -d "FK2/" "${DATAVERSE_URL}/api/admin/settings/:Shoulder" -curl -X PUT -d DataCite "${DATAVERSE_URL}/api/admin/settings/:DoiProvider" curl -X PUT -d burrito "${DATAVERSE_URL}/api/admin/settings/BuiltinUsers.KEY" curl -X PUT -d localhost-only "${DATAVERSE_URL}/api/admin/settings/:BlockedApiPolicy" curl -X PUT -d 'native/http' "${DATAVERSE_URL}/api/admin/settings/:UploadMethods" diff --git a/scripts/api/setup-optional-harvard.sh b/scripts/api/setup-optional-harvard.sh index fcbcc08a8e6..1311464e8ff 100755 --- a/scripts/api/setup-optional-harvard.sh +++ b/scripts/api/setup-optional-harvard.sh @@ -3,6 +3,7 @@ SERVER=http://localhost:8080/api echo "Setting up Harvard-specific settings" # :Authority and :Shoulder are commented out so this script can be used on test servers +# Should now use the new multipid JVM options instead of these settings #curl -X PUT -d 10.7910 "$SERVER/admin/settings/:Authority" #curl -X PUT -d "DVN/" "$SERVER/admin/settings/:Shoulder" echo "- Application Status header" diff --git a/scripts/deploy/phoenix.dataverse.org/post b/scripts/deploy/phoenix.dataverse.org/post index e4c8817844b..9d37c183a1a 100755 --- a/scripts/deploy/phoenix.dataverse.org/post +++ b/scripts/deploy/phoenix.dataverse.org/post @@ -4,7 +4,6 @@ cd scripts/api cd ../.. psql -U dvnapp dvndb -f scripts/database/reference_data.sql psql -U dvnapp dvndb -f doc/sphinx-guides/source/_static/util/createsequence.sql -curl http://localhost:8080/api/admin/settings/:DoiProvider -X PUT -d FAKE scripts/search/tests/publish-dataverse-root git checkout scripts/api/data/dv-root.json scripts/search/tests/grant-authusers-add-on-root diff --git a/scripts/dev/dev-rebuild.sh b/scripts/dev/dev-rebuild.sh index 9eae195b135..898212b4664 100755 --- a/scripts/dev/dev-rebuild.sh +++ b/scripts/dev/dev-rebuild.sh @@ -56,9 +56,6 @@ cd ../.. echo "Creating SQL sequence..." psql -h localhost -U $DB_USER $DB_NAME -f doc/sphinx-guides/source/_static/util/createsequence.sql -echo "Setting DOI provider to \"FAKE\"..." -curl http://localhost:8080/api/admin/settings/:DoiProvider -X PUT -d FAKE - echo "Allowing GUI edits to be visible without redeploy..." $PAYARA_DIR/glassfish/bin/asadmin create-system-properties "dataverse.jsf.refresh-period=1" diff --git a/scripts/dev/docker-final-setup.sh b/scripts/dev/docker-final-setup.sh index d2453619ec2..e20ce7ad6b6 100755 --- a/scripts/dev/docker-final-setup.sh +++ b/scripts/dev/docker-final-setup.sh @@ -10,9 +10,6 @@ cd ../.. echo "Setting system mail address..." curl -X PUT -d "dataverse@localhost" "http://localhost:8080/api/admin/settings/:SystemEmail" -echo "Setting DOI provider to \"FAKE\"..." -curl "http://localhost:8080/api/admin/settings/:DoiProvider" -X PUT -d FAKE - API_TOKEN=$(grep apiToken "/tmp/setup-all.sh.out" | jq ".data.apiToken" | tr -d \") export API_TOKEN diff --git a/scripts/installer/as-setup.sh b/scripts/installer/as-setup.sh index fc5b378cff5..c89bcb4ff4d 100755 --- a/scripts/installer/as-setup.sh +++ b/scripts/installer/as-setup.sh @@ -102,17 +102,18 @@ function preliminary_setup() # password reset token timeout in minutes ./asadmin $ASADMIN_OPTS create-jvm-options "\-Ddataverse.auth.password-reset-timeout-in-minutes=60" - # DataCite DOI Settings + # Fake DOI Settings # (we can no longer offer EZID with their shared test account) # jvm-options use colons as separators, escape as literal DOI_BASEURL_ESC=`echo $DOI_BASEURL | sed -e 's/:/\\\:/'` - ./asadmin $ASADMIN_OPTS create-jvm-options "\-Ddataverse.pid.datacite.username=${DOI_USERNAME}" - ./asadmin $ASADMIN_OPTS create-jvm-options '\-Ddataverse.pid.datacite.password=${ALIAS=doi_password_alias}' - ./asadmin $ASADMIN_OPTS create-jvm-options "\-Ddataverse.pid.datacite.mds-api-url=$DOI_BASEURL_ESC" - + ./asadmin $ASADMIN_OPTS create-jvm-options "\-Ddataverse.pid.providers=fake" + ./asadmin $ASADMIN_OPTS create-jvm-options "\-Ddataverse.pid.fake.type=FAKE" + ./asadmin $ASADMIN_OPTS create-jvm-options "\-Ddataverse.pid.fake.label=Fake DOI Provider" + ./asadmin $ASADMIN_OPTS create-jvm-options "\-Ddataverse.pid.fake.authority=10.5072" + ./asadmin $ASADMIN_OPTS create-jvm-options "\-Ddataverse.pid.fake.shoulder=FK2/" # jvm-options use colons as separators, escape as literal - DOI_DATACITERESTAPIURL_ESC=`echo $DOI_DATACITERESTAPIURL | sed -e 's/:/\\\:/'` - ./asadmin $ASADMIN_OPTS create-jvm-options "\-Ddataverse.pid.datacite.rest-api-url=$DOI_DATACITERESTAPIURL_ESC" + #DOI_DATACITERESTAPIURL_ESC=`echo $DOI_DATACITERESTAPIURL | sed -e 's/:/\\\:/'` + #./asadmin $ASADMIN_OPTS create-jvm-options "\-Ddataverse.pid.testDC.datacite.rest-api-url=$DOI_DATACITERESTAPIURL_ESC" ./asadmin $ASADMIN_OPTS create-jvm-options "-Ddataverse.timerServer=true" diff --git a/scripts/installer/install.py b/scripts/installer/install.py index 18995695638..99316efb83b 100644 --- a/scripts/installer/install.py +++ b/scripts/installer/install.py @@ -591,15 +591,14 @@ print("\n\nYou should now have a running Dataverse instance at") print(" http://" + hostName + ":8080\n\n") -# DataCite instructions: +# PID instructions: -print("\nYour Dataverse has been configured to use DataCite, to register DOI global identifiers in the ") +print("\nYour Dataverse has been configured to use a Fake DOI Provider, registering (non-resolvable) DOI global identifiers in the ") print("test name space \"10.5072\" with the \"shoulder\" \"FK2\"") -print("However, you have to contact DataCite (support\@datacite.org) and request a test account, before you ") -print("can publish datasets. Once you receive the account name and password, add them to your domain.xml,") -print("as the following two JVM options:") -print("\t-Ddataverse.pid.datacite.username=...") -print("\t-Ddataverse.pid.datacite.password=...") +print("You can reconfigure to use additional/alternative providers.") +print("If you intend to use DOIs, you should contact DataCite (support\@datacite.org) or GDCC (see https://www.gdcc.io/about.html) and request a test account.") +print("Once you receive the account information (name, password, authority, shoulder), add them to your configuration ") +print("as described in the Dataverse Guides (see https://guides.dataverse.org/en/latest/installation/config.html#persistent-identifiers-and-publishing-datasets),") print("and restart payara") print("If this is a production Dataverse and you are planning to register datasets as ") print("\"real\", non-test DOIs or Handles, consult the \"Persistent Identifiers and Publishing Datasets\"") diff --git a/src/main/java/edu/harvard/iq/dataverse/AbstractGlobalIdServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/AbstractGlobalIdServiceBean.java deleted file mode 100644 index f1bfc3e290b..00000000000 --- a/src/main/java/edu/harvard/iq/dataverse/AbstractGlobalIdServiceBean.java +++ /dev/null @@ -1,700 +0,0 @@ -package edu.harvard.iq.dataverse; - -import edu.harvard.iq.dataverse.settings.SettingsServiceBean; -import edu.harvard.iq.dataverse.util.SystemConfig; -import java.io.InputStream; -import jakarta.ejb.EJB; -import jakarta.inject.Inject; -import java.util.*; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.apache.commons.lang3.RandomStringUtils; -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; - -public abstract class AbstractGlobalIdServiceBean implements GlobalIdServiceBean { - - private static final Logger logger = Logger.getLogger(AbstractGlobalIdServiceBean.class.getCanonicalName()); - - @Inject - DataverseServiceBean dataverseService; - @EJB - protected - SettingsServiceBean settingsService; - @Inject - protected - DvObjectServiceBean dvObjectService; - @Inject - SystemConfig systemConfig; - - protected Boolean configured = null; - - public static String UNAVAILABLE = ":unav"; - - @Override - public Map getMetadataForCreateIndicator(DvObject dvObjectIn) { - logger.log(Level.FINE,"getMetadataForCreateIndicator(DvObject)"); - Map metadata = new HashMap<>(); - metadata = addBasicMetadata(dvObjectIn, metadata); - metadata.put("datacite.publicationyear", generateYear(dvObjectIn)); - metadata.put("_target", getTargetUrl(dvObjectIn)); - return metadata; - } - - protected Map getUpdateMetadata(DvObject dvObjectIn) { - logger.log(Level.FINE,"getUpdateMetadataFromDataset"); - Map metadata = new HashMap<>(); - metadata = addBasicMetadata(dvObjectIn, metadata); - return metadata; - } - - protected Map addBasicMetadata(DvObject dvObjectIn, Map metadata) { - - String authorString = dvObjectIn.getAuthorString(); - if (authorString.isEmpty() || authorString.contains(DatasetField.NA_VALUE)) { - authorString = UNAVAILABLE; - } - - String producerString = dataverseService.getRootDataverseName(); - - if (producerString.isEmpty() || producerString.equals(DatasetField.NA_VALUE)) { - producerString = UNAVAILABLE; - } - - String titleString = dvObjectIn.getCurrentName(); - - if (titleString.isEmpty() || titleString.equals(DatasetField.NA_VALUE)) { - titleString = UNAVAILABLE; - } - - metadata.put("datacite.creator", authorString); - metadata.put("datacite.title", titleString); - metadata.put("datacite.publisher", producerString); - metadata.put("datacite.publicationyear", generateYear(dvObjectIn)); - return metadata; - } - - protected Map addDOIMetadataForDestroyedDataset(DvObject dvObjectIn) { - Map metadata = new HashMap<>(); - String authorString = UNAVAILABLE; - String producerString = UNAVAILABLE; - String titleString = "This item has been removed from publication"; - - metadata.put("datacite.creator", authorString); - metadata.put("datacite.title", titleString); - metadata.put("datacite.publisher", producerString); - metadata.put("datacite.publicationyear", "9999"); - return metadata; - } - - protected String getTargetUrl(DvObject dvObjectIn) { - logger.log(Level.FINE,"getTargetUrl"); - return systemConfig.getDataverseSiteUrl() + dvObjectIn.getTargetUrl() + dvObjectIn.getGlobalId().asString(); - } - - @Override - public String getIdentifier(DvObject dvObject) { - GlobalId gid = dvObject.getGlobalId(); - return gid != null ? gid.asString() : null; - } - - protected String generateYear (DvObject dvObjectIn){ - return dvObjectIn.getYearPublishedCreated(); - } - - public Map getMetadataForTargetURL(DvObject dvObject) { - logger.log(Level.FINE,"getMetadataForTargetURL"); - HashMap metadata = new HashMap<>(); - metadata.put("_target", getTargetUrl(dvObject)); - return metadata; - } - - @Override - public boolean alreadyRegistered(DvObject dvo) throws Exception { - if(dvo==null) { - logger.severe("Null DvObject sent to alreadyRegistered()."); - return false; - } - GlobalId globalId = dvo.getGlobalId(); - if(globalId == null) { - return false; - } - return alreadyRegistered(globalId, false); - } - - public abstract boolean alreadyRegistered(GlobalId globalId, boolean noProviderDefault) throws Exception; - - /* - * ToDo: the DvObject being sent in provides partial support for the case where - * it has a different authority/protocol than what is configured (i.e. a legacy - * Pid that can actually be updated by the Pid account being used.) Removing - * this now would potentially break/make it harder to handle that case prior to - * support for configuring multiple Pid providers. Once that exists, it would be - * cleaner to always find the PidProvider associated with the - * protocol/authority/shoulder of the current dataset and then not pass the - * DvObject as a param. (This would also remove calls to get the settings since - * that would be done at construction.) - */ - @Override - public DvObject generateIdentifier(DvObject dvObject) { - - String protocol = dvObject.getProtocol() == null ? settingsService.getValueForKey(SettingsServiceBean.Key.Protocol) : dvObject.getProtocol(); - String authority = dvObject.getAuthority() == null ? settingsService.getValueForKey(SettingsServiceBean.Key.Authority) : dvObject.getAuthority(); - if (dvObject.isInstanceofDataset()) { - dvObject.setIdentifier(generateDatasetIdentifier((Dataset) dvObject)); - } else { - dvObject.setIdentifier(generateDataFileIdentifier((DataFile) dvObject)); - } - if (dvObject.getProtocol() == null) { - dvObject.setProtocol(protocol); - } - if (dvObject.getAuthority() == null) { - dvObject.setAuthority(authority); - } - return dvObject; - } - - //ToDo just send the DvObject.DType - public String generateDatasetIdentifier(Dataset dataset) { - //ToDo - track these in the bean - String identifierType = settingsService.getValueForKey(SettingsServiceBean.Key.IdentifierGenerationStyle, "randomString"); - String shoulder = settingsService.getValueForKey(SettingsServiceBean.Key.Shoulder, ""); - - switch (identifierType) { - case "randomString": - return generateIdentifierAsRandomString(dataset, shoulder); - case "storedProcGenerated": - return generateIdentifierFromStoredProcedureIndependent(dataset, shoulder); - default: - /* Should we throw an exception instead?? -- L.A. 4.6.2 */ - return generateIdentifierAsRandomString(dataset, shoulder); - } - } - - - /** - * Check that a identifier entered by the user is unique (not currently used - * for any other study in this Dataverse Network) also check for duplicate - * in EZID if needed - * @param userIdentifier - * @param dataset - * @return {@code true} if the identifier is unique, {@code false} otherwise. - */ - public boolean isGlobalIdUnique(GlobalId globalId) { - if ( ! dvObjectService.isGlobalIdLocallyUnique(globalId) ) { - return false; // duplication found in local database - } - - // not in local DB, look in the persistent identifier service - try { - return ! alreadyRegistered(globalId, false); - } catch (Exception e){ - //we can live with failure - means identifier not found remotely - } - - return true; - } - - /** - * Parse a Persistent Id and set the protocol, authority, and identifier - * - * Example 1: doi:10.5072/FK2/BYM3IW - * protocol: doi - * authority: 10.5072 - * identifier: FK2/BYM3IW - * - * Example 2: hdl:1902.1/111012 - * protocol: hdl - * authority: 1902.1 - * identifier: 111012 - * - * @param identifierString - * @param separator the string that separates the authority from the identifier. - * @param destination the global id that will contain the parsed data. - * @return {@code destination}, after its fields have been updated, or - * {@code null} if parsing failed. - */ - @Override - public GlobalId parsePersistentId(String fullIdentifierString) { - if(!isConfigured()) { - return null; - } - // Occasionally, the protocol separator character ':' comes in still - // URL-encoded as %3A (usually as a result of the URL having been - // encoded twice): - fullIdentifierString = fullIdentifierString.replace("%3A", ":"); - - int index1 = fullIdentifierString.indexOf(':'); - if (index1 > 0) { // ':' found with one or more characters before it - String protocol = fullIdentifierString.substring(0, index1); - GlobalId globalId = parsePersistentId(protocol, fullIdentifierString.substring(index1+1)); - return globalId; - } - logger.log(Level.INFO, "Error parsing identifier: {0}: '':'' not found in string", fullIdentifierString); - return null; - } - - protected GlobalId parsePersistentId(String protocol, String identifierString) { - if(!isConfigured()) { - return null; - } - String authority; - String identifier; - if (identifierString == null) { - return null; - } - int index = identifierString.indexOf('/'); - if (index > 0 && (index + 1) < identifierString.length()) { - // '/' found with one or more characters - // before and after it - // Strip any whitespace, ; and ' from authority (should finding them cause a - // failure instead?) - authority = GlobalIdServiceBean.formatIdentifierString(identifierString.substring(0, index)); - if (GlobalIdServiceBean.testforNullTerminator(authority)) { - return null; - } - identifier = GlobalIdServiceBean.formatIdentifierString(identifierString.substring(index + 1)); - if (GlobalIdServiceBean.testforNullTerminator(identifier)) { - return null; - } - } else { - logger.log(Level.INFO, "Error parsing identifier: {0}: '':/'' not found in string", - identifierString); - return null; - } - return parsePersistentId(protocol, authority, identifier); - } - - public GlobalId parsePersistentId(String protocol, String authority, String identifier) { - if(!isConfigured()) { - return null; - } - logger.fine("Parsing: " + protocol + ":" + authority + getSeparator() + identifier + " in " + getProviderInformation().get(0)); - if(!GlobalIdServiceBean.isValidGlobalId(protocol, authority, identifier)) { - return null; - } - return new GlobalId(protocol, authority, identifier, getSeparator(), getUrlPrefix(), - getProviderInformation().get(0)); - } - - - public String getSeparator() { - //The standard default - return "/"; - } - - @Override - public String generateDataFileIdentifier(DataFile datafile) { - String doiIdentifierType = settingsService.getValueForKey(SettingsServiceBean.Key.IdentifierGenerationStyle, "randomString"); - String doiDataFileFormat = settingsService.getValueForKey(SettingsServiceBean.Key.DataFilePIDFormat, SystemConfig.DataFilePIDFormat.DEPENDENT.toString()); - - String prepend = ""; - if (doiDataFileFormat.equals(SystemConfig.DataFilePIDFormat.DEPENDENT.toString())){ - //If format is dependent then pre-pend the dataset identifier - prepend = datafile.getOwner().getIdentifier() + "/"; - datafile.setProtocol(datafile.getOwner().getProtocol()); - datafile.setAuthority(datafile.getOwner().getAuthority()); - } else { - //If there's a shoulder prepend independent identifiers with it - prepend = settingsService.getValueForKey(SettingsServiceBean.Key.Shoulder, ""); - datafile.setProtocol(settingsService.getValueForKey(SettingsServiceBean.Key.Protocol)); - datafile.setAuthority(settingsService.getValueForKey(SettingsServiceBean.Key.Authority)); - } - - switch (doiIdentifierType) { - case "randomString": - return generateIdentifierAsRandomString(datafile, prepend); - case "storedProcGenerated": - if (doiDataFileFormat.equals(SystemConfig.DataFilePIDFormat.INDEPENDENT.toString())){ - return generateIdentifierFromStoredProcedureIndependent(datafile, prepend); - } else { - return generateIdentifierFromStoredProcedureDependent(datafile, prepend); - } - default: - /* Should we throw an exception instead?? -- L.A. 4.6.2 */ - return generateIdentifierAsRandomString(datafile, prepend); - } - } - - - /* - * This method checks locally for a DvObject with the same PID and if that is OK, checks with the PID service. - * @param dvo - the object to check (ToDo - get protocol/authority from this PidProvider object) - * @param prepend - for Datasets, this is always the shoulder, for DataFiles, it could be the shoulder or the parent Dataset identifier - */ - private String generateIdentifierAsRandomString(DvObject dvo, String prepend) { - String identifier = null; - do { - identifier = prepend + RandomStringUtils.randomAlphanumeric(6).toUpperCase(); - } while (!isGlobalIdUnique(new GlobalId(dvo.getProtocol(), dvo.getAuthority(), identifier, this.getSeparator(), this.getUrlPrefix(), this.getProviderInformation().get(0)))); - - return identifier; - } - - /* - * This method checks locally for a DvObject with the same PID and if that is OK, checks with the PID service. - * @param dvo - the object to check (ToDo - get protocol/authority from this PidProvider object) - * @param prepend - for Datasets, this is always the shoulder, for DataFiles, it could be the shoulder or the parent Dataset identifier - */ - - private String generateIdentifierFromStoredProcedureIndependent(DvObject dvo, String prepend) { - String identifier; - do { - String identifierFromStoredProcedure = dvObjectService.generateNewIdentifierByStoredProcedure(); - // some diagnostics here maybe - is it possible to determine that it's failing - // because the stored procedure hasn't been created in the database? - if (identifierFromStoredProcedure == null) { - return null; - } - identifier = prepend + identifierFromStoredProcedure; - } while (!isGlobalIdUnique(new GlobalId(dvo.getProtocol(), dvo.getAuthority(), identifier, this.getSeparator(), this.getUrlPrefix(), this.getProviderInformation().get(0)))); - - return identifier; - } - - /*This method is only used for DataFiles with DEPENDENT Pids. It is not for Datasets - * - */ - private String generateIdentifierFromStoredProcedureDependent(DataFile datafile, String prepend) { - String identifier; - Long retVal; - retVal = Long.valueOf(0L); - //ToDo - replace loops with one lookup for largest entry? (the do loop runs ~n**2/2 calls). The check for existingIdentifiers means this is mostly a local loop now, versus involving db or PidProvider calls, but still...) - - // This will catch identifiers already assigned in the current transaction (e.g. - // in FinalizeDatasetPublicationCommand) that haven't been committed to the db - // without having to make a call to the PIDProvider - Set existingIdentifiers = new HashSet(); - List files = datafile.getOwner().getFiles(); - for(DataFile f:files) { - existingIdentifiers.add(f.getIdentifier()); - } - - do { - retVal++; - identifier = prepend + retVal.toString(); - - } while (existingIdentifiers.contains(identifier) || !isGlobalIdUnique(new GlobalId(datafile.getProtocol(), datafile.getAuthority(), identifier, this.getSeparator(), this.getUrlPrefix(), this.getProviderInformation().get(0)))); - - return identifier; - } - - - class GlobalIdMetadataTemplate { - - - private String template; - - public GlobalIdMetadataTemplate(){ - try (InputStream in = GlobalIdMetadataTemplate.class.getResourceAsStream("datacite_metadata_template.xml")) { - template = Util.readAndClose(in, "utf-8"); - } catch (Exception e) { - logger.log(Level.SEVERE, "datacite metadata template load error"); - logger.log(Level.SEVERE, "String " + e.toString()); - logger.log(Level.SEVERE, "localized message " + e.getLocalizedMessage()); - logger.log(Level.SEVERE, "cause " + e.getCause()); - logger.log(Level.SEVERE, "message " + e.getMessage()); - } - } - - private String xmlMetadata; - private String identifier; - private List datafileIdentifiers; - private List creators; - private String title; - private String publisher; - private String publisherYear; - private List authors; - private String description; - private List contacts; - private List producers; - - public List getProducers() { - return producers; - } - - public void setProducers(List producers) { - this.producers = producers; - } - - public List getContacts() { - return contacts; - } - - public void setContacts(List contacts) { - this.contacts = contacts; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public List getAuthors() { - return authors; - } - - public void setAuthors(List authors) { - this.authors = authors; - } - - - public List getDatafileIdentifiers() { - return datafileIdentifiers; - } - - public void setDatafileIdentifiers(List datafileIdentifiers) { - this.datafileIdentifiers = datafileIdentifiers; - } - - public GlobalIdMetadataTemplate(String xmlMetaData) { - this.xmlMetadata = xmlMetaData; - Document doc = Jsoup.parseBodyFragment(xmlMetaData); - Elements identifierElements = doc.select("identifier"); - if (identifierElements.size() > 0) { - identifier = identifierElements.get(0).html(); - } - Elements creatorElements = doc.select("creatorName"); - creators = new ArrayList<>(); - for (Element creatorElement : creatorElements) { - creators.add(creatorElement.html()); - } - Elements titleElements = doc.select("title"); - if (titleElements.size() > 0) { - title = titleElements.get(0).html(); - } - Elements publisherElements = doc.select("publisher"); - if (publisherElements.size() > 0) { - publisher = publisherElements.get(0).html(); - } - Elements publisherYearElements = doc.select("publicationYear"); - if (publisherYearElements.size() > 0) { - publisherYear = publisherYearElements.get(0).html(); - } - } - - public String generateXML(DvObject dvObject) { - // Can't use "UNKNOWN" here because DataCite will respond with "[facet 'pattern'] the value 'unknown' is not accepted by the pattern '[\d]{4}'" - String publisherYearFinal = "9999"; - // FIXME: Investigate why this.publisherYear is sometimes null now that pull request #4606 has been merged. - if (this.publisherYear != null) { - // Added to prevent a NullPointerException when trying to destroy datasets when using DataCite rather than EZID. - publisherYearFinal = this.publisherYear; - } - xmlMetadata = template.replace("${identifier}", getIdentifier().trim()) - .replace("${title}", this.title) - .replace("${publisher}", this.publisher) - .replace("${publisherYear}", publisherYearFinal) - .replace("${description}", this.description); - StringBuilder creatorsElement = new StringBuilder(); - for (DatasetAuthor author : authors) { - creatorsElement.append(""); - creatorsElement.append(author.getName().getDisplayValue()); - creatorsElement.append(""); - - if (author.getIdType() != null && author.getIdValue() != null && !author.getIdType().isEmpty() && !author.getIdValue().isEmpty() && author.getAffiliation() != null && !author.getAffiliation().getDisplayValue().isEmpty()) { - - if (author.getIdType().equals("ORCID")) { - creatorsElement.append("" + author.getIdValue() + ""); - } - if (author.getIdType().equals("ISNI")) { - creatorsElement.append("" + author.getIdValue() + ""); - } - if (author.getIdType().equals("LCNA")) { - creatorsElement.append("" + author.getIdValue() + ""); - } - } - if (author.getAffiliation() != null && !author.getAffiliation().getDisplayValue().isEmpty()) { - creatorsElement.append("" + author.getAffiliation().getDisplayValue() + ""); - } - creatorsElement.append(""); - } - xmlMetadata = xmlMetadata.replace("${creators}", creatorsElement.toString()); - - StringBuilder contributorsElement = new StringBuilder(); - for (String[] contact : this.getContacts()) { - if (!contact[0].isEmpty()) { - contributorsElement.append("" + contact[0] + ""); - if (!contact[1].isEmpty()) { - contributorsElement.append("" + contact[1] + ""); - } - contributorsElement.append(""); - } - } - for (String[] producer : this.getProducers()) { - contributorsElement.append("" + producer[0] + ""); - if (!producer[1].isEmpty()) { - contributorsElement.append("" + producer[1] + ""); - } - contributorsElement.append(""); - } - - String relIdentifiers = generateRelatedIdentifiers(dvObject); - - xmlMetadata = xmlMetadata.replace("${relatedIdentifiers}", relIdentifiers); - - xmlMetadata = xmlMetadata.replace("{$contributors}", contributorsElement.toString()); - return xmlMetadata; - } - - private String generateRelatedIdentifiers(DvObject dvObject) { - - StringBuilder sb = new StringBuilder(); - if (dvObject.isInstanceofDataset()) { - Dataset dataset = (Dataset) dvObject; - if (!dataset.getFiles().isEmpty() && !(dataset.getFiles().get(0).getIdentifier() == null)) { - - datafileIdentifiers = new ArrayList<>(); - for (DataFile dataFile : dataset.getFiles()) { - if (!dataFile.getGlobalId().asString().isEmpty()) { - if (sb.toString().isEmpty()) { - sb.append(""); - } - sb.append("" + dataFile.getGlobalId() + ""); - } - } - - if (!sb.toString().isEmpty()) { - sb.append(""); - } - } - } else if (dvObject.isInstanceofDataFile()) { - DataFile df = (DataFile) dvObject; - sb.append(""); - sb.append("" + df.getOwner().getGlobalId() + ""); - sb.append(""); - } - return sb.toString(); - } - - public void generateFileIdentifiers(DvObject dvObject) { - - if (dvObject.isInstanceofDataset()) { - Dataset dataset = (Dataset) dvObject; - - if (!dataset.getFiles().isEmpty() && !(dataset.getFiles().get(0).getIdentifier() == null)) { - - datafileIdentifiers = new ArrayList<>(); - for (DataFile dataFile : dataset.getFiles()) { - datafileIdentifiers.add(dataFile.getIdentifier()); - int x = xmlMetadata.indexOf("") - 1; - xmlMetadata = xmlMetadata.replace("{relatedIdentifier}", dataFile.getIdentifier()); - xmlMetadata = xmlMetadata.substring(0, x) + "${relatedIdentifier}" + template.substring(x, template.length() - 1); - - } - - } else { - xmlMetadata = xmlMetadata.replace("${relatedIdentifier}", ""); - } - } - } - - public String getTemplate() { - return template; - } - - public void setTemplate(String templateIn) { - template = templateIn; - } - - public String getIdentifier() { - return identifier; - } - - public void setIdentifier(String identifier) { - this.identifier = identifier; - } - - public List getCreators() { - return creators; - } - - public void setCreators(List creators) { - this.creators = creators; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getPublisher() { - return publisher; - } - - public void setPublisher(String publisher) { - this.publisher = publisher; - } - - public String getPublisherYear() { - return publisherYear; - } - - public void setPublisherYear(String publisherYear) { - this.publisherYear = publisherYear; - } -} - public String getMetadataFromDvObject(String identifier, Map metadata, DvObject dvObject) { - - Dataset dataset = null; - - if (dvObject instanceof Dataset) { - dataset = (Dataset) dvObject; - } else { - dataset = (Dataset) dvObject.getOwner(); - } - - GlobalIdMetadataTemplate metadataTemplate = new GlobalIdMetadataTemplate(); - metadataTemplate.setIdentifier(identifier.substring(identifier.indexOf(':') + 1)); - metadataTemplate.setCreators(Util.getListFromStr(metadata.get("datacite.creator"))); - metadataTemplate.setAuthors(dataset.getLatestVersion().getDatasetAuthors()); - if (dvObject.isInstanceofDataset()) { - metadataTemplate.setDescription(dataset.getLatestVersion().getDescriptionPlainText()); - } - if (dvObject.isInstanceofDataFile()) { - DataFile df = (DataFile) dvObject; - String fileDescription = df.getDescription(); - metadataTemplate.setDescription(fileDescription == null ? "" : fileDescription); - } - - metadataTemplate.setContacts(dataset.getLatestVersion().getDatasetContacts()); - metadataTemplate.setProducers(dataset.getLatestVersion().getDatasetProducers()); - metadataTemplate.setTitle(dvObject.getCurrentName()); - String producerString = dataverseService.getRootDataverseName(); - if (producerString.isEmpty() || producerString.equals(DatasetField.NA_VALUE) ) { - producerString = UNAVAILABLE; - } - metadataTemplate.setPublisher(producerString); - metadataTemplate.setPublisherYear(metadata.get("datacite.publicationyear")); - - String xmlMetadata = metadataTemplate.generateXML(dvObject); - logger.log(Level.FINE, "XML to send to DataCite: {0}", xmlMetadata); - return xmlMetadata; - } - - @Override - public boolean canManagePID() { - //The default expectation is that PID providers are configured to manage some set (i.e. based on protocol/authority/shoulder) of PIDs - return true; - } - - @Override - public boolean isConfigured() { - if(configured==null) { - return false; - } else { - return configured.booleanValue(); - } - } -} diff --git a/src/main/java/edu/harvard/iq/dataverse/DOIDataCiteRegisterCache.java b/src/main/java/edu/harvard/iq/dataverse/DOIDataCiteRegisterCache.java deleted file mode 100644 index 7c75b1a4da6..00000000000 --- a/src/main/java/edu/harvard/iq/dataverse/DOIDataCiteRegisterCache.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package edu.harvard.iq.dataverse; - - -import java.io.Serializable; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.Lob; -import jakarta.persistence.NamedQueries; -import jakarta.persistence.NamedQuery; -import org.hibernate.validator.constraints.NotBlank; - -/** - * - * @author luopc - */ -@NamedQueries( - @NamedQuery( name="DOIDataCiteRegisterCache.findByDoi", - query="SELECT d FROM DOIDataCiteRegisterCache d WHERE d.doi=:doi") -) -@Entity -public class DOIDataCiteRegisterCache implements Serializable{ - - private static final long serialVersionUID = 8030143094734315681L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @NotBlank - @Column(unique=true) - private String doi; - - @NotBlank - private String url; - - @NotBlank - private String status; - - @NotBlank - @Lob - private String xml; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getDoi() { - return doi; - } - - public void setDoi(String doi) { - this.doi = doi; - } - - public String getStatus() { - return status; - } - - public void setStatus(String status) { - this.status = status; - } - - public String getXml() { - return xml; - } - - public void setXml(String xml) { - this.xml = xml; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } -} \ No newline at end of file diff --git a/src/main/java/edu/harvard/iq/dataverse/DOIDataCiteRegisterService.java b/src/main/java/edu/harvard/iq/dataverse/DOIDataCiteRegisterService.java deleted file mode 100644 index 9ecc4a3ecc9..00000000000 --- a/src/main/java/edu/harvard/iq/dataverse/DOIDataCiteRegisterService.java +++ /dev/null @@ -1,707 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package edu.harvard.iq.dataverse; - -import edu.harvard.iq.dataverse.branding.BrandingUtil; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; -import jakarta.ejb.EJB; -import jakarta.ejb.Stateless; -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; -import jakarta.persistence.TypedQuery; - -import edu.harvard.iq.dataverse.settings.JvmSettings; -import org.apache.commons.text.StringEscapeUtils; -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; - -/** - * - * @author luopc - */ -@Stateless -public class DOIDataCiteRegisterService { - - private static final Logger logger = Logger.getLogger(DOIDataCiteRegisterService.class.getCanonicalName()); - - @PersistenceContext(unitName = "VDCNet-ejbPU") - private EntityManager em; - - @EJB - DataverseServiceBean dataverseService; - - @EJB - DOIDataCiteServiceBean doiDataCiteServiceBean; - - - //A singleton since it, and the httpClient in it can be reused. - private DataCiteRESTfullClient client=null; - - private DataCiteRESTfullClient getClient() throws IOException { - if (client == null) { - client = new DataCiteRESTfullClient( - JvmSettings.DATACITE_MDS_API_URL.lookup(), - JvmSettings.DATACITE_USERNAME.lookup(), - JvmSettings.DATACITE_PASSWORD.lookup() - ); - } - return client; - } - - /** - * This method is deprecated and unused. We switched away from this method - * when adjusting the code to reserve DOIs from DataCite on dataset create. - * - * Note that the DOIDataCiteRegisterCache entity/table used in this method - * might be a candidate for deprecation as well. Removing it would require - * some refactoring as it is used throughout the DataCite code. - */ - @Deprecated - public String createIdentifierLocal(String identifier, Map metadata, DvObject dvObject) { - - String xmlMetadata = getMetadataFromDvObject(identifier, metadata, dvObject); - String status = metadata.get("_status").trim(); - String target = metadata.get("_target"); - String retString = ""; - DOIDataCiteRegisterCache rc = findByDOI(identifier); - if (rc == null) { - rc = new DOIDataCiteRegisterCache(); - rc.setDoi(identifier); - rc.setXml(xmlMetadata); - rc.setStatus("reserved"); - rc.setUrl(target); - em.persist(rc); - } else { - rc.setDoi(identifier); - rc.setXml(xmlMetadata); - rc.setStatus("reserved"); - rc.setUrl(target); - } - retString = "success to reserved " + identifier; - - return retString; - } - - /** - * This "reserveIdentifier" method is heavily based on the - * "registerIdentifier" method below but doesn't, this one doesn't doesn't - * register a URL, which causes the "state" of DOI to transition from - * "draft" to "findable". Here are some DataCite docs on the matter: - * - * "DOIs can exist in three states: draft, registered, and findable. DOIs - * are in the draft state when metadata have been registered, and will - * transition to the findable state when registering a URL." -- - * https://support.datacite.org/docs/mds-api-guide#doi-states - */ - public String reserveIdentifier(String identifier, Map metadata, DvObject dvObject) throws IOException { - String retString = ""; - String xmlMetadata = getMetadataFromDvObject(identifier, metadata, dvObject); - DOIDataCiteRegisterCache rc = findByDOI(identifier); - String target = metadata.get("_target"); - if (rc != null) { - rc.setDoi(identifier); - rc.setXml(xmlMetadata); - // DataCite uses the term "draft" instead of "reserved". - rc.setStatus("reserved"); - if (target == null || target.trim().length() == 0) { - target = rc.getUrl(); - } else { - rc.setUrl(target); - } - } - - DataCiteRESTfullClient client = getClient(); - retString = client.postMetadata(xmlMetadata); - - return retString; - } - - public String registerIdentifier(String identifier, Map metadata, DvObject dvObject) throws IOException { - String retString = ""; - String xmlMetadata = getMetadataFromDvObject(identifier, metadata, dvObject); - DOIDataCiteRegisterCache rc = findByDOI(identifier); - String target = metadata.get("_target"); - if (rc != null) { - rc.setDoi(identifier); - rc.setXml(xmlMetadata); - rc.setStatus("public"); - if (target == null || target.trim().length() == 0) { - target = rc.getUrl(); - } else { - rc.setUrl(target); - } - } - - DataCiteRESTfullClient client = getClient(); - retString = client.postMetadata(xmlMetadata); - client.postUrl(identifier.substring(identifier.indexOf(":") + 1), target); - - return retString; - } - - public String deactivateIdentifier(String identifier, Map metadata, DvObject dvObject) throws IOException { - String retString = ""; - - String metadataString = getMetadataForDeactivateIdentifier(identifier, metadata, dvObject); - retString = client.postMetadata(metadataString); - retString = client.inactiveDataset(identifier.substring(identifier.indexOf(":") + 1)); - - return retString; - } - - public static String getMetadataFromDvObject(String identifier, Map metadata, DvObject dvObject) { - - Dataset dataset = null; - - if (dvObject instanceof Dataset) { - dataset = (Dataset) dvObject; - } else { - dataset = (Dataset) dvObject.getOwner(); - } - - DataCiteMetadataTemplate metadataTemplate = new DataCiteMetadataTemplate(); - metadataTemplate.setIdentifier(identifier.substring(identifier.indexOf(':') + 1)); - metadataTemplate.setCreators(Util.getListFromStr(metadata.get("datacite.creator"))); - metadataTemplate.setAuthors(dataset.getLatestVersion().getDatasetAuthors()); - if (dvObject.isInstanceofDataset()) { - //While getDescriptionPlainText strips < and > from HTML, it leaves '&' (at least so we need to xml escape as well - String description = StringEscapeUtils.escapeXml10(dataset.getLatestVersion().getDescriptionPlainText()); - if (description.isEmpty() || description.equals(DatasetField.NA_VALUE)) { - description = AbstractGlobalIdServiceBean.UNAVAILABLE; - } - metadataTemplate.setDescription(description); - } - if (dvObject.isInstanceofDataFile()) { - DataFile df = (DataFile) dvObject; - //Note: File metadata is not escaped like dataset metadata is, so adding an xml escape here. - //This could/should be removed if the datafile methods add escaping - String fileDescription = StringEscapeUtils.escapeXml10(df.getDescription()); - metadataTemplate.setDescription(fileDescription == null ? AbstractGlobalIdServiceBean.UNAVAILABLE : fileDescription); - String datasetPid = df.getOwner().getGlobalId().asString(); - metadataTemplate.setDatasetIdentifier(datasetPid); - } else { - metadataTemplate.setDatasetIdentifier(""); - } - - metadataTemplate.setContacts(dataset.getLatestVersion().getDatasetContacts()); - metadataTemplate.setProducers(dataset.getLatestVersion().getDatasetProducers()); - String title = dvObject.getCurrentName(); - if(dvObject.isInstanceofDataFile()) { - //Note file title is not currently escaped the way the dataset title is, so adding it here. - title = StringEscapeUtils.escapeXml10(title); - } - - if (title.isEmpty() || title.equals(DatasetField.NA_VALUE)) { - title = AbstractGlobalIdServiceBean.UNAVAILABLE; - } - - metadataTemplate.setTitle(title); - String producerString = BrandingUtil.getRootDataverseCollectionName(); - if (producerString.isEmpty() || producerString.equals(DatasetField.NA_VALUE)) { - producerString = AbstractGlobalIdServiceBean.UNAVAILABLE; - } - metadataTemplate.setPublisher(producerString); - metadataTemplate.setPublisherYear(metadata.get("datacite.publicationyear")); - - String xmlMetadata = metadataTemplate.generateXML(dvObject); - logger.log(Level.FINE, "XML to send to DataCite: {0}", xmlMetadata); - return xmlMetadata; - } - - public static String getMetadataForDeactivateIdentifier(String identifier, Map metadata, DvObject dvObject) { - - DataCiteMetadataTemplate metadataTemplate = new DataCiteMetadataTemplate(); - metadataTemplate.setIdentifier(identifier.substring(identifier.indexOf(':') + 1)); - metadataTemplate.setCreators(Util.getListFromStr(metadata.get("datacite.creator"))); - - metadataTemplate.setDescription(AbstractGlobalIdServiceBean.UNAVAILABLE); - - String title =metadata.get("datacite.title"); - - System.out.print("Map metadata title: "+ metadata.get("datacite.title")); - - metadataTemplate.setAuthors(null); - - metadataTemplate.setTitle(title); - String producerString = AbstractGlobalIdServiceBean.UNAVAILABLE; - - metadataTemplate.setPublisher(producerString); - metadataTemplate.setPublisherYear(metadata.get("datacite.publicationyear")); - - String xmlMetadata = metadataTemplate.generateXML(dvObject); - logger.log(Level.FINE, "XML to send to DataCite: {0}", xmlMetadata); - return xmlMetadata; - } - - public String modifyIdentifier(String identifier, HashMap metadata, DvObject dvObject) throws IOException { - - String xmlMetadata = getMetadataFromDvObject(identifier, metadata, dvObject); - - logger.fine("XML to send to DataCite: " + xmlMetadata); - - String status = metadata.get("_status").trim(); - String target = metadata.get("_target"); - String retString = ""; - if (status.equals("reserved")) { - DOIDataCiteRegisterCache rc = findByDOI(identifier); - if (rc == null) { - rc = new DOIDataCiteRegisterCache(); - rc.setDoi(identifier); - rc.setXml(xmlMetadata); - rc.setStatus("reserved"); - rc.setUrl(target); - em.persist(rc); - } else { - rc.setDoi(identifier); - rc.setXml(xmlMetadata); - rc.setStatus("reserved"); - rc.setUrl(target); - } - retString = "success to reserved " + identifier; - } else if (status.equals("public")) { - DOIDataCiteRegisterCache rc = findByDOI(identifier); - if (rc != null) { - rc.setDoi(identifier); - rc.setXml(xmlMetadata); - rc.setStatus("public"); - if (target == null || target.trim().length() == 0) { - target = rc.getUrl(); - } else { - rc.setUrl(target); - } - try { - DataCiteRESTfullClient client = getClient(); - retString = client.postMetadata(xmlMetadata); - client.postUrl(identifier.substring(identifier.indexOf(":") + 1), target); - - } catch (UnsupportedEncodingException ex) { - logger.log(Level.SEVERE, null, ex); - - } catch (RuntimeException rte) { - logger.log(Level.SEVERE, "Error creating DOI at DataCite: {0}", rte.getMessage()); - logger.log(Level.SEVERE, "Exception", rte); - - } - } - } else if (status.equals("unavailable")) { - DOIDataCiteRegisterCache rc = findByDOI(identifier); - try { - DataCiteRESTfullClient client = getClient(); - if (rc != null) { - rc.setStatus("unavailable"); - retString = client.inactiveDataset(identifier.substring(identifier.indexOf(":") + 1)); - } - } catch (IOException io) { - - } - } - return retString; - } - - public boolean testDOIExists(String identifier) { - boolean doiExists; - try { - DataCiteRESTfullClient client = getClient(); - doiExists = client.testDOIExists(identifier.substring(identifier.indexOf(":") + 1)); - } catch (Exception e) { - logger.log(Level.INFO, identifier, e); - return false; - } - return doiExists; - } - - public HashMap getMetadata(String identifier) throws IOException { - HashMap metadata = new HashMap<>(); - try { - DataCiteRESTfullClient client = getClient(); - String xmlMetadata = client.getMetadata(identifier.substring(identifier.indexOf(":") + 1)); - DOIDataCiteServiceBean.GlobalIdMetadataTemplate template = doiDataCiteServiceBean.new GlobalIdMetadataTemplate(xmlMetadata); - metadata.put("datacite.creator", Util.getStrFromList(template.getCreators())); - metadata.put("datacite.title", template.getTitle()); - metadata.put("datacite.publisher", template.getPublisher()); - metadata.put("datacite.publicationyear", template.getPublisherYear()); - DOIDataCiteRegisterCache rc = findByDOI(identifier); - if (rc != null) { - metadata.put("_status", rc.getStatus()); - } else { - metadata.put("_status", "public"); - } - } catch (RuntimeException e) { - logger.log(Level.INFO, identifier, e); - } - return metadata; - } - - public DOIDataCiteRegisterCache findByDOI(String doi) { - TypedQuery query = em.createNamedQuery("DOIDataCiteRegisterCache.findByDoi", - DOIDataCiteRegisterCache.class); - query.setParameter("doi", doi); - List rc = query.getResultList(); - if (rc.size() == 1) { - return rc.get(0); - } - return null; - } - - public void deleteIdentifier(String identifier) { - DOIDataCiteRegisterCache rc = findByDOI(identifier); - if (rc != null) { - em.remove(rc); - } - } - -} - -class DataCiteMetadataTemplate { - - private static final Logger logger = Logger.getLogger("edu.harvard.iq.dataverse.DataCiteMetadataTemplate"); - private static String template; - - static { - try (InputStream in = DataCiteMetadataTemplate.class.getResourceAsStream("datacite_metadata_template.xml")) { - template = Util.readAndClose(in, "utf-8"); - } catch (Exception e) { - logger.log(Level.SEVERE, "datacite metadata template load error"); - logger.log(Level.SEVERE, "String " + e.toString()); - logger.log(Level.SEVERE, "localized message " + e.getLocalizedMessage()); - logger.log(Level.SEVERE, "cause " + e.getCause()); - logger.log(Level.SEVERE, "message " + e.getMessage()); - } - } - - private String xmlMetadata; - private String identifier; - private String datasetIdentifier; - private List datafileIdentifiers; - private List creators; - private String title; - private String publisher; - private String publisherYear; - private List authors; - private String description; - private List contacts; - private List producers; - - public List getProducers() { - return producers; - } - - public void setProducers(List producers) { - this.producers = producers; - } - - public List getContacts() { - return contacts; - } - - public void setContacts(List contacts) { - this.contacts = contacts; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public List getAuthors() { - return authors; - } - - public void setAuthors(List authors) { - this.authors = authors; - } - - public DataCiteMetadataTemplate() { - } - - public List getDatafileIdentifiers() { - return datafileIdentifiers; - } - - public void setDatafileIdentifiers(List datafileIdentifiers) { - this.datafileIdentifiers = datafileIdentifiers; - } - - public DataCiteMetadataTemplate(String xmlMetaData) { - this.xmlMetadata = xmlMetaData; - Document doc = Jsoup.parseBodyFragment(xmlMetaData); - Elements identifierElements = doc.select("identifier"); - if (identifierElements.size() > 0) { - identifier = identifierElements.get(0).html(); - } - Elements creatorElements = doc.select("creatorName"); - creators = new ArrayList<>(); - for (Element creatorElement : creatorElements) { - creators.add(creatorElement.html()); - } - Elements titleElements = doc.select("title"); - if (titleElements.size() > 0) { - title = titleElements.get(0).html(); - } - Elements publisherElements = doc.select("publisher"); - if (publisherElements.size() > 0) { - publisher = publisherElements.get(0).html(); - } - Elements publisherYearElements = doc.select("publicationYear"); - if (publisherYearElements.size() > 0) { - publisherYear = publisherYearElements.get(0).html(); - } - } - - public String generateXML(DvObject dvObject) { - // Can't use "UNKNOWN" here because DataCite will respond with "[facet 'pattern'] the value 'unknown' is not accepted by the pattern '[\d]{4}'" - String publisherYearFinal = "9999"; - // FIXME: Investigate why this.publisherYear is sometimes null now that pull request #4606 has been merged. - if (this.publisherYear != null) { - // Added to prevent a NullPointerException when trying to destroy datasets when using DataCite rather than EZID. - publisherYearFinal = this.publisherYear; - } - xmlMetadata = template.replace("${identifier}", this.identifier.trim()) - .replace("${title}", this.title) - .replace("${publisher}", this.publisher) - .replace("${publisherYear}", publisherYearFinal) - .replace("${description}", this.description); - - StringBuilder creatorsElement = new StringBuilder(); - if (authors!= null && !authors.isEmpty()) { - for (DatasetAuthor author : authors) { - creatorsElement.append(""); - creatorsElement.append(author.getName().getDisplayValue()); - creatorsElement.append(""); - - if (author.getIdType() != null && author.getIdValue() != null && !author.getIdType().isEmpty() && !author.getIdValue().isEmpty() && author.getAffiliation() != null && !author.getAffiliation().getDisplayValue().isEmpty()) { - - if (author.getIdType().equals("ORCID")) { - creatorsElement.append("" + author.getIdValue() + ""); - } - if (author.getIdType().equals("ISNI")) { - creatorsElement.append("" + author.getIdValue() + ""); - } - if (author.getIdType().equals("LCNA")) { - creatorsElement.append("" + author.getIdValue() + ""); - } - } - if (author.getAffiliation() != null && !author.getAffiliation().getDisplayValue().isEmpty()) { - creatorsElement.append("" + author.getAffiliation().getDisplayValue() + ""); - } - creatorsElement.append(""); - } - - } else { - creatorsElement.append("").append(AbstractGlobalIdServiceBean.UNAVAILABLE).append(""); - } - - xmlMetadata = xmlMetadata.replace("${creators}", creatorsElement.toString()); - - StringBuilder contributorsElement = new StringBuilder(); - if (this.getContacts() != null) { - for (String[] contact : this.getContacts()) { - if (!contact[0].isEmpty()) { - contributorsElement.append("" + contact[0] + ""); - if (!contact[1].isEmpty()) { - contributorsElement.append("" + contact[1] + ""); - } - contributorsElement.append(""); - } - } - } - - if (this.getProducers() != null) { - for (String[] producer : this.getProducers()) { - contributorsElement.append("" + producer[0] + ""); - if (!producer[1].isEmpty()) { - contributorsElement.append("" + producer[1] + ""); - } - contributorsElement.append(""); - } - } - - String relIdentifiers = generateRelatedIdentifiers(dvObject); - - xmlMetadata = xmlMetadata.replace("${relatedIdentifiers}", relIdentifiers); - - xmlMetadata = xmlMetadata.replace("{$contributors}", contributorsElement.toString()); - return xmlMetadata; - } - - private String generateRelatedIdentifiers(DvObject dvObject) { - - StringBuilder sb = new StringBuilder(); - if (dvObject.isInstanceofDataset()) { - Dataset dataset = (Dataset) dvObject; - if (!dataset.getFiles().isEmpty() && !(dataset.getFiles().get(0).getIdentifier() == null)) { - - datafileIdentifiers = new ArrayList<>(); - for (DataFile dataFile : dataset.getFiles()) { - if (dataFile.getGlobalId() != null) { - if (sb.toString().isEmpty()) { - sb.append(""); - } - sb.append("" + dataFile.getGlobalId() + ""); - } - } - - if (!sb.toString().isEmpty()) { - sb.append(""); - } - } - } else if (dvObject.isInstanceofDataFile()) { - DataFile df = (DataFile) dvObject; - sb.append(""); - sb.append("" + df.getOwner().getGlobalId() + ""); - sb.append(""); - } - return sb.toString(); - } - - public void generateFileIdentifiers(DvObject dvObject) { - - if (dvObject.isInstanceofDataset()) { - Dataset dataset = (Dataset) dvObject; - - if (!dataset.getFiles().isEmpty() && !(dataset.getFiles().get(0).getIdentifier() == null)) { - - datafileIdentifiers = new ArrayList<>(); - for (DataFile dataFile : dataset.getFiles()) { - datafileIdentifiers.add(dataFile.getIdentifier()); - int x = xmlMetadata.indexOf("") - 1; - xmlMetadata = xmlMetadata.replace("{relatedIdentifier}", dataFile.getIdentifier()); - xmlMetadata = xmlMetadata.substring(0, x) + "${relatedIdentifier}" + template.substring(x, template.length() - 1); - - } - - } else { - xmlMetadata = xmlMetadata.replace("${relatedIdentifier}", ""); - } - } - } - - public static String getTemplate() { - return template; - } - - public static void setTemplate(String template) { - DataCiteMetadataTemplate.template = template; - } - - public String getIdentifier() { - return identifier; - } - - public void setIdentifier(String identifier) { - this.identifier = identifier; - } - - public void setDatasetIdentifier(String datasetIdentifier) { - this.datasetIdentifier = datasetIdentifier; - } - - public List getCreators() { - return creators; - } - - public void setCreators(List creators) { - this.creators = creators; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getPublisher() { - return publisher; - } - - public void setPublisher(String publisher) { - this.publisher = publisher; - } - - public String getPublisherYear() { - return publisherYear; - } - - public void setPublisherYear(String publisherYear) { - this.publisherYear = publisherYear; - } -} - -class Util { - - public static void close(InputStream in) { - if (in != null) { - try { - in.close(); - } catch (IOException e) { - throw new RuntimeException("Fail to close InputStream"); - } - } - } - - public static String readAndClose(InputStream inStream, String encoding) { - ByteArrayOutputStream outStream = new ByteArrayOutputStream(); - byte[] buf = new byte[128]; - String data; - try { - int cnt; - while ((cnt = inStream.read(buf)) >= 0) { - outStream.write(buf, 0, cnt); - } - data = outStream.toString(encoding); - } catch (IOException ioe) { - throw new RuntimeException("IOException"); - } finally { - close(inStream); - } - return data; - } - - public static List getListFromStr(String str) { - return Arrays.asList(str.split("; ")); -// List authors = new ArrayList(); -// int preIdx = 0; -// for(int i=0;i authors) { - StringBuilder str = new StringBuilder(); - for (String author : authors) { - if (str.length() > 0) { - str.append("; "); - } - str.append(author); - } - return str.toString(); - } - -} diff --git a/src/main/java/edu/harvard/iq/dataverse/DOIDataCiteServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/DOIDataCiteServiceBean.java deleted file mode 100644 index 48786b41824..00000000000 --- a/src/main/java/edu/harvard/iq/dataverse/DOIDataCiteServiceBean.java +++ /dev/null @@ -1,248 +0,0 @@ -package edu.harvard.iq.dataverse; - -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.Base64; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import jakarta.ejb.EJB; -import jakarta.ejb.Stateless; - -import edu.harvard.iq.dataverse.settings.JvmSettings; -import org.apache.commons.httpclient.HttpException; -import org.apache.commons.httpclient.HttpStatus; - - -/** - * - * @author luopc - */ -@Stateless -public class DOIDataCiteServiceBean extends DOIServiceBean { - - private static final Logger logger = Logger.getLogger(DOIDataCiteServiceBean.class.getCanonicalName()); - - private static final String PUBLIC = "public"; - private static final String FINDABLE = "findable"; - private static final String RESERVED = "reserved"; - private static final String DRAFT = "draft"; - - @EJB - DOIDataCiteRegisterService doiDataCiteRegisterService; - - @Override - public boolean registerWhenPublished() { - return false; - } - - - - @Override - public boolean alreadyRegistered(GlobalId pid, boolean noProviderDefault) { - logger.log(Level.FINE,"alreadyRegistered"); - if(pid==null || pid.asString().isEmpty()) { - logger.fine("No identifier sent."); - return false; - } - boolean alreadyRegistered; - String identifier = pid.asString(); - try{ - alreadyRegistered = doiDataCiteRegisterService.testDOIExists(identifier); - } catch (Exception e){ - logger.log(Level.WARNING, "alreadyRegistered failed"); - return false; - } - return alreadyRegistered; - } - - @Override - public String createIdentifier(DvObject dvObject) throws Exception { - logger.log(Level.FINE,"createIdentifier"); - if(dvObject.getIdentifier() == null || dvObject.getIdentifier().isEmpty() ){ - dvObject = generateIdentifier(dvObject); - } - String identifier = getIdentifier(dvObject); - Map metadata = getMetadataForCreateIndicator(dvObject); - metadata.put("_status", "reserved"); - try { - String retString = doiDataCiteRegisterService.reserveIdentifier(identifier, metadata, dvObject); - logger.log(Level.FINE, "create DOI identifier retString : " + retString); - return retString; - } catch (Exception e) { - logger.log(Level.WARNING, "Identifier not created: create failed", e); - throw e; - } - } - - @Override - public Map getIdentifierMetadata(DvObject dvObject) { - logger.log(Level.FINE,"getIdentifierMetadata"); - String identifier = getIdentifier(dvObject); - Map metadata = new HashMap<>(); - try { - metadata = doiDataCiteRegisterService.getMetadata(identifier); - } catch (Exception e) { - logger.log(Level.WARNING, "getIdentifierMetadata failed", e); - } - return metadata; - } - - - /** - * Modifies the DOI metadata for a Dataset - * @param dvObject the dvObject whose metadata needs to be modified - * @return the Dataset identifier, or null if the modification failed - * @throws java.lang.Exception - */ - @Override - public String modifyIdentifierTargetURL(DvObject dvObject) throws Exception { - logger.log(Level.FINE,"modifyIdentifier"); - String identifier = getIdentifier(dvObject); - try { - HashMap metadata = doiDataCiteRegisterService.getMetadata(identifier); - doiDataCiteRegisterService.modifyIdentifier(identifier, metadata, dvObject); - } catch (Exception e) { - logger.log(Level.WARNING, "modifyMetadata failed", e); - throw e; - } - return identifier; - } - - public void deleteRecordFromCache(Dataset datasetIn){ - logger.log(Level.FINE,"deleteRecordFromCache"); - String identifier = getIdentifier(datasetIn); - HashMap doiMetadata = new HashMap(); - try { - doiMetadata = doiDataCiteRegisterService.getMetadata(identifier); - } catch (Exception e) { - logger.log(Level.WARNING, "get matadata failed cannot delete"); - logger.log(Level.WARNING, "String {0}", e.toString()); - logger.log(Level.WARNING, "localized message {0}", e.getLocalizedMessage()); - logger.log(Level.WARNING, "cause", e.getCause()); - logger.log(Level.WARNING, "message {0}", e.getMessage()); - } - - String idStatus = (String) doiMetadata.get("_status"); - - if (idStatus == null || idStatus.equals("reserved")) { - logger.log(Level.WARNING, "Delete status is reserved.."); - try { - doiDataCiteRegisterService.deleteIdentifier(identifier); - } catch (Exception e) { - logger.log(Level.WARNING, "delete failed"); - logger.log(Level.WARNING, "String {0}", e.toString()); - logger.log(Level.WARNING, "localized message {0}", e.getLocalizedMessage()); - logger.log(Level.WARNING, "cause", e.getCause()); - logger.log(Level.WARNING, "message {0}", e.getMessage()); - throw new RuntimeException(e); - } - } - } - - /* - * Deletes a DOI if it is in DRAFT/RESERVED state or removes metadata and changes it from PUBLIC/FINDABLE to REGISTERED. - */ - @Override - public void deleteIdentifier(DvObject dvObject) throws IOException, HttpException { - logger.log(Level.FINE,"deleteIdentifier"); - String identifier = getIdentifier(dvObject); - //ToDo - PidUtils currently has a DataCite API call that would get the status at DataCite for this identifier - that could be more accurate than assuming based on whether the dvObject has been published - String idStatus = DRAFT; - if(dvObject.isReleased()) { - idStatus = PUBLIC; - } - if ( idStatus != null ) { - switch ( idStatus ) { - case RESERVED: - case DRAFT: - logger.log(Level.INFO, "Delete status is reserved.."); - //service only removes the identifier from the cache (since it was written before DOIs could be registered in draft state) - doiDataCiteRegisterService.deleteIdentifier(identifier); - //So we call the deleteDraftIdentifier method below until things are refactored - deleteDraftIdentifier(dvObject); - break; - - case PUBLIC: - case FINDABLE: - //if public then it has been released set to unavailable and reset target to n2t url - Map metadata = addDOIMetadataForDestroyedDataset(dvObject); - metadata.put("_status", "registered"); - metadata.put("_target", getTargetUrl(dvObject)); - doiDataCiteRegisterService.deactivateIdentifier(identifier, metadata, dvObject); - break; - } - } - } - - /** - * Deletes DOI from the DataCite side, if possible. Only "draft" DOIs can be - * deleted. - */ - private void deleteDraftIdentifier(DvObject dvObject) throws IOException { - - //ToDo - incorporate into DataCiteRESTfulClient - String baseUrl = JvmSettings.DATACITE_REST_API_URL.lookup(); - String username = JvmSettings.DATACITE_USERNAME.lookup(); - String password = JvmSettings.DATACITE_PASSWORD.lookup(); - GlobalId doi = dvObject.getGlobalId(); - /** - * Deletes the DOI from DataCite if it can. Returns 204 if PID was deleted - * (only possible for "draft" DOIs), 405 (method not allowed) if the DOI - * wasn't deleted (because it's in "findable" state, for example, 404 if the - * DOI wasn't found, and possibly other status codes such as 500 if DataCite - * is down. - */ - - URL url = new URL(baseUrl + "/dois/" + doi.getAuthority() + "/" + doi.getIdentifier()); - HttpURLConnection connection = null; - connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod("DELETE"); - String userpass = username + ":" + password; - String basicAuth = "Basic " + new String(Base64.getEncoder().encode(userpass.getBytes())); - connection.setRequestProperty("Authorization", basicAuth); - int status = connection.getResponseCode(); - if(status!=HttpStatus.SC_NO_CONTENT) { - logger.warning("Incorrect Response Status from DataCite: " + status + " : " + connection.getResponseMessage()); - throw new HttpException("Status: " + status); - } - logger.fine("deleteDoi status for " + doi.asString() + ": " + status); - } - - @Override - public boolean publicizeIdentifier(DvObject dvObject) { - logger.log(Level.FINE,"updateIdentifierStatus"); - if(dvObject.getIdentifier() == null || dvObject.getIdentifier().isEmpty() ){ - dvObject = generateIdentifier(dvObject); - } - String identifier = getIdentifier(dvObject); - Map metadata = getUpdateMetadata(dvObject); - metadata.put("_status", PUBLIC); - metadata.put("datacite.publicationyear", generateYear(dvObject)); - metadata.put("_target", getTargetUrl(dvObject)); - try { - doiDataCiteRegisterService.registerIdentifier(identifier, metadata, dvObject); - return true; - } catch (Exception e) { - logger.log(Level.WARNING, "modifyMetadata failed: " + e.getMessage(), e); - return false; - } - } - - - @Override - public List getProviderInformation(){ - return List.of("DataCite", "https://status.datacite.org"); - } - - - - @Override - protected String getProviderKeyName() { - return "DataCite"; - } -} diff --git a/src/main/java/edu/harvard/iq/dataverse/DOIServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/DOIServiceBean.java deleted file mode 100644 index 0182c745cd0..00000000000 --- a/src/main/java/edu/harvard/iq/dataverse/DOIServiceBean.java +++ /dev/null @@ -1,78 +0,0 @@ -package edu.harvard.iq.dataverse; - -import edu.harvard.iq.dataverse.settings.SettingsServiceBean.Key; - -public abstract class DOIServiceBean extends AbstractGlobalIdServiceBean { - - public static final String DOI_PROTOCOL = "doi"; - public static final String DOI_RESOLVER_URL = "https://doi.org/"; - public static final String HTTP_DOI_RESOLVER_URL = "http://doi.org/"; - public static final String DXDOI_RESOLVER_URL = "https://dx.doi.org/"; - public static final String HTTP_DXDOI_RESOLVER_URL = "http://dx.doi.org/"; - - public DOIServiceBean() { - super(); - } - - @Override - public GlobalId parsePersistentId(String pidString) { - if (pidString.startsWith(DOI_RESOLVER_URL)) { - pidString = pidString.replace(DOI_RESOLVER_URL, - (DOI_PROTOCOL + ":")); - } else if (pidString.startsWith(HTTP_DOI_RESOLVER_URL)) { - pidString = pidString.replace(HTTP_DOI_RESOLVER_URL, - (DOI_PROTOCOL + ":")); - } else if (pidString.startsWith(DXDOI_RESOLVER_URL)) { - pidString = pidString.replace(DXDOI_RESOLVER_URL, - (DOI_PROTOCOL + ":")); - } - return super.parsePersistentId(pidString); - } - - @Override - public GlobalId parsePersistentId(String protocol, String identifierString) { - - if (!DOI_PROTOCOL.equals(protocol)) { - return null; - } - GlobalId globalId = super.parsePersistentId(protocol, identifierString); - if (globalId!=null && !GlobalIdServiceBean.checkDOIAuthority(globalId.getAuthority())) { - return null; - } - return globalId; - } - - @Override - public GlobalId parsePersistentId(String protocol, String authority, String identifier) { - - if (!DOI_PROTOCOL.equals(protocol)) { - return null; - } - return super.parsePersistentId(protocol, authority, identifier); - } - - public String getUrlPrefix() { - return DOI_RESOLVER_URL; - } - - @Override - public boolean isConfigured() { - if (configured == null) { - if (getProviderKeyName() == null) { - configured = false; - } else { - String doiProvider = settingsService.getValueForKey(Key.DoiProvider, ""); - if (getProviderKeyName().equals(doiProvider)) { - configured = true; - } else if (!doiProvider.isEmpty()) { - configured = false; - } - } - } - return super.isConfigured(); - } - - protected String getProviderKeyName() { - return null; - } -} \ No newline at end of file diff --git a/src/main/java/edu/harvard/iq/dataverse/DataCitation.java b/src/main/java/edu/harvard/iq/dataverse/DataCitation.java index 9b4b89db44f..a012175deae 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DataCitation.java +++ b/src/main/java/edu/harvard/iq/dataverse/DataCitation.java @@ -7,6 +7,7 @@ import edu.harvard.iq.dataverse.branding.BrandingUtil; import edu.harvard.iq.dataverse.harvest.client.HarvestingClient; +import edu.harvard.iq.dataverse.pidproviders.AbstractPidProvider; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; @@ -635,12 +636,12 @@ public Map getDataCiteMetadata() { String authorString = getAuthorsString(); if (authorString.isEmpty()) { - authorString = AbstractGlobalIdServiceBean.UNAVAILABLE; + authorString = AbstractPidProvider.UNAVAILABLE; } String producerString = getPublisher(); if (producerString.isEmpty()) { - producerString = AbstractGlobalIdServiceBean.UNAVAILABLE; + producerString = AbstractPidProvider.UNAVAILABLE; } metadata.put("datacite.creator", authorString); diff --git a/src/main/java/edu/harvard/iq/dataverse/DataFileServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/DataFileServiceBean.java index c9d50bbed9d..8ceb529a5d4 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DataFileServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/DataFileServiceBean.java @@ -1242,9 +1242,8 @@ public List selectFilesWithMissingOriginalSizes() { * Check that a identifier entered by the user is unique (not currently used * for any other study in this Dataverse Network). Also check for duplicate * in the remote PID service if needed - * @param userIdentifier - * @param datafile - * @param idServiceBean + * @param datafileId + * @param storageLocation * @return {@code true} iff the global identifier is unique. */ public void finalizeFileDelete(Long dataFileId, String storageLocation) throws IOException { diff --git a/src/main/java/edu/harvard/iq/dataverse/Dataset.java b/src/main/java/edu/harvard/iq/dataverse/Dataset.java index a2f560bc959..bafec4ed7ba 100644 --- a/src/main/java/edu/harvard/iq/dataverse/Dataset.java +++ b/src/main/java/edu/harvard/iq/dataverse/Dataset.java @@ -317,6 +317,7 @@ public boolean isDeaccessioned() { } return hasDeaccessionedVersions; // since any published version would have already returned } + public DatasetVersion getLatestVersion() { return getVersions().get(0); diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java b/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java index b79f387f20b..88b1f4f49bc 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java @@ -43,7 +43,10 @@ import edu.harvard.iq.dataverse.ingest.IngestServiceBean; import edu.harvard.iq.dataverse.license.LicenseServiceBean; import edu.harvard.iq.dataverse.metadataimport.ForeignMetadataImportServiceBean; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; import edu.harvard.iq.dataverse.pidproviders.PidUtil; +import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider; +import edu.harvard.iq.dataverse.pidproviders.doi.datacite.DataCiteDOIProvider; import edu.harvard.iq.dataverse.privateurl.PrivateUrl; import edu.harvard.iq.dataverse.privateurl.PrivateUrlServiceBean; import edu.harvard.iq.dataverse.privateurl.PrivateUrlUtil; @@ -1924,9 +1927,6 @@ private String init(boolean initFull) { guestbookResponse = new GuestbookResponse(); - String nonNullDefaultIfKeyNotFound = ""; - protocol = settingsWrapper.getValueForKey(SettingsServiceBean.Key.Protocol, nonNullDefaultIfKeyNotFound); - authority = settingsWrapper.getValueForKey(SettingsServiceBean.Key.Authority, nonNullDefaultIfKeyNotFound); String sortOrder = getSortOrder(); if(sortOrder != null) { FileMetadata.setCategorySortOrder(sortOrder); @@ -2108,8 +2108,6 @@ private String init(boolean initFull) { editMode = EditMode.CREATE; selectedHostDataverse = dataverseService.find(ownerId); dataset.setOwner(selectedHostDataverse); - dataset.setProtocol(protocol); - dataset.setAuthority(authority); if (dataset.getOwner() == null) { return permissionsWrapper.notFound(); @@ -2119,9 +2117,9 @@ private String init(boolean initFull) { //Wait until the create command before actually getting an identifier, except if we're using directUpload //Need to assign an identifier prior to calls to requestDirectUploadUrl if direct upload is used. if ( isEmpty(dataset.getIdentifier()) && systemConfig.directUploadEnabled(dataset) ) { - CommandContext ctxt = commandEngine.getContext(); - GlobalIdServiceBean idServiceBean = GlobalIdServiceBean.getBean(ctxt); - dataset.setIdentifier(idServiceBean.generateDatasetIdentifier(dataset)); + CommandContext ctxt = commandEngine.getContext(); + PidProvider pidProvider = ctxt.dvObjects().getEffectivePidGenerator(dataset); + pidProvider.generatePid(dataset); } dataverseTemplates.addAll(dataverseService.find(ownerId).getTemplates()); if (!dataverseService.find(ownerId).isTemplateRoot()) { @@ -2326,14 +2324,17 @@ private void displayLockInfo(Dataset dataset) { lockedDueToIngestVar = true; } - // With DataCite, we try to reserve the DOI when the dataset is created. Sometimes this - // fails because DataCite is down. We show the message below to set expectations that the - // "Publish" button won't work until the DOI has been reserved using the "Reserve PID" API. - if (settingsWrapper.isDataCiteInstallation() && dataset.getGlobalIdCreateTime() == null && editMode != EditMode.CREATE) { - JH.addMessage(FacesMessage.SEVERITY_WARN, BundleUtil.getStringFromBundle("dataset.locked.pidNotReserved.message"), - BundleUtil.getStringFromBundle("dataset.locked.pidNotReserved.message.details")); + if (dataset.getGlobalIdCreateTime() == null && editMode != EditMode.CREATE) { + // With DataCite, we try to reserve the DOI when the dataset is created. Sometimes this + // fails because DataCite is down. We show the message below to set expectations that the + // "Publish" button won't work until the DOI has been reserved using the "Reserve PID" API. + PidProvider pidProvider = PidUtil.getPidProvider(dataset.getGlobalId().getProviderId()); + if (DataCiteDOIProvider.TYPE.equals(pidProvider.getProviderType())) { + JH.addMessage(FacesMessage.SEVERITY_WARN, + BundleUtil.getStringFromBundle("dataset.locked.pidNotReserved.message"), + BundleUtil.getStringFromBundle("dataset.locked.pidNotReserved.message.details")); + } } - //if necessary refresh publish message also displayPublishMessage(); @@ -6395,5 +6396,9 @@ public String getSignpostingLinkHeader() { } return signpostingLinkHeader; } + + public boolean isDOI() { + return AbstractDOIProvider.DOI_PROTOCOL.equals(dataset.getGlobalId().getProtocol()); + } } diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/DatasetServiceBean.java index c6df2a2e1ab..a32141b8baf 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetServiceBean.java @@ -19,6 +19,8 @@ import edu.harvard.iq.dataverse.export.ExportService; import edu.harvard.iq.dataverse.globus.GlobusServiceBean; import edu.harvard.iq.dataverse.harvest.server.OAIRecordServiceBean; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidUtil; import edu.harvard.iq.dataverse.search.IndexServiceBean; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import edu.harvard.iq.dataverse.util.BundleUtil; @@ -61,9 +63,6 @@ public class DatasetServiceBean implements java.io.Serializable { @EJB IndexServiceBean indexService; - @EJB - DOIEZIdServiceBean doiEZIdServiceBean; - @EJB SettingsServiceBean settingsService; @@ -940,80 +939,6 @@ public void callFinalizePublishCommandAsynchronously(Long datasetId, CommandCont } } - /* - Experimental asynchronous method for requesting persistent identifiers for - datafiles. We decided not to run this method on upload/create (so files - will not have persistent ids while in draft; when the draft is published, - we will force obtaining persistent ids for all the files in the version. - - If we go back to trying to register global ids on create, care will need to - be taken to make sure the asynchronous changes below are not conflicting with - the changes from file ingest (which may be happening in parallel, also - asynchronously). We would also need to lock the dataset (similarly to how - tabular ingest logs the dataset), to prevent the user from publishing the - version before all the identifiers get assigned - otherwise more conflicts - are likely. (It sounds like it would make sense to treat these two tasks - - persistent identifiers for files and ingest - as one post-upload job, so that - they can be run in sequence). -- L.A. Mar. 2018 - */ - @Asynchronous - public void obtainPersistentIdentifiersForDatafiles(Dataset dataset) { - GlobalIdServiceBean idServiceBean = GlobalIdServiceBean.getBean(dataset.getProtocol(), commandEngine.getContext()); - - //If the Id type is sequential and Dependent then write file idenitifiers outside the command - String datasetIdentifier = dataset.getIdentifier(); - Long maxIdentifier = null; - - if (systemConfig.isDataFilePIDSequentialDependent()) { - maxIdentifier = getMaximumExistingDatafileIdentifier(dataset); - } - - for (DataFile datafile : dataset.getFiles()) { - logger.info("Obtaining persistent id for datafile id=" + datafile.getId()); - - if (datafile.getIdentifier() == null || datafile.getIdentifier().isEmpty()) { - - logger.info("Obtaining persistent id for datafile id=" + datafile.getId()); - - if (maxIdentifier != null) { - maxIdentifier++; - datafile.setIdentifier(datasetIdentifier + "/" + maxIdentifier.toString()); - } else { - datafile.setIdentifier(idServiceBean.generateDataFileIdentifier(datafile)); - } - - if (datafile.getProtocol() == null) { - datafile.setProtocol(settingsService.getValueForKey(SettingsServiceBean.Key.Protocol, "")); - } - if (datafile.getAuthority() == null) { - datafile.setAuthority(settingsService.getValueForKey(SettingsServiceBean.Key.Authority, "")); - } - - logger.info("identifier: " + datafile.getIdentifier()); - - String doiRetString; - - try { - logger.log(Level.FINE, "creating identifier"); - doiRetString = idServiceBean.createIdentifier(datafile); - } catch (Throwable e) { - logger.log(Level.WARNING, "Exception while creating Identifier: " + e.getMessage(), e); - doiRetString = ""; - } - - // Check return value to make sure registration succeeded - if (!idServiceBean.registerWhenPublished() && doiRetString.contains(datafile.getIdentifier())) { - datafile.setIdentifierRegistered(true); - datafile.setGlobalIdCreateTime(new Date()); - } - - DataFile merged = em.merge(datafile); - merged = null; - } - - } - } - public long findStorageSize(Dataset dataset) throws IOException { return findStorageSize(dataset, false, GetDatasetStorageSizeCommand.Mode.STORAGE, null); } diff --git a/src/main/java/edu/harvard/iq/dataverse/DataversePage.java b/src/main/java/edu/harvard/iq/dataverse/DataversePage.java index 3dbc22902b0..10dfa4a0e4f 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DataversePage.java +++ b/src/main/java/edu/harvard/iq/dataverse/DataversePage.java @@ -15,6 +15,9 @@ import edu.harvard.iq.dataverse.engine.command.impl.LinkDataverseCommand; import edu.harvard.iq.dataverse.engine.command.impl.PublishDataverseCommand; import edu.harvard.iq.dataverse.engine.command.impl.UpdateDataverseCommand; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidProviderFactoryBean; +import edu.harvard.iq.dataverse.pidproviders.PidUtil; import edu.harvard.iq.dataverse.search.FacetCategory; import edu.harvard.iq.dataverse.search.IndexServiceBean; import edu.harvard.iq.dataverse.search.SearchFields; @@ -34,9 +37,12 @@ import jakarta.faces.view.ViewScoped; import jakarta.inject.Inject; import jakarta.inject.Named; + +import java.util.AbstractMap; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -109,7 +115,9 @@ public enum LinkMode { @EJB DataverseLinkingServiceBean linkingService; @Inject PermissionsWrapper permissionsWrapper; - @Inject DataverseHeaderFragment dataverseHeaderFragment; + @Inject DataverseHeaderFragment dataverseHeaderFragment; + @EJB + PidProviderFactoryBean pidProviderFactoryBean; private Dataverse dataverse = new Dataverse(); @@ -1289,4 +1297,25 @@ public String getCurationLabelSetNameLabel() { public Set> getGuestbookEntryOptions() { return settingsWrapper.getGuestbookEntryOptions(this.dataverse).entrySet(); } + + public Set> getPidProviderOptions() { + PidProvider defaultPidProvider = pidProviderFactoryBean.getDefaultPidGenerator(); + Set providerIds = PidUtil.getManagedProviderIds(); + Set> options = new HashSet>(); + if (providerIds.size() > 1) { + String label = defaultPidProvider.getLabel() + BundleUtil.getStringFromBundle("dataverse.default") + ": " + + defaultPidProvider.getProtocol() + ":" + defaultPidProvider.getAuthority() + + defaultPidProvider.getSeparator() + defaultPidProvider.getShoulder(); + Entry option = new AbstractMap.SimpleEntry("default", label); + options.add(option); + } + for (String providerId : providerIds) { + PidProvider pidProvider = PidUtil.getPidProvider(providerId); + String label = pidProvider.getLabel() + ": " + pidProvider.getProtocol() + ":" + pidProvider.getAuthority() + + pidProvider.getSeparator() + pidProvider.getShoulder(); + Entry option = new AbstractMap.SimpleEntry(providerId, label); + options.add(option); + } + return options; + } } diff --git a/src/main/java/edu/harvard/iq/dataverse/DvObjectContainer.java b/src/main/java/edu/harvard/iq/dataverse/DvObjectContainer.java index 82057315fbb..c991c4c02d2 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DvObjectContainer.java +++ b/src/main/java/edu/harvard/iq/dataverse/DvObjectContainer.java @@ -1,14 +1,20 @@ package edu.harvard.iq.dataverse; import edu.harvard.iq.dataverse.dataaccess.DataAccess; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidUtil; import edu.harvard.iq.dataverse.settings.JvmSettings; import edu.harvard.iq.dataverse.storageuse.StorageUse; import edu.harvard.iq.dataverse.util.SystemConfig; +import edu.harvard.iq.dataverse.util.json.JsonUtil; +import jakarta.json.JsonObject; +import jakarta.json.JsonObjectBuilder; import jakarta.persistence.CascadeType; import java.util.Optional; - import jakarta.persistence.MappedSuperclass; import jakarta.persistence.OneToOne; +import jakarta.persistence.Transient; + import org.apache.commons.lang3.StringUtils; /** @@ -42,6 +48,11 @@ public boolean isEffectivelyPermissionRoot() { private String metadataLanguage=null; private Boolean guestbookAtRequest = null; + + private String pidGeneratorSpecs = null; + + @Transient + private PidProvider pidGenerator = null; @OneToOne(mappedBy = "dvObjectContainer",cascade={ CascadeType.REMOVE, CascadeType.PERSIST}, orphanRemoval=true) private StorageUse storageUse; @@ -175,4 +186,75 @@ public void setCurationLabelSetName(String setName) { public void setStorageUse(StorageUse storageUse) { this.storageUse = storageUse; } + + + /* Dataverse collections and dataset can be configured to use different PidProviders as PID generators for contained objects (datasets or data files). + * This mechanism is similar to others except that the stored value is a JSON object defining the protocol, authority, shoulder, and, optionally, the separator for the PidProvider. + */ + + public String getPidGeneratorSpecs() { + return pidGeneratorSpecs; + } + + public void setPidGeneratorSpecs(String pidGeneratorSpecs) { + this.pidGeneratorSpecs = pidGeneratorSpecs; + } + + // Used in JSF when selecting the PidGenerator + public String getPidGeneratorId() { + PidProvider pidGenerator = getEffectivePidGenerator(); + if (pidGenerator == null) { + return "default"; + } else { + return getEffectivePidGenerator().getId(); + } + } + + //Used in JSF when setting the PidGenerator + public void setPidGeneratorId(String pidGeneratorId) { + // Note that the "default" provider will not be found so will result in + // setPidGenerator(null), which unsets the pidGenerator/Specs as desired + setPidGenerator(PidUtil.getPidProvider(pidGeneratorId)); + } + + public void setPidGenerator(PidProvider pidGenerator) { + this.pidGenerator = pidGenerator; + if (pidGenerator != null) { + JsonObjectBuilder job = jakarta.json.Json.createObjectBuilder(); + this.pidGeneratorSpecs = job.add("protocol", pidGenerator.getProtocol()) + .add("authority", pidGenerator.getAuthority()).add("shoulder", pidGenerator.getShoulder()) + .add("separator", pidGenerator.getSeparator()).build().toString(); + } else { + this.pidGeneratorSpecs = null; + } + } + + public PidProvider getEffectivePidGenerator() { + if (pidGenerator == null) { + String specs = getPidGeneratorSpecs(); + if (StringUtils.isBlank(specs)) { + GlobalId pid = getGlobalId(); + if ((pid != null) && PidUtil.getPidProvider(pid.getProviderId()).canCreatePidsLike(pid)) { + pidGenerator = PidUtil.getPidProvider(pid.getProviderId()); + } else { + if (getOwner() != null) { + pidGenerator = getOwner().getEffectivePidGenerator(); + } + } + } else { + JsonObject providerSpecs = JsonUtil.getJsonObject(specs); + if (providerSpecs.containsKey("separator")) { + pidGenerator = PidUtil.getPidProvider(providerSpecs.getString("protocol"), + providerSpecs.getString("authority"), providerSpecs.getString("shoulder"), + providerSpecs.getString("separator")); + } else { + pidGenerator = PidUtil.getPidProvider(providerSpecs.getString("protocol"), + providerSpecs.getString("authority"), providerSpecs.getString("shoulder")); + } + } + setPidGenerator(pidGenerator); + } + return pidGenerator; + } + } diff --git a/src/main/java/edu/harvard/iq/dataverse/DvObjectServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/DvObjectServiceBean.java index d4219c36149..bd7fbeaff10 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DvObjectServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/DvObjectServiceBean.java @@ -1,8 +1,9 @@ package edu.harvard.iq.dataverse; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidProviderFactoryBean; import edu.harvard.iq.dataverse.pidproviders.PidUtil; - import java.sql.Timestamp; import java.util.ArrayList; import java.util.Date; @@ -12,6 +13,8 @@ import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; + +import jakarta.ejb.EJB; import jakarta.ejb.Stateless; import jakarta.ejb.TransactionAttribute; import static jakarta.ejb.TransactionAttributeType.REQUIRES_NEW; @@ -38,6 +41,9 @@ public class DvObjectServiceBean implements java.io.Serializable { @PersistenceContext(unitName = "VDCNet-ejbPU") private EntityManager em; + @EJB + PidProviderFactoryBean pidProviderFactoryBean; + private static final Logger logger = Logger.getLogger(DvObjectServiceBean.class.getCanonicalName()); /** * @param dvoc The object we check @@ -389,4 +395,19 @@ public String generateNewIdentifierByStoredProcedure() { return (String) query.getOutputParameterValue(1); } + /** @deprecated Backward-compatibility method to get the effective pid generator for a DvObjectContainer. + * If the dvObjectContainer method fails, this method will check for the old global default settings. + * If/when those are no longer supported, this method can be removed and replaced with calls directly + * to dvObjectContainer.getEffectivePidGenerator(); + * + */ + @Deprecated(forRemoval = true, since = "2024-02-09") + public PidProvider getEffectivePidGenerator(DvObjectContainer dvObjectContainer) { + PidProvider pidGenerator = dvObjectContainer.getEffectivePidGenerator(); + if (pidGenerator == null) { + pidGenerator = pidProviderFactoryBean.getDefaultPidGenerator(); + } + return pidGenerator; + } + } diff --git a/src/main/java/edu/harvard/iq/dataverse/EditDatafilesPage.java b/src/main/java/edu/harvard/iq/dataverse/EditDatafilesPage.java index a6f31e24764..993cb02b66b 100644 --- a/src/main/java/edu/harvard/iq/dataverse/EditDatafilesPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/EditDatafilesPage.java @@ -1237,9 +1237,6 @@ public String save() { - We decided not to bother obtaining persistent ids for new files as they are uploaded and created. The identifiers will be assigned later, when the version is published. - - logger.info("starting async job for obtaining persistent ids for files."); - datasetService.obtainPersistentIdentifiersForDatafiles(dataset); */ } diff --git a/src/main/java/edu/harvard/iq/dataverse/EjbDataverseEngine.java b/src/main/java/edu/harvard/iq/dataverse/EjbDataverseEngine.java index 5a689c06019..3793b6eeeb4 100644 --- a/src/main/java/edu/harvard/iq/dataverse/EjbDataverseEngine.java +++ b/src/main/java/edu/harvard/iq/dataverse/EjbDataverseEngine.java @@ -17,8 +17,7 @@ import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.engine.command.exception.PermissionException; import edu.harvard.iq.dataverse.ingest.IngestServiceBean; -import edu.harvard.iq.dataverse.pidproviders.FakePidProviderServiceBean; -import edu.harvard.iq.dataverse.pidproviders.PermaLinkPidProviderServiceBean; +import edu.harvard.iq.dataverse.pidproviders.PidProviderFactoryBean; import edu.harvard.iq.dataverse.privateurl.PrivateUrlServiceBean; import edu.harvard.iq.dataverse.search.IndexBatchServiceBean; import edu.harvard.iq.dataverse.search.IndexServiceBean; @@ -49,7 +48,6 @@ import static jakarta.ejb.TransactionAttributeType.SUPPORTS; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; -import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolationException; /** @@ -114,20 +112,8 @@ public class EjbDataverseEngine { DataverseFieldTypeInputLevelServiceBean fieldTypeInputLevels; @EJB - DOIEZIdServiceBean doiEZId; - - @EJB - DOIDataCiteServiceBean doiDataCite; + PidProviderFactoryBean pidProviderFactory; - @EJB - FakePidProviderServiceBean fakePidProvider; - - @EJB - HandlenetServiceBean handleNet; - - @EJB - PermaLinkPidProviderServiceBean permaLinkProvider; - @EJB SettingsServiceBean settings; @@ -484,28 +470,8 @@ public DataverseFieldTypeInputLevelServiceBean fieldTypeInputLevels() { } @Override - public DOIEZIdServiceBean doiEZId() { - return doiEZId; - } - - @Override - public DOIDataCiteServiceBean doiDataCite() { - return doiDataCite; - } - - @Override - public FakePidProviderServiceBean fakePidProvider() { - return fakePidProvider; - } - - @Override - public HandlenetServiceBean handleNet() { - return handleNet; - } - - @Override - public PermaLinkPidProviderServiceBean permaLinkProvider() { - return permaLinkProvider; + public PidProviderFactoryBean pidProviderFactory() { + return pidProviderFactory; } @Override diff --git a/src/main/java/edu/harvard/iq/dataverse/GlobalId.java b/src/main/java/edu/harvard/iq/dataverse/GlobalId.java index 890b146a61c..a542cb52ac0 100644 --- a/src/main/java/edu/harvard/iq/dataverse/GlobalId.java +++ b/src/main/java/edu/harvard/iq/dataverse/GlobalId.java @@ -6,7 +6,7 @@ package edu.harvard.iq.dataverse; -import edu.harvard.iq.dataverse.pidproviders.PermaLinkPidProviderServiceBean; +import edu.harvard.iq.dataverse.pidproviders.perma.PermaLinkPidProvider; import edu.harvard.iq.dataverse.util.BundleUtil; import static edu.harvard.iq.dataverse.util.StringUtil.isEmpty; import java.net.MalformedURLException; @@ -33,7 +33,7 @@ public GlobalId(String protocol, String authority, String identifier, String sep this.separator = separator; } this.urlPrefix = urlPrefix; - this.managingProviderName = providerName; + this.managingProviderId = providerName; } // protocol the identifier system, e.g. "doi" @@ -42,7 +42,7 @@ public GlobalId(String protocol, String authority, String identifier, String sep private String protocol; private String authority; private String identifier; - private String managingProviderName; + private String managingProviderId; private String separator = "/"; private String urlPrefix; @@ -67,8 +67,8 @@ public String getIdentifier() { return identifier; } - public String getProvider() { - return managingProviderName; + public String getProviderId() { + return managingProviderId; } public String toString() { diff --git a/src/main/java/edu/harvard/iq/dataverse/S3PackageImporter.java b/src/main/java/edu/harvard/iq/dataverse/S3PackageImporter.java index 71318a0184a..a387b27d98b 100644 --- a/src/main/java/edu/harvard/iq/dataverse/S3PackageImporter.java +++ b/src/main/java/edu/harvard/iq/dataverse/S3PackageImporter.java @@ -17,6 +17,7 @@ import com.amazonaws.services.s3.model.S3Object; import com.amazonaws.services.s3.model.S3ObjectSummary; import edu.harvard.iq.dataverse.api.AbstractApiBean; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import edu.harvard.iq.dataverse.util.FileUtil; import java.io.BufferedReader; @@ -203,35 +204,21 @@ public DataFile createPackageDataFile(Dataset dataset, String folderName, long t fmd.setDatasetVersion(dataset.getLatestVersion()); FileUtil.generateS3PackageStorageIdentifier(packageFile); - - GlobalIdServiceBean idServiceBean = GlobalIdServiceBean.getBean(packageFile.getProtocol(), commandEngine.getContext()); + PidProvider pidProvider = commandEngine.getContext().dvObjects().getEffectivePidGenerator(dataset); if (packageFile.getIdentifier() == null || packageFile.getIdentifier().isEmpty()) { - String packageIdentifier = idServiceBean.generateDataFileIdentifier(packageFile); - packageFile.setIdentifier(packageIdentifier); - } - - String nonNullDefaultIfKeyNotFound = ""; - String protocol = commandEngine.getContext().settings().getValueForKey(SettingsServiceBean.Key.Protocol, nonNullDefaultIfKeyNotFound); - String authority = commandEngine.getContext().settings().getValueForKey(SettingsServiceBean.Key.Authority, nonNullDefaultIfKeyNotFound); - - if (packageFile.getProtocol() == null) { - packageFile.setProtocol(protocol); - } - if (packageFile.getAuthority() == null) { - packageFile.setAuthority(authority); + pidProvider.generatePid(packageFile); } if (!packageFile.isIdentifierRegistered()) { String doiRetString = ""; - idServiceBean = GlobalIdServiceBean.getBean(commandEngine.getContext()); try { - doiRetString = idServiceBean.createIdentifier(packageFile); + doiRetString = pidProvider.createIdentifier(packageFile); } catch (Throwable e) { } // Check return value to make sure registration succeeded - if (!idServiceBean.registerWhenPublished() && doiRetString.contains(packageFile.getIdentifier())) { + if (!pidProvider.registerWhenPublished() && doiRetString.contains(packageFile.getIdentifier())) { packageFile.setIdentifierRegistered(true); packageFile.setGlobalIdCreateTime(new Date()); } diff --git a/src/main/java/edu/harvard/iq/dataverse/SettingsWrapper.java b/src/main/java/edu/harvard/iq/dataverse/SettingsWrapper.java index 8ab1e87aef2..964c58b75f6 100644 --- a/src/main/java/edu/harvard/iq/dataverse/SettingsWrapper.java +++ b/src/main/java/edu/harvard/iq/dataverse/SettingsWrapper.java @@ -400,13 +400,6 @@ public boolean isHTTPUpload(){ return httpUpload; } - public boolean isDataFilePIDSequentialDependent(){ - if (dataFilePIDSequentialDependent == null) { - dataFilePIDSequentialDependent = systemConfig.isDataFilePIDSequentialDependent(); - } - return dataFilePIDSequentialDependent; - } - public String getSupportTeamName() { String systemEmail = getValueForKey(SettingsServiceBean.Key.SystemEmail); InternetAddress systemAddress = MailUtil.parseSystemAddress(systemEmail); @@ -470,23 +463,6 @@ public Map getConfiguredLocales() { return configuredLocales; } - public boolean isDoiInstallation() { - String protocol = getValueForKey(SettingsServiceBean.Key.Protocol); - if ("doi".equals(protocol)) { - return true; - } else { - return false; - } - } - - public boolean isDataCiteInstallation() { - String protocol = getValueForKey(SettingsServiceBean.Key.DoiProvider); - if ("DataCite".equals(protocol)) { - return true; - } else { - return false; - } - } public boolean isMakeDataCountDisplayEnabled() { boolean safeDefaultIfKeyNotFound = (getValueForKey(SettingsServiceBean.Key.MDCLogPath)!=null); //Backward compatible diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index 48f9e19d835..d098c2fe16a 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -14,11 +14,11 @@ import edu.harvard.iq.dataverse.DataverseServiceBean; import edu.harvard.iq.dataverse.DataverseSession; import edu.harvard.iq.dataverse.DvObject; +import edu.harvard.iq.dataverse.DvObjectServiceBean; import edu.harvard.iq.dataverse.api.auth.AuthRequired; import edu.harvard.iq.dataverse.settings.JvmSettings; import edu.harvard.iq.dataverse.validation.EMailValidator; import edu.harvard.iq.dataverse.EjbDataverseEngine; -import edu.harvard.iq.dataverse.HandlenetServiceBean; import edu.harvard.iq.dataverse.Template; import edu.harvard.iq.dataverse.TemplateServiceBean; import edu.harvard.iq.dataverse.UserServiceBean; @@ -97,6 +97,7 @@ import edu.harvard.iq.dataverse.engine.command.impl.DeleteTemplateCommand; import edu.harvard.iq.dataverse.engine.command.impl.RegisterDvObjectCommand; import edu.harvard.iq.dataverse.ingest.IngestServiceBean; +import edu.harvard.iq.dataverse.pidproviders.handle.HandlePidProvider; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import edu.harvard.iq.dataverse.userdata.UserListMaker; import edu.harvard.iq.dataverse.userdata.UserListResult; @@ -136,46 +137,48 @@ public class Admin extends AbstractApiBean { private static final Logger logger = Logger.getLogger(Admin.class.getName()); - @EJB - AuthenticationProvidersRegistrationServiceBean authProvidersRegistrationSvc; - @EJB - BuiltinUserServiceBean builtinUserService; - @EJB - ShibServiceBean shibService; - @EJB - AuthTestDataServiceBean authTestDataService; - @EJB - UserServiceBean userService; - @EJB - IngestServiceBean ingestService; - @EJB - DataFileServiceBean fileService; - @EJB - DatasetServiceBean datasetService; - @EJB - DataverseServiceBean dataverseService; - @EJB - DatasetVersionServiceBean datasetversionService; - @Inject - DataverseRequestServiceBean dvRequestService; - @EJB - EjbDataverseEngine commandEngine; - @EJB - GroupServiceBean groupService; - @EJB - SettingsServiceBean settingsService; - @EJB - DatasetVersionServiceBean datasetVersionService; - @EJB - ExplicitGroupServiceBean explicitGroupService; - @EJB - BannerMessageServiceBean bannerMessageService; - @EJB - TemplateServiceBean templateService; - - // Make the session available - @Inject - DataverseSession session; + @EJB + AuthenticationProvidersRegistrationServiceBean authProvidersRegistrationSvc; + @EJB + BuiltinUserServiceBean builtinUserService; + @EJB + ShibServiceBean shibService; + @EJB + AuthTestDataServiceBean authTestDataService; + @EJB + UserServiceBean userService; + @EJB + IngestServiceBean ingestService; + @EJB + DataFileServiceBean fileService; + @EJB + DatasetServiceBean datasetService; + @EJB + DataverseServiceBean dataverseService; + @EJB + DvObjectServiceBean dvObjectService; + @EJB + DatasetVersionServiceBean datasetversionService; + @Inject + DataverseRequestServiceBean dvRequestService; + @EJB + EjbDataverseEngine commandEngine; + @EJB + GroupServiceBean groupService; + @EJB + SettingsServiceBean settingsService; + @EJB + DatasetVersionServiceBean datasetVersionService; + @EJB + ExplicitGroupServiceBean explicitGroupService; + @EJB + BannerMessageServiceBean bannerMessageService; + @EJB + TemplateServiceBean templateService; + + // Make the session available + @Inject + DataverseSession session; public static final String listUsersPartialAPIPath = "list-users"; public static final String listUsersFullAPIPath = "/api/admin/" + listUsersPartialAPIPath; @@ -1474,10 +1477,7 @@ public Response isOrcidEnabled() { public Response reregisterHdlToPID(@Context ContainerRequestContext crc, @PathParam("id") String id) { logger.info("Starting to reregister " + id + " Dataset Id. (from hdl to doi)" + new Date()); try { - if (settingsSvc.get(SettingsServiceBean.Key.Protocol.toString()).equals(HandlenetServiceBean.HDL_PROTOCOL)) { - logger.info("Bad Request protocol set to handle " ); - return error(Status.BAD_REQUEST, BundleUtil.getStringFromBundle("admin.api.migrateHDL.failure.must.be.set.for.doi")); - } + User u = getRequestUser(crc); if (!u.isSuperuser()) { @@ -1487,7 +1487,12 @@ public Response reregisterHdlToPID(@Context ContainerRequestContext crc, @PathPa DataverseRequest r = createDataverseRequest(u); Dataset ds = findDatasetOrDie(id); - if (ds.getIdentifier() != null && !ds.getIdentifier().isEmpty() && ds.getProtocol().equals(HandlenetServiceBean.HDL_PROTOCOL)) { + + if (HandlePidProvider.HDL_PROTOCOL.equals(dvObjectService.getEffectivePidGenerator(ds).getProtocol())) { + logger.info("Bad Request protocol set to handle " ); + return error(Status.BAD_REQUEST, BundleUtil.getStringFromBundle("admin.api.migrateHDL.failure.must.be.set.for.doi")); + } + if (ds.getIdentifier() != null && !ds.getIdentifier().isEmpty() && ds.getProtocol().equals(HandlePidProvider.HDL_PROTOCOL)) { execCommand(new RegisterDvObjectCommand(r, ds, true)); } else { return error(Status.BAD_REQUEST, BundleUtil.getStringFromBundle("admin.api.migrateHDL.failure.must.be.hdl.dataset")); diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java b/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java index 04af43931cb..e312d6ec15b 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java @@ -39,6 +39,7 @@ import edu.harvard.iq.dataverse.makedatacount.*; import edu.harvard.iq.dataverse.makedatacount.MakeDataCountLoggingServiceBean.MakeDataCountEntry; import edu.harvard.iq.dataverse.metrics.MetricsUtil; +import edu.harvard.iq.dataverse.pidproviders.PidUtil; import edu.harvard.iq.dataverse.privateurl.PrivateUrl; import edu.harvard.iq.dataverse.privateurl.PrivateUrlServiceBean; import edu.harvard.iq.dataverse.search.IndexServiceBean; @@ -4583,4 +4584,86 @@ public Response getCanDownloadAtLeastOneFile(@Context ContainerRequestContext cr return ok(permissionService.canDownloadAtLeastOneFile(req, datasetVersion)); }, getRequestUser(crc)); } + + @GET + @AuthRequired + @Path("{identifier}/pidGenerator") + public Response getPidGenerator(@Context ContainerRequestContext crc, @PathParam("identifier") String dvIdtf, + @Context HttpHeaders headers) throws WrappedResponse { + + Dataset dataset; + + try { + dataset = findDatasetOrDie(dvIdtf); + } catch (WrappedResponse ex) { + return error(Response.Status.NOT_FOUND, "No such dataset"); + } + String pidGeneratorId = dataset.getPidGeneratorId(); + return ok(pidGeneratorId); + } + + @PUT + @AuthRequired + @Path("{identifier}/pidGenerator") + public Response setPidGenerator(@Context ContainerRequestContext crc, @PathParam("identifier") String datasetId, + String generatorId, @Context HttpHeaders headers) throws WrappedResponse { + + // Superuser-only: + AuthenticatedUser user; + try { + user = getRequestAuthenticatedUserOrDie(crc); + } catch (WrappedResponse ex) { + return error(Response.Status.UNAUTHORIZED, "Authentication is required."); + } + if (!user.isSuperuser()) { + return error(Response.Status.FORBIDDEN, "Superusers only."); + } + + Dataset dataset; + + try { + dataset = findDatasetOrDie(datasetId); + } catch (WrappedResponse ex) { + return error(Response.Status.NOT_FOUND, "No such dataset"); + } + if (PidUtil.getManagedProviderIds().contains(generatorId)) { + dataset.setPidGeneratorId(generatorId); + datasetService.merge(dataset); + return ok("PID Generator set to: " + generatorId); + } else { + return error(Response.Status.NOT_FOUND, "No PID Generator found for the give id"); + } + + } + + @DELETE + @AuthRequired + @Path("{identifier}/pidGenerator") + public Response resetPidGenerator(@Context ContainerRequestContext crc, @PathParam("identifier") String dvIdtf, + @Context HttpHeaders headers) throws WrappedResponse { + + // Superuser-only: + AuthenticatedUser user; + try { + user = getRequestAuthenticatedUserOrDie(crc); + } catch (WrappedResponse ex) { + return error(Response.Status.BAD_REQUEST, "Authentication is required."); + } + if (!user.isSuperuser()) { + return error(Response.Status.FORBIDDEN, "Superusers only."); + } + + Dataset dataset; + + try { + dataset = findDatasetOrDie(dvIdtf); + } catch (WrappedResponse ex) { + return error(Response.Status.NOT_FOUND, "No such dataset"); + } + + dataset.setPidGenerator(null); + datasetService.merge(dataset); + return ok("Pid Generator reset to default: " + dataset.getEffectivePidGenerator().getId()); + } + } diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java index 88c6c85802d..a1dbc3a1de6 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java @@ -15,7 +15,6 @@ import edu.harvard.iq.dataverse.authorization.DataverseRole; import edu.harvard.iq.dataverse.DvObject; import edu.harvard.iq.dataverse.GlobalId; -import edu.harvard.iq.dataverse.GlobalIdServiceBean; import edu.harvard.iq.dataverse.GuestbookResponseServiceBean; import edu.harvard.iq.dataverse.GuestbookServiceBean; import edu.harvard.iq.dataverse.MetadataBlock; @@ -74,6 +73,8 @@ import edu.harvard.iq.dataverse.engine.command.impl.UpdateExplicitGroupCommand; import edu.harvard.iq.dataverse.engine.command.impl.UpdateMetadataBlockFacetsCommand; import edu.harvard.iq.dataverse.engine.command.impl.ValidateDatasetJsonCommand; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidUtil; import edu.harvard.iq.dataverse.settings.JvmSettings; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import edu.harvard.iq.dataverse.util.BundleUtil; @@ -421,7 +422,7 @@ public Response importDataset(@Context ContainerRequestContext crc, String jsonB if (!GlobalId.verifyImportCharacters(pidParam)) { return badRequest("PID parameter contains characters that are not allowed by the Dataverse application. On import, the PID must only contain characters specified in this regex: " + BundleUtil.getStringFromBundle("pid.allowedCharacters")); } - Optional maybePid = GlobalIdServiceBean.parse(pidParam); + Optional maybePid = PidProvider.parse(pidParam); if (maybePid.isPresent()) { ds.setGlobalId(maybePid.get()); } else { @@ -496,7 +497,7 @@ public Response importDatasetDdi(@Context ContainerRequestContext crc, String xm if (!GlobalId.verifyImportCharacters(pidParam)) { return badRequest("PID parameter contains characters that are not allowed by the Dataverse application. On import, the PID must only contain characters specified in this regex: " + BundleUtil.getStringFromBundle("pid.allowedCharacters")); } - Optional maybePid = GlobalIdServiceBean.parse(pidParam); + Optional maybePid = PidProvider.parse(pidParam); if (maybePid.isPresent()) { ds.setGlobalId(maybePid.get()); } else { @@ -559,12 +560,10 @@ public Response recreateDataset(@Context ContainerRequestContext crc, String jso ds.setOwner(owner); ds = JSONLDUtil.updateDatasetMDFromJsonLD(ds, jsonLDBody, metadataBlockSvc, datasetFieldSvc, false, true, licenseSvc); //ToDo - verify PID is one Dataverse can manage (protocol/authority/shoulder match) - if(! - (ds.getAuthority().equals(settingsService.getValueForKey(SettingsServiceBean.Key.Authority))&& - ds.getProtocol().equals(settingsService.getValueForKey(SettingsServiceBean.Key.Protocol))&& - ds.getIdentifier().startsWith(settingsService.getValueForKey(SettingsServiceBean.Key.Shoulder)))) { - throw new BadRequestException("Cannot recreate a dataset that has a PID that doesn't match the server's settings"); - } + if (!PidUtil.getPidProvider(ds.getGlobalId().getProviderId()).canManagePID()) { + throw new BadRequestException( + "Cannot recreate a dataset that has a PID that doesn't match the server's settings"); + } if(!dvObjectSvc.isGlobalIdLocallyUnique(ds.getGlobalId())) { throw new BadRequestException("Cannot recreate a dataset whose PID is already in use"); } diff --git a/src/main/java/edu/harvard/iq/dataverse/api/LDNInbox.java b/src/main/java/edu/harvard/iq/dataverse/api/LDNInbox.java index 05d12f1083c..6a9c608dc13 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/LDNInbox.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/LDNInbox.java @@ -1,12 +1,9 @@ package edu.harvard.iq.dataverse.api; -import edu.harvard.iq.dataverse.DOIServiceBean; import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.DatasetServiceBean; import edu.harvard.iq.dataverse.DataverseRoleServiceBean; import edu.harvard.iq.dataverse.GlobalId; -import edu.harvard.iq.dataverse.GlobalIdServiceBean; -import edu.harvard.iq.dataverse.HandlenetServiceBean; import edu.harvard.iq.dataverse.MailServiceBean; import edu.harvard.iq.dataverse.RoleAssigneeServiceBean; import edu.harvard.iq.dataverse.RoleAssignment; @@ -15,6 +12,9 @@ import edu.harvard.iq.dataverse.authorization.Permission; import edu.harvard.iq.dataverse.authorization.groups.impl.ipaddress.ip.IpAddress; import edu.harvard.iq.dataverse.engine.command.DataverseRequest; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider; +import edu.harvard.iq.dataverse.pidproviders.handle.HandlePidProvider; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import edu.harvard.iq.dataverse.util.json.JSONLDUtil; import edu.harvard.iq.dataverse.util.json.JsonLDNamespace; @@ -134,13 +134,13 @@ public Response acceptMessage(String body) { .getString("@id"); if (citedResource.getString("@type").equals(JsonLDTerm.schemaOrg("Dataset").getUrl())) { logger.fine("Raw PID: " + pid); - if (pid.startsWith(DOIServiceBean.DOI_RESOLVER_URL)) { - pid = pid.replace(DOIServiceBean.DOI_RESOLVER_URL, DOIServiceBean.DOI_PROTOCOL + ":"); - } else if (pid.startsWith(HandlenetServiceBean.HDL_RESOLVER_URL)) { - pid = pid.replace(HandlenetServiceBean.HDL_RESOLVER_URL, HandlenetServiceBean.HDL_PROTOCOL + ":"); + if (pid.startsWith(AbstractDOIProvider.DOI_RESOLVER_URL)) { + pid = pid.replace(AbstractDOIProvider.DOI_RESOLVER_URL, AbstractDOIProvider.DOI_PROTOCOL + ":"); + } else if (pid.startsWith(HandlePidProvider.HDL_RESOLVER_URL)) { + pid = pid.replace(HandlePidProvider.HDL_RESOLVER_URL, HandlePidProvider.HDL_PROTOCOL + ":"); } logger.fine("Protocol PID: " + pid); - Optional id = GlobalIdServiceBean.parse(pid); + Optional id = PidProvider.parse(pid); Dataset dataset = datasetSvc.findByGlobalId(pid); if (dataset != null) { JsonObject citingResource = Json.createObjectBuilder().add("@id", citingPID) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/MakeDataCountApi.java b/src/main/java/edu/harvard/iq/dataverse/api/MakeDataCountApi.java index b2696757220..08e776a3eb8 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/MakeDataCountApi.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/MakeDataCountApi.java @@ -2,10 +2,14 @@ import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.DatasetServiceBean; +import edu.harvard.iq.dataverse.GlobalId; import edu.harvard.iq.dataverse.makedatacount.DatasetExternalCitations; import edu.harvard.iq.dataverse.makedatacount.DatasetExternalCitationsServiceBean; import edu.harvard.iq.dataverse.makedatacount.DatasetMetrics; import edu.harvard.iq.dataverse.makedatacount.DatasetMetricsServiceBean; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidUtil; +import edu.harvard.iq.dataverse.pidproviders.doi.datacite.DataCiteDOIProvider; import edu.harvard.iq.dataverse.settings.JvmSettings; import edu.harvard.iq.dataverse.util.SystemConfig; import edu.harvard.iq.dataverse.util.json.JsonUtil; @@ -131,8 +135,14 @@ public Response addUsageMetricsFromSushiReportAll(@PathParam("id") String id, @Q public Response updateCitationsForDataset(@PathParam("id") String id) throws IOException { try { Dataset dataset = findDatasetOrDie(id); - String persistentId = dataset.getGlobalId().toString(); - //ToDo - if this isn't a DOI? + GlobalId pid = dataset.getGlobalId(); + PidProvider pidProvider = PidUtil.getPidProvider(pid.getProviderId()); + // Only supported for DOIs and for DataCite DOI providers + if(!DataCiteDOIProvider.TYPE.equals(pidProvider.getProviderType())) { + return error(Status.BAD_REQUEST, "Only DataCite DOI providers are supported"); + } + String persistentId = pid.toString(); + // DataCite wants "doi=", not "doi:". String authorityPlusIdentifier = persistentId.replaceFirst("doi:", ""); // Request max page size and then loop to handle multiple pages diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Pids.java b/src/main/java/edu/harvard/iq/dataverse/api/Pids.java index 534e42fd505..4ad57bceb58 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Pids.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Pids.java @@ -130,4 +130,41 @@ public Response deletePid(@Context ContainerRequestContext crc, @PathParam("id") } } + @GET + @AuthRequired + @Path("providers") + @Produces(MediaType.APPLICATION_JSON) + public Response getPidProviders(@Context ContainerRequestContext crc) throws WrappedResponse { + try { + getRequestAuthenticatedUserOrDie(crc); + } catch (WrappedResponse ex) { + return ex.getResponse(); + } + return ok(PidUtil.getProviders()); + } + + @GET + @AuthRequired + // The :.+ suffix allows PIDs with a / char to be entered w/o escaping + @Path("providers/{persistentId:.+}") + @Produces(MediaType.APPLICATION_JSON) + public Response getPidProviderId(@Context ContainerRequestContext crc, @PathParam("persistentId") String persistentId) throws WrappedResponse { + try { + getRequestAuthenticatedUserOrDie(crc); + } catch (WrappedResponse ex) { + return ex.getResponse(); + } + GlobalId globalId = PidUtil.parseAsGlobalID(persistentId); + if(globalId== null) { + return error(Response.Status.NOT_FOUND, "No provider found for PID"); + } else { + String providerId = globalId.getProviderId(); + if(PidUtil.getManagedProviderIds().contains(providerId)) { + return ok(globalId.getProviderId()); + } else { + return ok("PID recognized as an unmanaged " + globalId.getProtocol()); + } + } + } + } diff --git a/src/main/java/edu/harvard/iq/dataverse/api/datadeposit/CollectionDepositManagerImpl.java b/src/main/java/edu/harvard/iq/dataverse/api/datadeposit/CollectionDepositManagerImpl.java index 5bc50903be8..a81848bd7af 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/datadeposit/CollectionDepositManagerImpl.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/datadeposit/CollectionDepositManagerImpl.java @@ -6,6 +6,7 @@ import edu.harvard.iq.dataverse.DatasetVersion; import edu.harvard.iq.dataverse.Dataverse; import edu.harvard.iq.dataverse.DataverseServiceBean; +import edu.harvard.iq.dataverse.DvObjectServiceBean; import edu.harvard.iq.dataverse.EjbDataverseEngine; import edu.harvard.iq.dataverse.PermissionServiceBean; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; @@ -14,6 +15,7 @@ import edu.harvard.iq.dataverse.api.imports.ImportGenericServiceBean; import edu.harvard.iq.dataverse.engine.command.DataverseRequest; import edu.harvard.iq.dataverse.engine.command.impl.CreateNewDatasetCommand; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import edu.harvard.iq.dataverse.util.ConstraintViolationUtil; import java.util.logging.Level; @@ -44,6 +46,8 @@ public class CollectionDepositManagerImpl implements CollectionDepositManager { @EJB DatasetServiceBean datasetService; @EJB + DvObjectServiceBean dvObjectService; + @EJB PermissionServiceBean permissionService; @Inject SwordAuth swordAuth; @@ -96,13 +100,10 @@ public DepositReceipt createNew(String collectionUri, Deposit deposit, AuthCrede Dataset dataset = new Dataset(); dataset.setOwner(dvThatWillOwnDataset); - String nonNullDefaultIfKeyNotFound = ""; - String protocol = settingsService.getValueForKey(SettingsServiceBean.Key.Protocol, nonNullDefaultIfKeyNotFound); - String authority = settingsService.getValueForKey(SettingsServiceBean.Key.Authority, nonNullDefaultIfKeyNotFound); - - dataset.setProtocol(protocol); - dataset.setAuthority(authority); - //Wait until the create command before actually getting an identifier + PidProvider pidProvider = dvObjectService.getEffectivePidGenerator(dataset); + dataset.setProtocol(pidProvider.getProtocol()); + dataset.setAuthority(pidProvider.getAuthority()); + //Wait until the create command before actually getting an identifier logger.log(Level.FINE, "DS Deposit identifier: {0}", dataset.getIdentifier()); AbstractCreateDatasetCommand createDatasetCommand = new CreateNewDatasetCommand(dataset, dvReq); diff --git a/src/main/java/edu/harvard/iq/dataverse/api/imports/ImportGenericServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/api/imports/ImportGenericServiceBean.java index f7a6cf54dd5..6068ec45e4f 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/imports/ImportGenericServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/imports/ImportGenericServiceBean.java @@ -2,7 +2,6 @@ import com.google.gson.Gson; -import edu.harvard.iq.dataverse.DOIServiceBean; import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.DatasetFieldCompoundValue; import edu.harvard.iq.dataverse.DatasetFieldConstant; @@ -11,13 +10,14 @@ import edu.harvard.iq.dataverse.DatasetVersion; import edu.harvard.iq.dataverse.ForeignMetadataFieldMapping; import edu.harvard.iq.dataverse.ForeignMetadataFormatMapping; -import edu.harvard.iq.dataverse.HandlenetServiceBean; import edu.harvard.iq.dataverse.MetadataBlockServiceBean; import edu.harvard.iq.dataverse.api.dto.*; import edu.harvard.iq.dataverse.api.dto.FieldDTO; import edu.harvard.iq.dataverse.api.dto.MetadataBlockDTO; import edu.harvard.iq.dataverse.license.LicenseServiceBean; -import edu.harvard.iq.dataverse.pidproviders.PermaLinkPidProviderServiceBean; +import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider; +import edu.harvard.iq.dataverse.pidproviders.handle.HandlePidProvider; +import edu.harvard.iq.dataverse.pidproviders.perma.PermaLinkPidProvider; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import edu.harvard.iq.dataverse.util.StringUtil; import edu.harvard.iq.dataverse.util.json.JsonParseException; @@ -352,7 +352,7 @@ private String getOtherIdFromDTO(DatasetVersionDTO datasetVersionDTO) { if (!otherIds.isEmpty()) { // We prefer doi or hdl identifiers like "doi:10.7910/DVN/1HE30F" for (String otherId : otherIds) { - if (otherId.startsWith(DOIServiceBean.DOI_PROTOCOL) || otherId.startsWith(HandlenetServiceBean.HDL_PROTOCOL) || otherId.startsWith(DOIServiceBean.DOI_RESOLVER_URL) || otherId.startsWith(HandlenetServiceBean.HDL_RESOLVER_URL) || otherId.startsWith(DOIServiceBean.HTTP_DOI_RESOLVER_URL) || otherId.startsWith(HandlenetServiceBean.HTTP_HDL_RESOLVER_URL) || otherId.startsWith(DOIServiceBean.DXDOI_RESOLVER_URL) || otherId.startsWith(DOIServiceBean.HTTP_DXDOI_RESOLVER_URL)) { + if (otherId.startsWith(AbstractDOIProvider.DOI_PROTOCOL) || otherId.startsWith(HandlePidProvider.HDL_PROTOCOL) || otherId.startsWith(AbstractDOIProvider.DOI_RESOLVER_URL) || otherId.startsWith(HandlePidProvider.HDL_RESOLVER_URL) || otherId.startsWith(AbstractDOIProvider.HTTP_DOI_RESOLVER_URL) || otherId.startsWith(HandlePidProvider.HTTP_HDL_RESOLVER_URL) || otherId.startsWith(AbstractDOIProvider.DXDOI_RESOLVER_URL) || otherId.startsWith(AbstractDOIProvider.HTTP_DXDOI_RESOLVER_URL)) { return otherId; } } @@ -361,7 +361,7 @@ private String getOtherIdFromDTO(DatasetVersionDTO datasetVersionDTO) { try { HandleResolver hr = new HandleResolver(); hr.resolveHandle(otherId); - return HandlenetServiceBean.HDL_PROTOCOL + ":" + otherId; + return HandlePidProvider.HDL_PROTOCOL + ":" + otherId; } catch (HandleException e) { logger.fine("Not a valid handle: " + e.toString()); } @@ -388,7 +388,7 @@ public String reassignIdentifierAsGlobalId(String identifierString, DatasetDTO d String protocol = identifierString.substring(0, index1); - if (DOIServiceBean.DOI_PROTOCOL.equals(protocol) || HandlenetServiceBean.HDL_PROTOCOL.equals(protocol) || PermaLinkPidProviderServiceBean.PERMA_PROTOCOL.equals(protocol)) { + if (AbstractDOIProvider.DOI_PROTOCOL.equals(protocol) || HandlePidProvider.HDL_PROTOCOL.equals(protocol) || PermaLinkPidProvider.PERMA_PROTOCOL.equals(protocol)) { logger.fine("Processing hdl:- or doi:- or perma:-style identifier : "+identifierString); } else if ("http".equalsIgnoreCase(protocol) || "https".equalsIgnoreCase(protocol)) { @@ -396,21 +396,21 @@ public String reassignIdentifierAsGlobalId(String identifierString, DatasetDTO d // We also recognize global identifiers formatted as global resolver URLs: //ToDo - refactor index1 always has -1 here so that we can use index1+1 later //ToDo - single map of protocol/url, are all three cases the same then? - if (identifierString.startsWith(HandlenetServiceBean.HDL_RESOLVER_URL) || identifierString.startsWith(HandlenetServiceBean.HTTP_HDL_RESOLVER_URL)) { + if (identifierString.startsWith(HandlePidProvider.HDL_RESOLVER_URL) || identifierString.startsWith(HandlePidProvider.HTTP_HDL_RESOLVER_URL)) { logger.fine("Processing Handle identifier formatted as a resolver URL: "+identifierString); - protocol = HandlenetServiceBean.HDL_PROTOCOL; - index1 = (identifierString.startsWith(HandlenetServiceBean.HDL_RESOLVER_URL)) ? HandlenetServiceBean.HDL_RESOLVER_URL.length() - 1 : HandlenetServiceBean.HTTP_HDL_RESOLVER_URL.length() - 1; + protocol = HandlePidProvider.HDL_PROTOCOL; + index1 = (identifierString.startsWith(HandlePidProvider.HDL_RESOLVER_URL)) ? HandlePidProvider.HDL_RESOLVER_URL.length() - 1 : HandlePidProvider.HTTP_HDL_RESOLVER_URL.length() - 1; index2 = identifierString.indexOf("/", index1 + 1); - } else if (identifierString.startsWith(DOIServiceBean.DOI_RESOLVER_URL) || identifierString.startsWith(DOIServiceBean.HTTP_DOI_RESOLVER_URL) || identifierString.startsWith(DOIServiceBean.DXDOI_RESOLVER_URL) || identifierString.startsWith(DOIServiceBean.HTTP_DXDOI_RESOLVER_URL)) { + } else if (identifierString.startsWith(AbstractDOIProvider.DOI_RESOLVER_URL) || identifierString.startsWith(AbstractDOIProvider.HTTP_DOI_RESOLVER_URL) || identifierString.startsWith(AbstractDOIProvider.DXDOI_RESOLVER_URL) || identifierString.startsWith(AbstractDOIProvider.HTTP_DXDOI_RESOLVER_URL)) { logger.fine("Processing DOI identifier formatted as a resolver URL: "+identifierString); - protocol = DOIServiceBean.DOI_PROTOCOL; - identifierString = identifierString.replace(DOIServiceBean.DXDOI_RESOLVER_URL, DOIServiceBean.DOI_RESOLVER_URL); - identifierString = identifierString.replace(DOIServiceBean.HTTP_DXDOI_RESOLVER_URL, DOIServiceBean.HTTP_DOI_RESOLVER_URL); - index1 = (identifierString.startsWith(DOIServiceBean.DOI_RESOLVER_URL)) ? DOIServiceBean.DOI_RESOLVER_URL.length() - 1 : DOIServiceBean.HTTP_DOI_RESOLVER_URL.length() - 1; + protocol = AbstractDOIProvider.DOI_PROTOCOL; + identifierString = identifierString.replace(AbstractDOIProvider.DXDOI_RESOLVER_URL, AbstractDOIProvider.DOI_RESOLVER_URL); + identifierString = identifierString.replace(AbstractDOIProvider.HTTP_DXDOI_RESOLVER_URL, AbstractDOIProvider.HTTP_DOI_RESOLVER_URL); + index1 = (identifierString.startsWith(AbstractDOIProvider.DOI_RESOLVER_URL)) ? AbstractDOIProvider.DOI_RESOLVER_URL.length() - 1 : AbstractDOIProvider.HTTP_DOI_RESOLVER_URL.length() - 1; index2 = identifierString.indexOf("/", index1 + 1); - } else if (identifierString.startsWith(PermaLinkPidProviderServiceBean.PERMA_RESOLVER_URL + Dataset.TARGET_URL)) { - protocol = PermaLinkPidProviderServiceBean.PERMA_PROTOCOL; - index1 = PermaLinkPidProviderServiceBean.PERMA_RESOLVER_URL.length() + + Dataset.TARGET_URL.length() - 1; + } else if (identifierString.startsWith(PermaLinkPidProvider.PERMA_RESOLVER_URL + Dataset.TARGET_URL)) { + protocol = PermaLinkPidProvider.PERMA_PROTOCOL; + index1 = PermaLinkPidProvider.PERMA_RESOLVER_URL.length() + + Dataset.TARGET_URL.length() - 1; index2 = identifierString.indexOf("/", index1 + 1); } else { logger.warning("HTTP Url in supplied as the identifier is neither a Handle nor DOI resolver: "+identifierString); diff --git a/src/main/java/edu/harvard/iq/dataverse/api/imports/ImportServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/api/imports/ImportServiceBean.java index c17ba909230..39977190691 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/imports/ImportServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/imports/ImportServiceBean.java @@ -38,6 +38,8 @@ import edu.harvard.iq.dataverse.util.json.JsonParser; import edu.harvard.iq.dataverse.util.json.JsonUtil; import edu.harvard.iq.dataverse.license.LicenseServiceBean; +import edu.harvard.iq.dataverse.pidproviders.PidUtil; + import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -421,8 +423,9 @@ public JsonObjectBuilder doImport(DataverseRequest dataverseRequest, Dataverse o // For ImportType.NEW, if the user supplies a global identifier, and it's not a protocol // we support, it will be rejected. + if (importType.equals(ImportType.NEW)) { - if (ds.getGlobalId().asString() != null && !ds.getProtocol().equals(settingsService.getValueForKey(SettingsServiceBean.Key.Protocol, ""))) { + if (ds.getGlobalId().asString() != null && !PidUtil.getPidProvider(ds.getGlobalId().getProviderId()).canManagePID()) { throw new ImportException("Could not register id " + ds.getGlobalId().asString() + ", protocol not supported"); } } diff --git a/src/main/java/edu/harvard/iq/dataverse/batch/jobs/importer/filesystem/FileRecordWriter.java b/src/main/java/edu/harvard/iq/dataverse/batch/jobs/importer/filesystem/FileRecordWriter.java index ba34a3d1ed1..af1e9c6a294 100644 --- a/src/main/java/edu/harvard/iq/dataverse/batch/jobs/importer/filesystem/FileRecordWriter.java +++ b/src/main/java/edu/harvard/iq/dataverse/batch/jobs/importer/filesystem/FileRecordWriter.java @@ -33,6 +33,7 @@ import edu.harvard.iq.dataverse.engine.command.DataverseRequest; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.engine.command.impl.UpdateDatasetVersionCommand; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import edu.harvard.iq.dataverse.util.FileUtil; @@ -58,7 +59,6 @@ import java.util.logging.Level; import java.util.logging.Logger; import jakarta.servlet.http.HttpServletRequest; -import edu.harvard.iq.dataverse.GlobalIdServiceBean; @Named @Dependent @@ -360,31 +360,22 @@ private DataFile createPackageDataFile(List files) { if (commandEngine.getContext().systemConfig().isFilePIDsEnabledForCollection(dataset.getOwner())) { - GlobalIdServiceBean idServiceBean = GlobalIdServiceBean.getBean(packageFile.getProtocol(), commandEngine.getContext()); + PidProvider pidProvider = commandEngine.getContext().dvObjects().getEffectivePidGenerator(dataset); if (packageFile.getIdentifier() == null || packageFile.getIdentifier().isEmpty()) { - packageFile.setIdentifier(idServiceBean.generateDataFileIdentifier(packageFile)); - } - String nonNullDefaultIfKeyNotFound = ""; - String protocol = commandEngine.getContext().settings().getValueForKey(SettingsServiceBean.Key.Protocol, nonNullDefaultIfKeyNotFound); - String authority = commandEngine.getContext().settings().getValueForKey(SettingsServiceBean.Key.Authority, nonNullDefaultIfKeyNotFound); - if (packageFile.getProtocol() == null) { - packageFile.setProtocol(protocol); - } - if (packageFile.getAuthority() == null) { - packageFile.setAuthority(authority); + pidProvider.generatePid(packageFile); } if (!packageFile.isIdentifierRegistered()) { String doiRetString = ""; - idServiceBean = GlobalIdServiceBean.getBean(commandEngine.getContext()); + try { - doiRetString = idServiceBean.createIdentifier(packageFile); + doiRetString = pidProvider.createIdentifier(packageFile); } catch (Throwable e) { } // Check return value to make sure registration succeeded - if (!idServiceBean.registerWhenPublished() && doiRetString.contains(packageFile.getIdentifier())) { + if (!pidProvider.registerWhenPublished() && doiRetString.contains(packageFile.getIdentifier())) { packageFile.setIdentifierRegistered(true); packageFile.setGlobalIdCreateTime(new Date()); } diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/CommandContext.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/CommandContext.java index f74c1222bb0..6c4d63e3e35 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/CommandContext.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/CommandContext.java @@ -1,8 +1,5 @@ package edu.harvard.iq.dataverse.engine.command; -import edu.harvard.iq.dataverse.DOIDataCiteServiceBean; -import edu.harvard.iq.dataverse.DOIEZIdServiceBean; -import edu.harvard.iq.dataverse.HandlenetServiceBean; import edu.harvard.iq.dataverse.DataFileServiceBean; import edu.harvard.iq.dataverse.DatasetLinkingServiceBean; import edu.harvard.iq.dataverse.DatasetServiceBean; @@ -32,8 +29,7 @@ import edu.harvard.iq.dataverse.datacapturemodule.DataCaptureModuleServiceBean; import edu.harvard.iq.dataverse.engine.DataverseEngine; import edu.harvard.iq.dataverse.ingest.IngestServiceBean; -import edu.harvard.iq.dataverse.pidproviders.FakePidProviderServiceBean; -import edu.harvard.iq.dataverse.pidproviders.PermaLinkPidProviderServiceBean; +import edu.harvard.iq.dataverse.pidproviders.PidProviderFactoryBean; import edu.harvard.iq.dataverse.privateurl.PrivateUrlServiceBean; import edu.harvard.iq.dataverse.search.IndexBatchServiceBean; import edu.harvard.iq.dataverse.search.SolrIndexServiceBean; @@ -100,15 +96,7 @@ public interface CommandContext { public DataverseFieldTypeInputLevelServiceBean fieldTypeInputLevels(); - public DOIEZIdServiceBean doiEZId(); - - public DOIDataCiteServiceBean doiDataCite(); - - public FakePidProviderServiceBean fakePidProvider(); - - public HandlenetServiceBean handleNet(); - - public PermaLinkPidProviderServiceBean permaLinkProvider(); + public PidProviderFactoryBean pidProviderFactory(); public GuestbookServiceBean guestbooks(); diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractCreateDatasetCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractCreateDatasetCommand.java index 303d8e1c25f..d8302024c14 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractCreateDatasetCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractCreateDatasetCommand.java @@ -12,6 +12,8 @@ import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.engine.command.exception.CommandExecutionException; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidUtil; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import static edu.harvard.iq.dataverse.util.StringUtil.isEmpty; import java.io.IOException; @@ -81,9 +83,10 @@ public Dataset execute(CommandContext ctxt) throws CommandException { additionalParameterTests(ctxt); Dataset theDataset = getDataset(); - GlobalIdServiceBean idServiceBean = GlobalIdServiceBean.getBean(ctxt); + PidProvider pidProvider = ctxt.dvObjects().getEffectivePidGenerator(theDataset); + if ( isEmpty(theDataset.getIdentifier()) ) { - theDataset.setIdentifier(idServiceBean.generateDatasetIdentifier(theDataset)); + pidProvider.generatePid(theDataset); } DatasetVersion dsv = getVersionToPersist(theDataset); @@ -105,19 +108,18 @@ public Dataset execute(CommandContext ctxt) throws CommandException { dataFile.setCreateDate(theDataset.getCreateDate()); } - String nonNullDefaultIfKeyNotFound = ""; if (theDataset.getProtocol()==null) { - theDataset.setProtocol(ctxt.settings().getValueForKey(SettingsServiceBean.Key.Protocol, nonNullDefaultIfKeyNotFound)); + theDataset.setProtocol(pidProvider.getProtocol()); } if (theDataset.getAuthority()==null) { - theDataset.setAuthority(ctxt.settings().getValueForKey(SettingsServiceBean.Key.Authority, nonNullDefaultIfKeyNotFound)); + theDataset.setAuthority(pidProvider.getAuthority()); } if (theDataset.getStorageIdentifier() == null) { String driverId = theDataset.getEffectiveStorageDriverId(); theDataset.setStorageIdentifier(driverId + DataAccess.SEPARATOR + theDataset.getAuthorityForFileStorage() + "/" + theDataset.getIdentifierForFileStorage()); } if (theDataset.getIdentifier()==null) { - theDataset.setIdentifier(idServiceBean.generateDatasetIdentifier(theDataset)); + pidProvider.generatePid(theDataset); } // Attempt the registration if importing dataset through the API, or the app (but not harvest) diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractDatasetCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractDatasetCommand.java index 6061461306d..85e417ac5f3 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractDatasetCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractDatasetCommand.java @@ -13,6 +13,8 @@ import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.engine.command.exception.CommandExecutionException; import edu.harvard.iq.dataverse.engine.command.exception.IllegalCommandException; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidUtil; import edu.harvard.iq.dataverse.util.BundleUtil; import java.sql.Timestamp; @@ -23,7 +25,6 @@ import static java.util.stream.Collectors.joining; import jakarta.validation.ConstraintViolation; -import edu.harvard.iq.dataverse.GlobalIdServiceBean; import edu.harvard.iq.dataverse.MetadataBlock; import edu.harvard.iq.dataverse.TermsOfUseAndAccess; import edu.harvard.iq.dataverse.settings.JvmSettings; @@ -152,18 +153,18 @@ protected void validateOrDie(DatasetVersion dsv, Boolean lenient) throws Command */ protected void registerExternalIdentifier(Dataset theDataset, CommandContext ctxt, boolean retry) throws CommandException { if (!theDataset.isIdentifierRegistered()) { - GlobalIdServiceBean globalIdServiceBean = GlobalIdServiceBean.getBean(theDataset.getProtocol(), ctxt); - if ( globalIdServiceBean != null ) { + PidProvider pidProvider = PidUtil.getPidProvider(theDataset.getGlobalId().getProviderId()); + if ( pidProvider != null ) { try { - if (globalIdServiceBean.alreadyRegistered(theDataset)) { + if (pidProvider.alreadyRegistered(theDataset)) { int attempts = 0; if(retry) { do { - theDataset.setIdentifier(globalIdServiceBean.generateDatasetIdentifier(theDataset)); + pidProvider.generatePid(theDataset); logger.log(Level.INFO, "Attempting to register external identifier for dataset {0} (trying: {1}).", new Object[]{theDataset.getId(), theDataset.getIdentifier()}); attempts++; - } while (globalIdServiceBean.alreadyRegistered(theDataset) && attempts <= FOOLPROOF_RETRIAL_ATTEMPTS_LIMIT); + } while (pidProvider.alreadyRegistered(theDataset) && attempts <= FOOLPROOF_RETRIAL_ATTEMPTS_LIMIT); } if(!retry) { logger.warning("Reserving PID for: " + getDataset().getId() + " during publication failed."); @@ -177,7 +178,7 @@ protected void registerExternalIdentifier(Dataset theDataset, CommandContext ctx } // Invariant: Dataset identifier does not exist in the remote registry try { - globalIdServiceBean.createIdentifier(theDataset); + pidProvider.createIdentifier(theDataset); theDataset.setGlobalIdCreateTime(getTimestamp()); theDataset.setIdentifierRegistered(true); } catch (Throwable ex) { @@ -185,7 +186,7 @@ protected void registerExternalIdentifier(Dataset theDataset, CommandContext ctx } } catch (Throwable e) { - throw new CommandException(BundleUtil.getStringFromBundle("dataset.publish.error", globalIdServiceBean.getProviderInformation()), this); + throw new CommandException(BundleUtil.getStringFromBundle("dataset.publish.error", pidProvider.getProviderInformation()), this); } } else { throw new IllegalCommandException("This dataset may not be published because its id registry service is not supported.", this); diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractSubmitToArchiveCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractSubmitToArchiveCommand.java index b988fd05f03..29c27d0396d 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractSubmitToArchiveCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractSubmitToArchiveCommand.java @@ -1,6 +1,5 @@ package edu.harvard.iq.dataverse.engine.command.impl; -import edu.harvard.iq.dataverse.DOIDataCiteRegisterService; import edu.harvard.iq.dataverse.DataCitation; import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.DatasetVersion; @@ -14,6 +13,7 @@ import edu.harvard.iq.dataverse.engine.command.DataverseRequest; import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; +import edu.harvard.iq.dataverse.pidproviders.doi.datacite.DOIDataCiteRegisterService; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import edu.harvard.iq.dataverse.util.bagit.BagGenerator; import edu.harvard.iq.dataverse.util.bagit.OREMap; diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/CreateNewDatasetCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/CreateNewDatasetCommand.java index c9ebe735e31..c22a2cdb4a2 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/CreateNewDatasetCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/CreateNewDatasetCommand.java @@ -3,6 +3,7 @@ import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.DatasetVersion; import edu.harvard.iq.dataverse.Dataverse; +import edu.harvard.iq.dataverse.GlobalId; import edu.harvard.iq.dataverse.RoleAssignment; import edu.harvard.iq.dataverse.Template; import edu.harvard.iq.dataverse.UserNotification; @@ -12,12 +13,13 @@ import edu.harvard.iq.dataverse.engine.command.DataverseRequest; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.engine.command.exception.IllegalCommandException; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidUtil; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import static edu.harvard.iq.dataverse.util.StringUtil.nonEmpty; import java.util.logging.Logger; -import edu.harvard.iq.dataverse.GlobalIdServiceBean; import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; import java.util.List; import java.sql.Timestamp; @@ -71,13 +73,18 @@ public CreateNewDatasetCommand(Dataset theDataset, DataverseRequest aRequest, Te */ @Override protected void additionalParameterTests(CommandContext ctxt) throws CommandException { - if ( nonEmpty(getDataset().getIdentifier()) ) { - GlobalIdServiceBean idServiceBean = GlobalIdServiceBean.getBean(getDataset().getProtocol(), ctxt); - if ( !idServiceBean.isGlobalIdUnique(getDataset().getGlobalId()) ) { - throw new IllegalCommandException(String.format("Dataset with identifier '%s', protocol '%s' and authority '%s' already exists", - getDataset().getIdentifier(), getDataset().getProtocol(), getDataset().getAuthority()), - this); - } + if (nonEmpty(getDataset().getIdentifier())) { + GlobalId pid = getDataset().getGlobalId(); + if (pid != null) { + PidProvider pidProvider = PidUtil.getPidProvider(pid.getProviderId()); + + if (!pidProvider.isGlobalIdUnique(pid)) { + throw new IllegalCommandException(String.format( + "Dataset with identifier '%s', protocol '%s' and authority '%s' already exists", + getDataset().getIdentifier(), getDataset().getProtocol(), getDataset().getAuthority()), + this); + } + } } } @@ -88,11 +95,11 @@ protected DatasetVersion getVersionToPersist( Dataset theDataset ) { @Override protected void handlePid(Dataset theDataset, CommandContext ctxt) throws CommandException { - GlobalIdServiceBean idServiceBean = GlobalIdServiceBean.getBean(ctxt); - if(!idServiceBean.isConfigured()) { - throw new IllegalCommandException("PID Provider " + idServiceBean.getProviderInformation().get(0) + " is not configured.", this); + PidProvider pidProvider = PidUtil.getPidProvider(theDataset.getGlobalId().getProviderId()); + if(!pidProvider.canManagePID()) { + throw new IllegalCommandException("PID Provider " + pidProvider.getId() + " is not configured.", this); } - if ( !idServiceBean.registerWhenPublished() ) { + if ( !pidProvider.registerWhenPublished() ) { // pre-register a persistent id registerExternalIdentifier(theDataset, ctxt, true); } diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeleteDataFileCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeleteDataFileCommand.java index e2730ec06d3..0812c52a846 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeleteDataFileCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeleteDataFileCommand.java @@ -1,6 +1,7 @@ package edu.harvard.iq.dataverse.engine.command.impl; import edu.harvard.iq.dataverse.DataFile; +import edu.harvard.iq.dataverse.GlobalId; import edu.harvard.iq.dataverse.search.IndexServiceBean; import edu.harvard.iq.dataverse.authorization.Permission; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; @@ -11,6 +12,8 @@ import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.engine.command.exception.CommandExecutionException; import edu.harvard.iq.dataverse.engine.command.exception.PermissionException; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidUtil; import edu.harvard.iq.dataverse.util.FileUtil; import edu.harvard.iq.dataverse.util.StringUtil; import java.io.IOException; @@ -23,7 +26,6 @@ import java.util.Collections; import java.util.logging.Level; import java.util.logging.Logger; -import edu.harvard.iq.dataverse.GlobalIdServiceBean; /** * Deletes a data file, both DB entity and filesystem object. @@ -202,15 +204,18 @@ public FileVisitResult postVisitDirectory(final Path dir, final IOException e) */ } } - GlobalIdServiceBean idServiceBean = GlobalIdServiceBean.getBean(ctxt); - try { - if (idServiceBean.alreadyRegistered(doomed)) { - idServiceBean.deleteIdentifier(doomed); + GlobalId pid = doomed.getGlobalId(); + if (pid != null) { + PidProvider pidProvider = PidUtil.getPidProvider(pid.getProviderId()); + + try { + if (pidProvider.alreadyRegistered(doomed)) { + pidProvider.deleteIdentifier(doomed); + } + } catch (Exception e) { + logger.log(Level.WARNING, "Identifier deletion was not successfull:", e.getMessage()); } - } catch (Exception e) { - logger.log(Level.WARNING, "Identifier deletion was not successfull:", e.getMessage()); } - DataFile doomedAndMerged = ctxt.em().merge(doomed); ctxt.em().remove(doomedAndMerged); /** diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeletePidCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeletePidCommand.java index 274aeb3c3fd..c4910dd10c2 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeletePidCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DeletePidCommand.java @@ -1,7 +1,6 @@ package edu.harvard.iq.dataverse.engine.command.impl; import edu.harvard.iq.dataverse.Dataset; -import edu.harvard.iq.dataverse.GlobalIdServiceBean; import edu.harvard.iq.dataverse.authorization.Permission; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.engine.command.AbstractVoidCommand; @@ -11,7 +10,8 @@ import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.engine.command.exception.IllegalCommandException; import edu.harvard.iq.dataverse.engine.command.exception.PermissionException; -import edu.harvard.iq.dataverse.settings.SettingsServiceBean; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidUtil; import edu.harvard.iq.dataverse.util.BundleUtil; import org.apache.commons.httpclient.HttpException; @@ -38,25 +38,26 @@ public DeletePidCommand(DataverseRequest request, Dataset dataset) { protected void executeImpl(CommandContext ctxt) throws CommandException { if (!(getUser() instanceof AuthenticatedUser) || !getUser().isSuperuser()) { - throw new PermissionException(BundleUtil.getStringFromBundle("admin.api.auth.mustBeSuperUser"), - this, Collections.singleton(Permission.EditDataset), dataset); + throw new PermissionException(BundleUtil.getStringFromBundle("admin.api.auth.mustBeSuperUser"), this, + Collections.singleton(Permission.EditDataset), dataset); } - String nonNullDefaultIfKeyNotFound = ""; - String protocol = ctxt.settings().getValueForKey(SettingsServiceBean.Key.Protocol, nonNullDefaultIfKeyNotFound); - GlobalIdServiceBean idServiceBean = GlobalIdServiceBean.getBean(protocol, ctxt); + PidProvider pidProvider = PidUtil.getPidProvider(dataset.getGlobalId().getProviderId()); + try { - idServiceBean.deleteIdentifier(dataset); + pidProvider.deleteIdentifier(dataset); // Success! Clear the create time, etc. dataset.setGlobalIdCreateTime(null); dataset.setIdentifierRegistered(false); ctxt.datasets().merge(dataset); } catch (HttpException hex) { - String message = BundleUtil.getStringFromBundle("pids.deletePid.failureExpected", Arrays.asList(dataset.getGlobalId().asString(), Integer.toString(hex.getReasonCode()))); + String message = BundleUtil.getStringFromBundle("pids.deletePid.failureExpected", + Arrays.asList(dataset.getGlobalId().asString(), Integer.toString(hex.getReasonCode()))); logger.info(message); throw new IllegalCommandException(message, this); } catch (Exception ex) { - String message = BundleUtil.getStringFromBundle("pids.deletePid.failureOther", Arrays.asList(dataset.getGlobalId().asString(), ex.getLocalizedMessage())); + String message = BundleUtil.getStringFromBundle("pids.deletePid.failureOther", + Arrays.asList(dataset.getGlobalId().asString(), ex.getLocalizedMessage())); logger.info(message); throw new IllegalCommandException(message, this); } diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DestroyDatasetCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DestroyDatasetCommand.java index 41093444360..877f3b81d7e 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DestroyDatasetCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/DestroyDatasetCommand.java @@ -3,6 +3,7 @@ import edu.harvard.iq.dataverse.DataFile; import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.Dataverse; +import edu.harvard.iq.dataverse.GlobalId; import edu.harvard.iq.dataverse.authorization.DataverseRole; import edu.harvard.iq.dataverse.search.IndexServiceBean; import edu.harvard.iq.dataverse.RoleAssignment; @@ -15,6 +16,8 @@ import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.engine.command.exception.PermissionException; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidUtil; import edu.harvard.iq.dataverse.search.IndexResponse; import java.util.ArrayList; import java.util.Collections; @@ -22,7 +25,7 @@ import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; -import edu.harvard.iq.dataverse.GlobalIdServiceBean; + import edu.harvard.iq.dataverse.batch.util.LoggingUtil; import java.io.IOException; import java.util.concurrent.Future; @@ -99,18 +102,21 @@ protected void executeImpl(CommandContext ctxt) throws CommandException { } if (!doomed.isHarvested()) { - GlobalIdServiceBean idServiceBean = GlobalIdServiceBean.getBean(ctxt); - try { - if (idServiceBean.alreadyRegistered(doomed)) { - idServiceBean.deleteIdentifier(doomed); - for (DataFile df : doomed.getFiles()) { - idServiceBean.deleteIdentifier(df); + GlobalId pid = doomed.getGlobalId(); + if (pid != null) { + PidProvider pidProvider = PidUtil.getPidProvider(pid.getProviderId()); + try { + if (pidProvider.alreadyRegistered(doomed)) { + pidProvider.deleteIdentifier(doomed); + for (DataFile df : doomed.getFiles()) { + pidProvider.deleteIdentifier(df); + } } + } catch (Exception e) { + logger.log(Level.WARNING, "Identifier deletion was not successful:", e.getMessage()); } - } catch (Exception e) { - logger.log(Level.WARNING, "Identifier deletion was not successful:", e.getMessage()); } - } + } toReIndex = managedDoomed.getOwner(); diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/FinalizeDatasetPublicationCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/FinalizeDatasetPublicationCommand.java index 89cfc732455..37aeee231e1 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/FinalizeDatasetPublicationCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/FinalizeDatasetPublicationCommand.java @@ -20,6 +20,8 @@ import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.export.ExportService; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidUtil; import edu.harvard.iq.dataverse.privateurl.PrivateUrl; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import edu.harvard.iq.dataverse.util.BundleUtil; @@ -30,7 +32,7 @@ import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; -import edu.harvard.iq.dataverse.GlobalIdServiceBean; + import edu.harvard.iq.dataverse.batch.util.LoggingUtil; import edu.harvard.iq.dataverse.dataaccess.StorageIO; import edu.harvard.iq.dataverse.engine.command.Command; @@ -349,7 +351,7 @@ private void validateDataFiles(Dataset dataset, CommandContext ctxt) throws Comm // major release; we can revisit the decision if there's any // indication that this makes publishing take significantly longer. String driverId = FileUtil.getStorageDriver(dataFile); - if(StorageIO.isDataverseAccessible(driverId) && maxFileSize == -1 || dataFile.getFilesize() < maxFileSize) { + if(StorageIO.isDataverseAccessible(driverId) && (maxFileSize == -1 || dataFile.getFilesize() < maxFileSize)) { FileUtil.validateDataFileChecksum(dataFile); } else { @@ -384,56 +386,52 @@ private void validateDataFiles(Dataset dataset, CommandContext ctxt) throws Comm } private void publicizeExternalIdentifier(Dataset dataset, CommandContext ctxt) throws CommandException { - String protocol = getDataset().getProtocol(); - String authority = getDataset().getAuthority(); - GlobalIdServiceBean idServiceBean = GlobalIdServiceBean.getBean(protocol, ctxt); - - if (idServiceBean != null) { - - try { - String currentGlobalIdProtocol = ctxt.settings().getValueForKey(SettingsServiceBean.Key.Protocol, ""); - String currentGlobalAuthority = ctxt.settings().getValueForKey(SettingsServiceBean.Key.Authority, ""); - String dataFilePIDFormat = ctxt.settings().getValueForKey(SettingsServiceBean.Key.DataFilePIDFormat, "DEPENDENT"); - boolean isFilePIDsEnabled = ctxt.systemConfig().isFilePIDsEnabledForCollection(getDataset().getOwner()); - // We will skip trying to register the global identifiers for datafiles - // if "dependent" file-level identifiers are requested, AND the naming - // protocol, or the authority of the dataset global id is different from - // what's currently configured for the Dataverse. In other words - // we can't get "dependent" DOIs assigned to files in a dataset - // with the registered id that is a handle; or even a DOI, but in - // an authority that's different from what's currently configured. - // Additionaly in 4.9.3 we have added a system variable to disable - // registering file PIDs on the installation level. - if (((currentGlobalIdProtocol.equals(protocol) && currentGlobalAuthority.equals(authority)) - || dataFilePIDFormat.equals("INDEPENDENT")) - && isFilePIDsEnabled - && dataset.getLatestVersion().getMinorVersionNumber() != null - && dataset.getLatestVersion().getMinorVersionNumber().equals((long) 0)) { - //A false return value indicates a failure in calling the service - for (DataFile df : dataset.getFiles()) { - logger.log(Level.FINE, "registering global id for file {0}", df.getId()); - //A false return value indicates a failure in calling the service - if (!idServiceBean.publicizeIdentifier(df)) { - throw new Exception(); - } - df.setGlobalIdCreateTime(getTimestamp()); - df.setIdentifierRegistered(true); + PidProvider pidProvider = ctxt.dvObjects().getEffectivePidGenerator(dataset); + try { + // We will skip trying to register the global identifiers for datafiles + // if "dependent" file-level identifiers are requested, AND the naming + // protocol, or the authority of the dataset global id is different from + // what's currently configured for the Dataverse. In other words + // we can't get "dependent" DOIs assigned to files in a dataset + // with the registered id that is a handle; or even a DOI, but in + // an authority that's different from what's currently configured. + // Additionaly in 4.9.3 we have added a system variable to disable + // registering file PIDs on the installation level. + boolean registerGlobalIdsForFiles = ctxt.systemConfig().isFilePIDsEnabledForCollection( + getDataset().getOwner()) + && pidProvider.canCreatePidsLike(dataset.getGlobalId()); + + if (registerGlobalIdsForFiles + && dataset.getLatestVersion().getMinorVersionNumber() != null + && dataset.getLatestVersion().getMinorVersionNumber().equals((long) 0)) { + // A false return value indicates a failure in calling the service + for (DataFile df : dataset.getFiles()) { + logger.log(Level.FINE, "registering global id for file {0}", df.getId()); + // A false return value indicates a failure in calling the service + if (!pidProvider.publicizeIdentifier(df)) { + throw new Exception(); } + df.setGlobalIdCreateTime(getTimestamp()); + df.setIdentifierRegistered(true); } - if (!idServiceBean.publicizeIdentifier(dataset)) { - throw new Exception(); - } - dataset.setGlobalIdCreateTime(new Date()); // TODO these two methods should be in the responsibility of the idServiceBean. - dataset.setIdentifierRegistered(true); - } catch (Throwable e) { - logger.warning("Failed to register the identifier "+dataset.getGlobalId().asString()+", or to register a file in the dataset; notifying the user(s), unlocking the dataset"); - - // Send failure notification to the user: - notifyUsersDatasetPublishStatus(ctxt, dataset, UserNotification.Type.PUBLISHFAILED_PIDREG); - - ctxt.datasets().removeDatasetLocks(dataset, DatasetLock.Reason.finalizePublication); - throw new CommandException(BundleUtil.getStringFromBundle("dataset.publish.error", idServiceBean.getProviderInformation()), this); } + if (!pidProvider.publicizeIdentifier(dataset)) { + throw new Exception(); + } + dataset.setGlobalIdCreateTime(new Date()); // TODO these two methods should be in the responsibility of the + // pidProvider. + dataset.setIdentifierRegistered(true); + } catch (Throwable e) { + logger.warning("Failed to register the identifier " + dataset.getGlobalId().asString() + + ", or to register a file in the dataset; notifying the user(s), unlocking the dataset"); + + // Send failure notification to the user: + notifyUsersDatasetPublishStatus(ctxt, dataset, UserNotification.Type.PUBLISHFAILED_PIDREG); + + ctxt.datasets().removeDatasetLocks(dataset, DatasetLock.Reason.finalizePublication); + throw new CommandException( + BundleUtil.getStringFromBundle("dataset.publish.error", pidProvider.getProviderInformation()), + this); } } diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GrantSuperuserStatusCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GrantSuperuserStatusCommand.java index 42af43b7247..ec8c8976260 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GrantSuperuserStatusCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GrantSuperuserStatusCommand.java @@ -14,7 +14,7 @@ import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.engine.command.exception.PermissionException; -import edu.harvard.iq.dataverse.GlobalIdServiceBean; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; /** * diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ImportDatasetCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ImportDatasetCommand.java index 478272950bd..772c989264c 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ImportDatasetCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ImportDatasetCommand.java @@ -1,14 +1,14 @@ package edu.harvard.iq.dataverse.engine.command.impl; import edu.harvard.iq.dataverse.Dataset; -import edu.harvard.iq.dataverse.GlobalIdServiceBean; import edu.harvard.iq.dataverse.engine.command.CommandContext; import edu.harvard.iq.dataverse.engine.command.DataverseRequest; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.engine.command.exception.CommandExecutionException; import edu.harvard.iq.dataverse.engine.command.exception.IllegalCommandException; import edu.harvard.iq.dataverse.engine.command.exception.PermissionException; -import edu.harvard.iq.dataverse.pidproviders.FakePidProviderServiceBean; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidUtil; import java.io.IOException; import java.util.Collections; @@ -80,9 +80,9 @@ protected void additionalParameterTests(CommandContext ctxt) throws CommandExcep * Dataverse) but aren't findable to be used. That could be the case if, for * example, someone was importing a draft dataset from elsewhere. */ - GlobalIdServiceBean globalIdServiceBean = GlobalIdServiceBean.getBean(ds.getProtocol(), ctxt); - if (globalIdServiceBean != null) { - if (globalIdServiceBean.alreadyRegistered(ds.getGlobalId(), true)) { + PidProvider pidProvider = PidUtil.getPidProvider(ds.getGlobalId().getProviderId()); + if (pidProvider != null) { + if (pidProvider.alreadyRegistered(ds.getGlobalId(), true)) { return; } } diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/PublishDatasetCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/PublishDatasetCommand.java index f5ef121dee2..6b95f3b6de1 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/PublishDatasetCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/PublishDatasetCommand.java @@ -2,7 +2,6 @@ import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.DatasetLock; -import edu.harvard.iq.dataverse.GlobalIdServiceBean; import edu.harvard.iq.dataverse.authorization.Permission; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.engine.command.Command; @@ -11,6 +10,7 @@ import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.engine.command.exception.IllegalCommandException; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; import edu.harvard.iq.dataverse.privateurl.PrivateUrl; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import edu.harvard.iq.dataverse.util.BundleUtil; @@ -130,24 +130,15 @@ public PublishDatasetResult execute(CommandContext ctxt) throws CommandException // ... // Additionaly in 4.9.3 we have added a system variable to disable // registering file PIDs on the installation level. - String currentGlobalIdProtocol = ctxt.settings().getValueForKey(SettingsServiceBean.Key.Protocol, ""); - String currentGlobalAuthority= ctxt.settings().getValueForKey(SettingsServiceBean.Key.Authority, ""); - String dataFilePIDFormat = ctxt.settings().getValueForKey(SettingsServiceBean.Key.DataFilePIDFormat, "DEPENDENT"); boolean registerGlobalIdsForFiles = - (currentGlobalIdProtocol.equals(theDataset.getProtocol()) || dataFilePIDFormat.equals("INDEPENDENT")) - && ctxt.systemConfig().isFilePIDsEnabledForCollection(theDataset.getOwner()); - - if ( registerGlobalIdsForFiles ){ - registerGlobalIdsForFiles = currentGlobalAuthority.equals( theDataset.getAuthority() ); - } + ctxt.systemConfig().isFilePIDsEnabledForCollection(getDataset().getOwner()) && + ctxt.dvObjects().getEffectivePidGenerator(getDataset()).canCreatePidsLike(getDataset().getGlobalId()); boolean validatePhysicalFiles = ctxt.systemConfig().isDatafileValidationOnPublishEnabled(); // As of v5.0, publishing a dataset is always done asynchronously, // with the dataset locked for the duration of the operation. - //if ((registerGlobalIdsForFiles || validatePhysicalFiles) - // && theDataset.getFiles().size() > ctxt.systemConfig().getPIDAsynchRegFileCount()) { String info = "Publishing the dataset; "; info += registerGlobalIdsForFiles ? "Registering PIDs for Datafiles; " : ""; @@ -178,15 +169,6 @@ public PublishDatasetResult execute(CommandContext ctxt) throws CommandException // method: //ctxt.datasets().callFinalizePublishCommandAsynchronously(theDataset.getId(), ctxt, request, datasetExternallyReleased); return new PublishDatasetResult(theDataset, Status.Inprogress); - - /** - * Code for for "synchronous" (while-you-wait) publishing - * is preserved below, commented out: - } else { - // Synchronous publishing (no workflow involved) - theDataset = ctxt.engine().submit(new FinalizeDatasetPublicationCommand(theDataset, getRequest(),datasetExternallyReleased)); - return new PublishDatasetResult(theDataset, Status.Completed); - } */ } } diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/RegisterDvObjectCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/RegisterDvObjectCommand.java index 779bc7fb7fe..7b80871a1e0 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/RegisterDvObjectCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/RegisterDvObjectCommand.java @@ -4,20 +4,17 @@ import edu.harvard.iq.dataverse.DataFile; import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.DvObject; -import edu.harvard.iq.dataverse.GlobalId; +import edu.harvard.iq.dataverse.DvObjectContainer; import edu.harvard.iq.dataverse.engine.command.AbstractVoidCommand; import edu.harvard.iq.dataverse.engine.command.CommandContext; import edu.harvard.iq.dataverse.engine.command.DataverseRequest; import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; -import edu.harvard.iq.dataverse.settings.SettingsServiceBean; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.handle.HandlePidProvider; + import java.sql.Timestamp; import java.util.Date; -import edu.harvard.iq.dataverse.GlobalIdServiceBean; -import edu.harvard.iq.dataverse.HandlenetServiceBean; -import edu.harvard.iq.dataverse.batch.util.LoggingUtil; -import java.io.IOException; -import org.apache.solr.client.solrj.SolrServerException; /** * @@ -44,48 +41,37 @@ public RegisterDvObjectCommand(DataverseRequest aRequest, DvObject target, Boole @Override protected void executeImpl(CommandContext ctxt) throws CommandException { + DvObjectContainer container = (target instanceof DvObjectContainer) ? (DvObjectContainer) target : target.getOwner(); + // Get the pidProvider that is configured to mint new IDs + PidProvider pidProvider = ctxt.dvObjects().getEffectivePidGenerator(container); if(this.migrateHandle){ //Only continue if you can successfully migrate the handle - if (!processMigrateHandle(ctxt)) return; + if (HandlePidProvider.HDL_PROTOCOL.equals(pidProvider.getProtocol()) || !processMigrateHandle(ctxt)) return; } - String nonNullDefaultIfKeyNotFound = ""; - String protocol = ctxt.settings().getValueForKey(SettingsServiceBean.Key.Protocol, nonNullDefaultIfKeyNotFound); - String authority = ctxt.settings().getValueForKey(SettingsServiceBean.Key.Authority, nonNullDefaultIfKeyNotFound); - // Get the idServiceBean that is configured to mint new IDs - GlobalIdServiceBean idServiceBean = GlobalIdServiceBean.getBean(protocol, ctxt); + try { //Test to see if identifier already present //if so, leave. if (target.getIdentifier() == null || target.getIdentifier().isEmpty()) { - if (target.isInstanceofDataset()) { - target.setIdentifier(idServiceBean.generateDatasetIdentifier((Dataset) target)); - - } else { - target.setIdentifier(idServiceBean.generateDataFileIdentifier((DataFile) target)); - } - if (target.getProtocol() == null) { - target.setProtocol(protocol); - } - if (target.getAuthority() == null) { - target.setAuthority(authority); - } + pidProvider.generatePid(target); } - if (idServiceBean.alreadyRegistered(target)) { + + if (pidProvider.alreadyRegistered(target)) { return; } - String doiRetString = idServiceBean.createIdentifier(target); + String doiRetString = pidProvider.createIdentifier(target); if (doiRetString != null && doiRetString.contains(target.getIdentifier())) { - if (!idServiceBean.registerWhenPublished()) { + if (!pidProvider.registerWhenPublished()) { // Should register ID before publicize() is called - // For example, DOIEZIdServiceBean tries to recreate the id if the identifier isn't registered before + // For example, DOIEZIdProvider tries to recreate the id if the identifier isn't registered before // publicizeIdentifier is called target.setIdentifierRegistered(true); target.setGlobalIdCreateTime(new Timestamp(new Date().getTime())); } if (target.isReleased()) { - idServiceBean.publicizeIdentifier(target); + pidProvider.publicizeIdentifier(target); } - if (idServiceBean.registerWhenPublished() && target.isReleased()) { + if (pidProvider.registerWhenPublished() && target.isReleased()) { target.setGlobalIdCreateTime(new Timestamp(new Date().getTime())); target.setIdentifierRegistered(true); } @@ -95,27 +81,21 @@ protected void executeImpl(CommandContext ctxt) throws CommandException { Dataset dataset = (Dataset) target; for (DataFile df : dataset.getFiles()) { if (df.getIdentifier() == null || df.getIdentifier().isEmpty()) { - df.setIdentifier(idServiceBean.generateDataFileIdentifier(df)); - if (df.getProtocol() == null || df.getProtocol().isEmpty()) { - df.setProtocol(protocol); - } - if (df.getAuthority() == null || df.getAuthority().isEmpty()) { - df.setAuthority(authority); - } + pidProvider.generatePid(df); } - doiRetString = idServiceBean.createIdentifier(df); + doiRetString = pidProvider.createIdentifier(df); if (doiRetString != null && doiRetString.contains(df.getIdentifier())) { - if (!idServiceBean.registerWhenPublished()) { + if (!pidProvider.registerWhenPublished()) { // Should register ID before publicize() is called - // For example, DOIEZIdServiceBean tries to recreate the id if the identifier isn't registered before + // For example, DOIEZIdProvider tries to recreate the id if the identifier isn't registered before // publicizeIdentifier is called df.setIdentifierRegistered(true); df.setGlobalIdCreateTime(new Timestamp(new Date().getTime())); } if (df.isReleased()) { - idServiceBean.publicizeIdentifier(df); + pidProvider.publicizeIdentifier(df); } - if (idServiceBean.registerWhenPublished() && df.isReleased()) { + if (pidProvider.registerWhenPublished() && df.isReleased()) { df.setGlobalIdCreateTime(new Timestamp(new Date().getTime())); df.setIdentifierRegistered(true); } @@ -145,7 +125,7 @@ protected void executeImpl(CommandContext ctxt) throws CommandException { private Boolean processMigrateHandle (CommandContext ctxt){ boolean retval = true; if(!target.isInstanceofDataset()) return false; - if(!target.getProtocol().equals(HandlenetServiceBean.HDL_PROTOCOL)) return false; + if(!target.getProtocol().equals(HandlePidProvider.HDL_PROTOCOL)) return false; AlternativePersistentIdentifier api = new AlternativePersistentIdentifier(); api.setProtocol(target.getProtocol()); diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ReservePidCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ReservePidCommand.java index 6b2872f3397..b7e3ddd8ce6 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ReservePidCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ReservePidCommand.java @@ -1,7 +1,6 @@ package edu.harvard.iq.dataverse.engine.command.impl; import edu.harvard.iq.dataverse.Dataset; -import edu.harvard.iq.dataverse.GlobalIdServiceBean; import edu.harvard.iq.dataverse.authorization.Permission; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.engine.command.AbstractVoidCommand; @@ -11,6 +10,8 @@ import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.engine.command.exception.IllegalCommandException; import edu.harvard.iq.dataverse.engine.command.exception.PermissionException; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidUtil; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import edu.harvard.iq.dataverse.util.BundleUtil; import java.util.Arrays; @@ -41,11 +42,10 @@ protected void executeImpl(CommandContext ctxt) throws CommandException { this, Collections.singleton(Permission.EditDataset), dataset); } - String nonNullDefaultIfKeyNotFound = ""; - String protocol = ctxt.settings().getValueForKey(SettingsServiceBean.Key.Protocol, nonNullDefaultIfKeyNotFound); - GlobalIdServiceBean idServiceBean = GlobalIdServiceBean.getBean(protocol, ctxt); + PidProvider pidProvider = ctxt.dvObjects().getEffectivePidGenerator(dataset); + try { - String returnString = idServiceBean.createIdentifier(dataset); + String returnString = pidProvider.createIdentifier(dataset); logger.fine(returnString); // No errors caught, so mark PID as reserved. dataset.setGlobalIdCreateTime(new Date()); diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/RevokeSuperuserStatusCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/RevokeSuperuserStatusCommand.java index 0abb53ea4fb..7e55102ef5f 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/RevokeSuperuserStatusCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/RevokeSuperuserStatusCommand.java @@ -14,7 +14,7 @@ import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.engine.command.exception.PermissionException; -import edu.harvard.iq.dataverse.GlobalIdServiceBean; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; /** * diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateDatasetTargetURLCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateDatasetTargetURLCommand.java index 1f5989c9e08..5a0ae7cbf5d 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateDatasetTargetURLCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateDatasetTargetURLCommand.java @@ -10,10 +10,12 @@ import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.engine.command.exception.PermissionException; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidUtil; + import java.sql.Timestamp; import java.util.Collections; import java.util.Date; -import edu.harvard.iq.dataverse.GlobalIdServiceBean; /** * @@ -36,15 +38,15 @@ protected void executeImpl(CommandContext ctxt) throws CommandException { throw new PermissionException("Update Target URL can only be called by superusers.", this, Collections.singleton(Permission.EditDataset), target); } - GlobalIdServiceBean idServiceBean = GlobalIdServiceBean.getBean(target.getProtocol(), ctxt); + PidProvider pidProvider = PidUtil.getPidProvider(target.getGlobalId().getProviderId()); try { - String doiRetString = idServiceBean.modifyIdentifierTargetURL(target); + String doiRetString = pidProvider.modifyIdentifierTargetURL(target); if (doiRetString != null && doiRetString.contains(target.getIdentifier())) { target.setGlobalIdCreateTime(new Timestamp(new Date().getTime())); ctxt.em().merge(target); ctxt.em().flush(); for (DataFile df : target.getFiles()) { - doiRetString = idServiceBean.modifyIdentifierTargetURL(df); + doiRetString = pidProvider.modifyIdentifierTargetURL(df); if (doiRetString != null && doiRetString.contains(df.getIdentifier())) { df.setGlobalIdCreateTime(new Timestamp(new Date().getTime())); ctxt.em().merge(df); diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateDvObjectPIDMetadataCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateDvObjectPIDMetadataCommand.java index 7230f9f9c0a..0c463cddec1 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateDvObjectPIDMetadataCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateDvObjectPIDMetadataCommand.java @@ -2,7 +2,6 @@ import edu.harvard.iq.dataverse.DataFile; import edu.harvard.iq.dataverse.Dataset; -import edu.harvard.iq.dataverse.GlobalIdServiceBean; import edu.harvard.iq.dataverse.authorization.Permission; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.engine.command.AbstractVoidCommand; @@ -11,6 +10,8 @@ import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.engine.command.exception.PermissionException; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidUtil; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import edu.harvard.iq.dataverse.util.BundleUtil; import java.sql.Timestamp; @@ -46,31 +47,31 @@ protected void executeImpl(CommandContext ctxt) throws CommandException { //the single dataset update api checks for drafts before calling the command return; } - GlobalIdServiceBean idServiceBean = GlobalIdServiceBean.getBean(target.getProtocol(), ctxt); + PidProvider pidProvider = PidUtil.getPidProvider(target.getGlobalId().getProviderId()); + try { - Boolean doiRetString = idServiceBean.publicizeIdentifier(target); + Boolean doiRetString = pidProvider.publicizeIdentifier(target); if (doiRetString) { target.setGlobalIdCreateTime(new Timestamp(new Date().getTime())); ctxt.em().merge(target); ctxt.em().flush(); // When updating, we want to traverse through files even if the dataset itself // didn't need updating. - String currentGlobalIdProtocol = ctxt.settings().getValueForKey(SettingsServiceBean.Key.Protocol, ""); - String dataFilePIDFormat = ctxt.settings().getValueForKey(SettingsServiceBean.Key.DataFilePIDFormat, "DEPENDENT"); boolean isFilePIDsEnabled = ctxt.systemConfig().isFilePIDsEnabledForCollection(target.getOwner()); // We will skip trying to update the global identifiers for datafiles if they // aren't being used. // If they are, we need to assure that there's an existing PID or, as when - // creating PIDs, that the protocol matches that of the dataset DOI if - // we're going to create a DEPENDENT file PID. - String protocol = target.getProtocol(); + // creating PIDs, that it's possible. + + boolean canCreatePidsForFiles = + isFilePIDsEnabled && ctxt.dvObjects().getEffectivePidGenerator(target).canCreatePidsLike(target.getGlobalId()); + for (DataFile df : target.getFiles()) { if (isFilePIDsEnabled && // using file PIDs and (!(df.getIdentifier() == null || df.getIdentifier().isEmpty()) || // identifier exists, or - currentGlobalIdProtocol.equals(protocol) || // right protocol to create dependent DOIs, or - dataFilePIDFormat.equals("INDEPENDENT"))// or independent. TODO(pm) - check authority too + canCreatePidsForFiles) // we can create PIDs for files ) { - doiRetString = idServiceBean.publicizeIdentifier(df); + doiRetString = pidProvider.publicizeIdentifier(df); if (doiRetString) { df.setGlobalIdCreateTime(new Timestamp(new Date().getTime())); ctxt.em().merge(df); diff --git a/src/main/java/edu/harvard/iq/dataverse/export/InternalExportDataProvider.java b/src/main/java/edu/harvard/iq/dataverse/export/InternalExportDataProvider.java index a7967f6ccb6..f0d77eb8b52 100644 --- a/src/main/java/edu/harvard/iq/dataverse/export/InternalExportDataProvider.java +++ b/src/main/java/edu/harvard/iq/dataverse/export/InternalExportDataProvider.java @@ -8,12 +8,11 @@ import jakarta.json.JsonArrayBuilder; import jakarta.json.JsonObject; import jakarta.json.JsonObjectBuilder; - -import edu.harvard.iq.dataverse.DOIDataCiteRegisterService; import edu.harvard.iq.dataverse.DataCitation; import edu.harvard.iq.dataverse.DataFile; import edu.harvard.iq.dataverse.DatasetVersion; import edu.harvard.iq.dataverse.FileMetadata; +import edu.harvard.iq.dataverse.pidproviders.doi.datacite.DOIDataCiteRegisterService; import io.gdcc.spi.export.ExportDataProvider; import edu.harvard.iq.dataverse.util.bagit.OREMap; import edu.harvard.iq.dataverse.util.json.JsonPrinter; diff --git a/src/main/java/edu/harvard/iq/dataverse/export/openaire/OpenAireExportUtil.java b/src/main/java/edu/harvard/iq/dataverse/export/openaire/OpenAireExportUtil.java index 7b0a92a4372..49ceabc5900 100644 --- a/src/main/java/edu/harvard/iq/dataverse/export/openaire/OpenAireExportUtil.java +++ b/src/main/java/edu/harvard/iq/dataverse/export/openaire/OpenAireExportUtil.java @@ -13,16 +13,16 @@ import com.google.gson.Gson; -import edu.harvard.iq.dataverse.DOIServiceBean; import edu.harvard.iq.dataverse.DatasetFieldConstant; import edu.harvard.iq.dataverse.GlobalId; -import edu.harvard.iq.dataverse.HandlenetServiceBean; import edu.harvard.iq.dataverse.api.dto.DatasetDTO; import edu.harvard.iq.dataverse.api.dto.DatasetVersionDTO; import edu.harvard.iq.dataverse.api.dto.FieldDTO; import edu.harvard.iq.dataverse.api.dto.MetadataBlockDTO; import edu.harvard.iq.dataverse.util.PersonOrOrgUtil; import edu.harvard.iq.dataverse.pidproviders.PidUtil; +import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider; +import edu.harvard.iq.dataverse.pidproviders.handle.HandlePidProvider; import edu.harvard.iq.dataverse.util.json.JsonUtil; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -189,10 +189,10 @@ public static void writeIdentifierElement(XMLStreamWriter xmlw, String identifie if (StringUtils.isNotBlank(identifier)) { Map identifier_map = new HashMap(); - if (StringUtils.containsIgnoreCase(identifier, DOIServiceBean.DOI_RESOLVER_URL)) { + if (StringUtils.containsIgnoreCase(identifier, AbstractDOIProvider.DOI_RESOLVER_URL)) { identifier_map.put("identifierType", "DOI"); identifier = StringUtils.substring(identifier, identifier.indexOf("10.")); - } else if (StringUtils.containsIgnoreCase(identifier, HandlenetServiceBean.HDL_RESOLVER_URL)) { + } else if (StringUtils.containsIgnoreCase(identifier, HandlePidProvider.HDL_RESOLVER_URL)) { identifier_map.put("identifierType", "Handle"); if (StringUtils.contains(identifier, "http")) { identifier = identifier.replace(identifier.substring(0, identifier.indexOf("/") + 2), ""); diff --git a/src/main/java/edu/harvard/iq/dataverse/pidproviders/AbstractPidProvider.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/AbstractPidProvider.java new file mode 100644 index 00000000000..a3dcf6cbb3b --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/AbstractPidProvider.java @@ -0,0 +1,550 @@ +package edu.harvard.iq.dataverse.pidproviders; + +import edu.harvard.iq.dataverse.DataFile; +import edu.harvard.iq.dataverse.Dataset; +import edu.harvard.iq.dataverse.DatasetField; +import edu.harvard.iq.dataverse.DvObject; +import edu.harvard.iq.dataverse.GlobalId; +import edu.harvard.iq.dataverse.util.SystemConfig; +import jakarta.json.Json; +import jakarta.json.JsonObject; +import jakarta.json.JsonObjectBuilder; + +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.commons.lang3.RandomStringUtils; +import com.beust.jcommander.Strings; + +public abstract class AbstractPidProvider implements PidProvider { + + private static final Logger logger = Logger.getLogger(AbstractPidProvider.class.getCanonicalName()); + + public static String UNAVAILABLE = ":unav"; + public static final String SEPARATOR = "/"; + + protected PidProviderFactoryBean pidProviderService; + + private String protocol; + + private String authority = null; + + private String shoulder = null; + + private String identifierGenerationStyle = null; + + private String datafilePidFormat = null; + + private HashSet managedSet; + + private HashSet excludedSet; + + private String id; + private String label; + + protected AbstractPidProvider(String id, String label, String protocol) { + this.id = id; + this.label = label; + this.protocol = protocol; + this.managedSet = new HashSet(); + this.excludedSet = new HashSet(); + } + + protected AbstractPidProvider(String id, String label, String protocol, String authority, String shoulder, + String identifierGenerationStyle, String datafilePidFormat, String managedList, String excludedList) { + this.id = id; + this.label = label; + this.protocol = protocol; + this.authority = authority; + this.shoulder = shoulder; + this.identifierGenerationStyle = identifierGenerationStyle; + this.datafilePidFormat = datafilePidFormat; + this.managedSet = new HashSet(Arrays.asList(managedList.split(",\\s"))); + this.excludedSet = new HashSet(Arrays.asList(excludedList.split(",\\s"))); + if (logger.isLoggable(Level.FINE)) { + Iterator iter = managedSet.iterator(); + while (iter.hasNext()) { + logger.fine("managedSet in " + getId() + ": " + iter.next()); + } + iter = excludedSet.iterator(); + while (iter.hasNext()) { + logger.fine("excludedSet in " + getId() + ": " + iter.next()); + } + } + } + + @Override + public Map getMetadataForCreateIndicator(DvObject dvObjectIn) { + logger.log(Level.FINE, "getMetadataForCreateIndicator(DvObject)"); + Map metadata = new HashMap<>(); + metadata = addBasicMetadata(dvObjectIn, metadata); + metadata.put("datacite.publicationyear", generateYear(dvObjectIn)); + metadata.put("_target", getTargetUrl(dvObjectIn)); + return metadata; + } + + protected Map getUpdateMetadata(DvObject dvObjectIn) { + logger.log(Level.FINE, "getUpdateMetadataFromDataset"); + Map metadata = new HashMap<>(); + metadata = addBasicMetadata(dvObjectIn, metadata); + return metadata; + } + + protected Map addBasicMetadata(DvObject dvObjectIn, Map metadata) { + + String authorString = dvObjectIn.getAuthorString(); + if (authorString.isEmpty() || authorString.contains(DatasetField.NA_VALUE)) { + authorString = UNAVAILABLE; + } + + String producerString = pidProviderService.getProducer(); + + if (producerString.isEmpty() || producerString.equals(DatasetField.NA_VALUE)) { + producerString = UNAVAILABLE; + } + + String titleString = dvObjectIn.getCurrentName(); + + if (titleString.isEmpty() || titleString.equals(DatasetField.NA_VALUE)) { + titleString = UNAVAILABLE; + } + + metadata.put("datacite.creator", authorString); + metadata.put("datacite.title", titleString); + metadata.put("datacite.publisher", producerString); + metadata.put("datacite.publicationyear", generateYear(dvObjectIn)); + return metadata; + } + + protected Map addDOIMetadataForDestroyedDataset(DvObject dvObjectIn) { + Map metadata = new HashMap<>(); + String authorString = UNAVAILABLE; + String producerString = UNAVAILABLE; + String titleString = "This item has been removed from publication"; + + metadata.put("datacite.creator", authorString); + metadata.put("datacite.title", titleString); + metadata.put("datacite.publisher", producerString); + metadata.put("datacite.publicationyear", "9999"); + return metadata; + } + + protected String getTargetUrl(DvObject dvObjectIn) { + logger.log(Level.FINE, "getTargetUrl"); + return SystemConfig.getDataverseSiteUrlStatic() + dvObjectIn.getTargetUrl() + + dvObjectIn.getGlobalId().asString(); + } + + @Override + public String getIdentifier(DvObject dvObject) { + GlobalId gid = dvObject.getGlobalId(); + return gid != null ? gid.asString() : null; + } + + protected String generateYear(DvObject dvObjectIn) { + return dvObjectIn.getYearPublishedCreated(); + } + + public Map getMetadataForTargetURL(DvObject dvObject) { + logger.log(Level.FINE, "getMetadataForTargetURL"); + HashMap metadata = new HashMap<>(); + metadata.put("_target", getTargetUrl(dvObject)); + return metadata; + } + + @Override + public boolean alreadyRegistered(DvObject dvo) throws Exception { + if (dvo == null) { + logger.severe("Null DvObject sent to alreadyRegistered()."); + return false; + } + GlobalId globalId = dvo.getGlobalId(); + if (globalId == null) { + return false; + } + return alreadyRegistered(globalId, false); + } + + public abstract boolean alreadyRegistered(GlobalId globalId, boolean noProviderDefault) throws Exception; + + /* + * ToDo: the DvObject being sent in provides partial support for the case where + * it has a different authority/protocol than what is configured (i.e. a legacy + * Pid that can actually be updated by the Pid account being used.) Removing + * this now would potentially break/make it harder to handle that case prior to + * support for configuring multiple Pid providers. Once that exists, it would be + * cleaner to always find the PidProvider associated with the + * protocol/authority/shoulder of the current dataset and then not pass the + * DvObject as a param. (This would also remove calls to get the settings since + * that would be done at construction.) + */ + @Override + public DvObject generatePid(DvObject dvObject) { + + if (dvObject.getProtocol() == null) { + dvObject.setProtocol(getProtocol()); + } else { + if (!dvObject.getProtocol().equals(getProtocol())) { + logger.warning("The protocol of the DvObject (" + dvObject.getProtocol() + + ") does not match the configured protocol (" + getProtocol() + ")"); + throw new IllegalArgumentException("The protocol of the DvObject (" + dvObject.getProtocol() + + ") doesn't match that of the provider, id: " + getId()); + } + } + if (dvObject.getAuthority() == null) { + dvObject.setAuthority(getAuthority()); + } else { + if (!dvObject.getAuthority().equals(getAuthority())) { + logger.warning("The authority of the DvObject (" + dvObject.getAuthority() + + ") does not match the configured authority (" + getAuthority() + ")"); + throw new IllegalArgumentException("The authority of the DvObject (" + dvObject.getAuthority() + + ") doesn't match that of the provider, id: " + getId()); + } + } + if (dvObject.isInstanceofDataset()) { + dvObject.setIdentifier(generateDatasetIdentifier((Dataset) dvObject)); + } else { + dvObject.setIdentifier(generateDataFileIdentifier((DataFile) dvObject)); + } + return dvObject; + } + + private String generateDatasetIdentifier(Dataset dataset) { + String shoulder = getShoulder(); + + switch (getIdentifierGenerationStyle()) { + case "randomString": + return generateIdentifierAsRandomString(dataset, shoulder); + case "storedProcGenerated": + return generateIdentifierFromStoredProcedureIndependent(dataset, shoulder); + default: + /* Should we throw an exception instead?? -- L.A. 4.6.2 */ + return generateIdentifierAsRandomString(dataset, shoulder); + } + } + + /** + * Check that a identifier entered by the user is unique (not currently used for + * any other study in this Dataverse Network) also check for duplicate in EZID + * if needed + * + * @param userIdentifier + * @param dataset + * @return {@code true} if the identifier is unique, {@code false} otherwise. + */ + public boolean isGlobalIdUnique(GlobalId globalId) { + if (!pidProviderService.isGlobalIdLocallyUnique(globalId)) { + return false; // duplication found in local database + } + + // not in local DB, look in the persistent identifier service + try { + return !alreadyRegistered(globalId, false); + } catch (Exception e) { + // we can live with failure - means identifier not found remotely + } + + return true; + } + + /** + * Parse a Persistent Id and set the protocol, authority, and identifier + * + * Example 1: doi:10.5072/FK2/BYM3IW protocol: doi authority: 10.5072 + * identifier: FK2/BYM3IW + * + * Example 2: hdl:1902.1/111012 protocol: hdl authority: 1902.1 identifier: + * 111012 + * + * @param identifierString + * @param separator the string that separates the authority from the + * identifier. + * @param destination the global id that will contain the parsed data. + * @return {@code destination}, after its fields have been updated, or + * {@code null} if parsing failed. + */ + @Override + public GlobalId parsePersistentId(String fullIdentifierString) { + // Occasionally, the protocol separator character ':' comes in still + // URL-encoded as %3A (usually as a result of the URL having been + // encoded twice): + fullIdentifierString = fullIdentifierString.replace("%3A", ":"); + + int index1 = fullIdentifierString.indexOf(':'); + if (index1 > 0) { // ':' found with one or more characters before it + String protocol = fullIdentifierString.substring(0, index1); + GlobalId globalId = parsePersistentId(protocol, fullIdentifierString.substring(index1 + 1)); + return globalId; + } + logger.log(Level.INFO, "Error parsing identifier: {0}: '':'' not found in string", + fullIdentifierString); + return null; + } + + protected GlobalId parsePersistentId(String protocol, String identifierString) { + String authority; + String identifier; + if (identifierString == null) { + return null; + } + int index = identifierString.indexOf(getSeparator()); + if (index > 0 && (index + 1) < identifierString.length()) { + // '/' found with one or more characters + // before and after it + // Strip any whitespace, ; and ' from authority (should finding them cause a + // failure instead?) + authority = PidProvider.formatIdentifierString(identifierString.substring(0, index)); + + if (PidProvider.testforNullTerminator(authority)) { + return null; + } + identifier = PidProvider.formatIdentifierString(identifierString.substring(index + 1)); + if (PidProvider.testforNullTerminator(identifier)) { + return null; + } + + } else { + logger.log(Level.INFO, "Error parsing identifier: {0}: '':/'' not found in string", + identifierString); + return null; + } + return parsePersistentId(protocol, authority, identifier); + } + + public GlobalId parsePersistentId(String protocol, String authority, String identifier) { + logger.fine("Parsing: " + protocol + ":" + authority + getSeparator() + identifier + " in " + getId()); + if (!PidProvider.isValidGlobalId(protocol, authority, identifier)) { + return null; + } + // Check authority/identifier if this is a provider that manages specific + // identifiers + // /is not one of the unmanaged providers that has null authority + if (getAuthority() != null) { + + String cleanIdentifier = protocol + ":" + authority + getSeparator() + identifier; + /* + * Test if this provider manages this identifier - return null if it does not. + * It does match if ((the identifier's authority and shoulder match the + * provider's), or the identifier is in the managed set), and, in either case, + * the identifier is not in the excluded set. + */ + logger.fine("clean pid in " + getId() + ": " + cleanIdentifier); + logger.fine("managed in " + getId() + ": " + getManagedSet().contains(cleanIdentifier)); + logger.fine("excluded from " + getId() + ": " + getExcludedSet().contains(cleanIdentifier)); + + if (!(((authority.equals(getAuthority()) && identifier.startsWith(getShoulder())) + || getManagedSet().contains(cleanIdentifier)) && !getExcludedSet().contains(cleanIdentifier))) { + return null; + } + } + return new GlobalId(protocol, authority, identifier, getSeparator(), getUrlPrefix(), getId()); + } + + public String getSeparator() { + // The standard default + return SEPARATOR; + } + + private String generateDataFileIdentifier(DataFile datafile) { + String doiDataFileFormat = getDatafilePidFormat(); + + String prepend = ""; + if (doiDataFileFormat.equals(SystemConfig.DataFilePIDFormat.DEPENDENT.toString())) { + // If format is dependent then pre-pend the dataset identifier + prepend = datafile.getOwner().getIdentifier() + SEPARATOR; + datafile.setProtocol(datafile.getOwner().getProtocol()); + datafile.setAuthority(datafile.getOwner().getAuthority()); + } else { + // If there's a shoulder prepend independent identifiers with it + prepend = getShoulder(); + datafile.setProtocol(getProtocol()); + datafile.setAuthority(getAuthority()); + } + + switch (getIdentifierGenerationStyle()) { + case "randomString": + return generateIdentifierAsRandomString(datafile, prepend); + case "storedProcGenerated": + if (doiDataFileFormat.equals(SystemConfig.DataFilePIDFormat.INDEPENDENT.toString())) { + return generateIdentifierFromStoredProcedureIndependent(datafile, prepend); + } else { + return generateIdentifierFromStoredProcedureDependent(datafile, prepend); + } + default: + /* Should we throw an exception instead?? -- L.A. 4.6.2 */ + return generateIdentifierAsRandomString(datafile, prepend); + } + } + + /* + * This method checks locally for a DvObject with the same PID and if that is + * OK, checks with the PID service. + * + * @param dvo - the object to check (ToDo - get protocol/authority from this + * PidProvider object) + * + * @param prepend - for Datasets, this is always the shoulder, for DataFiles, it + * could be the shoulder or the parent Dataset identifier + */ + private String generateIdentifierAsRandomString(DvObject dvo, String prepend) { + String identifier = null; + do { + identifier = prepend + RandomStringUtils.randomAlphanumeric(6).toUpperCase(); + } while (!isGlobalIdUnique(new GlobalId(dvo.getProtocol(), dvo.getAuthority(), identifier, this.getSeparator(), + this.getUrlPrefix(), this.getId()))); + + return identifier; + } + + /* + * This method checks locally for a DvObject with the same PID and if that is + * OK, checks with the PID service. + * + * @param dvo - the object to check (ToDo - get protocol/authority from this + * PidProvider object) + * + * @param prepend - for Datasets, this is always the shoulder, for DataFiles, it + * could be the shoulder or the parent Dataset identifier + */ + + private String generateIdentifierFromStoredProcedureIndependent(DvObject dvo, String prepend) { + String identifier; + do { + String identifierFromStoredProcedure = pidProviderService.generateNewIdentifierByStoredProcedure(); + // some diagnostics here maybe - is it possible to determine that it's failing + // because the stored procedure hasn't been created in the database? + if (identifierFromStoredProcedure == null) { + return null; + } + identifier = prepend + identifierFromStoredProcedure; + } while (!isGlobalIdUnique(new GlobalId(dvo.getProtocol(), dvo.getAuthority(), identifier, this.getSeparator(), + this.getUrlPrefix(), this.getId()))); + + return identifier; + } + + /* + * This method is only used for DataFiles with DEPENDENT Pids. It is not for + * Datasets + * + */ + private String generateIdentifierFromStoredProcedureDependent(DataFile datafile, String prepend) { + String identifier; + Long retVal; + retVal = Long.valueOf(0L); + // ToDo - replace loops with one lookup for largest entry? (the do loop runs + // ~n**2/2 calls). The check for existingIdentifiers means this is mostly a + // local loop now, versus involving db or PidProvider calls, but still...) + + // This will catch identifiers already assigned in the current transaction (e.g. + // in FinalizeDatasetPublicationCommand) that haven't been committed to the db + // without having to make a call to the PIDProvider + Set existingIdentifiers = new HashSet(); + List files = datafile.getOwner().getFiles(); + for (DataFile f : files) { + existingIdentifiers.add(f.getIdentifier()); + } + + do { + retVal++; + identifier = prepend + retVal.toString(); + + } while (existingIdentifiers.contains(identifier) || !isGlobalIdUnique(new GlobalId(datafile.getProtocol(), + datafile.getAuthority(), identifier, this.getSeparator(), this.getUrlPrefix(), this.getId()))); + + return identifier; + } + + + @Override + public boolean canManagePID() { + // The default expectation is that PID providers are configured to manage some + // set (i.e. based on protocol/authority/shoulder) of PIDs + return true; + } + + @Override + public void setPidProviderServiceBean(PidProviderFactoryBean pidProviderServiceBean) { + this.pidProviderService = pidProviderServiceBean; + } + + @Override + public String getProtocol() { + return protocol; + } + + @Override + public String getAuthority() { + return authority; + } + + @Override + public String getShoulder() { + return shoulder; + } + + @Override + public String getIdentifierGenerationStyle() { + return identifierGenerationStyle; + } + + @Override + public String getDatafilePidFormat() { + return datafilePidFormat; + } + + @Override + public Set getManagedSet() { + return managedSet; + } + + @Override + public Set getExcludedSet() { + return excludedSet; + } + + @Override + public String getId() { + return id; + } + + @Override + public String getLabel() { + return label; + } + + @Override + /** + * True if this provider can manage PIDs in general, this pid is not in the + * managedSet (meaning it is managed but the provider does not generally manage + * it's protocol/authority/separator/shoulder) and either this provider is the + * same as the pid's or we're allowed to create INDEPENDENT pids. The latter + * clause covers the potential case where the effective pid provider/generator + * for the dataset is set to a different one that handles the dataset's pid + * itself. In this case, we can create file PIDs if they are independent. + * + * @param pid - the related pid to check + * @return true if this provider can manage PIDs like the one supplied + */ + public boolean canCreatePidsLike(GlobalId pid) { + return canManagePID() && !managedSet.contains(pid.asString()) + && (getIdentifierGenerationStyle().equals("INDEPENDENT") || getId().equals(pid.getProviderId())); + } + + @Override + public JsonObject getProviderSpecification() { + JsonObjectBuilder providerSpecification = Json.createObjectBuilder(); + providerSpecification.add("id", id); + providerSpecification.add("label", label); + providerSpecification.add("protocol", protocol); + providerSpecification.add("authority", authority); + providerSpecification.add("separator", getSeparator()); + providerSpecification.add("shoulder", shoulder); + providerSpecification.add("identifierGenerationStyle", identifierGenerationStyle); + providerSpecification.add("datafilePidFormat", datafilePidFormat); + providerSpecification.add("managedSet", Strings.join(",", managedSet.toArray())); + providerSpecification.add("excludedSet", Strings.join(",", excludedSet.toArray())); + return providerSpecification.build(); + } +} diff --git a/src/main/java/edu/harvard/iq/dataverse/pidproviders/PermaLinkPidProviderServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/PermaLinkPidProviderServiceBean.java deleted file mode 100644 index d145a7ec106..00000000000 --- a/src/main/java/edu/harvard/iq/dataverse/pidproviders/PermaLinkPidProviderServiceBean.java +++ /dev/null @@ -1,160 +0,0 @@ -package edu.harvard.iq.dataverse.pidproviders; - -import edu.harvard.iq.dataverse.AbstractGlobalIdServiceBean; -import edu.harvard.iq.dataverse.DvObject; -import edu.harvard.iq.dataverse.GlobalId; -import edu.harvard.iq.dataverse.GlobalIdServiceBean; -import edu.harvard.iq.dataverse.settings.JvmSettings; -import edu.harvard.iq.dataverse.settings.SettingsServiceBean.Key; -import edu.harvard.iq.dataverse.util.SystemConfig; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.logging.Logger; - -import jakarta.annotation.PostConstruct; -import jakarta.ejb.Stateless; - -/** - * PermaLink provider - * This is a minimalist permanent ID provider intended for use with 'real' datasets/files where the use case none-the-less doesn't lend itself to the use of DOIs or Handles, e.g. - * * due to cost - * * for a catalog/archive where Dataverse has a dataset representing a dataset with DOI/handle stored elsewhere - * - * The initial implementation will mint identifiers locally and will provide the existing page URLs (using the ?persistentID= format). - * This will be overridable by a configurable parameter to support use of an external resolver. - * - */ -@Stateless -public class PermaLinkPidProviderServiceBean extends AbstractGlobalIdServiceBean { - - private static final Logger logger = Logger.getLogger(PermaLinkPidProviderServiceBean.class.getCanonicalName()); - - public static final String PERMA_PROTOCOL = "perma"; - public static final String PERMA_PROVIDER_NAME = "PERMA"; - - //ToDo - handle dataset/file defaults for local system - public static final String PERMA_RESOLVER_URL = JvmSettings.PERMALINK_BASEURL - .lookupOptional() - .orElse(SystemConfig.getDataverseSiteUrlStatic()); - - String authority = null; - private String separator = ""; - - @PostConstruct - private void init() { - if(PERMA_PROTOCOL.equals(settingsService.getValueForKey(Key.Protocol))){ - authority = settingsService.getValueForKey(Key.Authority); - configured=true; - }; - - } - - - //Only used in PidUtilTest - haven't figured out how to mock a PostConstruct call directly - // ToDo - remove after work to allow more than one Pid Provider which is expected to not use stateless beans - public void reInit() { - init(); - } - - @Override - public String getSeparator() { - //The perma default - return separator; - } - - @Override - public boolean alreadyRegistered(GlobalId globalId, boolean noProviderDefault) { - // Perma doesn't manage registration, so we assume all local PIDs can be treated - // as registered - boolean existsLocally = !dvObjectService.isGlobalIdLocallyUnique(globalId); - return existsLocally ? existsLocally : noProviderDefault; - } - - @Override - public boolean registerWhenPublished() { - return false; - } - - @Override - public List getProviderInformation() { - return List.of(PERMA_PROVIDER_NAME, PERMA_RESOLVER_URL); - } - - @Override - public String createIdentifier(DvObject dvo) throws Throwable { - //Call external resolver and send landing URL? - //FWIW: Return value appears to only be used in RegisterDvObjectCommand where success requires finding the dvo identifier in this string. (Also logged a couple places). - return(dvo.getGlobalId().asString()); - } - - @Override - public Map getIdentifierMetadata(DvObject dvo) { - Map map = new HashMap<>(); - return map; - } - - @Override - public String modifyIdentifierTargetURL(DvObject dvo) throws Exception { - return getTargetUrl(dvo); - } - - @Override - public void deleteIdentifier(DvObject dvo) throws Exception { - // no-op - } - - @Override - public boolean publicizeIdentifier(DvObject dvObject) { - //Generate if needed (i.e. datafile case where we don't create/register early (even with reigsterWhenPublished == false)) - if(dvObject.getIdentifier() == null || dvObject.getIdentifier().isEmpty() ){ - dvObject = generateIdentifier(dvObject); - } - //Call external resolver and send landing URL? - return true; - } - - @Override - public GlobalId parsePersistentId(String pidString) { - //ToDo - handle local PID resolver for dataset/file - if (pidString.startsWith(getUrlPrefix())) { - pidString = pidString.replace(getUrlPrefix(), - (PERMA_PROTOCOL + ":")); - } - return super.parsePersistentId(pidString); - } - - @Override - public GlobalId parsePersistentId(String protocol, String identifierString) { - logger.fine("Checking Perma: " + identifierString); - if (!PERMA_PROTOCOL.equals(protocol)) { - return null; - } - String identifier = null; - if (authority != null) { - if (identifierString.startsWith(authority)) { - identifier = identifierString.substring(authority.length()); - } - } - identifier = GlobalIdServiceBean.formatIdentifierString(identifier); - if (GlobalIdServiceBean.testforNullTerminator(identifier)) { - return null; - } - return new GlobalId(PERMA_PROTOCOL, authority, identifier, separator, getUrlPrefix(), PERMA_PROVIDER_NAME); - } - - @Override - public GlobalId parsePersistentId(String protocol, String authority, String identifier) { - if (!PERMA_PROTOCOL.equals(protocol)) { - return null; - } - return super.parsePersistentId(protocol, authority, identifier); - } - - @Override - public String getUrlPrefix() { - - return PERMA_RESOLVER_URL + "/citation?persistentId=" + PERMA_PROTOCOL + ":"; - } -} diff --git a/src/main/java/edu/harvard/iq/dataverse/pidproviders/PidHelper.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/PidHelper.java deleted file mode 100644 index 5bc855a9593..00000000000 --- a/src/main/java/edu/harvard/iq/dataverse/pidproviders/PidHelper.java +++ /dev/null @@ -1,43 +0,0 @@ -package edu.harvard.iq.dataverse.pidproviders; - -import java.util.Arrays; -import jakarta.annotation.PostConstruct; -import jakarta.ejb.EJB; -import jakarta.ejb.Singleton; -import jakarta.ejb.Startup; - -import edu.harvard.iq.dataverse.DOIDataCiteServiceBean; -import edu.harvard.iq.dataverse.DOIEZIdServiceBean; -import edu.harvard.iq.dataverse.HandlenetServiceBean; - - /** - * This is a small helper bean - * As it is a singleton and built at application start (=deployment), it will inject the (stateless) - * dataverse service into the BrandingUtil once it's ready. - */ - @Startup - @Singleton - public class PidHelper { - - @EJB - DOIDataCiteServiceBean datacitePidSvc; - @EJB - DOIEZIdServiceBean ezidPidSvc; - @EJB - HandlenetServiceBean handlePidSvc; - @EJB - FakePidProviderServiceBean fakePidSvc; - @EJB - PermaLinkPidProviderServiceBean permaPidSvc; - @EJB - UnmanagedDOIServiceBean unmanagedDOISvc; - @EJB - UnmanagedHandlenetServiceBean unmanagedHandleSvc; - - @PostConstruct - public void listServices() { - PidUtil.addAllToProviderList(Arrays.asList(datacitePidSvc, ezidPidSvc, handlePidSvc, permaPidSvc, fakePidSvc)); - PidUtil.addAllToUnmanagedProviderList(Arrays.asList(unmanagedDOISvc, unmanagedHandleSvc)); - } - - } \ No newline at end of file diff --git a/src/main/java/edu/harvard/iq/dataverse/GlobalIdServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/PidProvider.java similarity index 56% rename from src/main/java/edu/harvard/iq/dataverse/GlobalIdServiceBean.java rename to src/main/java/edu/harvard/iq/dataverse/pidproviders/PidProvider.java index aebf13778c3..ea3a243f25c 100644 --- a/src/main/java/edu/harvard/iq/dataverse/GlobalIdServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/PidProvider.java @@ -1,19 +1,16 @@ -package edu.harvard.iq.dataverse; +package edu.harvard.iq.dataverse.pidproviders; -import static edu.harvard.iq.dataverse.GlobalIdServiceBean.logger; -import edu.harvard.iq.dataverse.engine.command.CommandContext; -import edu.harvard.iq.dataverse.pidproviders.PermaLinkPidProviderServiceBean; -import edu.harvard.iq.dataverse.pidproviders.PidUtil; -import edu.harvard.iq.dataverse.settings.SettingsServiceBean.Key; +import edu.harvard.iq.dataverse.DvObject; +import edu.harvard.iq.dataverse.GlobalId; +import jakarta.json.JsonObject; +import jakarta.json.JsonValue; import java.util.*; -import java.util.function.Function; -import java.util.logging.Level; import java.util.logging.Logger; -public interface GlobalIdServiceBean { +public interface PidProvider { - static final Logger logger = Logger.getLogger(GlobalIdServiceBean.class.getCanonicalName()); + static final Logger logger = Logger.getLogger(PidProvider.class.getCanonicalName()); boolean alreadyRegistered(DvObject dvo) throws Exception; @@ -36,7 +33,6 @@ public interface GlobalIdServiceBean { boolean registerWhenPublished(); boolean canManagePID(); - boolean isConfigured(); List getProviderInformation(); @@ -52,36 +48,24 @@ public interface GlobalIdServiceBean { Map getMetadataForTargetURL(DvObject dvObject); - DvObject generateIdentifier(DvObject dvObject); + DvObject generatePid(DvObject dvObject); String getIdentifier(DvObject dvObject); boolean publicizeIdentifier(DvObject studyIn); - String generateDatasetIdentifier(Dataset dataset); - String generateDataFileIdentifier(DataFile datafile); boolean isGlobalIdUnique(GlobalId globalId); String getUrlPrefix(); String getSeparator(); - static GlobalIdServiceBean getBean(String protocol, CommandContext ctxt) { - final Function protocolHandler = BeanDispatcher.DISPATCHER.get(protocol); - if ( protocolHandler != null ) { - GlobalIdServiceBean theBean = protocolHandler.apply(ctxt); - if(theBean != null && theBean.isConfigured()) { - logger.fine("getBean returns " + theBean.getProviderInformation().get(0) + " for protocol " + protocol); - } - return theBean; - } else { - logger.log(Level.SEVERE, "Unknown protocol: {0}", protocol); - return null; - } - } - - static GlobalIdServiceBean getBean(CommandContext ctxt) { - return getBean(ctxt.settings().getValueForKey(Key.Protocol, ""), ctxt); - } + String getProtocol(); + String getProviderType(); + String getId(); + String getLabel(); + String getAuthority(); + String getShoulder(); + String getIdentifierGenerationStyle(); public static Optional parse(String identifierString) { try { @@ -111,6 +95,7 @@ public static Optional parse(String identifierString) { * {@code null} if parsing failed. */ public GlobalId parsePersistentId(String identifierString); + public GlobalId parsePersistentId(String protocol, String authority, String identifier); @@ -119,16 +104,16 @@ public static boolean isValidGlobalId(String protocol, String authority, String if (protocol == null || authority == null || identifier == null) { return false; } - if(!authority.equals(GlobalIdServiceBean.formatIdentifierString(authority))) { + if(!authority.equals(PidProvider.formatIdentifierString(authority))) { return false; } - if (GlobalIdServiceBean.testforNullTerminator(authority)) { + if (PidProvider.testforNullTerminator(authority)) { return false; } - if(!identifier.equals(GlobalIdServiceBean.formatIdentifierString(identifier))) { + if(!identifier.equals(PidProvider.formatIdentifierString(identifier))) { return false; } - if (GlobalIdServiceBean.testforNullTerminator(identifier)) { + if (PidProvider.testforNullTerminator(identifier)) { return false; } return true; @@ -177,40 +162,28 @@ static boolean checkDOIAuthority(String doiAuthority){ return true; } -} - - -/* - * ToDo - replace this with a mechanism like BrandingUtilHelper that would read - * the config and create PidProviders, one per set of config values and serve - * those as needed. The help has to be a bean to autostart and to hand the - * required service beans to the PidProviders. That may boil down to just the - * dvObjectService (to check for local identifier conflicts) since it will be - * the helper that has to read settings/get systewmConfig values. - * - */ - -/** - * Static utility class for dispatching implementing beans, based on protocol and providers. - * @author michael - */ -class BeanDispatcher { - static final Map> DISPATCHER = new HashMap<>(); - - static { - DISPATCHER.put("hdl", ctxt->ctxt.handleNet() ); - DISPATCHER.put("doi", ctxt->{ - String doiProvider = ctxt.settings().getValueForKey(Key.DoiProvider, ""); - switch ( doiProvider ) { - case "EZID": return ctxt.doiEZId(); - case "DataCite": return ctxt.doiDataCite(); - case "FAKE": return ctxt.fakePidProvider(); - default: - logger.log(Level.SEVERE, "Unknown doiProvider: {0}", doiProvider); - return null; - } - }); - - DISPATCHER.put(PermaLinkPidProviderServiceBean.PERMA_PROTOCOL, ctxt->ctxt.permaLinkProvider() ); - } + + public void setPidProviderServiceBean(PidProviderFactoryBean pidProviderFactoryBean); + + String getDatafilePidFormat(); + + Set getManagedSet(); + + Set getExcludedSet(); + + /** + * Whether related pids can be created by this pid provider + * @see edu.harvard.iq.dataverse.pidproviders.AbstractPidProvider#canCreatePidsLike(GlobalId) more details in the abstract implementation + * + * @param pid + * @return - whether related pids can be created by this pid provider. + */ + boolean canCreatePidsLike(GlobalId pid); + + /** + * Returns a JSON representation of this pid provider including it's id, label, protocol, authority, separator, and identifier. + * @return + */ + public JsonObject getProviderSpecification(); + } \ No newline at end of file diff --git a/src/main/java/edu/harvard/iq/dataverse/pidproviders/PidProviderFactory.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/PidProviderFactory.java new file mode 100644 index 00000000000..f7c1a4b9174 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/PidProviderFactory.java @@ -0,0 +1,8 @@ +package edu.harvard.iq.dataverse.pidproviders; + +public interface PidProviderFactory { + + String getType(); + + PidProvider createPidProvider(String id); +} diff --git a/src/main/java/edu/harvard/iq/dataverse/pidproviders/PidProviderFactoryBean.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/PidProviderFactoryBean.java new file mode 100644 index 00000000000..7d6e5f57ea9 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/PidProviderFactoryBean.java @@ -0,0 +1,251 @@ +package edu.harvard.iq.dataverse.pidproviders; + +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.ServiceLoader; +import java.util.logging.Level; +import java.util.logging.Logger; + +import jakarta.annotation.PostConstruct; +import jakarta.ejb.EJB; +import jakarta.ejb.Singleton; +import jakarta.ejb.Startup; +import jakarta.inject.Inject; +import edu.harvard.iq.dataverse.settings.JvmSettings; +import edu.harvard.iq.dataverse.settings.SettingsServiceBean; +import edu.harvard.iq.dataverse.util.SystemConfig; +import edu.harvard.iq.dataverse.DataverseServiceBean; +import edu.harvard.iq.dataverse.DvObjectServiceBean; +import edu.harvard.iq.dataverse.GlobalId; +import edu.harvard.iq.dataverse.pidproviders.doi.UnmanagedDOIProvider; +import edu.harvard.iq.dataverse.pidproviders.doi.datacite.DataCiteDOIProvider; +import edu.harvard.iq.dataverse.pidproviders.doi.ezid.EZIdDOIProvider; +import edu.harvard.iq.dataverse.pidproviders.doi.fake.FakeDOIProvider; +import edu.harvard.iq.dataverse.pidproviders.handle.HandlePidProvider; +import edu.harvard.iq.dataverse.pidproviders.handle.UnmanagedHandlePidProvider; +import edu.harvard.iq.dataverse.pidproviders.perma.PermaLinkPidProvider; +import edu.harvard.iq.dataverse.pidproviders.perma.UnmanagedPermaLinkPidProvider; + +/** + * This Bean loads all of the PidProviderFactory types available (e.g. EZID, + * DataCite, Handle, PermaLink) and then reads the configuration to load + * particular PidProviders (e.g. a DataCite provider with a specific + * authority/shoulder, username/password, etc.) + */ +@Startup +@Singleton +public class PidProviderFactoryBean { + + private static final Logger logger = Logger.getLogger(PidProviderFactoryBean.class.getCanonicalName()); + + @Inject + DataverseServiceBean dataverseService; + @EJB + protected SettingsServiceBean settingsService; + @Inject + protected DvObjectServiceBean dvObjectService; + @Inject + SystemConfig systemConfig; + + private ServiceLoader loader; + private Map pidProviderFactoryMap = new HashMap<>(); + + @PostConstruct + public void init() { + loadProviderFactories(); + loadProviders(); + } + + private void loadProviderFactories() { + /* + * Step 1 - find the PROVIDERS dir and add all jar files there to a class loader + */ + List jarUrls = new ArrayList<>(); + Optional providerPathSetting = JvmSettings.PIDPROVIDERS_DIRECTORY.lookupOptional(String.class); + if (providerPathSetting.isPresent()) { + Path providersDir = Paths.get(providerPathSetting.get()); + // Get all JAR files from the configured directory + try (DirectoryStream stream = Files.newDirectoryStream(providersDir, "*.jar")) { + // Using the foreach loop here to enable catching the URI/URL exceptions + for (Path path : stream) { + logger.log(Level.FINE, "Adding {0}", path.toUri().toURL()); + // This is the syntax required to indicate a jar file from which classes should + // be loaded (versus a class file). + jarUrls.add(new URL("jar:" + path.toUri().toURL() + "!/")); + } + } catch (IOException e) { + logger.warning("Problem accessing external Providers: " + e.getLocalizedMessage()); + } + } + URLClassLoader cl = URLClassLoader.newInstance(jarUrls.toArray(new URL[0]), this.getClass().getClassLoader()); + + /* + * Step 2 - load all PidProcviderFactories that can be found, using the jars as + * additional sources + */ + loader = ServiceLoader.load(PidProviderFactory.class, cl); + /* + * Step 3 - Fill pidProviderFactoryMap with type as the key, allow external + * factories to replace internal ones for the same type. FWIW: From the logging + * it appears that ServiceLoader returns classes in ~ alphabetical order rather + * than by class loader, so internal classes handling a given providerName may + * be processed before or after external ones. + */ + loader.forEach(providerFactory -> { + String type = providerFactory.getType(); + logger.fine("Loaded PidProviderFactory of type: " + type); + // If no entry for this providerName yet or if it is an external provider + if (!pidProviderFactoryMap.containsKey(type) || providerFactory.getClass().getClassLoader().equals(cl)) { + logger.fine("Adding PidProviderFactory of type: " + type + " to the map"); + pidProviderFactoryMap.put(type, providerFactory); + } + logger.log(Level.FINE, + "Loaded PidProviderFactory of type: " + type + " from " + + providerFactory.getClass().getCanonicalName() + " and classloader: " + + providerFactory.getClass().getClassLoader().getClass().getCanonicalName()); + }); + } + + private void loadProviders() { + Optional providers = JvmSettings.PID_PROVIDERS.lookupOptional(String[].class); + if (!providers.isPresent()) { + logger.warning( + "No PidProviders configured via dataverse.pid.providers. Please consider updating as older PIDProvider configuration mechanisms will be removed in a future version of Dataverse."); + return; + } else { + for (String id : providers.get()) { + //Allows spaces in PID_PROVIDERS setting + id=id.trim(); + Optional type = JvmSettings.PID_PROVIDER_TYPE.lookupOptional(id); + if (!type.isPresent()) { + logger.warning("PidProvider " + id + + " listed in dataverse.pid.providers is not properly configured and will not be used."); + } else { + String typeString = type.get(); + if (pidProviderFactoryMap.containsKey(typeString)) { + PidProvider provider = pidProviderFactoryMap.get(typeString).createPidProvider(id); + provider.setPidProviderServiceBean(this); + PidUtil.addToProviderList(provider); + } + } + } + } + String protocol = settingsService.getValueForKey(SettingsServiceBean.Key.Protocol); + String authority = settingsService.getValueForKey(SettingsServiceBean.Key.Authority); + String shoulder = settingsService.getValueForKey(SettingsServiceBean.Key.Shoulder); + String provider = settingsService.getValueForKey(SettingsServiceBean.Key.DoiProvider); + + if (protocol != null && authority != null && shoulder != null && provider != null) { + logger.warning("Found legacy settings: " + protocol + " " + authority + " " + shoulder + " " + provider + + "Please consider updating as this PIDProvider configuration mechanism will be removed in a future version of Dataverse"); + if (PidUtil.getPidProvider(protocol, authority, shoulder) != null) { + logger.warning( + "Legacy PID provider settings found - ignored since a provider for the same protocol, authority, shoulder has been registered"); + } else { + PidProvider legacy = null; + // Try to add a legacy provider + String identifierGenerationStyle = settingsService + .getValueForKey(SettingsServiceBean.Key.IdentifierGenerationStyle, "random"); + String dataFilePidFormat = settingsService.getValueForKey(SettingsServiceBean.Key.DataFilePIDFormat, + "DEPENDENT"); + switch (protocol) { + case "doi": + switch (provider) { + case "EZID": + + String baseUrl = JvmSettings.LEGACY_EZID_API_URL.lookup(); + String username = JvmSettings.LEGACY_EZID_USERNAME.lookup(); + String password = JvmSettings.LEGACY_EZID_PASSWORD.lookup(); + PidUtil.addToProviderList(new EZIdDOIProvider("legacy", "legacy", authority, shoulder, + identifierGenerationStyle, dataFilePidFormat, "", "", baseUrl, username, password)); + + break; + case "DataCite": + String mdsUrl = JvmSettings.LEGACY_DATACITE_MDS_API_URL.lookup(); + String restUrl = JvmSettings.LEGACY_DATACITE_REST_API_URL.lookup(); + // Defaults for testing where no account is set up + String dcUsername = JvmSettings.LEGACY_DATACITE_USERNAME.lookup(); + String dcPassword = JvmSettings.LEGACY_DATACITE_PASSWORD.lookup(); + if (mdsUrl != null && restUrl != null && dcUsername != null && dcPassword != null) { + legacy = new DataCiteDOIProvider("legacy", "legacy", authority, shoulder, + identifierGenerationStyle, dataFilePidFormat, "", "", mdsUrl, restUrl, dcUsername, + dcPassword); + } + break; + case "FAKE": + logger.warning("Adding FAKE provider"); + legacy = new FakeDOIProvider("legacy", "legacy", authority, shoulder, identifierGenerationStyle, + dataFilePidFormat, "", ""); + break; + } + break; + case "hdl": + int index = JvmSettings.LEGACY_HANDLENET_INDEX.lookup(Integer.class); + String path = JvmSettings.LEGACY_HANDLENET_KEY_PATH.lookup(); + String passphrase = JvmSettings.LEGACY_HANDLENET_KEY_PASSPHRASE.lookup(); + boolean independentHandleService = settingsService + .isTrueForKey(SettingsServiceBean.Key.IndependentHandleService, false); + String handleAuthHandle = settingsService.getValueForKey(SettingsServiceBean.Key.HandleAuthHandle); + + legacy = new HandlePidProvider("legacy", "legacy", authority, shoulder, identifierGenerationStyle, + dataFilePidFormat, "", "", index, independentHandleService, handleAuthHandle, path, + passphrase); + break; + case "perma": + String baseUrl = JvmSettings.LEGACY_PERMALINK_BASEURL.lookup(); + legacy = new PermaLinkPidProvider("legacy", "legacy", authority, shoulder, + identifierGenerationStyle, dataFilePidFormat, "", "", baseUrl, + PermaLinkPidProvider.SEPARATOR); + } + if (legacy != null) { + legacy.setPidProviderServiceBean(this); + PidUtil.addToProviderList(legacy); + } + } + logger.info("Have " + PidUtil.getManagedProviderIds().size() + " managed PID providers"); + } + PidUtil.addAllToUnmanagedProviderList(Arrays.asList(new UnmanagedDOIProvider(), + new UnmanagedHandlePidProvider(), new UnmanagedPermaLinkPidProvider())); + } + + public String getProducer() { + return dataverseService.getRootDataverseName(); + } + + public boolean isGlobalIdLocallyUnique(GlobalId globalId) { + return dvObjectService.isGlobalIdLocallyUnique(globalId); + } + + String generateNewIdentifierByStoredProcedure() { + return dvObjectService.generateNewIdentifierByStoredProcedure(); + } + + public PidProvider getDefaultPidGenerator() { + Optional pidProviderDefaultId = JvmSettings.PID_DEFAULT_PROVIDER.lookupOptional(String.class); + if (pidProviderDefaultId.isPresent()) { + return PidUtil.getPidProvider(pidProviderDefaultId.get()); + } else { + String nonNullDefaultIfKeyNotFound = ""; + String protocol = settingsService.getValueForKey(SettingsServiceBean.Key.Protocol, + nonNullDefaultIfKeyNotFound); + String authority = settingsService.getValueForKey(SettingsServiceBean.Key.Authority, + nonNullDefaultIfKeyNotFound); + String shoulder = settingsService.getValueForKey(SettingsServiceBean.Key.Shoulder, + nonNullDefaultIfKeyNotFound); + + return PidUtil.getPidProvider(protocol, authority, shoulder); + } + } +} \ No newline at end of file diff --git a/src/main/java/edu/harvard/iq/dataverse/pidproviders/PidUtil.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/PidUtil.java index 78305648f67..279f18dcd0e 100644 --- a/src/main/java/edu/harvard/iq/dataverse/pidproviders/PidUtil.java +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/PidUtil.java @@ -1,9 +1,8 @@ package edu.harvard.iq.dataverse.pidproviders; -import edu.harvard.iq.dataverse.DOIServiceBean; import edu.harvard.iq.dataverse.GlobalId; -import edu.harvard.iq.dataverse.GlobalIdServiceBean; -import edu.harvard.iq.dataverse.HandlenetServiceBean; +import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider; +import edu.harvard.iq.dataverse.pidproviders.handle.HandlePidProvider; import edu.harvard.iq.dataverse.util.BundleUtil; import java.io.IOException; import java.io.InputStream; @@ -14,6 +13,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.logging.Logger; import jakarta.json.Json; @@ -113,24 +113,22 @@ public static JsonObjectBuilder queryDoi(GlobalId globalId, String baseUrl, Stri * @return DOI in the form 10.7910/DVN/TJCLKP (no "doi:") */ private static String acceptOnlyDoi(GlobalId globalId) { - if (!DOIServiceBean.DOI_PROTOCOL.equals(globalId.getProtocol())) { + if (!AbstractDOIProvider.DOI_PROTOCOL.equals(globalId.getProtocol())) { throw new IllegalArgumentException(BundleUtil.getStringFromBundle("pids.datacite.errors.DoiOnly")); } return globalId.getAuthority() + "/" + globalId.getIdentifier(); } - static Map providerMap = new HashMap(); - static Map unmanagedProviderMap = new HashMap(); + static Map providerMap = new HashMap(); + static Map unmanagedProviderMap = new HashMap(); - public static void addAllToProviderList(List list) { - for (GlobalIdServiceBean pidProvider : list) { - providerMap.put(pidProvider.getProviderInformation().get(0), pidProvider); - } + public static void addToProviderList(PidProvider pidProvider) { + providerMap.put(pidProvider.getId(), pidProvider); } - public static void addAllToUnmanagedProviderList(List list) { - for (GlobalIdServiceBean pidProvider : list) { - unmanagedProviderMap.put(pidProvider.getProviderInformation().get(0), pidProvider); + public static void addAllToUnmanagedProviderList(List list) { + for (PidProvider pidProvider : list) { + unmanagedProviderMap.put(pidProvider.getId(), pidProvider); } } @@ -141,7 +139,7 @@ public static void addAllToUnmanagedProviderList(List list) */ public static GlobalId parseAsGlobalID(String identifier) { logger.fine("In parseAsGlobalId: " + providerMap.size()); - for (GlobalIdServiceBean pidProvider : providerMap.values()) { + for (PidProvider pidProvider : providerMap.values()) { logger.fine(" Checking " + String.join(",", pidProvider.getProviderInformation())); GlobalId globalId = pidProvider.parsePersistentId(identifier); if (globalId != null) { @@ -149,7 +147,7 @@ public static GlobalId parseAsGlobalID(String identifier) { } } // If no providers can managed this PID, at least allow it to be recognized - for (GlobalIdServiceBean pidProvider : unmanagedProviderMap.values()) { + for (PidProvider pidProvider : unmanagedProviderMap.values()) { logger.fine(" Checking " + String.join(",", pidProvider.getProviderInformation())); GlobalId globalId = pidProvider.parsePersistentId(identifier); if (globalId != null) { @@ -167,14 +165,14 @@ public static GlobalId parseAsGlobalID(String identifier) { public static GlobalId parseAsGlobalID(String protocol, String authority, String identifier) { logger.fine("Looking for " + protocol + " " + authority + " " + identifier); logger.fine("In parseAsGlobalId: " + providerMap.size()); - for (GlobalIdServiceBean pidProvider : providerMap.values()) { + for (PidProvider pidProvider : providerMap.values()) { logger.fine(" Checking " + String.join(",", pidProvider.getProviderInformation())); GlobalId globalId = pidProvider.parsePersistentId(protocol, authority, identifier); if (globalId != null) { return globalId; } } - for (GlobalIdServiceBean pidProvider : unmanagedProviderMap.values()) { + for (PidProvider pidProvider : unmanagedProviderMap.values()) { logger.fine(" Checking " + String.join(",", pidProvider.getProviderInformation())); GlobalId globalId = pidProvider.parsePersistentId(protocol, authority, identifier); if (globalId != null) { @@ -191,28 +189,96 @@ public static GlobalId parseAsGlobalID(String protocol, String authority, String * This method should be deprecated/removed when further refactoring to support * multiple PID providers is done. At that point, when the providers aren't * beans, this code can be moved into other classes that go in the providerMap. - * If this method is not kept in sync with the DOIServiceBean and - * HandlenetServiceBean implementations, the tests using it won't be valid tests - * of the production code. + * If this method is not kept in sync with the AbstractDOIProvider and HandlePidProvider + * implementations, the tests using it won't be valid tests of the production + * code. */ private static GlobalId parseUnmanagedDoiOrHandle(String protocol, String authority, String identifier) { // Default recognition - could be moved to new classes in the future. - if (!GlobalIdServiceBean.isValidGlobalId(protocol, authority, identifier)) { + if (!PidProvider.isValidGlobalId(protocol, authority, identifier)) { return null; } String urlPrefix = null; switch (protocol) { - case DOIServiceBean.DOI_PROTOCOL: - if (!GlobalIdServiceBean.checkDOIAuthority(authority)) { + case AbstractDOIProvider.DOI_PROTOCOL: + if (!PidProvider.checkDOIAuthority(authority)) { return null; } - urlPrefix = DOIServiceBean.DOI_RESOLVER_URL; + urlPrefix = AbstractDOIProvider.DOI_RESOLVER_URL; break; - case HandlenetServiceBean.HDL_PROTOCOL: - urlPrefix = HandlenetServiceBean.HDL_RESOLVER_URL; + case HandlePidProvider.HDL_PROTOCOL: + urlPrefix = HandlePidProvider.HDL_RESOLVER_URL; break; } return new GlobalId(protocol, authority, identifier, "/", urlPrefix, null); } + + /** + * Get a PidProvider by name. GlobalIds have a getProviderName() method so this + * method is often used as + * getPidProvider(dvObject.getGlobalId().getProviderName(); (which will fail if + * the GlobalId is null - use PidProviderFactoryBean.getPidProvider(DvObject) if + * you aren't sure. + * + */ + + public static PidProvider getPidProvider(String name) { + for (PidProvider pidProvider : providerMap.values()) { + if (name.equals(pidProvider.getId())) { + return pidProvider; + } + } + for (PidProvider pidProvider : unmanagedProviderMap.values()) { + if (name.equals(pidProvider.getId())) { + return pidProvider; + } + } + return null; + } + + + + /** + * Method to clear all managed/unmanaged PidProviders. Only for testing as these + * lists are only loaded once by the @Stateless PidProviderFactoryBean in Dataverse. + */ + public static void clearPidProviders() { + providerMap.clear(); + unmanagedProviderMap.clear(); + } + + /** + * Get a PidProvider by protocol/authority/shoulder. + */ + public static PidProvider getPidProvider(String protocol, String authority, String shoulder) { + return getPidProvider(protocol, authority, shoulder, AbstractPidProvider.SEPARATOR); + } + + public static PidProvider getPidProvider(String protocol, String authority, String shoulder, String separator) { + for (PidProvider pidProvider : providerMap.values()) { + if (protocol.equals(pidProvider.getProtocol()) && authority.equals(pidProvider.getAuthority()) + && shoulder.equals(pidProvider.getShoulder()) && separator.equals(pidProvider.getSeparator())) { + return pidProvider; + } + } + for (PidProvider pidProvider : unmanagedProviderMap.values()) { + if (protocol.equals(pidProvider.getProtocol())) { + return pidProvider; + } + } + return null; + } + + public static Set getManagedProviderIds() { + return providerMap.keySet(); + } + + public static JsonObject getProviders() { + JsonObjectBuilder builder = Json.createObjectBuilder(); + for (PidProvider pidProvider : providerMap.values()) { + builder.add(pidProvider.getId(), pidProvider.getProviderSpecification()); + } + return builder.build(); + } } diff --git a/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/AbstractDOIProvider.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/AbstractDOIProvider.java new file mode 100644 index 00000000000..43e34e74c59 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/AbstractDOIProvider.java @@ -0,0 +1,123 @@ +package edu.harvard.iq.dataverse.pidproviders.doi; + +import java.util.Arrays; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import edu.harvard.iq.dataverse.DataFile; +import edu.harvard.iq.dataverse.Dataset; +import edu.harvard.iq.dataverse.DatasetField; +import edu.harvard.iq.dataverse.DvObject; +import edu.harvard.iq.dataverse.GlobalId; +import edu.harvard.iq.dataverse.pidproviders.AbstractPidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; + + +public abstract class AbstractDOIProvider extends AbstractPidProvider { + + private static final Logger logger = Logger.getLogger(AbstractDOIProvider.class.getCanonicalName()); + + public static final String DOI_PROTOCOL = "doi"; + public static final String DOI_RESOLVER_URL = "https://doi.org/"; + public static final String HTTP_DOI_RESOLVER_URL = "http://doi.org/"; + public static final String DXDOI_RESOLVER_URL = "https://dx.doi.org/"; + public static final String HTTP_DXDOI_RESOLVER_URL = "http://dx.doi.org/"; + + public AbstractDOIProvider(String id, String label, String providerAuthority, String providerShoulder, String identifierGenerationStyle, String datafilePidFormat, String managedList, String excludedList) { + super(id, label, DOI_PROTOCOL, providerAuthority, providerShoulder, identifierGenerationStyle, datafilePidFormat, managedList, excludedList); + } + + //For Unmanged provider + public AbstractDOIProvider(String name, String label) { + super(name, label, DOI_PROTOCOL); + } + + @Override + public GlobalId parsePersistentId(String pidString) { + if (pidString.startsWith(DOI_RESOLVER_URL)) { + pidString = pidString.replace(DOI_RESOLVER_URL, + (DOI_PROTOCOL + ":")); + } else if (pidString.startsWith(HTTP_DOI_RESOLVER_URL)) { + pidString = pidString.replace(HTTP_DOI_RESOLVER_URL, + (DOI_PROTOCOL + ":")); + } else if (pidString.startsWith(DXDOI_RESOLVER_URL)) { + pidString = pidString.replace(DXDOI_RESOLVER_URL, + (DOI_PROTOCOL + ":")); + } + return super.parsePersistentId(pidString); + } + + @Override + public GlobalId parsePersistentId(String protocol, String identifierString) { + + if (!DOI_PROTOCOL.equals(protocol)) { + return null; + } + GlobalId globalId = super.parsePersistentId(protocol, identifierString); + if (globalId!=null && !PidProvider.checkDOIAuthority(globalId.getAuthority())) { + return null; + } + return globalId; + } + + @Override + public GlobalId parsePersistentId(String protocol, String authority, String identifier) { + + if (!DOI_PROTOCOL.equals(protocol)) { + return null; + } + return super.parsePersistentId(protocol, authority, identifier); + } + + public String getUrlPrefix() { + return DOI_RESOLVER_URL; + } + + protected String getProviderKeyName() { + return null; + } + + public String getProtocol() { + return DOI_PROTOCOL; + } + + public String getMetadataFromDvObject(String identifier, Map metadata, DvObject dvObject) { + + Dataset dataset = null; + + if (dvObject instanceof Dataset) { + dataset = (Dataset) dvObject; + } else { + dataset = (Dataset) dvObject.getOwner(); + } + + XmlMetadataTemplate metadataTemplate = new XmlMetadataTemplate(); + metadataTemplate.setIdentifier(identifier.substring(identifier.indexOf(':') + 1)); + metadataTemplate.setCreators(Arrays.asList(metadata.get("datacite.creator").split("; "))); + metadataTemplate.setAuthors(dataset.getLatestVersion().getDatasetAuthors()); + if (dvObject.isInstanceofDataset()) { + metadataTemplate.setDescription(dataset.getLatestVersion().getDescriptionPlainText()); + } + if (dvObject.isInstanceofDataFile()) { + DataFile df = (DataFile) dvObject; + String fileDescription = df.getDescription(); + metadataTemplate.setDescription(fileDescription == null ? "" : fileDescription); + } + + metadataTemplate.setContacts(dataset.getLatestVersion().getDatasetContacts()); + metadataTemplate.setProducers(dataset.getLatestVersion().getDatasetProducers()); + metadataTemplate.setTitle(dvObject.getCurrentName()); + String producerString = pidProviderService.getProducer(); + if (producerString.isEmpty() || producerString.equals(DatasetField.NA_VALUE)) { + producerString = UNAVAILABLE; + } + metadataTemplate.setPublisher(producerString); + metadataTemplate.setPublisherYear(metadata.get("datacite.publicationyear")); + + String xmlMetadata = metadataTemplate.generateXML(dvObject); + logger.log(Level.FINE, "XML to send to DataCite: {0}", xmlMetadata); + return xmlMetadata; + } + +} \ No newline at end of file diff --git a/src/main/java/edu/harvard/iq/dataverse/pidproviders/UnmanagedDOIServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/UnmanagedDOIProvider.java similarity index 73% rename from src/main/java/edu/harvard/iq/dataverse/pidproviders/UnmanagedDOIServiceBean.java rename to src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/UnmanagedDOIProvider.java index f7e9372cc9b..d4e674f8396 100644 --- a/src/main/java/edu/harvard/iq/dataverse/pidproviders/UnmanagedDOIServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/UnmanagedDOIProvider.java @@ -1,17 +1,11 @@ -package edu.harvard.iq.dataverse.pidproviders; +package edu.harvard.iq.dataverse.pidproviders.doi; import java.io.IOException; import java.util.List; import java.util.Map; -import java.util.logging.Logger; - -import jakarta.annotation.PostConstruct; -import jakarta.ejb.Stateless; - import org.apache.commons.httpclient.HttpException; import org.apache.commons.lang3.NotImplementedException; -import edu.harvard.iq.dataverse.DOIServiceBean; import edu.harvard.iq.dataverse.DvObject; import edu.harvard.iq.dataverse.GlobalId; @@ -20,15 +14,13 @@ * */ -@Stateless -public class UnmanagedDOIServiceBean extends DOIServiceBean { +public class UnmanagedDOIProvider extends AbstractDOIProvider { - private static final Logger logger = Logger.getLogger(UnmanagedDOIServiceBean.class.getCanonicalName()); + public static final String ID = "UnmanagedDOIProvider"; - @PostConstruct - private void init() { - // Always on - configured = true; + public UnmanagedDOIProvider() { + //Also using ID as label + super(ID, ID); } @Override @@ -73,11 +65,15 @@ public boolean publicizeIdentifier(DvObject dvObject) { @Override public List getProviderInformation() { - return List.of("UnmanagedDOIProvider", ""); + return List.of(getId(), ""); } + @Override + public String getProviderType() { + return "unamagedDOI"; + } // PID recognition - // Done by DOIServiceBean + // Done by AbstractDOIProvider } diff --git a/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/XmlMetadataTemplate.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/XmlMetadataTemplate.java new file mode 100644 index 00000000000..30e4dfd79cc --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/XmlMetadataTemplate.java @@ -0,0 +1,314 @@ +package edu.harvard.iq.dataverse.pidproviders.doi; + +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import edu.harvard.iq.dataverse.DataFile; +import edu.harvard.iq.dataverse.Dataset; +import edu.harvard.iq.dataverse.DatasetAuthor; +import edu.harvard.iq.dataverse.DvObject; +import edu.harvard.iq.dataverse.pidproviders.AbstractPidProvider; + +public class XmlMetadataTemplate { + + private static final Logger logger = Logger.getLogger("edu.harvard.iq.dataverse.DataCiteMetadataTemplate"); + private static String template; + + static { + try (InputStream in = XmlMetadataTemplate.class.getResourceAsStream("datacite_metadata_template.xml")) { + template = new String(in.readAllBytes(), StandardCharsets.UTF_8); + } catch (Exception e) { + logger.log(Level.SEVERE, "datacite metadata template load error"); + logger.log(Level.SEVERE, "String " + e.toString()); + logger.log(Level.SEVERE, "localized message " + e.getLocalizedMessage()); + logger.log(Level.SEVERE, "cause " + e.getCause()); + logger.log(Level.SEVERE, "message " + e.getMessage()); + } + } + + private String xmlMetadata; + private String identifier; + private List datafileIdentifiers; + private List creators; + private String title; + private String publisher; + private String publisherYear; + private List authors; + private String description; + private List contacts; + private List producers; + + public List getProducers() { + return producers; + } + + public void setProducers(List producers) { + this.producers = producers; + } + + public List getContacts() { + return contacts; + } + + public void setContacts(List contacts) { + this.contacts = contacts; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public List getAuthors() { + return authors; + } + + public void setAuthors(List authors) { + this.authors = authors; + } + + public XmlMetadataTemplate() { + } + + public List getDatafileIdentifiers() { + return datafileIdentifiers; + } + + public void setDatafileIdentifiers(List datafileIdentifiers) { + this.datafileIdentifiers = datafileIdentifiers; + } + + public XmlMetadataTemplate(String xmlMetaData) { + this.xmlMetadata = xmlMetaData; + Document doc = Jsoup.parseBodyFragment(xmlMetaData); + Elements identifierElements = doc.select("identifier"); + if (identifierElements.size() > 0) { + identifier = identifierElements.get(0).html(); + } + Elements creatorElements = doc.select("creatorName"); + creators = new ArrayList<>(); + for (Element creatorElement : creatorElements) { + creators.add(creatorElement.html()); + } + Elements titleElements = doc.select("title"); + if (titleElements.size() > 0) { + title = titleElements.get(0).html(); + } + Elements publisherElements = doc.select("publisher"); + if (publisherElements.size() > 0) { + publisher = publisherElements.get(0).html(); + } + Elements publisherYearElements = doc.select("publicationYear"); + if (publisherYearElements.size() > 0) { + publisherYear = publisherYearElements.get(0).html(); + } + } + + public String generateXML(DvObject dvObject) { + // Can't use "UNKNOWN" here because DataCite will respond with "[facet + // 'pattern'] the value 'unknown' is not accepted by the pattern '[\d]{4}'" + String publisherYearFinal = "9999"; + // FIXME: Investigate why this.publisherYear is sometimes null now that pull + // request #4606 has been merged. + if (this.publisherYear != null) { + // Added to prevent a NullPointerException when trying to destroy datasets when + // using DataCite rather than EZID. + publisherYearFinal = this.publisherYear; + } + xmlMetadata = template.replace("${identifier}", getIdentifier().trim()).replace("${title}", this.title) + .replace("${publisher}", this.publisher).replace("${publisherYear}", publisherYearFinal) + .replace("${description}", this.description); + + StringBuilder creatorsElement = new StringBuilder(); + if (authors != null && !authors.isEmpty()) { + for (DatasetAuthor author : authors) { + creatorsElement.append(""); + creatorsElement.append(author.getName().getDisplayValue()); + creatorsElement.append(""); + + if (author.getIdType() != null && author.getIdValue() != null && !author.getIdType().isEmpty() + && !author.getIdValue().isEmpty() && author.getAffiliation() != null + && !author.getAffiliation().getDisplayValue().isEmpty()) { + + if (author.getIdType().equals("ORCID")) { + creatorsElement.append( + "" + + author.getIdValue() + ""); + } + if (author.getIdType().equals("ISNI")) { + creatorsElement.append( + "" + + author.getIdValue() + ""); + } + if (author.getIdType().equals("LCNA")) { + creatorsElement.append( + "" + + author.getIdValue() + ""); + } + } + if (author.getAffiliation() != null && !author.getAffiliation().getDisplayValue().isEmpty()) { + creatorsElement + .append("" + author.getAffiliation().getDisplayValue() + ""); + } + creatorsElement.append(""); + } + + } else { + creatorsElement.append("").append(AbstractPidProvider.UNAVAILABLE) + .append(""); + } + + xmlMetadata = xmlMetadata.replace("${creators}", creatorsElement.toString()); + + StringBuilder contributorsElement = new StringBuilder(); + if (this.getContacts() != null) { + for (String[] contact : this.getContacts()) { + if (!contact[0].isEmpty()) { + contributorsElement.append("" + + contact[0] + ""); + if (!contact[1].isEmpty()) { + contributorsElement.append("" + contact[1] + ""); + } + contributorsElement.append(""); + } + } + } + + if (this.getProducers() != null) { + for (String[] producer : this.getProducers()) { + contributorsElement.append("" + producer[0] + + ""); + if (!producer[1].isEmpty()) { + contributorsElement.append("" + producer[1] + ""); + } + contributorsElement.append(""); + } + } + + String relIdentifiers = generateRelatedIdentifiers(dvObject); + + xmlMetadata = xmlMetadata.replace("${relatedIdentifiers}", relIdentifiers); + + xmlMetadata = xmlMetadata.replace("{$contributors}", contributorsElement.toString()); + return xmlMetadata; + } + + private String generateRelatedIdentifiers(DvObject dvObject) { + + StringBuilder sb = new StringBuilder(); + if (dvObject.isInstanceofDataset()) { + Dataset dataset = (Dataset) dvObject; + if (!dataset.getFiles().isEmpty() && !(dataset.getFiles().get(0).getIdentifier() == null)) { + + datafileIdentifiers = new ArrayList<>(); + for (DataFile dataFile : dataset.getFiles()) { + if (dataFile.getGlobalId() != null) { + if (sb.toString().isEmpty()) { + sb.append(""); + } + sb.append("" + + dataFile.getGlobalId() + ""); + } + } + + if (!sb.toString().isEmpty()) { + sb.append(""); + } + } + } else if (dvObject.isInstanceofDataFile()) { + DataFile df = (DataFile) dvObject; + sb.append(""); + sb.append("" + + df.getOwner().getGlobalId() + ""); + sb.append(""); + } + return sb.toString(); + } + + public void generateFileIdentifiers(DvObject dvObject) { + + if (dvObject.isInstanceofDataset()) { + Dataset dataset = (Dataset) dvObject; + + if (!dataset.getFiles().isEmpty() && !(dataset.getFiles().get(0).getIdentifier() == null)) { + + datafileIdentifiers = new ArrayList<>(); + for (DataFile dataFile : dataset.getFiles()) { + datafileIdentifiers.add(dataFile.getIdentifier()); + int x = xmlMetadata.indexOf("") - 1; + xmlMetadata = xmlMetadata.replace("{relatedIdentifier}", dataFile.getIdentifier()); + xmlMetadata = xmlMetadata.substring(0, x) + "${relatedIdentifier}" + + template.substring(x, template.length() - 1); + + } + + } else { + xmlMetadata = xmlMetadata.replace( + "${relatedIdentifier}", + ""); + } + } + } + + public static String getTemplate() { + return template; + } + + public static void setTemplate(String template) { + XmlMetadataTemplate.template = template; + } + + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + public List getCreators() { + return creators; + } + + public void setCreators(List creators) { + this.creators = creators; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getPublisher() { + return publisher; + } + + public void setPublisher(String publisher) { + this.publisher = publisher; + } + + public String getPublisherYear() { + return publisherYear; + } + + public void setPublisherYear(String publisherYear) { + this.publisherYear = publisherYear; + } + +} \ No newline at end of file diff --git a/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DOIDataCiteRegisterService.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DOIDataCiteRegisterService.java new file mode 100644 index 00000000000..0e322eace05 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DOIDataCiteRegisterService.java @@ -0,0 +1,222 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package edu.harvard.iq.dataverse.pidproviders.doi.datacite; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.commons.text.StringEscapeUtils; + +import edu.harvard.iq.dataverse.DataFile; +import edu.harvard.iq.dataverse.Dataset; +import edu.harvard.iq.dataverse.DatasetField; +import edu.harvard.iq.dataverse.DvObject; +import edu.harvard.iq.dataverse.branding.BrandingUtil; +import edu.harvard.iq.dataverse.pidproviders.AbstractPidProvider; +import edu.harvard.iq.dataverse.pidproviders.doi.XmlMetadataTemplate; + +/** + * + * @author luopc + */ +public class DOIDataCiteRegisterService { + + private static final Logger logger = Logger.getLogger(DOIDataCiteRegisterService.class.getCanonicalName()); + + + //A singleton since it, and the httpClient in it can be reused. + private DataCiteRESTfullClient client=null; + + public DOIDataCiteRegisterService(String url, String username, String password) { + client = new DataCiteRESTfullClient(url, username, password); + } + + /** + * This "reserveIdentifier" method is heavily based on the + * "registerIdentifier" method below but doesn't, this one doesn't doesn't + * register a URL, which causes the "state" of DOI to transition from + * "draft" to "findable". Here are some DataCite docs on the matter: + * + * "DOIs can exist in three states: draft, registered, and findable. DOIs + * are in the draft state when metadata have been registered, and will + * transition to the findable state when registering a URL." -- + * https://support.datacite.org/docs/mds-api-guide#doi-states + */ + public String reserveIdentifier(String identifier, Map metadata, DvObject dvObject) throws IOException { + String retString = ""; + String xmlMetadata = getMetadataFromDvObject(identifier, metadata, dvObject); + + retString = client.postMetadata(xmlMetadata); + + return retString; + } + + public String registerIdentifier(String identifier, Map metadata, DvObject dvObject) throws IOException { + String retString = ""; + String xmlMetadata = getMetadataFromDvObject(identifier, metadata, dvObject); + String target = metadata.get("_target"); + + retString = client.postMetadata(xmlMetadata); + client.postUrl(identifier.substring(identifier.indexOf(":") + 1), target); + + return retString; + } + + public String deactivateIdentifier(String identifier, Map metadata, DvObject dvObject) throws IOException { + String retString = ""; + + String metadataString = getMetadataForDeactivateIdentifier(identifier, metadata, dvObject); + retString = client.postMetadata(metadataString); + retString = client.inactiveDataset(identifier.substring(identifier.indexOf(":") + 1)); + + return retString; + } + + public static String getMetadataFromDvObject(String identifier, Map metadata, DvObject dvObject) { + + Dataset dataset = null; + + if (dvObject instanceof Dataset) { + dataset = (Dataset) dvObject; + } else { + dataset = (Dataset) dvObject.getOwner(); + } + + XmlMetadataTemplate metadataTemplate = new XmlMetadataTemplate(); + metadataTemplate.setIdentifier(identifier.substring(identifier.indexOf(':') + 1)); + metadataTemplate.setCreators(Arrays.asList(metadata.get("datacite.creator").split("; "))); + metadataTemplate.setAuthors(dataset.getLatestVersion().getDatasetAuthors()); + if (dvObject.isInstanceofDataset()) { + //While getDescriptionPlainText strips < and > from HTML, it leaves '&' (at least so we need to xml escape as well + String description = StringEscapeUtils.escapeXml10(dataset.getLatestVersion().getDescriptionPlainText()); + if (description.isEmpty() || description.equals(DatasetField.NA_VALUE)) { + description = AbstractPidProvider.UNAVAILABLE; + } + metadataTemplate.setDescription(description); + } + if (dvObject.isInstanceofDataFile()) { + DataFile df = (DataFile) dvObject; + //Note: File metadata is not escaped like dataset metadata is, so adding an xml escape here. + //This could/should be removed if the datafile methods add escaping + String fileDescription = StringEscapeUtils.escapeXml10(df.getDescription()); + metadataTemplate.setDescription(fileDescription == null ? AbstractPidProvider.UNAVAILABLE : fileDescription); + } + + metadataTemplate.setContacts(dataset.getLatestVersion().getDatasetContacts()); + metadataTemplate.setProducers(dataset.getLatestVersion().getDatasetProducers()); + String title = dvObject.getCurrentName(); + if(dvObject.isInstanceofDataFile()) { + //Note file title is not currently escaped the way the dataset title is, so adding it here. + title = StringEscapeUtils.escapeXml10(title); + } + + if (title.isEmpty() || title.equals(DatasetField.NA_VALUE)) { + title = AbstractPidProvider.UNAVAILABLE; + } + + metadataTemplate.setTitle(title); + String producerString = BrandingUtil.getRootDataverseCollectionName(); + if (producerString.isEmpty() || producerString.equals(DatasetField.NA_VALUE)) { + producerString = AbstractPidProvider.UNAVAILABLE; + } + metadataTemplate.setPublisher(producerString); + metadataTemplate.setPublisherYear(metadata.get("datacite.publicationyear")); + + String xmlMetadata = metadataTemplate.generateXML(dvObject); + logger.log(Level.FINE, "XML to send to DataCite: {0}", xmlMetadata); + return xmlMetadata; + } + + public static String getMetadataForDeactivateIdentifier(String identifier, Map metadata, DvObject dvObject) { + + XmlMetadataTemplate metadataTemplate = new XmlMetadataTemplate(); + metadataTemplate.setIdentifier(identifier.substring(identifier.indexOf(':') + 1)); + metadataTemplate.setCreators(Arrays.asList(metadata.get("datacite.creator").split("; "))); + + metadataTemplate.setDescription(AbstractPidProvider.UNAVAILABLE); + + String title =metadata.get("datacite.title"); + + System.out.print("Map metadata title: "+ metadata.get("datacite.title")); + + metadataTemplate.setAuthors(null); + + metadataTemplate.setTitle(title); + String producerString = AbstractPidProvider.UNAVAILABLE; + + metadataTemplate.setPublisher(producerString); + metadataTemplate.setPublisherYear(metadata.get("datacite.publicationyear")); + + String xmlMetadata = metadataTemplate.generateXML(dvObject); + logger.log(Level.FINE, "XML to send to DataCite: {0}", xmlMetadata); + return xmlMetadata; + } + + public String modifyIdentifier(String identifier, Map metadata, DvObject dvObject) + throws IOException { + + String xmlMetadata = getMetadataFromDvObject(identifier, metadata, dvObject); + + logger.fine("XML to send to DataCite: " + xmlMetadata); + + String status = metadata.get("_status").trim(); + String target = metadata.get("_target"); + String retString = ""; + switch (status) { + case DataCiteDOIProvider.DRAFT: + // draft DOIs aren't currently being updated after every edit - ToDo - should + // this be changed or made optional? + retString = "success to reserved " + identifier; + break; + case DataCiteDOIProvider.FINDABLE: + try { + retString = client.postMetadata(xmlMetadata); + client.postUrl(identifier.substring(identifier.indexOf(":") + 1), target); + } catch (UnsupportedEncodingException ex) { + logger.log(Level.SEVERE, null, ex); + } catch (RuntimeException rte) { + logger.log(Level.SEVERE, "Error creating DOI at DataCite: {0}", rte.getMessage()); + logger.log(Level.SEVERE, "Exception", rte); + } + break; + case DataCiteDOIProvider.REGISTERED: + retString = client.inactiveDataset(identifier.substring(identifier.indexOf(":") + 1)); + break; + } + return retString; + } + + public boolean testDOIExists(String identifier) { + boolean doiExists; + try { + doiExists = client.testDOIExists(identifier.substring(identifier.indexOf(":") + 1)); + } catch (Exception e) { + logger.log(Level.INFO, identifier, e); + return false; + } + return doiExists; + } + + Map getMetadata(String identifier) throws IOException { + Map metadata = new HashMap<>(); + try { + String xmlMetadata = client.getMetadata(identifier.substring(identifier.indexOf(":") + 1)); + XmlMetadataTemplate template = new XmlMetadataTemplate(xmlMetadata); + metadata.put("datacite.creator", String.join("; ", template.getCreators())); + metadata.put("datacite.title", template.getTitle()); + metadata.put("datacite.publisher", template.getPublisher()); + metadata.put("datacite.publicationyear", template.getPublisherYear()); + } catch (RuntimeException e) { + logger.log(Level.INFO, identifier, e); + } + return metadata; + } +} diff --git a/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DataCiteDOIProvider.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DataCiteDOIProvider.java new file mode 100644 index 00000000000..23078e2719b --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DataCiteDOIProvider.java @@ -0,0 +1,319 @@ +package edu.harvard.iq.dataverse.pidproviders.doi.datacite; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Base64; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import edu.harvard.iq.dataverse.DataFile; +import edu.harvard.iq.dataverse.Dataset; +import edu.harvard.iq.dataverse.DatasetVersion; +import edu.harvard.iq.dataverse.DvObject; +import edu.harvard.iq.dataverse.FileMetadata; +import edu.harvard.iq.dataverse.GlobalId; +import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.HttpStatus; + +/** + * + * @author luopc + */ +public class DataCiteDOIProvider extends AbstractDOIProvider { + + private static final Logger logger = Logger.getLogger(DataCiteDOIProvider.class.getCanonicalName()); + + static final String FINDABLE = "findable"; //public - published dataset versions + static final String DRAFT = "draft"; //reserved but not findable yet - draft/unpublished datasets + static final String REGISTERED = "registered"; //was findable once, not anymore - deaccessioned datasets + static final String NONE = "none"; //no record - draft/unpublished datasets where the initial request to reserve has failed + + public static final String TYPE = "datacite"; + + + private String mdsUrl; + private String apiUrl; + private String username; + private String password; + + private DOIDataCiteRegisterService doiDataCiteRegisterService; + + public DataCiteDOIProvider(String id, String label, String providerAuthority, String providerShoulder, + String identifierGenerationStyle, String datafilePidFormat, String managedList, String excludedList, + String mdsUrl, String apiUrl, String username, String password) { + super(id, label, providerAuthority, providerShoulder, identifierGenerationStyle, datafilePidFormat, managedList, + excludedList); + this.mdsUrl = mdsUrl; + this.apiUrl = apiUrl; + this.username = username; + this.password = password; + doiDataCiteRegisterService = new DOIDataCiteRegisterService(mdsUrl, username, password); + } + + @Override + public boolean registerWhenPublished() { + return false; + } + + @Override + public boolean alreadyRegistered(GlobalId pid, boolean noProviderDefault) { + logger.log(Level.FINE, "alreadyRegistered"); + if (pid == null || pid.asString().isEmpty()) { + logger.fine("No identifier sent."); + return false; + } + boolean alreadyRegistered; + String identifier = pid.asString(); + try { + alreadyRegistered = doiDataCiteRegisterService.testDOIExists(identifier); + } catch (Exception e) { + logger.log(Level.WARNING, "alreadyRegistered failed"); + return false; + } + return alreadyRegistered; + } + + @Override + public String createIdentifier(DvObject dvObject) throws Exception { + logger.log(Level.FINE, "createIdentifier"); + if (dvObject.getIdentifier() == null || dvObject.getIdentifier().isEmpty()) { + dvObject = generatePid(dvObject); + } + String identifier = getIdentifier(dvObject); + Map metadata = getMetadataForCreateIndicator(dvObject); + metadata.put("_status", DRAFT); + try { + String retString = doiDataCiteRegisterService.reserveIdentifier(identifier, metadata, dvObject); + logger.log(Level.FINE, "create DOI identifier retString : " + retString); + return retString; + } catch (Exception e) { + logger.log(Level.WARNING, "Identifier not created: create failed", e); + throw e; + } + } + + @Override + public Map getIdentifierMetadata(DvObject dvObject) { + logger.log(Level.FINE, "getIdentifierMetadata"); + String identifier = getIdentifier(dvObject); + Map metadata = new HashMap<>(); + try { + metadata = doiDataCiteRegisterService.getMetadata(identifier); + metadata.put("_status", getPidStatus(dvObject)); + } catch (Exception e) { + logger.log(Level.WARNING, "getIdentifierMetadata failed", e); + } + return metadata; + } + + /** + * Modifies the DOI metadata for a Dataset + * + * @param dvObject the dvObject whose metadata needs to be modified + * @return the Dataset identifier, or null if the modification failed + * @throws java.lang.Exception + */ + @Override + public String modifyIdentifierTargetURL(DvObject dvObject) throws Exception { + logger.log(Level.FINE, "modifyIdentifier"); + String identifier = getIdentifier(dvObject); + try { + Map metadata = getIdentifierMetadata(dvObject); + doiDataCiteRegisterService.modifyIdentifier(identifier, metadata, dvObject); + } catch (Exception e) { + logger.log(Level.WARNING, "modifyMetadata failed", e); + throw e; + } + return identifier; + } + + /* + * Deletes a DOI if it is in DRAFT/DRAFT state or removes metadata and + * changes it from PUBLIC/FINDABLE to REGISTERED. + */ + @Override + public void deleteIdentifier(DvObject dvObject) throws IOException, HttpException { + logger.log(Level.FINE, "deleteIdentifier"); + String identifier = getIdentifier(dvObject); + String idStatus = getPidStatus(dvObject); + switch (idStatus) { + case DRAFT: + logger.log(Level.FINE, "Delete status is reserved.."); + deleteDraftIdentifier(dvObject); + break; + case FINDABLE: + // if public then it has been released set to REGISTERED/unavailable and reset + // target to n2t url + Map metadata = addDOIMetadataForDestroyedDataset(dvObject); + metadata.put("_status", "registered"); + metadata.put("_target", getTargetUrl(dvObject)); + doiDataCiteRegisterService.deactivateIdentifier(identifier, metadata, dvObject); + break; + + case REGISTERED: + case NONE: + // Nothing to do + } + } + + /** + * Deletes DOI from the DataCite side, if possible. Only "draft" DOIs can be + * deleted. + */ + private void deleteDraftIdentifier(DvObject dvObject) throws IOException { + + GlobalId doi = dvObject.getGlobalId(); + /** + * Deletes the DOI from DataCite if it can. Returns 204 if PID was deleted (only + * possible for "draft" DOIs), 405 (method not allowed) if the DOI wasn't + * deleted (because it's in "findable" state, for example, 404 if the DOI wasn't + * found, and possibly other status codes such as 500 if DataCite is down. + */ + + URL url = new URL(getApiUrl() + "/dois/" + doi.getAuthority() + "/" + doi.getIdentifier()); + HttpURLConnection connection = null; + connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("DELETE"); + String userpass = getUsername() + ":" + getPassword(); + String basicAuth = "Basic " + new String(Base64.getEncoder().encode(userpass.getBytes())); + connection.setRequestProperty("Authorization", basicAuth); + int status = connection.getResponseCode(); + if (status != HttpStatus.SC_NO_CONTENT) { + logger.warning( + "Incorrect Response Status from DataCite: " + status + " : " + connection.getResponseMessage()); + throw new HttpException("Status: " + status); + } + logger.fine("deleteDoi status for " + doi.asString() + ": " + status); + } + + @Override + public boolean publicizeIdentifier(DvObject dvObject) { + logger.log(Level.FINE, "updateIdentifierStatus"); + if (dvObject.getIdentifier() == null || dvObject.getIdentifier().isEmpty()) { + dvObject = generatePid(dvObject); + } + String identifier = getIdentifier(dvObject); + Map metadata = getUpdateMetadata(dvObject); + metadata.put("_status", FINDABLE); + metadata.put("datacite.publicationyear", generateYear(dvObject)); + metadata.put("_target", getTargetUrl(dvObject)); + try { + doiDataCiteRegisterService.registerIdentifier(identifier, metadata, dvObject); + return true; + } catch (Exception e) { + logger.log(Level.WARNING, "modifyMetadata failed: " + e.getMessage(), e); + return false; + } + } + + @Override + public List getProviderInformation() { + return List.of(getId(), "https://status.datacite.org"); + } + + @Override + protected String getProviderKeyName() { + return "DataCite"; + } + + @Override + public String getProviderType() { + // TODO Auto-generated method stub + return null; + } + + public String getMdsUrl() { + return mdsUrl; + } + + public String getApiUrl() { + return apiUrl; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + /** + * Method to determine the status of a dvObject's PID. It replaces keeping a + * separate DOIDataCiteRegisterCache. We could also try to get this info from + * DataCite directly, but it appears to not be in the xml metadata return, so it + * would require another/different api call (possible ToDo). + * + * @param dvObject - Dataset or DataFile + * @return PID status - NONE, DRAFT, FINDABLE, or REGISTERED + */ + String getPidStatus(DvObject dvObject) { + String status = NONE; + if (dvObject instanceof Dataset) { + Dataset dataset = (Dataset) dvObject; + // return true, if all published versions were deaccessioned + boolean hasDeaccessionedVersions = false; + for (DatasetVersion testDsv : dataset.getVersions()) { + if (testDsv.isReleased()) { + // With any released version, we're done + return FINDABLE; + } + // Also check for draft version + if (testDsv.isDraft()) { + if (dataset.isIdentifierRegistered()) { + status = DRAFT; + // Keep interating to see if there's a released version + } + } + if (testDsv.isDeaccessioned()) { + hasDeaccessionedVersions = true; + // Keep interating to see if there's a released version + } + } + if (hasDeaccessionedVersions) { + if (dataset.isIdentifierRegistered()) { + return REGISTERED; + } + } + return status; + } else if (dvObject instanceof DataFile) { + DataFile df = (DataFile) dvObject; + // return true, if all published versions were deaccessioned + boolean isInDeaccessionedVersions = false; + for (FileMetadata fmd : df.getFileMetadatas()) { + DatasetVersion testDsv = fmd.getDatasetVersion(); + if (testDsv.isReleased()) { + // With any released version, we're done + return FINDABLE; + } + // Also check for draft version + if (testDsv.isDraft()) { + if (df.isIdentifierRegistered()) { + status = DRAFT; + // Keep interating to see if there's a released/deaccessioned version + } + } + if (testDsv.isDeaccessioned()) { + isInDeaccessionedVersions = true; + // Keep interating to see if there's a released version + } + } + if (isInDeaccessionedVersions) { + if (df.isIdentifierRegistered()) { + return REGISTERED; + } + } + + } + return status; + } + + + + +} diff --git a/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DataCiteProviderFactory.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DataCiteProviderFactory.java new file mode 100644 index 00000000000..99d13b2647c --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DataCiteProviderFactory.java @@ -0,0 +1,43 @@ +package edu.harvard.iq.dataverse.pidproviders.doi.datacite; + +import com.google.auto.service.AutoService; + +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidProviderFactory; +import edu.harvard.iq.dataverse.settings.JvmSettings; +import edu.harvard.iq.dataverse.util.SystemConfig; + +@AutoService(PidProviderFactory.class) +public class DataCiteProviderFactory implements PidProviderFactory { + + @Override + public PidProvider createPidProvider(String providerId) { + String providerType = JvmSettings.PID_PROVIDER_TYPE.lookup(providerId); + if (!providerType.equals(DataCiteDOIProvider.TYPE)) { + // Being asked to create a non-DataCite provider + return null; + } + String providerLabel = JvmSettings.PID_PROVIDER_LABEL.lookup(providerId); + String providerAuthority = JvmSettings.PID_PROVIDER_AUTHORITY.lookup(providerId); + String providerShoulder = JvmSettings.PID_PROVIDER_SHOULDER.lookupOptional(providerId).orElse(""); + String identifierGenerationStyle = JvmSettings.PID_PROVIDER_IDENTIFIER_GENERATION_STYLE + .lookupOptional(providerId).orElse("randomString"); + String datafilePidFormat = JvmSettings.PID_PROVIDER_DATAFILE_PID_FORMAT.lookupOptional(providerId) + .orElse(SystemConfig.DataFilePIDFormat.DEPENDENT.toString()); + String managedList = JvmSettings.PID_PROVIDER_MANAGED_LIST.lookupOptional(providerId).orElse(""); + String excludedList = JvmSettings.PID_PROVIDER_EXCLUDED_LIST.lookupOptional(providerId).orElse(""); + + String mdsUrl = JvmSettings.DATACITE_MDS_API_URL.lookupOptional(providerId).orElse("https://mds.test.datacite.org"); + String apiUrl = JvmSettings.DATACITE_REST_API_URL.lookupOptional(providerId).orElse("https://api.test.datacite.org"); + String username = JvmSettings.DATACITE_USERNAME.lookup(providerId); + String password = JvmSettings.DATACITE_PASSWORD.lookup(providerId); + + return new DataCiteDOIProvider(providerId, providerLabel, providerAuthority, providerShoulder, identifierGenerationStyle, + datafilePidFormat, managedList, excludedList, mdsUrl, apiUrl, username, password); + } + + public String getType() { + return DataCiteDOIProvider.TYPE; + } + +} diff --git a/src/main/java/edu/harvard/iq/dataverse/DataCiteRESTfullClient.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DataCiteRESTfullClient.java similarity index 92% rename from src/main/java/edu/harvard/iq/dataverse/DataCiteRESTfullClient.java rename to src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DataCiteRESTfullClient.java index 491f19ab36c..d185b0249b9 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DataCiteRESTfullClient.java +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DataCiteRESTfullClient.java @@ -3,7 +3,7 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package edu.harvard.iq.dataverse; +package edu.harvard.iq.dataverse.pidproviders.doi.datacite; import java.io.Closeable; @@ -45,21 +45,14 @@ public class DataCiteRESTfullClient implements Closeable { private HttpClientContext context; private String encoding = "utf-8"; - public DataCiteRESTfullClient(String url, String username, String password) throws IOException { + public DataCiteRESTfullClient(String url, String username, String password) { this.url = url; - try { - context = HttpClientContext.create(); - CredentialsProvider credsProvider = new BasicCredentialsProvider(); - credsProvider.setCredentials(new AuthScope(null, -1), - new UsernamePasswordCredentials(username, password)); - context.setCredentialsProvider(credsProvider); - - httpClient = HttpClients.createDefault(); - } catch (Exception ioe) { - close(); - logger.log(Level.SEVERE,"Fail to init Client",ioe); - throw new RuntimeException("Fail to init Client", ioe); - } + context = HttpClientContext.create(); + CredentialsProvider credsProvider = new BasicCredentialsProvider(); + credsProvider.setCredentials(new AuthScope(null, -1), new UsernamePasswordCredentials(username, password)); + context.setCredentialsProvider(credsProvider); + + httpClient = HttpClients.createDefault(); } public void close() { diff --git a/src/main/java/edu/harvard/iq/dataverse/DOIEZIdServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/ezid/EZIdDOIProvider.java similarity index 89% rename from src/main/java/edu/harvard/iq/dataverse/DOIEZIdServiceBean.java rename to src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/ezid/EZIdDOIProvider.java index 86b74b72f30..fe8f1ec9c70 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DOIEZIdServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/ezid/EZIdDOIProvider.java @@ -1,5 +1,10 @@ -package edu.harvard.iq.dataverse; +package edu.harvard.iq.dataverse.pidproviders.doi.ezid; +import edu.harvard.iq.dataverse.DataFile; +import edu.harvard.iq.dataverse.Dataset; +import edu.harvard.iq.dataverse.DvObject; +import edu.harvard.iq.dataverse.GlobalId; +import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider; import edu.harvard.iq.dataverse.settings.JvmSettings; import edu.ucsb.nceas.ezid.EZIDException; import edu.ucsb.nceas.ezid.EZIDService; @@ -13,40 +18,40 @@ * * @author skraffmiller */ -@Stateless -public class DOIEZIdServiceBean extends DOIServiceBean { +public class EZIdDOIProvider extends AbstractDOIProvider { - private static final Logger logger = Logger.getLogger(DOIEZIdServiceBean.class.getCanonicalName()); + + + private static final Logger logger = Logger.getLogger(EZIdDOIProvider.class.getCanonicalName()); EZIDService ezidService; - // This has a sane default in microprofile-config.properties - private final String baseUrl = JvmSettings.EZID_API_URL.lookup(); + public static final String TYPE = "ezid"; + + private String baseUrl; - public DOIEZIdServiceBean() { + + public EZIdDOIProvider(String id, String label, String providerAuthority, String providerShoulder, String identifierGenerationStyle, + String datafilePidFormat, String managedList, String excludedList, String baseUrl, String username, String password) { + super(id, label, providerAuthority, providerShoulder, identifierGenerationStyle, datafilePidFormat, managedList, excludedList); // Creating the service doesn't do any harm, just initializing some object data here. // Makes sure we don't run into NPEs from the other methods, but will obviously fail if the // login below does not work. - this.ezidService = new EZIDService(this.baseUrl); + this.baseUrl = baseUrl; + this.ezidService = new EZIDService(baseUrl); try { - // These have (obviously) no default, but still are optional to make the provider optional - String username = JvmSettings.EZID_USERNAME.lookupOptional().orElse(null); - String password = JvmSettings.EZID_PASSWORD.lookupOptional().orElse(null); - - if (username != null ^ password != null) { - logger.log(Level.WARNING, "You must give both username and password. Will not try to login."); - } - + if (username != null && password != null) { this.ezidService.login(username, password); - this.configured = true; + } else { + logger.log(Level.WARNING, "You must give both username and password. Will not try to login."); } } catch (EZIDException e) { // We only do the warnings here, but the object still needs to be created. // The EJB stateless thing expects this to go through, and it is requested on any // global id parsing. - logger.log(Level.WARNING, "Login failed to {0}", this.baseUrl); + logger.log(Level.WARNING, "Login failed to {0}", baseUrl); logger.log(Level.WARNING, "Exception String: {0}", e.toString()); logger.log(Level.WARNING, "Localized message: {0}", e.getLocalizedMessage()); logger.log(Level.WARNING, "Cause:", e.getCause()); @@ -227,14 +232,14 @@ private boolean updateIdentifierStatus(DvObject dvObject, String statusIn) { @Override public List getProviderInformation(){ - return List.of("EZID", this.baseUrl); + return List.of(getId(), this.baseUrl); } @Override public String createIdentifier(DvObject dvObject) throws Throwable { logger.log(Level.FINE, "createIdentifier"); if(dvObject.getIdentifier() == null || dvObject.getIdentifier().isEmpty() ){ - dvObject = generateIdentifier(dvObject); + dvObject = generatePid(dvObject); } String identifier = getIdentifier(dvObject); Map metadata = getMetadataForCreateIndicator(dvObject); @@ -271,7 +276,7 @@ public String createIdentifier(DvObject dvObject) throws Throwable { * @return A HashMap with the same values as {@code map} */ private HashMap asHashMap(Map map) { - return (map instanceof HashMap) ? (HashMap)map : new HashMap<>(map); + return (map instanceof HashMap) ? (HashMap)map : new HashMap<>(map); } @Override @@ -279,5 +284,9 @@ protected String getProviderKeyName() { return "EZID"; } + @Override + public String getProviderType() { + return TYPE; + } } diff --git a/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/ezid/EZIdProviderFactory.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/ezid/EZIdProviderFactory.java new file mode 100644 index 00000000000..95ad9bdeff0 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/ezid/EZIdProviderFactory.java @@ -0,0 +1,42 @@ +package edu.harvard.iq.dataverse.pidproviders.doi.ezid; + +import com.google.auto.service.AutoService; + +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidProviderFactory; +import edu.harvard.iq.dataverse.settings.JvmSettings; +import edu.harvard.iq.dataverse.util.SystemConfig; + +@AutoService(PidProviderFactory.class) +public class EZIdProviderFactory implements PidProviderFactory { + + @Override + public PidProvider createPidProvider(String providerId) { + String providerType = JvmSettings.PID_PROVIDER_TYPE.lookup(providerId); + if (!providerType.equals(EZIdDOIProvider.TYPE)) { + // Being asked to create a non-EZId provider + return null; + } + String providerLabel = JvmSettings.PID_PROVIDER_LABEL.lookup(providerId); + String providerAuthority = JvmSettings.PID_PROVIDER_AUTHORITY.lookup(providerId); + String providerShoulder = JvmSettings.PID_PROVIDER_SHOULDER.lookupOptional(providerId).orElse(""); + String identifierGenerationStyle = JvmSettings.PID_PROVIDER_IDENTIFIER_GENERATION_STYLE + .lookupOptional(providerId).orElse("randomString"); + String datafilePidFormat = JvmSettings.PID_PROVIDER_DATAFILE_PID_FORMAT.lookupOptional(providerId) + .orElse(SystemConfig.DataFilePIDFormat.DEPENDENT.toString()); + String managedList = JvmSettings.PID_PROVIDER_MANAGED_LIST.lookupOptional(providerId).orElse(""); + String excludedList = JvmSettings.PID_PROVIDER_EXCLUDED_LIST.lookupOptional(providerId).orElse(""); + + String baseUrl = JvmSettings.EZID_API_URL.lookupOptional(providerId).orElse("https://ezid.cdlib.org"); + String username = JvmSettings.EZID_USERNAME.lookup(providerId); + String password = JvmSettings.EZID_PASSWORD.lookup(providerId); + + return new EZIdDOIProvider(providerId, providerLabel, providerAuthority, providerShoulder, identifierGenerationStyle, datafilePidFormat, + managedList, excludedList, baseUrl, username, password); + } + + public String getType() { + return EZIdDOIProvider.TYPE; + } + +} diff --git a/src/main/java/edu/harvard/iq/dataverse/pidproviders/FakePidProviderServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/fake/FakeDOIProvider.java similarity index 59% rename from src/main/java/edu/harvard/iq/dataverse/pidproviders/FakePidProviderServiceBean.java rename to src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/fake/FakeDOIProvider.java index 3bd9d9dd022..a967fb40620 100644 --- a/src/main/java/edu/harvard/iq/dataverse/pidproviders/FakePidProviderServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/fake/FakeDOIProvider.java @@ -1,22 +1,22 @@ -package edu.harvard.iq.dataverse.pidproviders; +package edu.harvard.iq.dataverse.pidproviders.doi.fake; -import edu.harvard.iq.dataverse.DOIServiceBean; import edu.harvard.iq.dataverse.DvObject; import edu.harvard.iq.dataverse.GlobalId; +import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.logging.Logger; -import jakarta.ejb.Stateless; +public class FakeDOIProvider extends AbstractDOIProvider { -@Stateless -public class FakePidProviderServiceBean extends DOIServiceBean { + public static final String TYPE = "FAKE"; - private static final Logger logger = Logger.getLogger(FakePidProviderServiceBean.class.getCanonicalName()); + public FakeDOIProvider(String id, String label, String providerAuthority, String providerShoulder, String identifierGenerationStyle, + String datafilePidFormat, String managedList, String excludedList) { + super(id, label, providerAuthority, providerShoulder, identifierGenerationStyle, datafilePidFormat, managedList, excludedList); + } - //Only need to check locally public boolean isGlobalIdUnique(GlobalId globalId) { try { @@ -29,7 +29,7 @@ public boolean isGlobalIdUnique(GlobalId globalId) { @Override public boolean alreadyRegistered(GlobalId globalId, boolean noProviderDefault) { - boolean existsLocally = !dvObjectService.isGlobalIdLocallyUnique(globalId); + boolean existsLocally = !pidProviderService.isGlobalIdLocallyUnique(globalId); return existsLocally ? existsLocally : noProviderDefault; } @@ -40,7 +40,7 @@ public boolean registerWhenPublished() { @Override public List getProviderInformation() { - return List.of("FAKE", "https://dataverse.org"); + return List.of(getId(), "https://dataverse.org"); } @Override @@ -65,7 +65,10 @@ public void deleteIdentifier(DvObject dvo) throws Exception { } @Override - public boolean publicizeIdentifier(DvObject studyIn) { + public boolean publicizeIdentifier(DvObject dvObject) { + if(dvObject.isInstanceofDataFile() && dvObject.getGlobalId()==null) { + generatePid(dvObject); + } return true; } @@ -74,4 +77,9 @@ protected String getProviderKeyName() { return "FAKE"; } + @Override + public String getProviderType() { + return TYPE; + } + } diff --git a/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/fake/FakeProviderFactory.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/fake/FakeProviderFactory.java new file mode 100644 index 00000000000..292c39d4383 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/fake/FakeProviderFactory.java @@ -0,0 +1,38 @@ +package edu.harvard.iq.dataverse.pidproviders.doi.fake; + +import com.google.auto.service.AutoService; + +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidProviderFactory; +import edu.harvard.iq.dataverse.settings.JvmSettings; +import edu.harvard.iq.dataverse.util.SystemConfig; + +@AutoService(PidProviderFactory.class) +public class FakeProviderFactory implements PidProviderFactory { + + @Override + public PidProvider createPidProvider(String providerId) { + String providerType = JvmSettings.PID_PROVIDER_TYPE.lookup(providerId); + if (!providerType.equals(FakeDOIProvider.TYPE)) { + // Being asked to create a non-EZId provider + return null; + } + String providerLabel = JvmSettings.PID_PROVIDER_LABEL.lookup(providerId); + String providerAuthority = JvmSettings.PID_PROVIDER_AUTHORITY.lookup(providerId); + String providerShoulder = JvmSettings.PID_PROVIDER_SHOULDER.lookupOptional(providerId).orElse(""); + String identifierGenerationStyle = JvmSettings.PID_PROVIDER_IDENTIFIER_GENERATION_STYLE + .lookupOptional(providerId).orElse("randomString"); + String datafilePidFormat = JvmSettings.PID_PROVIDER_DATAFILE_PID_FORMAT.lookupOptional(providerId) + .orElse(SystemConfig.DataFilePIDFormat.DEPENDENT.toString()); + String managedList = JvmSettings.PID_PROVIDER_MANAGED_LIST.lookupOptional(providerId).orElse("");; + String excludedList = JvmSettings.PID_PROVIDER_EXCLUDED_LIST.lookupOptional(providerId).orElse("");; + + return new FakeDOIProvider(providerId, providerLabel, providerAuthority, providerShoulder, identifierGenerationStyle, + datafilePidFormat, managedList, excludedList); + } + + public String getType() { + return FakeDOIProvider.TYPE; + } + +} diff --git a/src/main/java/edu/harvard/iq/dataverse/HandlenetServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/handle/HandlePidProvider.java similarity index 87% rename from src/main/java/edu/harvard/iq/dataverse/HandlenetServiceBean.java rename to src/main/java/edu/harvard/iq/dataverse/pidproviders/handle/HandlePidProvider.java index 4942db9e7ec..2627bc76fd9 100644 --- a/src/main/java/edu/harvard/iq/dataverse/HandlenetServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/handle/HandlePidProvider.java @@ -18,10 +18,12 @@ Version 3.0. */ -package edu.harvard.iq.dataverse; +package edu.harvard.iq.dataverse.pidproviders.handle; -import edu.harvard.iq.dataverse.settings.JvmSettings; -import edu.harvard.iq.dataverse.settings.SettingsServiceBean; +import edu.harvard.iq.dataverse.Dataset; +import edu.harvard.iq.dataverse.DvObject; +import edu.harvard.iq.dataverse.GlobalId; +import edu.harvard.iq.dataverse.pidproviders.AbstractPidProvider; import java.io.File; import java.io.FileInputStream; @@ -29,8 +31,6 @@ import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; -import jakarta.ejb.EJB; -import jakarta.ejb.Stateless; import java.security.PrivateKey; /* Handlenet imports: */ @@ -60,23 +60,32 @@ * As of now, it only does the registration updates, to accommodate * the modifyRegistration datasets API sub-command. */ -@Stateless -public class HandlenetServiceBean extends AbstractGlobalIdServiceBean { - - @EJB - DataverseServiceBean dataverseService; - @EJB - SettingsServiceBean settingsService; - private static final Logger logger = Logger.getLogger(HandlenetServiceBean.class.getCanonicalName()); +public class HandlePidProvider extends AbstractPidProvider { + + private static final Logger logger = Logger.getLogger(HandlePidProvider.class.getCanonicalName()); public static final String HDL_PROTOCOL = "hdl"; - int handlenetIndex = JvmSettings.HANDLENET_INDEX.lookup(Integer.class); + public static final String TYPE = "hdl"; public static final String HTTP_HDL_RESOLVER_URL = "http://hdl.handle.net/"; public static final String HDL_RESOLVER_URL = "https://hdl.handle.net/"; + + - public HandlenetServiceBean() { - logger.log(Level.FINE,"Constructor"); - configured = true; + int handlenetIndex; + private boolean isIndependentHandleService; + private String authHandle; + private String keyPath; + private String keyPassphrase; + + public HandlePidProvider(String id, String label, String authority, String shoulder, String identifierGenerationStyle, + String datafilePidFormat, String managedList, String excludedList, int index, boolean isIndependentService, String authHandle, String path, String passphrase) { + super(id, label, HDL_PROTOCOL, authority, shoulder, identifierGenerationStyle, datafilePidFormat, managedList, excludedList); + this.handlenetIndex = index; + this.isIndependentHandleService = isIndependentService; + this.authHandle = authHandle; + this.keyPath = path; + this.keyPassphrase = passphrase; + } @Override @@ -231,10 +240,9 @@ private ResolutionRequest buildResolutionRequest(final String handle) { private PublicKeyAuthenticationInfo getAuthInfo(String handlePrefix) { logger.log(Level.FINE,"getAuthInfo"); byte[] key = null; - String adminCredFile = JvmSettings.HANDLENET_KEY_PATH.lookup(); - int handlenetIndex = JvmSettings.HANDLENET_INDEX.lookup(Integer.class); + String adminCredFile = getKeyPath(); - key = readKey(adminCredFile); + key = readKey(adminCredFile); PrivateKey privkey = null; privkey = readPrivKey(key, adminCredFile); String authHandle = getAuthenticationHandle(handlePrefix); @@ -244,8 +252,8 @@ private PublicKeyAuthenticationInfo getAuthInfo(String handlePrefix) { } private String getRegistrationUrl(DvObject dvObject) { logger.log(Level.FINE,"getRegistrationUrl"); - String siteUrl = systemConfig.getDataverseSiteUrl(); - String targetUrl = siteUrl + dvObject.getTargetUrl() + "hdl:" + dvObject.getAuthority() + String siteUrl = SystemConfig.getDataverseSiteUrlStatic(); + String targetUrl = siteUrl + dvObject.getTargetUrl() + "hdl:" + dvObject.getAuthority() + "/" + dvObject.getIdentifier(); return targetUrl; } @@ -278,8 +286,7 @@ private PrivateKey readPrivKey(byte[] key, final String file) { try { byte[] secKey = null; if ( Util.requiresSecretKey(key) ) { - String secret = JvmSettings.HANDLENET_KEY_PASSPHRASE.lookup(); - secKey = secret.getBytes(StandardCharsets.UTF_8); + secKey = getKeyPassphrase().getBytes(StandardCharsets.UTF_8); } key = Util.decrypt(key, secKey); privkey = Util.getPrivateKeyFromBytes(key, 0); @@ -304,9 +311,9 @@ private String getAuthenticationHandle(DvObject dvObject){ private String getAuthenticationHandle(String handlePrefix) { logger.log(Level.FINE,"getAuthenticationHandle"); - if (systemConfig.getHandleAuthHandle()!=null) { - return systemConfig.getHandleAuthHandle(); - } else if (systemConfig.isIndependentHandleService()) { + if (getHandleAuthHandle()!=null) { + return getHandleAuthHandle(); + } else if (isIndependentHandleService()) { return handlePrefix + "/ADMIN"; } else { return "0.NA/" + handlePrefix; @@ -348,9 +355,8 @@ public void deleteIdentifier(DvObject dvObject) throws Exception { String handle = getDvObjectHandle(dvObject); String authHandle = getAuthenticationHandle(dvObject); - String adminCredFile = JvmSettings.HANDLENET_KEY_PATH.lookup(); - int handlenetIndex = JvmSettings.HANDLENET_INDEX.lookup(Integer.class); - + String adminCredFile = getKeyPath(); + byte[] key = readKey(adminCredFile); PrivateKey privkey = readPrivKey(key, adminCredFile); @@ -383,7 +389,7 @@ private boolean updateIdentifierStatus(DvObject dvObject, String statusIn) { @Override public List getProviderInformation(){ - return List.of("Handle", "https://hdl.handle.net"); + return List.of(getId(), HDL_RESOLVER_URL); } @@ -401,7 +407,7 @@ public String createIdentifier(DvObject dvObject) throws Throwable { @Override public boolean publicizeIdentifier(DvObject dvObject) { if (dvObject.getIdentifier() == null || dvObject.getIdentifier().isEmpty()){ - generateIdentifier(dvObject); + generatePid(dvObject); } return updateIdentifierStatus(dvObject, "public"); @@ -438,6 +444,32 @@ public GlobalId parsePersistentId(String protocol, String authority, String iden public String getUrlPrefix() { return HDL_RESOLVER_URL; } + + @Override + public String getProtocol() { + return HDL_PROTOCOL; + } + + @Override + public String getProviderType() { + return TYPE; + } + + public String getKeyPath() { + return keyPath; + } + + public String getKeyPassphrase() { + return keyPassphrase; + } + + public boolean isIndependentHandleService() { + return isIndependentHandleService; + } + + public String getHandleAuthHandle() { + return authHandle; + } } diff --git a/src/main/java/edu/harvard/iq/dataverse/pidproviders/handle/HandleProviderFactory.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/handle/HandleProviderFactory.java new file mode 100644 index 00000000000..eef5bed8432 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/handle/HandleProviderFactory.java @@ -0,0 +1,45 @@ +package edu.harvard.iq.dataverse.pidproviders.handle; + +import com.google.auto.service.AutoService; + +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidProviderFactory; +import edu.harvard.iq.dataverse.settings.JvmSettings; +import edu.harvard.iq.dataverse.util.SystemConfig; + +@AutoService(PidProviderFactory.class) +public class HandleProviderFactory implements PidProviderFactory { + + @Override + public PidProvider createPidProvider(String providerId) { + String providerType = JvmSettings.PID_PROVIDER_TYPE.lookup(providerId); + if (!providerType.equals(HandlePidProvider.TYPE)) { + // Being asked to create a non-EZId provider + return null; + } + String providerLabel = JvmSettings.PID_PROVIDER_LABEL.lookup(providerId); + String providerAuthority = JvmSettings.PID_PROVIDER_AUTHORITY.lookup(providerId); + String providerShoulder = JvmSettings.PID_PROVIDER_SHOULDER.lookupOptional(providerId).orElse(""); + String identifierGenerationStyle = JvmSettings.PID_PROVIDER_IDENTIFIER_GENERATION_STYLE + .lookupOptional(providerId).orElse("randomString"); + String datafilePidFormat = JvmSettings.PID_PROVIDER_DATAFILE_PID_FORMAT.lookupOptional(providerId) + .orElse(SystemConfig.DataFilePIDFormat.DEPENDENT.toString()); + String managedList = JvmSettings.PID_PROVIDER_MANAGED_LIST.lookupOptional(providerId).orElse(""); + String excludedList = JvmSettings.PID_PROVIDER_EXCLUDED_LIST.lookupOptional(providerId).orElse(""); + + int index = JvmSettings.HANDLENET_INDEX.lookupOptional(Integer.class, providerId).orElse(300); + boolean independentHandleService = JvmSettings.HANDLENET_INDEPENDENT_SERVICE + .lookupOptional(Boolean.class, providerId).orElse(false); + String handleAuthHandle = JvmSettings.HANDLENET_AUTH_HANDLE.lookup(providerId); + String path = JvmSettings.HANDLENET_KEY_PATH.lookup(providerId); + String passphrase = JvmSettings.HANDLENET_KEY_PASSPHRASE.lookup(providerId); + return new HandlePidProvider(providerId, providerLabel, providerAuthority, providerShoulder, identifierGenerationStyle, + datafilePidFormat, managedList, excludedList, index, independentHandleService, handleAuthHandle, path, + passphrase); + } + + public String getType() { + return HandlePidProvider.TYPE; + } + +} diff --git a/src/main/java/edu/harvard/iq/dataverse/pidproviders/UnmanagedHandlenetServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/handle/UnmanagedHandlePidProvider.java similarity index 61% rename from src/main/java/edu/harvard/iq/dataverse/pidproviders/UnmanagedHandlenetServiceBean.java rename to src/main/java/edu/harvard/iq/dataverse/pidproviders/handle/UnmanagedHandlePidProvider.java index c856c5363e0..075e10d8164 100644 --- a/src/main/java/edu/harvard/iq/dataverse/pidproviders/UnmanagedHandlenetServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/handle/UnmanagedHandlePidProvider.java @@ -1,27 +1,32 @@ -package edu.harvard.iq.dataverse.pidproviders; +package edu.harvard.iq.dataverse.pidproviders.handle; -import edu.harvard.iq.dataverse.AbstractGlobalIdServiceBean; import edu.harvard.iq.dataverse.DvObject; import edu.harvard.iq.dataverse.GlobalId; -import edu.harvard.iq.dataverse.HandlenetServiceBean; +import edu.harvard.iq.dataverse.pidproviders.AbstractPidProvider; + import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; import jakarta.ejb.Stateless; import org.apache.commons.lang3.NotImplementedException; -/** This class is just used to parse Handles that are not managed by any account configured in Dataverse - * It does not implement any of the methods related to PID CRUD +/** + * This class is just used to parse Handles that are not managed by any account + * configured in Dataverse It does not implement any of the methods related to + * PID CRUD * */ -@Stateless -public class UnmanagedHandlenetServiceBean extends AbstractGlobalIdServiceBean { - private static final Logger logger = Logger.getLogger(UnmanagedHandlenetServiceBean.class.getCanonicalName()); +public class UnmanagedHandlePidProvider extends AbstractPidProvider { + + private static final Logger logger = Logger.getLogger(UnmanagedHandlePidProvider.class.getCanonicalName()); + public static final String ID = "UnmanagedHandleProvider"; - public UnmanagedHandlenetServiceBean() { + public UnmanagedHandlePidProvider() { + // Also using ID as label + super(ID, ID, HandlePidProvider.HDL_PROTOCOL); logger.log(Level.FINE, "Constructor"); - configured = true; + } @Override @@ -56,7 +61,7 @@ public void deleteIdentifier(DvObject dvObject) throws Exception { @Override public List getProviderInformation() { - return List.of("UnmanagedHandle", ""); + return List.of(getId(), ""); } @Override @@ -71,19 +76,18 @@ public boolean publicizeIdentifier(DvObject dvObject) { @Override public GlobalId parsePersistentId(String pidString) { - if (pidString.startsWith(HandlenetServiceBean.HDL_RESOLVER_URL)) { - pidString = pidString.replace(HandlenetServiceBean.HDL_RESOLVER_URL, - (HandlenetServiceBean.HDL_PROTOCOL + ":")); - } else if (pidString.startsWith(HandlenetServiceBean.HTTP_HDL_RESOLVER_URL)) { - pidString = pidString.replace(HandlenetServiceBean.HTTP_HDL_RESOLVER_URL, - (HandlenetServiceBean.HDL_PROTOCOL + ":")); + if (pidString.startsWith(HandlePidProvider.HDL_RESOLVER_URL)) { + pidString = pidString.replace(HandlePidProvider.HDL_RESOLVER_URL, (HandlePidProvider.HDL_PROTOCOL + ":")); + } else if (pidString.startsWith(HandlePidProvider.HTTP_HDL_RESOLVER_URL)) { + pidString = pidString.replace(HandlePidProvider.HTTP_HDL_RESOLVER_URL, + (HandlePidProvider.HDL_PROTOCOL + ":")); } return super.parsePersistentId(pidString); } @Override public GlobalId parsePersistentId(String protocol, String identifierString) { - if (!HandlenetServiceBean.HDL_PROTOCOL.equals(protocol)) { + if (!HandlePidProvider.HDL_PROTOCOL.equals(protocol)) { return null; } GlobalId globalId = super.parsePersistentId(protocol, identifierString); @@ -92,7 +96,7 @@ public GlobalId parsePersistentId(String protocol, String identifierString) { @Override public GlobalId parsePersistentId(String protocol, String authority, String identifier) { - if (!HandlenetServiceBean.HDL_PROTOCOL.equals(protocol)) { + if (!HandlePidProvider.HDL_PROTOCOL.equals(protocol)) { return null; } return super.parsePersistentId(protocol, authority, identifier); @@ -100,6 +104,11 @@ public GlobalId parsePersistentId(String protocol, String authority, String iden @Override public String getUrlPrefix() { - return HandlenetServiceBean.HDL_RESOLVER_URL; + return HandlePidProvider.HDL_RESOLVER_URL; + } + + @Override + public String getProviderType() { + return "unamagedHandle"; } } diff --git a/src/main/java/edu/harvard/iq/dataverse/pidproviders/perma/PermaLinkPidProvider.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/perma/PermaLinkPidProvider.java new file mode 100644 index 00000000000..91c7f527c88 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/perma/PermaLinkPidProvider.java @@ -0,0 +1,201 @@ +package edu.harvard.iq.dataverse.pidproviders.perma; + +import edu.harvard.iq.dataverse.DvObject; +import edu.harvard.iq.dataverse.GlobalId; +import edu.harvard.iq.dataverse.pidproviders.AbstractPidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.settings.JvmSettings; +import edu.harvard.iq.dataverse.util.SystemConfig; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +/** + * PermaLink provider This is a minimalist permanent ID provider intended for + * use with 'real' datasets/files where the use case none-the-less doesn't lend + * itself to the use of DOIs or Handles, e.g. * due to cost * for a + * catalog/archive where Dataverse has a dataset representing a dataset with + * DOI/handle stored elsewhere + * + * The initial implementation will mint identifiers locally and will provide the + * existing page URLs (using the ?persistentID= format). This will be + * overridable by a configurable parameter to support use of an external + * resolver. + * + */ +public class PermaLinkPidProvider extends AbstractPidProvider { + + private static final Logger logger = Logger.getLogger(PermaLinkPidProvider.class.getCanonicalName()); + + public static final String PERMA_PROTOCOL = "perma"; + public static final String TYPE = "perma"; + public static final String SEPARATOR = ""; + + // ToDo - remove + @Deprecated + public static final String PERMA_RESOLVER_URL = JvmSettings.PERMALINK_BASE_URL.lookupOptional("permalink") + .orElse(SystemConfig.getDataverseSiteUrlStatic()); + + + private String separator = SEPARATOR; + + private String baseUrl; + + public PermaLinkPidProvider(String id, String label, String providerAuthority, String providerShoulder, String identifierGenerationStyle, + String datafilePidFormat, String managedList, String excludedList, String baseUrl, String separator) { + super(id, label, PERMA_PROTOCOL, providerAuthority, providerShoulder, identifierGenerationStyle, datafilePidFormat, + managedList, excludedList); + this.baseUrl = baseUrl; + this.separator = separator; + } + + @Override + public String getSeparator() { + return separator; + } + + @Override + public boolean alreadyRegistered(GlobalId globalId, boolean noProviderDefault) { + // Perma doesn't manage registration, so we assume all local PIDs can be treated + // as registered + boolean existsLocally = !pidProviderService.isGlobalIdLocallyUnique(globalId); + return existsLocally ? existsLocally : noProviderDefault; + } + + @Override + public boolean registerWhenPublished() { + return false; + } + + @Override + public List getProviderInformation() { + return List.of(getId(), getBaseUrl()); + } + + @Override + public String createIdentifier(DvObject dvo) throws Throwable { + // Call external resolver and send landing URL? + // FWIW: Return value appears to only be used in RegisterDvObjectCommand where + // success requires finding the dvo identifier in this string. (Also logged a + // couple places). + return (dvo.getGlobalId().asString()); + } + + @Override + public Map getIdentifierMetadata(DvObject dvo) { + Map map = new HashMap<>(); + return map; + } + + @Override + public String modifyIdentifierTargetURL(DvObject dvo) throws Exception { + return getTargetUrl(dvo); + } + + @Override + public void deleteIdentifier(DvObject dvo) throws Exception { + // no-op + } + + @Override + public boolean publicizeIdentifier(DvObject dvObject) { + // Generate if needed (i.e. datafile case where we don't create/register early + // (even with registerWhenPublished == false)) + if (dvObject.getIdentifier() == null || dvObject.getIdentifier().isEmpty()) { + dvObject = generatePid(dvObject); + } + // Call external resolver and send landing URL? + return true; + } + + @Override + public GlobalId parsePersistentId(String pidString) { + // ToDo - handle local PID resolver for dataset/file + logger.info("Parsing in Perma: " + pidString); + if (pidString.startsWith(getUrlPrefix())) { + pidString = pidString.replace(getUrlPrefix(), (PERMA_PROTOCOL + ":")); + } + return super.parsePersistentId(pidString); + } + + @Override + public GlobalId parsePersistentId(String protocol, String identifierString) { + logger.info("Checking Perma: " + identifierString); + if (!PERMA_PROTOCOL.equals(protocol)) { + return null; + } + String cleanIdentifier = PERMA_PROTOCOL + ":" + identifierString; + // With permalinks, we have to check the sets before parsing since the permalinks in these sets could have different authority, spearator, and shoulders + if (getExcludedSet().contains(cleanIdentifier)) { + return null; + } + if(getManagedSet().contains(cleanIdentifier)) { + /** With a variable separator that could also be empty, there is no way to determine the authority and shoulder for an unknown permalink. + * Since knowing this split isn't relevant for permalinks except for minting, the code below just assumes the authority + * is the first 4 characters and that the separator and the shoulder are empty. + * If this is found to cause issues, users should be able to use a managed permalink provider as a work-around. The code here could + * be changed to allow default lengths for the authority, separator, and shoulder and/or to add a list of known (but unmanaged) authority, separator, shoulder combos. + */ + if(identifierString.length() < 4) { + return new GlobalId(protocol, "", identifierString, SEPARATOR, getUrlPrefix(), + getId()); + } + return new GlobalId(protocol, identifierString.substring(0,4), identifierString.substring(4), SEPARATOR, getUrlPrefix(), + getId()); + } + String identifier = null; + if (getAuthority() != null) { + if (identifierString.startsWith(getAuthority())) { + identifier = identifierString.substring(getAuthority().length()); + } else { + //Doesn't match authority + return null; + } + if (identifier.startsWith(separator)) { + identifier = identifier.substring(separator.length()); + } else { + //Doesn't match separator + return null; + } + } + identifier = PidProvider.formatIdentifierString(identifier); + if (PidProvider.testforNullTerminator(identifier)) { + return null; + } + if(!identifier.startsWith(getShoulder())) { + //Doesn't match shoulder + return null; + } + return new GlobalId(PERMA_PROTOCOL, getAuthority(), identifier, separator, getUrlPrefix(), getId()); + } + + @Override + public GlobalId parsePersistentId(String protocol, String authority, String identifier) { + if (!PERMA_PROTOCOL.equals(protocol)) { + return null; + } + return super.parsePersistentId(protocol, authority, identifier); + } + + @Override + public String getUrlPrefix() { + + return getBaseUrl() + "/citation?persistentId=" + PERMA_PROTOCOL + ":"; + } + + @Override + public String getProtocol() { + return PERMA_PROTOCOL; + } + + @Override + public String getProviderType() { + return PERMA_PROTOCOL; + } + + public String getBaseUrl() { + return baseUrl; + } +} diff --git a/src/main/java/edu/harvard/iq/dataverse/pidproviders/perma/PermaLinkProviderFactory.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/perma/PermaLinkProviderFactory.java new file mode 100644 index 00000000000..32b89223062 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/perma/PermaLinkProviderFactory.java @@ -0,0 +1,43 @@ +package edu.harvard.iq.dataverse.pidproviders.perma; + +import com.google.auto.service.AutoService; + +import edu.harvard.iq.dataverse.pidproviders.PidProvider; +import edu.harvard.iq.dataverse.pidproviders.PidProviderFactory; +import edu.harvard.iq.dataverse.settings.JvmSettings; +import edu.harvard.iq.dataverse.util.SystemConfig; + +@AutoService(PidProviderFactory.class) +public class PermaLinkProviderFactory implements PidProviderFactory { + + @Override + public PidProvider createPidProvider(String providerId) { + String providerType = JvmSettings.PID_PROVIDER_TYPE.lookup(providerId); + if (!providerType.equals(PermaLinkPidProvider.TYPE)) { + // Being asked to create a non-EZId provider + return null; + } + String providerLabel = JvmSettings.PID_PROVIDER_LABEL.lookup(providerId); + String providerAuthority = JvmSettings.PID_PROVIDER_AUTHORITY.lookup(providerId); + String providerShoulder = JvmSettings.PID_PROVIDER_SHOULDER.lookupOptional(providerId).orElse(""); + String identifierGenerationStyle = JvmSettings.PID_PROVIDER_IDENTIFIER_GENERATION_STYLE + .lookupOptional(providerId).orElse("randomString"); + String datafilePidFormat = JvmSettings.PID_PROVIDER_DATAFILE_PID_FORMAT.lookupOptional(providerId) + .orElse(SystemConfig.DataFilePIDFormat.DEPENDENT.toString()); + String managedList = JvmSettings.PID_PROVIDER_MANAGED_LIST.lookupOptional(providerId).orElse(""); + String excludedList = JvmSettings.PID_PROVIDER_EXCLUDED_LIST.lookupOptional(providerId).orElse(""); + + String baseUrl = JvmSettings.PERMALINK_BASE_URL.lookupOptional(providerId) + .orElse(SystemConfig.getDataverseSiteUrlStatic()); + ; + String separator = JvmSettings.PERMALINK_SEPARATOR.lookupOptional(providerId).orElse(""); + + return new PermaLinkPidProvider(providerId, providerLabel, providerAuthority, providerShoulder, identifierGenerationStyle, + datafilePidFormat, managedList, excludedList, baseUrl, separator); + } + + public String getType() { + return PermaLinkPidProvider.TYPE; + } + +} diff --git a/src/main/java/edu/harvard/iq/dataverse/pidproviders/perma/UnmanagedPermaLinkPidProvider.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/perma/UnmanagedPermaLinkPidProvider.java new file mode 100644 index 00000000000..b7961a41c50 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/perma/UnmanagedPermaLinkPidProvider.java @@ -0,0 +1,114 @@ +package edu.harvard.iq.dataverse.pidproviders.perma; + +import edu.harvard.iq.dataverse.DvObject; +import edu.harvard.iq.dataverse.GlobalId; +import edu.harvard.iq.dataverse.pidproviders.AbstractPidProvider; +import edu.harvard.iq.dataverse.util.SystemConfig; + +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; +import jakarta.ejb.Stateless; +import org.apache.commons.lang3.NotImplementedException; + +/** This class is just used to parse Handles that are not managed by any account configured in Dataverse + * It does not implement any of the methods related to PID CRUD + * + */ +public class UnmanagedPermaLinkPidProvider extends AbstractPidProvider { + + private static final Logger logger = Logger.getLogger(UnmanagedPermaLinkPidProvider.class.getCanonicalName()); + public static final String ID = "UnmanagedPermaLinkProvider"; + + public UnmanagedPermaLinkPidProvider() { + // Also using ID as label + super(ID, ID, PermaLinkPidProvider.PERMA_PROTOCOL); + logger.log(Level.FINE, "Constructor"); + } + + @Override + public boolean canManagePID() { + return false; + } + + @Override + public boolean registerWhenPublished() { + throw new NotImplementedException(); + } + + @Override + public boolean alreadyRegistered(GlobalId pid, boolean noProviderDefault) throws Exception { + throw new NotImplementedException(); + } + + @Override + public Map getIdentifierMetadata(DvObject dvObject) { + throw new NotImplementedException(); + } + + @Override + public String modifyIdentifierTargetURL(DvObject dvObject) throws Exception { + throw new NotImplementedException(); + } + + @Override + public void deleteIdentifier(DvObject dvObject) throws Exception { + throw new NotImplementedException(); + } + + @Override + public List getProviderInformation() { + return List.of(getId(), ""); + } + + @Override + public String createIdentifier(DvObject dvObject) throws Throwable { + throw new NotImplementedException(); + } + + @Override + public boolean publicizeIdentifier(DvObject dvObject) { + throw new NotImplementedException(); + } + + @Override + public GlobalId parsePersistentId(String protocol, String identifierString) { + if (!PermaLinkPidProvider.PERMA_PROTOCOL.equals(protocol)) { + return null; + } + /** With a variable separator that could also be empty, there is no way to determine the authority and shoulder for an unknown/unmanaged permalink. + * Since knowing this split isn't relevant for unmanaged permalinks, the code below just assumes the authority + * is the first 4 characters and that the separator and the shoulder are empty. + * If this is found to cause issues, users should be able to use a managed permalink provider as a work-around. The code here could + * be changed to allow default lengths for the authority, separator, and shoulder and/or to add a list of known (but unmanaged) authority, separator, shoulder combos. + */ + if(identifierString.length() < 4) { + logger.warning("A short unmanaged permalink was found - assuming the authority is empty: " + identifierString); + return super.parsePersistentId(protocol, "", identifierString); + } + return super.parsePersistentId(protocol, identifierString.substring(0, 4), identifierString.substring(4)); + } + + @Override + public GlobalId parsePersistentId(String protocol, String authority, String identifier) { + if (!PermaLinkPidProvider.PERMA_PROTOCOL.equals(protocol)) { + return null; + } + return super.parsePersistentId(protocol, authority, identifier); + } + + @Override + public String getUrlPrefix() { + return SystemConfig.getDataverseSiteUrlStatic()+ "/citation?persistentId=" + PermaLinkPidProvider.PERMA_PROTOCOL + ":"; + } + + @Override + public String getProviderType() { + return PermaLinkPidProvider.TYPE; + } + + @Override + public String getSeparator() { + return PermaLinkPidProvider.SEPARATOR; + } +} diff --git a/src/main/java/edu/harvard/iq/dataverse/settings/ConfigCheckService.java b/src/main/java/edu/harvard/iq/dataverse/settings/ConfigCheckService.java index a2c3f53d59d..7ca5fe04bcd 100644 --- a/src/main/java/edu/harvard/iq/dataverse/settings/ConfigCheckService.java +++ b/src/main/java/edu/harvard/iq/dataverse/settings/ConfigCheckService.java @@ -1,5 +1,6 @@ package edu.harvard.iq.dataverse.settings; +import edu.harvard.iq.dataverse.pidproviders.PidUtil; import edu.harvard.iq.dataverse.util.FileUtil; import jakarta.annotation.PostConstruct; @@ -16,9 +17,10 @@ @Startup @Singleton -@DependsOn("StartupFlywayMigrator") +@DependsOn({"StartupFlywayMigrator", "PidProviderFactoryBean"}) public class ConfigCheckService { + private static final Logger logger = Logger.getLogger(ConfigCheckService.class.getCanonicalName()); public static class ConfigurationError extends RuntimeException { @@ -29,11 +31,13 @@ public ConfigurationError(String message) { @PostConstruct public void startup() { - if (!checkSystemDirectories()) { + if (!checkSystemDirectories() || !checkPidProviders()) { throw new ConfigurationError("Not all configuration checks passed successfully. See logs above."); } } + + /** * In this method, we check the existence and write-ability of all important directories we use during * normal operations. It does not include checks for the storage system. If directories are not available, @@ -78,4 +82,14 @@ public boolean checkSystemDirectories() { return success; } + /** + * Verifies that at least one PidProvider capable of editing/minting PIDs is + * configured. Requires the @DependsOn("PidProviderFactoryBean") annotation above + * since it is the @PostCOnstruct init() method of that class that loads the PidProviders + * + * @return True if all checks successful, false otherwise. + */ + private boolean checkPidProviders() { + return PidUtil.getManagedProviderIds().size() > 0; + } } diff --git a/src/main/java/edu/harvard/iq/dataverse/settings/JvmSettings.java b/src/main/java/edu/harvard/iq/dataverse/settings/JvmSettings.java index 3bc06738a7e..b92618dab89 100644 --- a/src/main/java/edu/harvard/iq/dataverse/settings/JvmSettings.java +++ b/src/main/java/edu/harvard/iq/dataverse/settings/JvmSettings.java @@ -91,35 +91,101 @@ public enum JvmSettings { // PERSISTENT IDENTIFIER SETTINGS SCOPE_PID(PREFIX, "pid"), - - // PROVIDER EZID (legacy) - these settings were formerly kept together with DataCite ones - SCOPE_PID_EZID(SCOPE_PID, "ezid"), - EZID_API_URL(SCOPE_PID_EZID, "api-url", "doi.baseurlstring"), - EZID_USERNAME(SCOPE_PID_EZID, "username", "doi.username"), - EZID_PASSWORD(SCOPE_PID_EZID, "password", "doi.password"), + PID_PROVIDERS(SCOPE_PID, "providers"), + PID_DEFAULT_PROVIDER(SCOPE_PID, "default-provider"), + SCOPE_PID_PROVIDER(SCOPE_PID), + PID_PROVIDER_TYPE(SCOPE_PID_PROVIDER, "type"), + PID_PROVIDER_LABEL(SCOPE_PID_PROVIDER, "label"), + PID_PROVIDER_AUTHORITY(SCOPE_PID_PROVIDER, "authority"), + PID_PROVIDER_SHOULDER(SCOPE_PID_PROVIDER, "shoulder"), + PID_PROVIDER_IDENTIFIER_GENERATION_STYLE(SCOPE_PID_PROVIDER, "identifier-generation-style"), + PID_PROVIDER_DATAFILE_PID_FORMAT(SCOPE_PID_PROVIDER, "datafile-pid-format"), + PID_PROVIDER_MANAGED_LIST(SCOPE_PID_PROVIDER, "managed-list"), + PID_PROVIDER_EXCLUDED_LIST(SCOPE_PID_PROVIDER, "excluded-list"), + + + // PROVIDER EZID - these settings were formerly kept together with DataCite ones + SCOPE_PID_EZID(SCOPE_PID_PROVIDER, "ezid"), + EZID_API_URL(SCOPE_PID_EZID, "api-url"), + EZID_USERNAME(SCOPE_PID_EZID, "username"), + EZID_PASSWORD(SCOPE_PID_EZID, "password"), // PROVIDER DATACITE - SCOPE_PID_DATACITE(SCOPE_PID, "datacite"), - DATACITE_MDS_API_URL(SCOPE_PID_DATACITE, "mds-api-url", "doi.baseurlstring"), - DATACITE_REST_API_URL(SCOPE_PID_DATACITE, "rest-api-url", "doi.dataciterestapiurlstring", "doi.mdcbaseurlstring"), - DATACITE_USERNAME(SCOPE_PID_DATACITE, "username", "doi.username"), - DATACITE_PASSWORD(SCOPE_PID_DATACITE, "password", "doi.password"), + SCOPE_PID_DATACITE(SCOPE_PID_PROVIDER, "datacite"), + DATACITE_MDS_API_URL(SCOPE_PID_DATACITE, "mds-api-url"), + DATACITE_REST_API_URL(SCOPE_PID_DATACITE, "rest-api-url"), + DATACITE_USERNAME(SCOPE_PID_DATACITE, "username"), + DATACITE_PASSWORD(SCOPE_PID_DATACITE, "password"), // PROVIDER PERMALINK - SCOPE_PID_PERMALINK(SCOPE_PID, "permalink"), - PERMALINK_BASEURL(SCOPE_PID_PERMALINK, "base-url", "perma.baseurlstring"), + SCOPE_PID_PERMALINK(SCOPE_PID_PROVIDER, "permalink"), + PERMALINK_BASE_URL(SCOPE_PID_PERMALINK, "base-url"), + PERMALINK_SEPARATOR(SCOPE_PID_PERMALINK, "separator"), // PROVIDER HANDLE - SCOPE_PID_HANDLENET(SCOPE_PID, "handlenet"), - HANDLENET_INDEX(SCOPE_PID_HANDLENET, "index", "dataverse.handlenet.index"), + SCOPE_PID_HANDLENET(SCOPE_PID_PROVIDER, "handlenet"), + HANDLENET_INDEX(SCOPE_PID_HANDLENET, "index"), + HANDLENET_INDEPENDENT_SERVICE(SCOPE_PID_HANDLENET, "independent-service"), + HANDLENET_AUTH_HANDLE(SCOPE_PID_HANDLENET, "auth-handle"), SCOPE_PID_HANDLENET_KEY(SCOPE_PID_HANDLENET, "key"), - HANDLENET_KEY_PATH(SCOPE_PID_HANDLENET_KEY, "path", "dataverse.handlenet.admcredfile"), - HANDLENET_KEY_PASSPHRASE(SCOPE_PID_HANDLENET_KEY, "passphrase", "dataverse.handlenet.admprivphrase"), + HANDLENET_KEY_PATH(SCOPE_PID_HANDLENET_KEY, "path"), + HANDLENET_KEY_PASSPHRASE(SCOPE_PID_HANDLENET_KEY, "passphrase"), + + /* + * The deprecated legacy settings below are from when you could only have a + * single PIDProvider. They mirror the settings above, but are global,not within + * the SCOPE_PID_PROVIDER of an individual provider. + */ + /** + * DEPRECATED PROVIDER DATACITE + * + * @deprecated - legacy single provider setting providing backward compatibility + */ + @Deprecated(forRemoval = true, since = "2024-02-13") + SCOPE_LEGACY_PID_DATACITE(SCOPE_PID, "datacite"), + LEGACY_DATACITE_MDS_API_URL(SCOPE_LEGACY_PID_DATACITE, "mds-api-url", "doi.baseurlstring"), + LEGACY_DATACITE_REST_API_URL(SCOPE_LEGACY_PID_DATACITE, "rest-api-url", "doi.dataciterestapiurlstring", + "doi.mdcbaseurlstring"), + LEGACY_DATACITE_USERNAME(SCOPE_LEGACY_PID_DATACITE, "username", "doi.username"), + LEGACY_DATACITE_PASSWORD(SCOPE_LEGACY_PID_DATACITE, "password", "doi.password"), + + /** + * DEPRECATED PROVIDER EZID + * + * @deprecated - legacy single provider setting providing backward compatibility + */ + @Deprecated(forRemoval = true, since = "2024-02-13") + SCOPE_LEGACY_PID_EZID(SCOPE_PID, "ezid"), LEGACY_EZID_API_URL(SCOPE_LEGACY_PID_EZID, "api-url"), + LEGACY_EZID_USERNAME(SCOPE_LEGACY_PID_EZID, "username"), LEGACY_EZID_PASSWORD(SCOPE_LEGACY_PID_EZID, "password"), + + /** + * DEPRECATED PROVIDER PERMALINK + * + * @deprecated - legacy single provider setting providing backward compatibility + */ + @Deprecated(forRemoval = true, since = "2024-02-13") + SCOPE_LEGACY_PID_PERMALINK(SCOPE_PID, "permalink"), + LEGACY_PERMALINK_BASEURL(SCOPE_LEGACY_PID_PERMALINK, "base-url", "perma.baseurlstring"), + + /** + * DEPRECATED PROVIDER HANDLE + * + * @deprecated - legacy single provider setting providing backward compatibility + */ + @Deprecated(forRemoval = true, since = "2024-02-13") + SCOPE_LEGACY_PID_HANDLENET(SCOPE_PID, "handlenet"), + LEGACY_HANDLENET_INDEX(SCOPE_LEGACY_PID_HANDLENET, "index", "dataverse.handlenet.index"), + @Deprecated(forRemoval = true, since = "2024-02-13") + SCOPE_LEGACY_PID_HANDLENET_KEY(SCOPE_LEGACY_PID_HANDLENET, "key"), + LEGACY_HANDLENET_KEY_PATH(SCOPE_LEGACY_PID_HANDLENET_KEY, "path", "dataverse.handlenet.admcredfile"), + LEGACY_HANDLENET_KEY_PASSPHRASE(SCOPE_LEGACY_PID_HANDLENET_KEY, "passphrase", "dataverse.handlenet.admprivphrase"), // SPI SETTINGS SCOPE_SPI(PREFIX, "spi"), SCOPE_EXPORTERS(SCOPE_SPI, "exporters"), EXPORTERS_DIRECTORY(SCOPE_EXPORTERS, "directory"), + SCOPE_PIDPROVIDERS(SCOPE_SPI, "pidproviders"), + PIDPROVIDERS_DIRECTORY(SCOPE_PIDPROVIDERS, "directory"), // MAIL SETTINGS SCOPE_MAIL(PREFIX, "mail"), diff --git a/src/main/java/edu/harvard/iq/dataverse/settings/SettingsServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/settings/SettingsServiceBean.java index 3b7632f3d9e..b05c88c0be2 100644 --- a/src/main/java/edu/harvard/iq/dataverse/settings/SettingsServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/settings/SettingsServiceBean.java @@ -87,6 +87,15 @@ public enum Key { * StorageSite database table. */ LocalDataAccessPath, + /** + * The algorithm used to generate PIDs, randomString (default) or + * storedProcedure + * + * @deprecated New installations should not use this database setting, but use + * the settings within {@link JvmSettings#SCOPE_PID}. + * + */ + @Deprecated(forRemoval = true, since = "2024-02-13") IdentifierGenerationStyle, OAuth2CallbackUrl, DefaultAuthProvider, @@ -189,19 +198,42 @@ public enum Key { SignUpUrl, /** Key for whether we allow users to sign up */ AllowSignUp, - /** protocol for global id */ + /** + * protocol for global id + * + * @deprecated New installations should not use this database setting, but use + * the settings within {@link JvmSettings#SCOPE_PID}. + * + */ + @Deprecated(forRemoval = true, since = "2024-02-13") Protocol, - /** authority for global id */ + /** + * authority for global id + * + * @deprecated New installations should not use this database setting, but use + * the settings within {@link JvmSettings#SCOPE_PID}. + * + */ + @Deprecated(forRemoval = true, since = "2024-02-13") Authority, - /** DoiProvider for global id */ + /** + * DoiProvider for global id + * + * @deprecated New installations should not use this database setting, but use + * the settings within {@link JvmSettings#SCOPE_PID}. + * + */ + @Deprecated(forRemoval = true, since = "2024-02-13") DoiProvider, - /** Shoulder for global id - used to create a common prefix on identifiers */ + /** + * Shoulder for global id - used to create a common prefix on identifiers + * + * @deprecated New installations should not use this database setting, but use + * the settings within {@link JvmSettings#SCOPE_PID}. + * + */ + @Deprecated(forRemoval = true, since = "2024-02-13") Shoulder, - /* Removed for now - tried to add here but DOI Service Bean didn't like it at start-up - DoiUsername, - DoiPassword, - DoiBaseurlstring, - */ /** Optionally override http://guides.dataverse.org . */ GuidesBaseUrl, @@ -347,10 +379,16 @@ Whether Harvesting (OAI) service is enabled */ PVCustomPasswordResetAlertMessage, /* - String to describe DOI format for data files. Default is DEPENDENT. - 'DEPENEDENT' means the DOI will be the Dataset DOI plus a file DOI with a slash in between. - 'INDEPENDENT' means a new global id, completely independent from the dataset-level global id. - */ + * String to describe DOI format for data files. Default is DEPENDENT. + * 'DEPENDENT' means the DOI will be the Dataset DOI plus a file DOI with a + * slash in between. 'INDEPENDENT' means a new global id, completely independent + * from the dataset-level global id. + * + * @deprecated New installations should not use this database setting, but use + * the settings within {@link JvmSettings#SCOPE_PID}. + * + */ + @Deprecated(forRemoval = true, since = "2024-02-13") DataFilePIDFormat, /* Json array of supported languages */ @@ -358,7 +396,7 @@ Whether Harvesting (OAI) service is enabled /* Number for the minimum number of files to send PID registration to asynchronous workflow */ - PIDAsynchRegFileCount, + //PIDAsynchRegFileCount, /** * */ @@ -366,12 +404,22 @@ Whether Harvesting (OAI) service is enabled /** * Indicates if the Handle service is setup to work 'independently' (No communication with the Global Handle Registry) + * + * @deprecated New installations should not use this database setting, but use + * the settings within {@link JvmSettings#SCOPE_PID}. + * */ + @Deprecated(forRemoval = true, since = "2024-02-13") IndependentHandleService, /** Handle to use for authentication if the default is not being used - */ + * + * @deprecated New installations should not use this database setting, but use + * the settings within {@link JvmSettings#SCOPE_PID}. + * + */ + @Deprecated(forRemoval = true, since = "2024-02-13") HandleAuthHandle, /** diff --git a/src/main/java/edu/harvard/iq/dataverse/util/SystemConfig.java b/src/main/java/edu/harvard/iq/dataverse/util/SystemConfig.java index ded394833f1..3f1ec3dd7eb 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/SystemConfig.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/SystemConfig.java @@ -966,25 +966,6 @@ public Integer getUploadMethodCount(){ return Arrays.asList(uploadMethods.toLowerCase().split("\\s*,\\s*")).size(); } } - public boolean isDataFilePIDSequentialDependent(){ - String doiIdentifierType = settingsService.getValueForKey(SettingsServiceBean.Key.IdentifierGenerationStyle, "randomString"); - String doiDataFileFormat = settingsService.getValueForKey(SettingsServiceBean.Key.DataFilePIDFormat, "DEPENDENT"); - if (doiIdentifierType.equals("storedProcGenerated") && doiDataFileFormat.equals("DEPENDENT")){ - return true; - } - return false; - } - - public int getPIDAsynchRegFileCount() { - String fileCount = settingsService.getValueForKey(SettingsServiceBean.Key.PIDAsynchRegFileCount, "10"); - int retVal = 10; - try { - retVal = Integer.parseInt(fileCount); - } catch (NumberFormatException e) { - //if no number in the setting we'll return 10 - } - return retVal; - } public boolean isAllowCustomTerms() { boolean safeDefaultIfKeyNotFound = true; @@ -1016,16 +997,7 @@ public boolean isFilePIDsEnabledForCollection(Dataverse collection) { return thisCollection.getFilePIDsEnabled(); } - public boolean isIndependentHandleService() { - boolean safeDefaultIfKeyNotFound = false; - return settingsService.isTrueForKey(SettingsServiceBean.Key.IndependentHandleService, safeDefaultIfKeyNotFound); - - } - - public String getHandleAuthHandle() { - String handleAuthHandle = settingsService.getValueForKey(SettingsServiceBean.Key.HandleAuthHandle, null); - return handleAuthHandle; - } + public String getMDCLogPath() { String mDCLogPath = settingsService.getValueForKey(SettingsServiceBean.Key.MDCLogPath, null); diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JSONLDUtil.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JSONLDUtil.java index 4fb3ffe6c14..637f002f5ad 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JSONLDUtil.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JSONLDUtil.java @@ -39,7 +39,6 @@ import edu.harvard.iq.dataverse.DatasetFieldValue; import edu.harvard.iq.dataverse.DatasetVersion; import edu.harvard.iq.dataverse.GlobalId; -import edu.harvard.iq.dataverse.GlobalIdServiceBean; import edu.harvard.iq.dataverse.MetadataBlock; import edu.harvard.iq.dataverse.MetadataBlockServiceBean; import edu.harvard.iq.dataverse.TermsOfUseAndAccess; @@ -52,6 +51,7 @@ import edu.harvard.iq.dataverse.DatasetVersion.VersionState; import edu.harvard.iq.dataverse.license.License; import edu.harvard.iq.dataverse.license.LicenseServiceBean; +import edu.harvard.iq.dataverse.pidproviders.PidProvider; import jakarta.json.JsonReader; public class JSONLDUtil { @@ -83,7 +83,7 @@ public static Dataset updateDatasetMDFromJsonLD(Dataset ds, String jsonLDBody, JsonObject jsonld = decontextualizeJsonLD(jsonLDBody); if (migrating) { - Optional maybePid = GlobalIdServiceBean.parse(jsonld.getString("@id")); + Optional maybePid = PidProvider.parse(jsonld.getString("@id")); if (maybePid.isPresent()) { ds.setGlobalId(maybePid.get()); } else { diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java index 984c607aac7..2141fcc5fca 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java @@ -318,8 +318,8 @@ public DatasetVersion parseDatasetVersion(JsonObject obj) throws JsonParseExcept public Dataset parseDataset(JsonObject obj) throws JsonParseException { Dataset dataset = new Dataset(); - dataset.setAuthority(obj.getString("authority", null) == null ? settingsService.getValueForKey(SettingsServiceBean.Key.Authority) : obj.getString("authority")); - dataset.setProtocol(obj.getString("protocol", null) == null ? settingsService.getValueForKey(SettingsServiceBean.Key.Protocol) : obj.getString("protocol")); + dataset.setAuthority(obj.getString("authority", null)); + dataset.setProtocol(obj.getString("protocol", null)); dataset.setIdentifier(obj.getString("identifier",null)); String mdl = obj.getString("metadataLanguage",null); if(mdl==null || settingsService.getBaseMetadataLanguageMap(new HashMap(), true).containsKey(mdl)) { diff --git a/src/main/java/edu/harvard/iq/dataverse/workflow/WorkflowServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/workflow/WorkflowServiceBean.java index 47f24c9b8bd..757d447b60a 100644 --- a/src/main/java/edu/harvard/iq/dataverse/workflow/WorkflowServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/workflow/WorkflowServiceBean.java @@ -1,8 +1,10 @@ package edu.harvard.iq.dataverse.workflow; +import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.DatasetLock; import edu.harvard.iq.dataverse.DatasetServiceBean; import edu.harvard.iq.dataverse.DataverseRequestServiceBean; +import edu.harvard.iq.dataverse.DvObjectServiceBean; import edu.harvard.iq.dataverse.EjbDataverseEngine; import edu.harvard.iq.dataverse.RoleAssigneeServiceBean; import edu.harvard.iq.dataverse.UserNotification; @@ -58,6 +60,9 @@ public class WorkflowServiceBean { @EJB DatasetServiceBean datasets; + + @EJB + DvObjectServiceBean dvObjects; @EJB SettingsServiceBean settings; @@ -387,16 +392,11 @@ private void workflowCompleted(Workflow wf, WorkflowContext ctxt) { //Now lock for FinalizePublication - this block mirrors that in PublishDatasetCommand AuthenticatedUser user = ctxt.getRequest().getAuthenticatedUser(); DatasetLock lock = new DatasetLock(DatasetLock.Reason.finalizePublication, user); - lock.setDataset(ctxt.getDataset()); - String currentGlobalIdProtocol = settings.getValueForKey(SettingsServiceBean.Key.Protocol, ""); - String currentGlobalAuthority= settings.getValueForKey(SettingsServiceBean.Key.Authority, ""); - String dataFilePIDFormat = settings.getValueForKey(SettingsServiceBean.Key.DataFilePIDFormat, "DEPENDENT"); + Dataset dataset = ctxt.getDataset(); + lock.setDataset(dataset); boolean registerGlobalIdsForFiles = - (currentGlobalIdProtocol.equals(ctxt.getDataset().getProtocol()) || dataFilePIDFormat.equals("INDEPENDENT")) - && systemConfig.isFilePIDsEnabledForCollection(ctxt.getDataset().getOwner()); - if ( registerGlobalIdsForFiles ){ - registerGlobalIdsForFiles = currentGlobalAuthority.equals( ctxt.getDataset().getAuthority() ); - } + systemConfig.isFilePIDsEnabledForCollection(ctxt.getDataset().getOwner()) && + dvObjects.getEffectivePidGenerator(dataset).canCreatePidsLike(dataset.getGlobalId()); boolean validatePhysicalFiles = systemConfig.isDatafileValidationOnPublishEnabled(); String info = "Publishing the dataset; "; diff --git a/src/main/java/propertyFiles/Bundle.properties b/src/main/java/propertyFiles/Bundle.properties index 0b0e577a569..a986acd434d 100644 --- a/src/main/java/propertyFiles/Bundle.properties +++ b/src/main/java/propertyFiles/Bundle.properties @@ -56,6 +56,7 @@ storage=Storage curationLabels=Curation Labels metadataLanguage=Dataset Metadata Language guestbookEntryOption=Guestbook Entry Option +pidProviderOption=PID Provider Option createDataverse=Create Dataverse remove=Remove done=Done @@ -831,6 +832,7 @@ dataverse.curationLabels.disabled=Disabled dataverse.category=Category dataverse.category.title=The type that most closely reflects this dataverse. dataverse.guestbookentryatrequest.title=Whether Guestbooks are displayed to users when they request file access or when they download files. +dataverse.pidProvider.title=The source of PIDs (DOIs, Handles, etc.) when a new PID is created. dataverse.type.selectTab.top=Select one... dataverse.type.selectTab.researchers=Researcher dataverse.type.selectTab.researchProjects=Research Project diff --git a/src/main/resources/META-INF/microprofile-config.properties b/src/main/resources/META-INF/microprofile-config.properties index ec8427795ee..56c0fe0ff0a 100644 --- a/src/main/resources/META-INF/microprofile-config.properties +++ b/src/main/resources/META-INF/microprofile-config.properties @@ -50,17 +50,6 @@ dataverse.oai.server.maxsets=100 # can be customized via the setting below: #dataverse.oai.server.repositoryname= -# PERSISTENT IDENTIFIER PROVIDERS -# EZID -dataverse.pid.ezid.api-url=https://ezid.cdlib.org - -# DataCite -dataverse.pid.datacite.mds-api-url=https://mds.test.datacite.org -dataverse.pid.datacite.rest-api-url=https://api.test.datacite.org - -# Handle.Net -dataverse.pid.handlenet.index=300 - # AUTHENTICATION dataverse.auth.oidc.pkce.max-cache-size=10000 dataverse.auth.oidc.pkce.max-cache-age=300 diff --git a/src/main/resources/db/migration/V6.1.0.4__3623-multiple-pid-providers.sql b/src/main/resources/db/migration/V6.1.0.4__3623-multiple-pid-providers.sql new file mode 100644 index 00000000000..1d11e178abf --- /dev/null +++ b/src/main/resources/db/migration/V6.1.0.4__3623-multiple-pid-providers.sql @@ -0,0 +1,2 @@ +ALTER TABLE dataverse ADD COLUMN IF NOT EXISTS pidgeneratorspecs TEXT; +ALTER TABLE dataset ADD COLUMN IF NOT EXISTS pidgeneratorspecs TEXT; diff --git a/src/main/resources/edu/harvard/iq/dataverse/datacite_metadata_template.xml b/src/main/resources/edu/harvard/iq/dataverse/pidproviders/doi/datacite_metadata_template.xml similarity index 100% rename from src/main/resources/edu/harvard/iq/dataverse/datacite_metadata_template.xml rename to src/main/resources/edu/harvard/iq/dataverse/pidproviders/doi/datacite_metadata_template.xml diff --git a/src/main/webapp/dataset.xhtml b/src/main/webapp/dataset.xhtml index 2afae295082..4bb1ec869f6 100644 --- a/src/main/webapp/dataset.xhtml +++ b/src/main/webapp/dataset.xhtml @@ -585,7 +585,7 @@

    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 WN7MtqTsj1xKqS9VV&j&*ng0eP(x>YH literal 0 HcmV?d00001 diff --git a/doc/sphinx-guides/source/developers/classic-dev-env.rst b/doc/sphinx-guides/source/developers/classic-dev-env.rst index d7b7f281634..015ba43644d 100755 --- a/doc/sphinx-guides/source/developers/classic-dev-env.rst +++ b/doc/sphinx-guides/source/developers/classic-dev-env.rst @@ -88,6 +88,8 @@ On Mac, run this command: On Linux, install ``jq`` from your package manager or download a binary from https://stedolan.github.io/jq/ +.. _install-payara-dev: + Install Payara ~~~~~~~~~~~~~~ From efbdb72d8d8d985dc1efa4141bd14041e397c242 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Tue, 13 Feb 2024 22:18:01 -0500 Subject: [PATCH 044/141] US English spelling for consistency #9590 --- doc/sphinx-guides/source/container/dev-usage.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/sphinx-guides/source/container/dev-usage.rst b/doc/sphinx-guides/source/container/dev-usage.rst index 85b1b3e5f05..3e7dd374036 100644 --- a/doc/sphinx-guides/source/container/dev-usage.rst +++ b/doc/sphinx-guides/source/container/dev-usage.rst @@ -231,7 +231,7 @@ When opting for builtin features or Payara tools, please follow these steps: .. image:: img/intellij-payara-config-startup.png - You might want to tweak the hot deploy behaviour in the "Server" tab now. + You might want to tweak the hot deploy behavior in the "Server" tab now. "Update action" can be found in the run window (see below). "Frame deactivation" means switching from IntelliJ window to something else, e.g. your browser. *Note: static resources like properties, XHTML etc will only update when redeploying!* @@ -271,7 +271,7 @@ When opting for builtin features or Payara tools, please follow these steps: .. image:: img/intellij-payara-run-toolbar.png Watch the WAR build and the deployment unfold. - Note the "Update" action button (see config to change its behaviour). + Note the "Update" action button (see config to change its behavior). .. image:: img/intellij-payara-run-output.png From 6666857ef8d425bb46fd83569f6b3f1b1d620dc2 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Tue, 13 Feb 2024 22:22:12 -0500 Subject: [PATCH 045/141] switch away from hard-coded numbers in lists #9590 --- doc/sphinx-guides/source/container/dev-usage.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/sphinx-guides/source/container/dev-usage.rst b/doc/sphinx-guides/source/container/dev-usage.rst index 3e7dd374036..d2bf820d89a 100644 --- a/doc/sphinx-guides/source/container/dev-usage.rst +++ b/doc/sphinx-guides/source/container/dev-usage.rst @@ -154,21 +154,21 @@ IDE-triggered re-deployments You have at least two options: -1. Use builtin features of IDEs or plugins for different IDEs by Payara to ease the burden of redeploying an application during development to a running Payara application server. +#. Use builtin features of IDEs or plugins for different IDEs by Payara to ease the burden of redeploying an application during development to a running Payara application server. Their guides contain `documentation on Payara IDE plugins `_. -2. Use a paid product like `JRebel `_. +#. Use a paid product like `JRebel `_. The main difference between the first and the second option is support for hot deploys of non-class files plus limitations in what the JVM HotswapAgent can do for you. Find more `details in a blog article by JRebel `_. When opting for builtin features or Payara tools, please follow these steps: -1. | Download the Payara appserver to your machine, unzip and note the location for later. +#. | Download the Payara appserver to your machine, unzip and note the location for later. | - See :ref:`payara` for which version or run the following command | ``mvn help:evaluate -Dexpression=payara.version -q -DforceStdout`` | - To download, see :ref:`payara` or try `Maven Central `_. -2. Install Payara tools plugin in your IDE: +#. Install Payara tools plugin in your IDE: .. tabs:: .. group-tab:: Netbeans @@ -182,7 +182,7 @@ When opting for builtin features or Payara tools, please follow these steps: .. image:: img/intellij-payara-plugin-install.png -3. Configure a connection to the application server: +#. Configure a connection to the application server: .. tabs:: .. group-tab:: Netbeans @@ -238,13 +238,13 @@ When opting for builtin features or Payara tools, please follow these steps: .. image:: img/intellij-payara-config-server-behaviour.png -4. | Start all the containers. Follow the cheat sheet above, but take care to skip application deployment: +#. | Start all the containers. Follow the cheat sheet above, but take care to skip application deployment: | - When using the Maven commands, append ``-Dapp.deploy.skip``. For example: | ``mvn -Pct docker:run -Dapp.deploy.skip`` | - When using Docker Compose, prepend the command with ``SKIP_DEPLOY=1``. For example: | ``SKIP_DEPLOY=1 docker compose -f docker-compose-dev.yml up`` | - Note: the Admin Console can be reached at http://localhost:4848 or https://localhost:4949 -5. To deploy the application to the running server, use the configured tools to deploy. +#. To deploy the application to the running server, use the configured tools to deploy. Using the "Run" configuration only deploys and enables redeploys, while running "Debug" enables hot swapping of classes via JDWP. .. tabs:: From 0c0067e5e21775c6ea8a8635cb16599493708930 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Tue, 13 Feb 2024 22:56:16 -0500 Subject: [PATCH 046/141] various doc tweaks #9590 --- .../source/container/dev-usage.rst | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/doc/sphinx-guides/source/container/dev-usage.rst b/doc/sphinx-guides/source/container/dev-usage.rst index d2bf820d89a..6dbd0276cb3 100644 --- a/doc/sphinx-guides/source/container/dev-usage.rst +++ b/doc/sphinx-guides/source/container/dev-usage.rst @@ -144,29 +144,30 @@ Alternatives: Redeploying ----------- -Rebuild and Running Images -^^^^^^^^^^^^^^^^^^^^^^^^^^ +Rebuilding and Running Images +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The safest way to redeploy code is to stop the running containers (with Ctrl-c if you started them in the foreground) and then build and run them again with ``mvn -Pct clean package docker:run``. +The safest and most reliable way to redeploy code is to stop the running containers (with Ctrl-c if you started them in the foreground) and then build and run them again with ``mvn -Pct clean package docker:run``. -IDE-triggered re-deployments -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +IDE-Triggered Redeployments +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Triggering redeployment using an IDE can greatly improve your feedback look when changing code. You have at least two options: -#. Use builtin features of IDEs or plugins for different IDEs by Payara to ease the burden of redeploying an application during development to a running Payara application server. - Their guides contain `documentation on Payara IDE plugins `_. +#. Use builtin features of IDEs or `IDE plugins from Payara `_. #. Use a paid product like `JRebel `_. -The main difference between the first and the second option is support for hot deploys of non-class files plus limitations in what the JVM HotswapAgent can do for you. -Find more `details in a blog article by JRebel `_. +The main differences between the first and the second options are support for hot deploys of non-class files and limitations in what the JVM HotswapAgent can do for you. +Find more details in a `blog article by JRebel `_. -When opting for builtin features or Payara tools, please follow these steps: +To make use of builtin features or Payara tools (option 1), please follow these steps: -#. | Download the Payara appserver to your machine, unzip and note the location for later. - | - See :ref:`payara` for which version or run the following command - | ``mvn help:evaluate -Dexpression=payara.version -q -DforceStdout`` - | - To download, see :ref:`payara` or try `Maven Central `_. +#. | Download the version of Payara shown in :ref:`install-payara-dev` and unzip it to a reasonable location such as ``/usr/local/payara6``. + | - Note that Payara can also be downloaded from `Maven Central `_. + | - Note that another way to check the expected version of Payara is to run this command: + | ``mvn help:evaluate -Dexpression=payara.version -q -DforceStdout`` #. Install Payara tools plugin in your IDE: @@ -182,16 +183,14 @@ When opting for builtin features or Payara tools, please follow these steps: .. image:: img/intellij-payara-plugin-install.png -#. Configure a connection to the application server: +#. Configure a connection to Payara: .. tabs:: .. group-tab:: Netbeans - Unzip Payara to ``/usr/local/payara6`` as explained in :ref:`install-payara-dev`. - - Launch Netbeans and click "Tools" and then "Servers". Click "Add Server" and select "Payara Server" and set the installation location to ``/usr/local/payara6``. Use the settings in the screenshot below. Most of the defaults are fine. + Launch Netbeans and click "Tools" and then "Servers". Click "Add Server" and select "Payara Server" and set the installation location to ``/usr/local/payara6`` (or wherever you unzipped Payara). Choose "Remote Domain". Use the settings in the screenshot below. Most of the defaults are fine. - Under "Common", the password should be "admin". Make sure "Enable Hot Deploy" is checked. + Under "Common", the username and password should be "admin". Make sure "Enable Hot Deploy" is checked. .. image:: img/netbeans-servers-common.png @@ -203,7 +202,7 @@ When opting for builtin features or Payara tools, please follow these steps: .. image:: img/netbeans-compile.png - Under "Run", select "Payara Server" under "Server" and make sure "Deploy on Save" is checked. + Under "Run", under "Server", select "Payara Server". Make sure "Deploy on Save" is checked. .. image:: img/netbeans-run.png @@ -265,6 +264,12 @@ When opting for builtin features or Payara tools, please follow these steps: Check to make sure the change is live by visiting, for example, http://localhost:8080/api/info/version + See below for a `video `_ demonstrating the steps above but please note that the ports used have changed and now that we have the concept of "skip deploy" the undeployment step shown is no longer necessary. + + .. raw:: html + + + .. group-tab:: IntelliJ Choose "Run" or "Debug" in the toolbar. From b2d5ea8381e15cc861e04b7a33a20a10b20762e0 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Tue, 13 Feb 2024 23:03:05 -0500 Subject: [PATCH 047/141] add release note #9590 --- doc/release-notes/9590-faster-redeploy.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 doc/release-notes/9590-faster-redeploy.md diff --git a/doc/release-notes/9590-faster-redeploy.md b/doc/release-notes/9590-faster-redeploy.md new file mode 100644 index 00000000000..caaa688bf58 --- /dev/null +++ b/doc/release-notes/9590-faster-redeploy.md @@ -0,0 +1,3 @@ +In the Container Guide, documentation for developers on how to quickly redeploy code has been improved for IntelliJ and Netbeans is now covered. + +Also in the context of containers, a new option to skip deployment has been added and the war file is now consistently named "dataverse.war" rather than having a version in the filename, such as "dataverse-6.1.war". This predictability makes tooling easier. From fc8aac32fa7f1b5d53cdc8f4ca1127b5493f2885 Mon Sep 17 00:00:00 2001 From: GPortas Date: Wed, 14 Feb 2024 11:50:29 +0000 Subject: [PATCH 048/141] Fixed: GetLatestAccessibleFileMetadataCommand --- .../GetLatestAccessibleFileMetadataCommand.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java index 980563a5489..a2022adbc27 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java @@ -2,6 +2,7 @@ import edu.harvard.iq.dataverse.DataFile; import edu.harvard.iq.dataverse.FileMetadata; +import edu.harvard.iq.dataverse.authorization.Permission; import edu.harvard.iq.dataverse.engine.command.AbstractCommand; import edu.harvard.iq.dataverse.engine.command.CommandContext; import edu.harvard.iq.dataverse.engine.command.DataverseRequest; @@ -19,16 +20,20 @@ public GetLatestAccessibleFileMetadataCommand(DataverseRequest aRequest, DataFil @Override public FileMetadata execute(CommandContext ctxt) throws CommandException { - FileMetadata fileMetadata = ctxt.engine().submit( - new GetLatestPublishedFileMetadataCommand(getRequest(), dataFile) - ); + FileMetadata fileMetadata = null; - if (fileMetadata == null) { + if (ctxt.permissions().requestOn(getRequest(), dataFile.getOwner()).has(Permission.ViewUnpublishedDataset)) { fileMetadata = ctxt.engine().submit( new GetDraftFileMetadataIfAvailableCommand(getRequest(), dataFile) ); } + if (fileMetadata == null) { + fileMetadata = ctxt.engine().submit( + new GetLatestPublishedFileMetadataCommand(getRequest(), dataFile) + ); + } + return fileMetadata; } } From 153b9ae0f04283386c6f7a70920285aece25a990 Mon Sep 17 00:00:00 2001 From: GPortas Date: Wed, 14 Feb 2024 12:00:23 +0000 Subject: [PATCH 049/141] Added: FilesIT testGetFileInfo test cases --- .../edu/harvard/iq/dataverse/api/FilesIT.java | 45 ++++++++++++++++--- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java index d84b0ed77ac..9af457c35c4 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java @@ -11,8 +11,7 @@ import org.junit.jupiter.api.BeforeAll; import io.restassured.path.json.JsonPath; -import static edu.harvard.iq.dataverse.api.ApiConstants.DS_VERSION_DRAFT; -import static edu.harvard.iq.dataverse.api.ApiConstants.DS_VERSION_LATEST_PUBLISHED; +import static edu.harvard.iq.dataverse.api.ApiConstants.*; import static io.restassured.path.json.JsonPath.with; import io.restassured.path.xml.XmlPath; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; @@ -1450,9 +1449,9 @@ public void testGetFileInfo() { .statusCode(NOT_FOUND.getStatusCode()); // Update the file metadata - String newFileName = "trees_2.png"; + String newFileNameFirstUpdate = "trees_2.png"; JsonObjectBuilder updateFileMetadata = Json.createObjectBuilder() - .add("label", newFileName); + .add("label", newFileNameFirstUpdate); Response updateFileMetadataResponse = UtilIT.updateFileMetadata(dataFileId, updateFileMetadata.build().toString(), superUserApiToken); updateFileMetadataResponse.then().statusCode(OK.getStatusCode()); @@ -1471,12 +1470,46 @@ public void testGetFileInfo() { publishDatasetResp.then().assertThat() .statusCode(OK.getStatusCode()); + // Update the file metadata once again + String newFileNameSecondUpdate = "trees_3.png"; + updateFileMetadata = Json.createObjectBuilder() + .add("label", newFileNameSecondUpdate); + updateFileMetadataResponse = UtilIT.updateFileMetadata(dataFileId, updateFileMetadata.build().toString(), superUserApiToken); + updateFileMetadataResponse.then().statusCode(OK.getStatusCode()); + // Regular user should get to see latest published file data getFileDataResponse = UtilIT.getFileData(dataFileId, apiTokenRegular, DS_VERSION_LATEST_PUBLISHED); getFileDataResponse.then().assertThat() .statusCode(OK.getStatusCode()) - .body("data.label", equalTo(newFileName)); - // TODO + .body("data.label", equalTo(newFileNameFirstUpdate)); + + // Regular user should get to see latest published file data if latest is requested + getFileDataResponse = UtilIT.getFileData(dataFileId, apiTokenRegular, DS_VERSION_LATEST); + getFileDataResponse.then().assertThat() + .statusCode(OK.getStatusCode()) + .body("data.label", equalTo(newFileNameFirstUpdate)); + + // Superuser should get to see draft file data if latest is requested + getFileDataResponse = UtilIT.getFileData(dataFileId, superUserApiToken, DS_VERSION_LATEST); + getFileDataResponse.then().assertThat() + .statusCode(OK.getStatusCode()) + .body("data.label", equalTo(newFileNameSecondUpdate)); + + // Publish dataset once again + publishDatasetResp = UtilIT.publishDatasetViaNativeApi(datasetId, "major", superUserApiToken); + publishDatasetResp.then().assertThat() + .statusCode(OK.getStatusCode()); + + // Regular user should get to see file data by specific version number + getFileDataResponse = UtilIT.getFileData(dataFileId, apiTokenRegular, "2.0"); + getFileDataResponse.then().assertThat() + .statusCode(OK.getStatusCode()) + .body("data.label", equalTo(newFileNameFirstUpdate)); + + getFileDataResponse = UtilIT.getFileData(dataFileId, apiTokenRegular, "3.0"); + getFileDataResponse.then().assertThat() + .statusCode(OK.getStatusCode()) + .body("data.label", equalTo(newFileNameSecondUpdate)); // Cleanup Response destroyDatasetResponse = UtilIT.destroyDataset(datasetId, superUserApiToken); From 2a30f328b91faade4a0827a826d51095a1788053 Mon Sep 17 00:00:00 2001 From: GPortas Date: Wed, 14 Feb 2024 14:05:51 +0000 Subject: [PATCH 050/141] Stash: includeDeaccessioned support on get file info endpoint wip --- ...etLatestAccessibleFileMetadataCommand.java | 6 ++-- ...GetLatestPublishedFileMetadataCommand.java | 4 ++- ...edFileMetadataByDatasetVersionCommand.java | 33 +++++++++++-------- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java index a2022adbc27..fa80b75c593 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestAccessibleFileMetadataCommand.java @@ -12,10 +12,12 @@ @RequiredPermissions({}) public class GetLatestAccessibleFileMetadataCommand extends AbstractCommand { private final DataFile dataFile; + private final boolean includeDeaccessioned; - public GetLatestAccessibleFileMetadataCommand(DataverseRequest aRequest, DataFile dataFile) { + public GetLatestAccessibleFileMetadataCommand(DataverseRequest aRequest, DataFile dataFile, boolean includeDeaccessioned) { super(aRequest, dataFile); this.dataFile = dataFile; + this.includeDeaccessioned = includeDeaccessioned; } @Override @@ -30,7 +32,7 @@ public FileMetadata execute(CommandContext ctxt) throws CommandException { if (fileMetadata == null) { fileMetadata = ctxt.engine().submit( - new GetLatestPublishedFileMetadataCommand(getRequest(), dataFile) + new GetLatestPublishedFileMetadataCommand(getRequest(), dataFile, includeDeaccessioned) ); } diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestPublishedFileMetadataCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestPublishedFileMetadataCommand.java index 147a0fdce76..4056d145917 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestPublishedFileMetadataCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetLatestPublishedFileMetadataCommand.java @@ -11,10 +11,12 @@ @RequiredPermissions({}) public class GetLatestPublishedFileMetadataCommand extends AbstractCommand { private final DataFile dataFile; + private final boolean includeDeaccessioned; - public GetLatestPublishedFileMetadataCommand(DataverseRequest aRequest, DataFile dataFile) { + public GetLatestPublishedFileMetadataCommand(DataverseRequest aRequest, DataFile dataFile, boolean includeDeaccessioned) { super(aRequest, dataFile); this.dataFile = dataFile; + this.includeDeaccessioned = includeDeaccessioned; } @Override diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetSpecificPublishedFileMetadataByDatasetVersionCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetSpecificPublishedFileMetadataByDatasetVersionCommand.java index 84a51f6b31d..82350d3bd95 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetSpecificPublishedFileMetadataByDatasetVersionCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GetSpecificPublishedFileMetadataByDatasetVersionCommand.java @@ -1,43 +1,48 @@ package edu.harvard.iq.dataverse.engine.command.impl; import edu.harvard.iq.dataverse.DataFile; +import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.DatasetVersion; import edu.harvard.iq.dataverse.FileMetadata; +import edu.harvard.iq.dataverse.authorization.Permission; import edu.harvard.iq.dataverse.engine.command.AbstractCommand; import edu.harvard.iq.dataverse.engine.command.CommandContext; import edu.harvard.iq.dataverse.engine.command.DataverseRequest; import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; -import java.util.List; - @RequiredPermissions({}) public class GetSpecificPublishedFileMetadataByDatasetVersionCommand extends AbstractCommand { private final long majorVersion; private final long minorVersion; private final DataFile dataFile; + private final boolean includeDeaccessioned; - public GetSpecificPublishedFileMetadataByDatasetVersionCommand(DataverseRequest aRequest, DataFile dataFile, long majorVersion, long minorVersion) { + public GetSpecificPublishedFileMetadataByDatasetVersionCommand(DataverseRequest aRequest, DataFile dataFile, long majorVersion, long minorVersion, boolean includeDeaccessioned) { super(aRequest, dataFile); this.dataFile = dataFile; this.majorVersion = majorVersion; this.minorVersion = minorVersion; + this.includeDeaccessioned = includeDeaccessioned; } @Override public FileMetadata execute(CommandContext ctxt) throws CommandException { - List fileMetadatas = dataFile.getFileMetadatas(); - - for (FileMetadata fileMetadata : fileMetadatas) { - DatasetVersion datasetVersion = fileMetadata.getDatasetVersion(); + return dataFile.getFileMetadatas().stream() + .filter(fileMetadata -> isRequestedVersionFileMetadata(fileMetadata, ctxt)) + .findFirst() + .orElse(null); + } - if (datasetVersion.isPublished() && - datasetVersion.getVersionNumber().equals(majorVersion) && - datasetVersion.getMinorVersionNumber().equals(minorVersion)) { - return fileMetadata; - } - } + private boolean isRequestedVersionFileMetadata(FileMetadata fileMetadata, CommandContext ctxt) { + DatasetVersion datasetVersion = fileMetadata.getDatasetVersion(); + Dataset ownerDataset = dataFile.getOwner(); + return (datasetVersion.isReleased() || isDatasetVersionDeaccessionedAndAccessible(datasetVersion, ownerDataset, ctxt)) + && datasetVersion.getVersionNumber().equals(majorVersion) + && datasetVersion.getMinorVersionNumber().equals(minorVersion); + } - return null; + private boolean isDatasetVersionDeaccessionedAndAccessible(DatasetVersion datasetVersion, Dataset ownerDataset, CommandContext ctxt) { + return includeDeaccessioned && datasetVersion.isDeaccessioned() && ctxt.permissions().requestOn(getRequest(), ownerDataset).has(Permission.EditDataset); } } From b5aeb258d025036c2da808d775e8d5bbf15add38 Mon Sep 17 00:00:00 2001 From: GPortas Date: Wed, 14 Feb 2024 14:06:20 +0000 Subject: [PATCH 051/141] Stash: includeDeaccessioned support on get file info endpoint wip (2) --- .../edu/harvard/iq/dataverse/api/Files.java | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Files.java b/src/main/java/edu/harvard/iq/dataverse/api/Files.java index 4116bf18973..55d65bae96b 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Files.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Files.java @@ -486,23 +486,37 @@ public Response updateFileMetadata(@Context ContainerRequestContext crc, @FormDa @GET @AuthRequired @Path("{id}") - public Response getFileData(@Context ContainerRequestContext crc, @PathParam("id") String fileIdOrPersistentId, @Context UriInfo uriInfo, @Context HttpHeaders headers) { - return response( req -> getFileDataResponse(req, fileIdOrPersistentId, uriInfo, headers, DS_VERSION_LATEST), getRequestUser(crc)); + public Response getFileData(@Context ContainerRequestContext crc, + @PathParam("id") String fileIdOrPersistentId, + @QueryParam("includeDeaccessioned") boolean includeDeaccessioned, + @Context UriInfo uriInfo, + @Context HttpHeaders headers) { + return response( req -> getFileDataResponse(req, fileIdOrPersistentId, DS_VERSION_LATEST, includeDeaccessioned, uriInfo, headers), getRequestUser(crc)); } @GET @AuthRequired @Path("{id}/versions/{datasetVersionId}") - public Response getFileData(@Context ContainerRequestContext crc, @PathParam("id") String fileIdOrPersistentId, @PathParam("datasetVersionId") String datasetVersionId, @Context UriInfo uriInfo, @Context HttpHeaders headers) { - return response( req -> getFileDataResponse(req, fileIdOrPersistentId, uriInfo, headers, datasetVersionId), getRequestUser(crc)); + public Response getFileData(@Context ContainerRequestContext crc, + @PathParam("id") String fileIdOrPersistentId, + @PathParam("datasetVersionId") String datasetVersionId, + @QueryParam("includeDeaccessioned") boolean includeDeaccessioned, + @Context UriInfo uriInfo, + @Context HttpHeaders headers) { + return response( req -> getFileDataResponse(req, fileIdOrPersistentId, datasetVersionId, includeDeaccessioned, uriInfo, headers), getRequestUser(crc)); } - private Response getFileDataResponse(final DataverseRequest req, String fileIdOrPersistentId, UriInfo uriInfo, HttpHeaders headers, String datasetVersionId) throws WrappedResponse { + private Response getFileDataResponse(final DataverseRequest req, + String fileIdOrPersistentId, + String datasetVersionId, + boolean includeDeaccessioned, + UriInfo uriInfo, + HttpHeaders headers) throws WrappedResponse { final DataFile dataFile = execCommand(new GetDataFileCommand(req, findDataFileOrDie(fileIdOrPersistentId))); FileMetadata fileMetadata = execCommand(handleVersion(datasetVersionId, new Datasets.DsVersionHandler<>() { @Override public Command handleLatest() { - return new GetLatestAccessibleFileMetadataCommand(req, dataFile); + return new GetLatestAccessibleFileMetadataCommand(req, dataFile, includeDeaccessioned); } @Override @@ -512,12 +526,12 @@ public Command handleDraft() { @Override public Command handleSpecific(long major, long minor) { - return new GetSpecificPublishedFileMetadataByDatasetVersionCommand(req, dataFile, major, minor); + return new GetSpecificPublishedFileMetadataByDatasetVersionCommand(req, dataFile, major, minor, includeDeaccessioned); } @Override public Command handleLatestPublished() { - return new GetLatestPublishedFileMetadataCommand(req, dataFile); + return new GetLatestPublishedFileMetadataCommand(req, dataFile, includeDeaccessioned); } })); From 48e71ec74a49ad6145f93f38c07b175533642813 Mon Sep 17 00:00:00 2001 From: GPortas Date: Wed, 14 Feb 2024 14:40:48 +0000 Subject: [PATCH 052/141] Refactor: DataFile getLatestFileMetadata and getLatestPublishedFileMetadata methods --- .../edu/harvard/iq/dataverse/DataFile.java | 68 +++++++++---------- 1 file changed, 31 insertions(+), 37 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/DataFile.java b/src/main/java/edu/harvard/iq/dataverse/DataFile.java index 3d8086b142b..8f2e0d4261e 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DataFile.java +++ b/src/main/java/edu/harvard/iq/dataverse/DataFile.java @@ -549,57 +549,51 @@ public void setDescription(String description) { public FileMetadata getFileMetadata() { return getLatestFileMetadata(); } - + public FileMetadata getLatestFileMetadata() { - FileMetadata fmd = null; + FileMetadata resultFileMetadata = null; - // for newly added or harvested, just return the one fmd if (fileMetadatas.size() == 1) { return fileMetadatas.get(0); } - + for (FileMetadata fileMetadata : fileMetadatas) { - // if it finds a draft, return it if (fileMetadata.getDatasetVersion().getVersionState().equals(VersionState.DRAFT)) { return fileMetadata; - } - - // otherwise return the one with the latest version number - // duplicate logic in getLatestPublishedFileMetadata() - if (fmd == null || fileMetadata.getDatasetVersion().getVersionNumber().compareTo( fmd.getDatasetVersion().getVersionNumber() ) > 0 ) { - fmd = fileMetadata; - } else if ((fileMetadata.getDatasetVersion().getVersionNumber().compareTo( fmd.getDatasetVersion().getVersionNumber())==0 )&& - ( fileMetadata.getDatasetVersion().getMinorVersionNumber().compareTo( fmd.getDatasetVersion().getMinorVersionNumber()) > 0 ) ) { - fmd = fileMetadata; } + resultFileMetadata = getTheNewerFileMetadata(resultFileMetadata, fileMetadata); } - return fmd; + + return resultFileMetadata; } - -// //Returns null if no published version + public FileMetadata getLatestPublishedFileMetadata() throws UnsupportedOperationException { - FileMetadata fmd = null; - - for (FileMetadata fileMetadata : fileMetadatas) { - // if it finds a draft, skip - if (fileMetadata.getDatasetVersion().getVersionState().equals(VersionState.DRAFT)) { - continue; - } - - // otherwise return the one with the latest version number - // duplicate logic in getLatestFileMetadata() - if (fmd == null || fileMetadata.getDatasetVersion().getVersionNumber().compareTo( fmd.getDatasetVersion().getVersionNumber() ) > 0 ) { - fmd = fileMetadata; - } else if ((fileMetadata.getDatasetVersion().getVersionNumber().compareTo( fmd.getDatasetVersion().getVersionNumber())==0 )&& - ( fileMetadata.getDatasetVersion().getMinorVersionNumber().compareTo( fmd.getDatasetVersion().getMinorVersionNumber()) > 0 ) ) { - fmd = fileMetadata; - } - } - if(fmd == null) { + FileMetadata resultFileMetadata = fileMetadatas.stream() + .filter(metadata -> !metadata.getDatasetVersion().getVersionState().equals(VersionState.DRAFT)) + .reduce(null, this::getTheNewerFileMetadata); + + if (resultFileMetadata == null) { throw new UnsupportedOperationException("No published metadata version for DataFile " + this.getId()); } - return fmd; + return resultFileMetadata; + } + + private FileMetadata getTheNewerFileMetadata(FileMetadata currentFileMetadata, FileMetadata newFileMetadata) { + if (currentFileMetadata == null) { + return newFileMetadata; + } + + DatasetVersion currentVersion = currentFileMetadata.getDatasetVersion(); + DatasetVersion newVersion = newFileMetadata.getDatasetVersion(); + + if (newVersion.getVersionNumber().compareTo(currentVersion.getVersionNumber()) > 0 || + (newVersion.getVersionNumber().compareTo(currentVersion.getVersionNumber()) == 0 && + newVersion.getMinorVersionNumber().compareTo(currentVersion.getMinorVersionNumber()) > 0)) { + return newFileMetadata; + } + + return currentFileMetadata; } /** @@ -610,7 +604,7 @@ public long getFilesize() { if (this.filesize == null) { // -1 means "unknown" return -1; - } + } return this.filesize; } From 227fe53ba707e24d89c3e045337cf5e3860a9820 Mon Sep 17 00:00:00 2001 From: GPortas Date: Wed, 14 Feb 2024 15:57:47 +0000 Subject: [PATCH 053/141] Refactor: using DatasetVersion.compareByVersion in getTheNewerFileMetadata --- .../edu/harvard/iq/dataverse/DataFile.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/DataFile.java b/src/main/java/edu/harvard/iq/dataverse/DataFile.java index 8f2e0d4261e..818cade1eef 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DataFile.java +++ b/src/main/java/edu/harvard/iq/dataverse/DataFile.java @@ -579,21 +579,19 @@ public FileMetadata getLatestPublishedFileMetadata() throws UnsupportedOperation return resultFileMetadata; } - private FileMetadata getTheNewerFileMetadata(FileMetadata currentFileMetadata, FileMetadata newFileMetadata) { - if (currentFileMetadata == null) { - return newFileMetadata; + private FileMetadata getTheNewerFileMetadata(FileMetadata current, FileMetadata candidate) { + if (current == null) { + return candidate; } - DatasetVersion currentVersion = currentFileMetadata.getDatasetVersion(); - DatasetVersion newVersion = newFileMetadata.getDatasetVersion(); + DatasetVersion currentVersion = current.getDatasetVersion(); + DatasetVersion candidateVersion = candidate.getDatasetVersion(); - if (newVersion.getVersionNumber().compareTo(currentVersion.getVersionNumber()) > 0 || - (newVersion.getVersionNumber().compareTo(currentVersion.getVersionNumber()) == 0 && - newVersion.getMinorVersionNumber().compareTo(currentVersion.getMinorVersionNumber()) > 0)) { - return newFileMetadata; + if (DatasetVersion.compareByVersion.compare(candidateVersion, currentVersion) > 0) { + return candidate; } - return currentFileMetadata; + return current; } /** From 1dc4825cb1aa2f204958782e238ad77ac4e231b6 Mon Sep 17 00:00:00 2001 From: qqmyers Date: Wed, 14 Feb 2024 13:19:13 -0500 Subject: [PATCH 054/141] update perms --- .../edu/harvard/iq/dataverse/FilePage.java | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/FilePage.java b/src/main/java/edu/harvard/iq/dataverse/FilePage.java index 4e5843964e7..37798f1cd3c 100644 --- a/src/main/java/edu/harvard/iq/dataverse/FilePage.java +++ b/src/main/java/edu/harvard/iq/dataverse/FilePage.java @@ -484,7 +484,7 @@ public String restrictFile(boolean restricted) throws CommandException{ public String ingestFile() throws CommandException{ User u = session.getUser(); - if(!u.isAuthenticated() || !(permissionService.permissionsFor(u, file).contains(Permission.PublishDataset))) { + if(!u.isAuthenticated() || !u.isSuperuser()) { //Shouldn't happen (choice not displayed for users who don't have the right permission), but check anyway logger.warning("User: " + u.getIdentifier() + " tried to ingest a file"); JH.addMessage(FacesMessage.SEVERITY_WARN, BundleUtil.getStringFromBundle("file.ingest.cantIngestFileWarning")); @@ -544,23 +544,29 @@ public String ingestFile() throws CommandException{ } public String uningestFile() throws CommandException { - + if (!file.isTabularData()) { - if(file.isIngestProblem()) { - User u = session.getUser(); - if(!u.isAuthenticated() || !(permissionService.permissionsFor(u, file).contains(Permission.PublishDataset))) { - logger.warning("User: " + u.getIdentifier() + " tried to uningest a file"); - //Shouldn't happen (choice not displayed for users who don't have the right permission), but check anyway - JH.addMessage(FacesMessage.SEVERITY_WARN, BundleUtil.getStringFromBundle("file.ingest.cantUningestFileWarning")); - return null; - } - file.setIngestDone(); - file.setIngestReport(null); + //Ingest never succeeded, either there was a failure or this is not a tabular data file + User u = session.getUser(); + if (!u.isAuthenticated() || !u.isSuperuser()) { + logger.warning("User: " + u.getIdentifier() + " tried to uningest a file"); + // Shouldn't happen (choice not displayed for users who don't have the right + // permission), but check anyway + JH.addMessage(FacesMessage.SEVERITY_WARN, + BundleUtil.getStringFromBundle("file.ingest.cantUningestFileWarning")); + return null; + } + if (file.isIngestProblem()) { + file.setIngestDone(); + file.setIngestReport(null); } else { - JH.addMessage(FacesMessage.SEVERITY_WARN, BundleUtil.getStringFromBundle("file.ingest.cantUningestFileWarning")); - return null; + //Shouldn't happen - got called when there is no tabular data or an ingest problem + JH.addMessage(FacesMessage.SEVERITY_WARN, + BundleUtil.getStringFromBundle("file.ingest.cantUningestFileWarning")); + return null; } } else { + //Uningest command does it's own check for isSuperuser commandEngine.submit(new UningestFileCommand(dvRequestService.getDataverseRequest(), file)); Long dataFileId = file.getId(); file = datafileService.find(dataFileId); @@ -580,12 +586,11 @@ public String uningestFile() throws CommandException { } } save(); - //Refresh filemetadata with file title, etc. + // Refresh filemetadata with file title, etc. init(); JH.addMessage(FacesMessage.SEVERITY_INFO, BundleUtil.getStringFromBundle("file.uningest.complete")); return returnToDraftVersion(); - } - + } private List filesToBeDeleted = new ArrayList<>(); From f15122615aea9109ed90b2ff5c4e6a4965f8efcf Mon Sep 17 00:00:00 2001 From: qqmyers Date: Wed, 14 Feb 2024 13:19:23 -0500 Subject: [PATCH 055/141] add bundle strings --- src/main/java/propertyFiles/Bundle.properties | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/propertyFiles/Bundle.properties b/src/main/java/propertyFiles/Bundle.properties index f1c8381816c..42c844e532e 100644 --- a/src/main/java/propertyFiles/Bundle.properties +++ b/src/main/java/propertyFiles/Bundle.properties @@ -2203,6 +2203,15 @@ ingest.csv.lineMismatch=Mismatch between line counts in first and final passes!, ingest.csv.recordMismatch=Reading mismatch, line {0} of the Data file: {1} delimited values expected, {2} found. ingest.csv.nullStream=Stream can't be null. +file.ingest=Ingest +file.uningest=Uningest +file.ingest.alreadyIngestedWarning=This file has already been ingested +file.ingest.ingestInProgressWarning=Ingestion of this file is already in progress +file.ingest.cantIngestFileWarning=Ingest not supported for this file type +file.ingest.ingestQueued=Ingestion has been requested +file.ingest.cantUningestFileWarning=This file cannot be uningested +file.uningest.complete=Uningestion of this file has been completed + # editdatafile.xhtml # editFilesFragment.xhtml From 14b280cf39dee856dfa9a1a6e97f1a7392418a02 Mon Sep 17 00:00:00 2001 From: qqmyers Date: Wed, 14 Feb 2024 13:19:33 -0500 Subject: [PATCH 056/141] doc updates --- doc/sphinx-guides/source/api/native-api.rst | 4 ++++ .../source/user/tabulardataingest/ingestprocess.rst | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index dbe769e2fd1..8cfa5deb96c 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -2854,6 +2854,8 @@ The fully expanded example above (without environment variables) looks like this curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X PUT -d true "https://demo.dataverse.org/api/files/:persistentId/restrict?persistentId=doi:10.5072/FK2/AAA000" +.. _file-uningest: + Uningest a File ~~~~~~~~~~~~~~~ @@ -2891,6 +2893,8 @@ The fully expanded example above (without environment variables) looks like this curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X POST "https://demo.dataverse.org/api/files/:persistentId/uningest?persistentId=doi:10.5072/FK2/AAA000" +.. _file-reingest: + Reingest a File ~~~~~~~~~~~~~~~ diff --git a/doc/sphinx-guides/source/user/tabulardataingest/ingestprocess.rst b/doc/sphinx-guides/source/user/tabulardataingest/ingestprocess.rst index 9e82ff12b9b..ac5fb5af4ec 100644 --- a/doc/sphinx-guides/source/user/tabulardataingest/ingestprocess.rst +++ b/doc/sphinx-guides/source/user/tabulardataingest/ingestprocess.rst @@ -66,11 +66,11 @@ This is non-fatal. The Dataverse software will not produce a .tab version of the who can see the draft version of the dataset containing the file that will indicate why ingest failed. When the file is published as part of the dataset, there will be no indication that ingest was attempted and failed. -If the warning message is a concern, the Dataverse software includes both an API call (see the Files section of the :doc:`/api/native-api` guide) +If the warning message is a concern, the Dataverse software includes both an API call (see :ref:`file-uningest` in the :doc:`/api/native-api` guide) and an Edit/Uningest menu option displayed on the file page, that allow a file to be Uningested. These are only available to superusers. Uningest will remove the warning. Uningest can also be done for a file that was successfully ingested. This will remove the .tab version of the file that was generated. If a file is a tabular format but was never ingested, .e.g. due to the ingest file size limit being lower in the past, or if ingest had failed, -e.g. in a prior Dataverse version, an reingest API (see the Files section of the :doc:`/api/native-api` guide) and a file page Edit/Reingest option +e.g. in a prior Dataverse version, an reingest API (see :ref:`file-reingest` in the :doc:`/api/native-api` guide) and a file page Edit/Reingest option in the user interface allow ingest to be tried again. As with Uningest, this fucntionality is only available to superusers. From 5dffe36c793fa25b9ee8199fda2104fb26f92b9a Mon Sep 17 00:00:00 2001 From: qqmyers Date: Wed, 14 Feb 2024 13:21:09 -0500 Subject: [PATCH 057/141] Apply suggestions from code review Co-authored-by: Philip Durbin --- .../source/user/tabulardataingest/ingestprocess.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/sphinx-guides/source/user/tabulardataingest/ingestprocess.rst b/doc/sphinx-guides/source/user/tabulardataingest/ingestprocess.rst index ac5fb5af4ec..4dce441de4a 100644 --- a/doc/sphinx-guides/source/user/tabulardataingest/ingestprocess.rst +++ b/doc/sphinx-guides/source/user/tabulardataingest/ingestprocess.rst @@ -61,13 +61,13 @@ Uningest and Reingest ===================== Ingest will only work for files whose content can be interpreted as a table. -Multi-sheets spreadsheets and CSV files with different number of entries per row are two examples where ingest will fail. +Multi-sheet spreadsheets and CSV files with a different number of entries per row are two examples where ingest will fail. This is non-fatal. The Dataverse software will not produce a .tab version of the file and will show a warning to users who can see the draft version of the dataset containing the file that will indicate why ingest failed. When the file is published as part of the dataset, there will be no indication that ingest was attempted and failed. If the warning message is a concern, the Dataverse software includes both an API call (see :ref:`file-uningest` in the :doc:`/api/native-api` guide) -and an Edit/Uningest menu option displayed on the file page, that allow a file to be Uningested. These are only available to superusers. +and an Edit/Uningest menu option displayed on the file page, that allow a file to be uningested. These are only available to superusers. Uningest will remove the warning. Uningest can also be done for a file that was successfully ingested. This will remove the .tab version of the file that was generated. From a828fd1ba8cc6d6c01c818ad1a24db7bcbd624e9 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Wed, 14 Feb 2024 14:17:32 -0500 Subject: [PATCH 058/141] #10286 add integration tests --- .../edu/harvard/iq/dataverse/api/Files.java | 1 - .../iq/dataverse/util/json/JsonPrinter.java | 3 +- .../iq/dataverse/api/DataversesIT.java | 28 ++++++++ .../edu/harvard/iq/dataverse/api/FilesIT.java | 69 +++++++++++++++++++ .../edu/harvard/iq/dataverse/api/UtilIT.java | 16 +++++ 5 files changed, 115 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Files.java b/src/main/java/edu/harvard/iq/dataverse/api/Files.java index 155d8953d15..4fd66d45e47 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Files.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Files.java @@ -514,7 +514,6 @@ public Response getFileDataDraft(@Context ContainerRequestContext crc, @PathPara @Path("{id}") public Response getFileData(@Context ContainerRequestContext crc, @PathParam("id") String fileIdOrPersistentId, @Context UriInfo uriInfo, @Context HttpHeaders headers, @Context HttpServletResponse response, @QueryParam("returnOwners") Boolean returnOwners) throws WrappedResponse, Exception { Boolean includeOwners = returnOwners == null ? false : returnOwners; - System.out.print("includeOwners: " + includeOwners); return getFileDataResponse(getRequestUser(crc), fileIdOrPersistentId, uriInfo, headers, response, false, includeOwners); } diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index 6f750eaddac..d64f77b3526 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -335,7 +335,8 @@ public static JsonArrayBuilder getOwnersFromDvObject(DvObject dvObject) { } if (dvo.isInstanceofDataset() || dvo.isInstanceofDataFile() ){ if (dvo.getIdentifier() != null){ - ownerObject.add("identifier", dvo.getIdentifier()); + Dataset ds = (Dataset) dvo; + ownerObject.add("identifier", ds.getGlobalId().asString()); } else { ownerObject.add("identifier", dvo.getId()); } diff --git a/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java index 78ece6ecc42..e41793a10d5 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java @@ -145,6 +145,34 @@ public void testMinimalDataverse() throws FileNotFoundException { deleteDataverse.prettyPrint(); deleteDataverse.then().assertThat().statusCode(OK.getStatusCode()); } + + + @Test + public void testGetDataverseOwners() throws FileNotFoundException { + Response createUser = UtilIT.createRandomUser(); + createUser.prettyPrint(); + String username = UtilIT.getUsernameFromResponse(createUser); + String apiToken = UtilIT.getApiTokenFromResponse(createUser); + Response createDataverse1Response = UtilIT.createRandomDataverse(apiToken); + + createDataverse1Response.prettyPrint(); + createDataverse1Response.then().assertThat().statusCode(CREATED.getStatusCode()); + + String first = UtilIT.getAliasFromResponse(createDataverse1Response); + + Response getWithOwnersFirst = UtilIT.getDataverseWithOwners(first, apiToken, true); + getWithOwnersFirst.prettyPrint(); + + Response createLevel1a = UtilIT.createSubDataverse(UtilIT.getRandomDvAlias() + "-level1a", null, apiToken, first); + createLevel1a.prettyPrint(); + String level1a = UtilIT.getAliasFromResponse(createLevel1a); + + Response getWithOwners = UtilIT.getDataverseWithOwners(level1a, apiToken, true); + getWithOwners.prettyPrint(); + + getWithOwners.then().assertThat().body("data.ownerArray[0].identifier", equalTo(first)); + + } /** * A regular user can create a Dataverse Collection and access its diff --git a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java index cfc6f9335b3..fe9985115e5 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java @@ -1465,6 +1465,75 @@ public void testGetFileInfo() { assertEquals(200, deleteUserResponse.getStatusCode()); } + @Test + public void testGetFileOwners() { + Response createUser = UtilIT.createRandomUser(); + String username = UtilIT.getUsernameFromResponse(createUser); + String apiToken = UtilIT.getApiTokenFromResponse(createUser); + Response makeSuperUser = UtilIT.makeSuperUser(username); + String dataverseAlias = createDataverseGetAlias(apiToken); + + + Response createDatasetResponse = UtilIT.createRandomDatasetViaNativeApi(dataverseAlias, apiToken); + createDatasetResponse.prettyPrint(); + Integer datasetId = JsonPath.from(createDatasetResponse.body().asString()).getInt("data.id"); + + String datasetPid = UtilIT.getDatasetPersistentIdFromResponse(createDatasetResponse); + + createUser = UtilIT.createRandomUser(); + String apiTokenRegular = UtilIT.getApiTokenFromResponse(createUser); + + msg("Add a non-tabular file"); + String pathToFile = "scripts/search/data/binary/trees.png"; + Response addResponse = UtilIT.uploadFileViaNative(datasetId.toString(), pathToFile, apiToken); + + String dataFileId = addResponse.getBody().jsonPath().getString("data.files[0].dataFile.id"); + msgt("datafile id: " + dataFileId); + + addResponse.prettyPrint(); + + Response getFileDataResponse = UtilIT.getFileWithOwners(dataFileId, apiToken, true); + + getFileDataResponse.prettyPrint(); + getFileDataResponse.then().assertThat() + .body("data.label", equalTo("trees.png")) + .body("data.dataFile.filename", equalTo("trees.png")) + .body("data.dataFile.contentType", equalTo("image/png")) + .body("data.dataFile.filesize", equalTo(8361)) + .statusCode(OK.getStatusCode()); + + getFileDataResponse.then().assertThat().body("data.dataFile.ownerArray[0].identifier", equalTo(datasetPid)); + + // ------------------------- + // Publish dataverse and dataset + // ------------------------- + msg("Publish dataverse and dataset"); + Response publishDataversetResp = UtilIT.publishDataverseViaSword(dataverseAlias, apiToken); + publishDataversetResp.then().assertThat() + .statusCode(OK.getStatusCode()); + + Response publishDatasetResp = UtilIT.publishDatasetViaNativeApi(datasetId, "major", apiToken); + publishDatasetResp.then().assertThat() + .statusCode(OK.getStatusCode()); + //regular user should get to see file data + getFileDataResponse = UtilIT.getFileData(dataFileId, apiTokenRegular); + getFileDataResponse.then().assertThat() + .statusCode(OK.getStatusCode()); + + //cleanup + /* + Response destroyDatasetResponse = UtilIT.destroyDataset(datasetId, apiToken); + assertEquals(200, destroyDatasetResponse.getStatusCode()); + + Response deleteDataverseResponse = UtilIT.deleteDataverse(dataverseAlias, apiToken); + assertEquals(200, deleteDataverseResponse.getStatusCode()); + + Response deleteUserResponse = UtilIT.deleteUser(username); + assertEquals(200, deleteUserResponse.getStatusCode()); + */ + + } + @Test public void testValidateDDI_issue6027() throws InterruptedException { msgt("testValidateDDI_issue6027"); diff --git a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java index 0598bb80ea6..0847aea1d37 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -1485,6 +1485,22 @@ static Response getDatasetWithOwners(String persistentId, String apiToken, bool + persistentId + (returnOwners ? "&returnOwners=true" : "")); } + + static Response getFileWithOwners(String datafileId, String apiToken, boolean returnOwners) { + return given() + .header(API_TOKEN_HTTP_HEADER, apiToken) + .get("/api/files/" + + datafileId + + (returnOwners ? "/?returnOwners=true" : "")); + } + + static Response getDataverseWithOwners(String alias, String apiToken, boolean returnOwners) { + return given() + .header(API_TOKEN_HTTP_HEADER, apiToken) + .get("/api/dataverses/" + + alias + + (returnOwners ? "/?returnOwners=true" : "")); + } static Response getMetadataBlockFromDatasetVersion(String persistentId, String versionNumber, String metadataBlock, String apiToken) { return given() From 923f02ef4a9aaff8c55f0f6ebc2dbfecad717246 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Wed, 14 Feb 2024 14:57:17 -0500 Subject: [PATCH 059/141] #10286 delete test data --- .../edu/harvard/iq/dataverse/api/DatasetsIT.java | 15 ++++++++++++++- .../edu/harvard/iq/dataverse/api/FilesIT.java | 4 ++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java b/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java index 3703a0d39c3..f4e70e03d45 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java @@ -1913,8 +1913,21 @@ public void testGetIncludeOwnerArray() { Response getDatasetWithOwners = UtilIT.getDatasetWithOwners(persistentId, apiToken, true); getDatasetWithOwners.prettyPrint(); - getDatasetWithOwners.then().assertThat().body("data.ownerArray[0].identifier", equalTo(dataverseAlias)); + getDatasetWithOwners.then().assertThat().body("data.ownerArray[0].identifier", equalTo(dataverseAlias)); + + Response destroyDatasetResponse = UtilIT.destroyDataset(datasetId, apiToken); + assertEquals(200, destroyDatasetResponse.getStatusCode()); + + Response deleteDataverseResponse = UtilIT.deleteDataverse(dataverseAlias, apiToken); + assertEquals(200, deleteDataverseResponse.getStatusCode()); + + Response deleteUserResponse = UtilIT.deleteUser(username); + assertEquals(200, deleteUserResponse.getStatusCode()); + } + + + /** * In order for this test to pass you must have the Data Capture Module ( diff --git a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java index fe9985115e5..7ac43bbae94 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java @@ -1521,7 +1521,7 @@ public void testGetFileOwners() { .statusCode(OK.getStatusCode()); //cleanup - /* + Response destroyDatasetResponse = UtilIT.destroyDataset(datasetId, apiToken); assertEquals(200, destroyDatasetResponse.getStatusCode()); @@ -1530,7 +1530,7 @@ public void testGetFileOwners() { Response deleteUserResponse = UtilIT.deleteUser(username); assertEquals(200, deleteUserResponse.getStatusCode()); - */ + } From 70db48f7b51c1f789674fed74ba39d6c6bed80c4 Mon Sep 17 00:00:00 2001 From: qqmyers Date: Wed, 14 Feb 2024 16:21:20 -0500 Subject: [PATCH 060/141] change to require publish to uningest for a problem --- .../edu/harvard/iq/dataverse/FilePage.java | 20 ++++++++++--------- .../webapp/file-edit-button-fragment.xhtml | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/FilePage.java b/src/main/java/edu/harvard/iq/dataverse/FilePage.java index 37798f1cd3c..909a616a4a3 100644 --- a/src/main/java/edu/harvard/iq/dataverse/FilePage.java +++ b/src/main/java/edu/harvard/iq/dataverse/FilePage.java @@ -547,16 +547,17 @@ public String uningestFile() throws CommandException { if (!file.isTabularData()) { //Ingest never succeeded, either there was a failure or this is not a tabular data file - User u = session.getUser(); - if (!u.isAuthenticated() || !u.isSuperuser()) { - logger.warning("User: " + u.getIdentifier() + " tried to uningest a file"); - // Shouldn't happen (choice not displayed for users who don't have the right - // permission), but check anyway - JH.addMessage(FacesMessage.SEVERITY_WARN, - BundleUtil.getStringFromBundle("file.ingest.cantUningestFileWarning")); - return null; - } if (file.isIngestProblem()) { + //We allow anyone who can publish to uningest in order to clear a problem + User u = session.getUser(); + if (!u.isAuthenticated() || !(permissionService.permissionsFor(u, file).contains(Permission.PublishDataset))) { + logger.warning("User: " + u.getIdentifier() + " tried to uningest a file"); + // Shouldn't happen (choice not displayed for users who don't have the right + // permission), but check anyway + JH.addMessage(FacesMessage.SEVERITY_WARN, + BundleUtil.getStringFromBundle("file.ingest.cantUningestFileWarning")); + return null; + } file.setIngestDone(); file.setIngestReport(null); } else { @@ -566,6 +567,7 @@ public String uningestFile() throws CommandException { return null; } } else { + //Superuser required to uningest after a success //Uningest command does it's own check for isSuperuser commandEngine.submit(new UningestFileCommand(dvRequestService.getDataverseRequest(), file)); Long dataFileId = file.getId(); diff --git a/src/main/webapp/file-edit-button-fragment.xhtml b/src/main/webapp/file-edit-button-fragment.xhtml index e08de716cda..fd455521c98 100644 --- a/src/main/webapp/file-edit-button-fragment.xhtml +++ b/src/main/webapp/file-edit-button-fragment.xhtml @@ -79,7 +79,7 @@ - +

    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

    -
    +
    diff --git a/src/main/webapp/dataverse.xhtml b/src/main/webapp/dataverse.xhtml index 41e2807c4fd..7f70f28e194 100644 --- a/src/main/webapp/dataverse.xhtml +++ b/src/main/webapp/dataverse.xhtml @@ -283,6 +283,19 @@
    +
    + + #{bundle.pidProviderOption} + + +
    + + + + +
    +
    diff --git a/src/test/java/edu/harvard/iq/dataverse/GlobalIdTest.java b/src/test/java/edu/harvard/iq/dataverse/GlobalIdTest.java index 394f08c6e93..7065e9689e1 100644 --- a/src/test/java/edu/harvard/iq/dataverse/GlobalIdTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/GlobalIdTest.java @@ -4,6 +4,8 @@ import org.junit.jupiter.api.Test; import edu.harvard.iq.dataverse.pidproviders.PidUtil; +import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider; +import edu.harvard.iq.dataverse.pidproviders.handle.HandlePidProvider; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -19,7 +21,7 @@ public class GlobalIdTest { @Test public void testValidDOI() { System.out.println("testValidDOI"); - GlobalId instance = new GlobalId(DOIServiceBean.DOI_PROTOCOL,"10.5072","FK2/BYM3IW", "/", DOIServiceBean.DOI_RESOLVER_URL, null); + GlobalId instance = new GlobalId(AbstractDOIProvider.DOI_PROTOCOL,"10.5072","FK2/BYM3IW", "/", AbstractDOIProvider.DOI_RESOLVER_URL, null); assertEquals("doi", instance.getProtocol()); assertEquals("10.5072", instance.getAuthority()); @@ -30,7 +32,7 @@ public void testValidDOI() { @Test public void testValidHandle() { System.out.println("testValidDOI"); - GlobalId instance = new GlobalId(HandlenetServiceBean.HDL_PROTOCOL, "1902.1","111012", "/", HandlenetServiceBean.HDL_RESOLVER_URL, null); + GlobalId instance = new GlobalId(HandlePidProvider.HDL_PROTOCOL, "1902.1","111012", "/", HandlePidProvider.HDL_RESOLVER_URL, null); assertEquals("hdl", instance.getProtocol()); assertEquals("1902.1", instance.getAuthority()); @@ -57,7 +59,7 @@ public void testInject() { System.out.println("testInject (weak test)"); // String badProtocol = "hdl:'Select value from datasetfieldvalue';/ha"; - GlobalId instance = PidUtil.parseAsGlobalID(HandlenetServiceBean.HDL_PROTOCOL, "'Select value from datasetfieldvalue';", "ha"); + GlobalId instance = PidUtil.parseAsGlobalID(HandlePidProvider.HDL_PROTOCOL, "'Select value from datasetfieldvalue';", "ha"); assertNull(instance); //exception.expect(IllegalArgumentException.class); diff --git a/src/test/java/edu/harvard/iq/dataverse/PersistentIdentifierServiceBeanTest.java b/src/test/java/edu/harvard/iq/dataverse/PersistentIdentifierServiceBeanTest.java deleted file mode 100644 index 542d00d0d78..00000000000 --- a/src/test/java/edu/harvard/iq/dataverse/PersistentIdentifierServiceBeanTest.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package edu.harvard.iq.dataverse; - -import edu.harvard.iq.dataverse.engine.TestCommandContext; -import edu.harvard.iq.dataverse.engine.command.CommandContext; -import edu.harvard.iq.dataverse.pidproviders.FakePidProviderServiceBean; -import edu.harvard.iq.dataverse.pidproviders.PermaLinkPidProviderServiceBean; -import edu.harvard.iq.dataverse.settings.SettingsServiceBean; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import org.mockito.junit.jupiter.MockitoExtension; - - -import static org.junit.jupiter.api.Assertions.*; - -/** - * - * @author michael - */ -@ExtendWith(MockitoExtension.class) -public class PersistentIdentifierServiceBeanTest { - - @Mock - private SettingsServiceBean settingsServiceBean; - - @InjectMocks - DOIEZIdServiceBean ezidServiceBean = new DOIEZIdServiceBean(); - @InjectMocks - DOIDataCiteServiceBean dataCiteServiceBean = new DOIDataCiteServiceBean(); - @InjectMocks - FakePidProviderServiceBean fakePidProviderServiceBean = new FakePidProviderServiceBean(); - HandlenetServiceBean hdlServiceBean = new HandlenetServiceBean(); - PermaLinkPidProviderServiceBean permaLinkServiceBean = new PermaLinkPidProviderServiceBean(); - - CommandContext ctxt; - - @BeforeEach - public void setup() { - MockitoAnnotations.initMocks(this); - ctxt = new TestCommandContext(){ - @Override - public HandlenetServiceBean handleNet() { - return hdlServiceBean; - } - - @Override - public DOIDataCiteServiceBean doiDataCite() { - return dataCiteServiceBean; - } - - @Override - public DOIEZIdServiceBean doiEZId() { - return ezidServiceBean; - } - - @Override - public FakePidProviderServiceBean fakePidProvider() { - return fakePidProviderServiceBean; - } - - @Override - public PermaLinkPidProviderServiceBean permaLinkProvider() { - return permaLinkServiceBean; - } - - }; - } - - /** - * Test of getBean method, of class PersistentIdentifierServiceBean. - */ - @Test - public void testGetBean_String_CommandContext_OK() { - ctxt.settings().setValueForKey( SettingsServiceBean.Key.DoiProvider, "EZID"); - Mockito.when(settingsServiceBean.getValueForKey(SettingsServiceBean.Key.DoiProvider, "")).thenReturn("EZID"); - - assertEquals(ezidServiceBean, - GlobalIdServiceBean.getBean("doi", ctxt)); - - ctxt.settings().setValueForKey( SettingsServiceBean.Key.DoiProvider, "DataCite"); - Mockito.when(settingsServiceBean.getValueForKey(SettingsServiceBean.Key.DoiProvider, "")).thenReturn("DataCite"); - - assertEquals(dataCiteServiceBean, - GlobalIdServiceBean.getBean("doi", ctxt)); - - ctxt.settings().setValueForKey(SettingsServiceBean.Key.DoiProvider, "FAKE"); - Mockito.when(settingsServiceBean.getValueForKey(SettingsServiceBean.Key.DoiProvider, "")).thenReturn("FAKE"); - - assertEquals(fakePidProviderServiceBean, - GlobalIdServiceBean.getBean("doi", ctxt)); - - assertEquals(hdlServiceBean, - GlobalIdServiceBean.getBean("hdl", ctxt)); - - assertEquals(permaLinkServiceBean, - GlobalIdServiceBean.getBean("perma", ctxt)); - } - - @Test - public void testGetBean_String_CommandContext_BAD() { - ctxt.settings().setValueForKey( SettingsServiceBean.Key.DoiProvider, "non-existent-provider"); - assertNull(GlobalIdServiceBean.getBean("doi", ctxt)); - - - assertNull(GlobalIdServiceBean.getBean("non-existent-protocol", ctxt)); - } - - /** - * Test of getBean method, of class PersistentIdentifierServiceBean. - */ - @Test - public void testGetBean_CommandContext() { - ctxt.settings().setValueForKey( SettingsServiceBean.Key.Protocol, "doi"); - ctxt.settings().setValueForKey( SettingsServiceBean.Key.DoiProvider, "EZID"); - Mockito.when(settingsServiceBean.getValueForKey(SettingsServiceBean.Key.DoiProvider, "")).thenReturn("EZID"); - - assertEquals(ezidServiceBean, - GlobalIdServiceBean.getBean("doi", ctxt)); - - ctxt.settings().setValueForKey( SettingsServiceBean.Key.Protocol, "hdl"); - assertEquals(hdlServiceBean, - GlobalIdServiceBean.getBean("hdl", ctxt)); - - ctxt.settings().setValueForKey( SettingsServiceBean.Key.Protocol, "perma"); - assertEquals(permaLinkServiceBean, - GlobalIdServiceBean.getBean("perma", ctxt)); - } - - -} diff --git a/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java b/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java index 304b0bd0438..c3036deb122 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java @@ -1217,6 +1217,10 @@ public void testExcludeEmail() { } + @Disabled + /*The identifier generation style is no longer a global, dynamically changeable setting. To make this test work after PR #10234, + * will require configuring a PidProvider that uses this style and creating a collection/dataset that uses that provider. + */ @Test public void testStoredProcGeneratedAsIdentifierGenerationStyle() { // Please note that this test only works if the stored procedure diff --git a/src/test/java/edu/harvard/iq/dataverse/dataaccess/GlobusOverlayAccessIOTest.java b/src/test/java/edu/harvard/iq/dataverse/dataaccess/GlobusOverlayAccessIOTest.java index ad980aa28cd..d173f65757f 100644 --- a/src/test/java/edu/harvard/iq/dataverse/dataaccess/GlobusOverlayAccessIOTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/dataaccess/GlobusOverlayAccessIOTest.java @@ -3,11 +3,11 @@ */ package edu.harvard.iq.dataverse.dataaccess; -import edu.harvard.iq.dataverse.DOIServiceBean; import edu.harvard.iq.dataverse.DataFile; import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.GlobalId; import edu.harvard.iq.dataverse.mocks.MocksFactory; +import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -94,8 +94,8 @@ public static void tearDown() { void testGlobusOverlayIdentifiers() throws IOException { dataset = MocksFactory.makeDataset(); - dataset.setGlobalId(new GlobalId(DOIServiceBean.DOI_PROTOCOL, authority, identifier, "/", - DOIServiceBean.DOI_RESOLVER_URL, null)); + dataset.setGlobalId(new GlobalId(AbstractDOIProvider.DOI_PROTOCOL, authority, identifier, "/", + AbstractDOIProvider.DOI_RESOLVER_URL, null)); mDatafile = MocksFactory.makeDataFile(); mDatafile.setOwner(dataset); mDatafile.setStorageIdentifier("globusm://" + baseStoreId1); diff --git a/src/test/java/edu/harvard/iq/dataverse/dataaccess/RemoteOverlayAccessIOTest.java b/src/test/java/edu/harvard/iq/dataverse/dataaccess/RemoteOverlayAccessIOTest.java index 1c371881ba6..2c0e0a5c6b7 100644 --- a/src/test/java/edu/harvard/iq/dataverse/dataaccess/RemoteOverlayAccessIOTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/dataaccess/RemoteOverlayAccessIOTest.java @@ -4,11 +4,11 @@ */ package edu.harvard.iq.dataverse.dataaccess; -import edu.harvard.iq.dataverse.DOIServiceBean; import edu.harvard.iq.dataverse.DataFile; import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.GlobalId; import edu.harvard.iq.dataverse.mocks.MocksFactory; +import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider; import edu.harvard.iq.dataverse.util.UrlSignerUtil; import org.junit.jupiter.api.AfterEach; @@ -50,7 +50,7 @@ public void setUp() { System.setProperty("dataverse.files.file.label", "default"); datafile = MocksFactory.makeDataFile(); dataset = MocksFactory.makeDataset(); - dataset.setGlobalId(new GlobalId(DOIServiceBean.DOI_PROTOCOL, authority, identifier, "/", DOIServiceBean.DOI_RESOLVER_URL, null)); + dataset.setGlobalId(new GlobalId(AbstractDOIProvider.DOI_PROTOCOL, authority, identifier, "/", AbstractDOIProvider.DOI_RESOLVER_URL, null)); datafile.setOwner(dataset); datafile.setStorageIdentifier("test://" + baseStoreId + "//" + logoPath); diff --git a/src/test/java/edu/harvard/iq/dataverse/engine/TestCommandContext.java b/src/test/java/edu/harvard/iq/dataverse/engine/TestCommandContext.java index a80adb33b8d..255125189ae 100644 --- a/src/test/java/edu/harvard/iq/dataverse/engine/TestCommandContext.java +++ b/src/test/java/edu/harvard/iq/dataverse/engine/TestCommandContext.java @@ -11,8 +11,7 @@ import edu.harvard.iq.dataverse.engine.command.Command; import edu.harvard.iq.dataverse.engine.command.CommandContext; import edu.harvard.iq.dataverse.ingest.IngestServiceBean; -import edu.harvard.iq.dataverse.pidproviders.FakePidProviderServiceBean; -import edu.harvard.iq.dataverse.pidproviders.PermaLinkPidProviderServiceBean; +import edu.harvard.iq.dataverse.pidproviders.PidProviderFactoryBean; import edu.harvard.iq.dataverse.privateurl.PrivateUrlServiceBean; import edu.harvard.iq.dataverse.search.IndexBatchServiceBean; import edu.harvard.iq.dataverse.search.IndexServiceBean; @@ -122,27 +121,7 @@ public DataverseFieldTypeInputLevelServiceBean fieldTypeInputLevels() { } @Override - public DOIEZIdServiceBean doiEZId() { - return null; - } - - @Override - public DOIDataCiteServiceBean doiDataCite() { - return null; - } - - @Override - public FakePidProviderServiceBean fakePidProvider() { - return null; - } - - @Override - public HandlenetServiceBean handleNet() { - return null; - } - - @Override - public PermaLinkPidProviderServiceBean permaLinkProvider() { + public PidProviderFactoryBean pidProviderFactory() { return null; } diff --git a/src/test/java/edu/harvard/iq/dataverse/export/OpenAireExportUtilTest.java b/src/test/java/edu/harvard/iq/dataverse/export/OpenAireExportUtilTest.java index 4fc84f7e72d..8ebdeea6243 100644 --- a/src/test/java/edu/harvard/iq/dataverse/export/OpenAireExportUtilTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/export/OpenAireExportUtilTest.java @@ -7,12 +7,13 @@ import com.google.gson.Gson; -import edu.harvard.iq.dataverse.DOIServiceBean; import edu.harvard.iq.dataverse.GlobalId; -import edu.harvard.iq.dataverse.HandlenetServiceBean; import edu.harvard.iq.dataverse.api.dto.DatasetDTO; import edu.harvard.iq.dataverse.api.dto.DatasetVersionDTO; import edu.harvard.iq.dataverse.export.openaire.OpenAireExportUtil; +import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider; +import edu.harvard.iq.dataverse.pidproviders.handle.HandlePidProvider; + import java.io.IOException; import java.io.StringWriter; import java.nio.charset.StandardCharsets; @@ -56,7 +57,7 @@ public void testWriteIdentifierElementDoi() throws XMLStreamException { String persistentAgency = "doi"; String persistentAuthority = "10.123"; String persistentId = "123"; - GlobalId globalId = new GlobalId(persistentAgency, persistentAuthority, persistentId, null, DOIServiceBean.DOI_RESOLVER_URL, null); + GlobalId globalId = new GlobalId(persistentAgency, persistentAuthority, persistentId, null, AbstractDOIProvider.DOI_RESOLVER_URL, null); // when OpenAireExportUtil.writeIdentifierElement(xmlWriter, globalId.asURL(), null); @@ -76,7 +77,7 @@ public void testWriteIdentifierElementHandle() throws XMLStreamException { String persistentAgency = "hdl"; String persistentAuthority = "1902.1"; String persistentId = "111012"; - GlobalId globalId = new GlobalId(persistentAgency, persistentAuthority, persistentId, null, HandlenetServiceBean.HDL_RESOLVER_URL, null); + GlobalId globalId = new GlobalId(persistentAgency, persistentAuthority, persistentId, null, HandlePidProvider.HDL_RESOLVER_URL, null); // when OpenAireExportUtil.writeIdentifierElement(xmlWriter, globalId.asURL(), null); diff --git a/src/test/java/edu/harvard/iq/dataverse/externaltools/ExternalToolHandlerTest.java b/src/test/java/edu/harvard/iq/dataverse/externaltools/ExternalToolHandlerTest.java index 6f0132e2bc9..639a7c542c4 100644 --- a/src/test/java/edu/harvard/iq/dataverse/externaltools/ExternalToolHandlerTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/externaltools/ExternalToolHandlerTest.java @@ -1,6 +1,5 @@ package edu.harvard.iq.dataverse.externaltools; -import edu.harvard.iq.dataverse.DOIServiceBean; import edu.harvard.iq.dataverse.DataFile; import edu.harvard.iq.dataverse.DataFileServiceBean; import edu.harvard.iq.dataverse.Dataset; @@ -9,6 +8,7 @@ import edu.harvard.iq.dataverse.GlobalId; import edu.harvard.iq.dataverse.authorization.users.ApiToken; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; +import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider; import edu.harvard.iq.dataverse.settings.JvmSettings; import edu.harvard.iq.dataverse.util.URLTokenUtil; import edu.harvard.iq.dataverse.util.json.JsonUtil; @@ -267,7 +267,7 @@ public void testDatasetConfigureTool() { .build().toString()); var dataset = new Dataset(); - dataset.setGlobalId(new GlobalId(DOIServiceBean.DOI_PROTOCOL, "10.5072", "ABC123", null, DOIServiceBean.DOI_RESOLVER_URL, null)); + dataset.setGlobalId(new GlobalId(AbstractDOIProvider.DOI_PROTOCOL, "10.5072", "ABC123", null, AbstractDOIProvider.DOI_RESOLVER_URL, null)); ApiToken nullApiToken = null; String nullLocaleCode = "en"; var externalToolHandler = new ExternalToolHandler(externalTool, dataset, nullApiToken, nullLocaleCode); diff --git a/src/test/java/edu/harvard/iq/dataverse/externaltools/ExternalToolServiceBeanTest.java b/src/test/java/edu/harvard/iq/dataverse/externaltools/ExternalToolServiceBeanTest.java index 4f5af8b97b0..bb39aecfa79 100644 --- a/src/test/java/edu/harvard/iq/dataverse/externaltools/ExternalToolServiceBeanTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/externaltools/ExternalToolServiceBeanTest.java @@ -1,6 +1,5 @@ package edu.harvard.iq.dataverse.externaltools; -import edu.harvard.iq.dataverse.DOIServiceBean; import edu.harvard.iq.dataverse.DataFile; import edu.harvard.iq.dataverse.DataFileServiceBean; import edu.harvard.iq.dataverse.DataTable; @@ -9,6 +8,7 @@ import edu.harvard.iq.dataverse.FileMetadata; import edu.harvard.iq.dataverse.GlobalId; import edu.harvard.iq.dataverse.authorization.users.ApiToken; +import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider; import edu.harvard.iq.dataverse.util.URLTokenUtil; import java.util.ArrayList; @@ -144,7 +144,7 @@ public void testParseAddFileToolFilePid() { assertEquals("explorer", externalTool.getToolName()); DataFile dataFile = new DataFile(); dataFile.setId(42l); - dataFile.setGlobalId(new GlobalId(DOIServiceBean.DOI_PROTOCOL,"10.5072","FK2/RMQT6J/G9F1A1", "/", DOIServiceBean.DOI_RESOLVER_URL, null)); + dataFile.setGlobalId(new GlobalId(AbstractDOIProvider.DOI_PROTOCOL,"10.5072","FK2/RMQT6J/G9F1A1", "/", AbstractDOIProvider.DOI_RESOLVER_URL, null)); FileMetadata fmd = new FileMetadata(); fmd.setId(2L); DatasetVersion dv = new DatasetVersion(); diff --git a/src/test/java/edu/harvard/iq/dataverse/globus/GlobusUtilTest.java b/src/test/java/edu/harvard/iq/dataverse/globus/GlobusUtilTest.java index 56f8731b9c8..095e798f229 100644 --- a/src/test/java/edu/harvard/iq/dataverse/globus/GlobusUtilTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/globus/GlobusUtilTest.java @@ -13,7 +13,6 @@ import org.mockito.Mock; import org.mockito.Mockito; -import edu.harvard.iq.dataverse.DOIServiceBean; import edu.harvard.iq.dataverse.DataFile; import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.GlobalId; @@ -21,6 +20,7 @@ import edu.harvard.iq.dataverse.dataaccess.DataAccess; import edu.harvard.iq.dataverse.dataaccess.GlobusAccessibleStore; import edu.harvard.iq.dataverse.mocks.MocksFactory; +import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider; import edu.harvard.iq.dataverse.util.json.JsonUtil; import jakarta.json.JsonObject; @@ -52,8 +52,8 @@ public void setUp() { "d7c42580-6538-4605-9ad8-116a61982644/hdc1"); dataset = MocksFactory.makeDataset(); - dataset.setGlobalId(new GlobalId(DOIServiceBean.DOI_PROTOCOL, authority, identifier, "/", - DOIServiceBean.DOI_RESOLVER_URL, null)); + dataset.setGlobalId(new GlobalId(AbstractDOIProvider.DOI_PROTOCOL, authority, identifier, "/", + AbstractDOIProvider.DOI_RESOLVER_URL, null)); mDatafile = MocksFactory.makeDataFile(); mDatafile.setOwner(dataset); mDatafile.setStorageIdentifier("globusm://" + baseStoreId1); diff --git a/src/test/java/edu/harvard/iq/dataverse/pidproviders/PidUtilTest.java b/src/test/java/edu/harvard/iq/dataverse/pidproviders/PidUtilTest.java index dabc7f68fce..dc226d2e85b 100644 --- a/src/test/java/edu/harvard/iq/dataverse/pidproviders/PidUtilTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/pidproviders/PidUtilTest.java @@ -1,18 +1,43 @@ package edu.harvard.iq.dataverse.pidproviders; -import edu.harvard.iq.dataverse.DOIServiceBean; +import edu.harvard.iq.dataverse.Dataset; +import edu.harvard.iq.dataverse.Dataverse; import edu.harvard.iq.dataverse.GlobalId; -import edu.harvard.iq.dataverse.GlobalIdServiceBean; +import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider; +import edu.harvard.iq.dataverse.pidproviders.doi.UnmanagedDOIProvider; +import edu.harvard.iq.dataverse.pidproviders.doi.datacite.DataCiteDOIProvider; +import edu.harvard.iq.dataverse.pidproviders.doi.datacite.DataCiteProviderFactory; +import edu.harvard.iq.dataverse.pidproviders.doi.ezid.EZIdDOIProvider; +import edu.harvard.iq.dataverse.pidproviders.doi.ezid.EZIdProviderFactory; +import edu.harvard.iq.dataverse.pidproviders.doi.fake.FakeDOIProvider; +import edu.harvard.iq.dataverse.pidproviders.doi.fake.FakeProviderFactory; +import edu.harvard.iq.dataverse.pidproviders.handle.HandlePidProvider; +import edu.harvard.iq.dataverse.pidproviders.handle.HandleProviderFactory; +import edu.harvard.iq.dataverse.pidproviders.handle.UnmanagedHandlePidProvider; +import edu.harvard.iq.dataverse.pidproviders.perma.PermaLinkPidProvider; +import edu.harvard.iq.dataverse.pidproviders.perma.PermaLinkProviderFactory; +import edu.harvard.iq.dataverse.pidproviders.perma.UnmanagedPermaLinkPidProvider; +import edu.harvard.iq.dataverse.settings.JvmSettings; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; +import edu.harvard.iq.dataverse.util.SystemConfig; import edu.harvard.iq.dataverse.util.json.JsonUtil; +import edu.harvard.iq.dataverse.util.testing.JvmSetting; +import edu.harvard.iq.dataverse.util.testing.LocalJvmSettings; + import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import jakarta.json.Json; import jakarta.json.JsonObjectBuilder; import jakarta.ws.rs.NotFoundException; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.ExtendWith; @@ -24,32 +49,128 @@ import static org.junit.jupiter.api.Assertions.*; -/** - * Useful for testing but requires DataCite credentials, etc. - */ + @ExtendWith(MockitoExtension.class) +@LocalJvmSettings +//Perma 1 +@JvmSetting(key = JvmSettings.PID_PROVIDER_LABEL, value = "perma 1", varArgs = "perma1") +@JvmSetting(key = JvmSettings.PID_PROVIDER_TYPE, value = PermaLinkPidProvider.TYPE, varArgs = "perma1") +@JvmSetting(key = JvmSettings.PID_PROVIDER_AUTHORITY, value = "DANSLINK", varArgs = "perma1") +@JvmSetting(key = JvmSettings.PID_PROVIDER_SHOULDER, value = "QE", varArgs = "perma1") +@JvmSetting(key = JvmSettings.PERMALINK_SEPARATOR, value = "-", varArgs = "perma1") +@JvmSetting(key = JvmSettings.PID_PROVIDER_EXCLUDED_LIST, value = "perma:DANSLINKQE123456, perma:bad, perma:LINKIT123456", varArgs ="perma1") + +//Perma 2 +@JvmSetting(key = JvmSettings.PID_PROVIDER_LABEL, value = "perma 2", varArgs = "perma2") +@JvmSetting(key = JvmSettings.PID_PROVIDER_TYPE, value = PermaLinkPidProvider.TYPE, varArgs = "perma2") +@JvmSetting(key = JvmSettings.PID_PROVIDER_AUTHORITY, value = "DANSLINK", varArgs = "perma2") +@JvmSetting(key = JvmSettings.PID_PROVIDER_SHOULDER, value = "QE", varArgs = "perma2") +@JvmSetting(key = JvmSettings.PID_PROVIDER_MANAGED_LIST, value = "perma:LINKIT/FK2ABCDEF", varArgs ="perma2") +@JvmSetting(key = JvmSettings.PERMALINK_SEPARATOR, value = "/", varArgs = "perma2") +@JvmSetting(key = JvmSettings.PERMALINK_BASE_URL, value = "https://example.org/123", varArgs = "perma2") +// Datacite 1 +@JvmSetting(key = JvmSettings.PID_PROVIDER_LABEL, value = "dataCite 1", varArgs = "dc1") +@JvmSetting(key = JvmSettings.PID_PROVIDER_TYPE, value = DataCiteDOIProvider.TYPE, varArgs = "dc1") +@JvmSetting(key = JvmSettings.PID_PROVIDER_AUTHORITY, value = "10.5073", varArgs = "dc1") +@JvmSetting(key = JvmSettings.PID_PROVIDER_SHOULDER, value = "FK2", varArgs = "dc1") +@JvmSetting(key = JvmSettings.PID_PROVIDER_EXCLUDED_LIST, value = "doi:10.5073/FK2123456", varArgs ="dc1") +@JvmSetting(key = JvmSettings.DATACITE_MDS_API_URL, value = "https://mds.test.datacite.org/", varArgs = "dc1") +@JvmSetting(key = JvmSettings.DATACITE_REST_API_URL, value = "https://api.test.datacite.org", varArgs ="dc1") +@JvmSetting(key = JvmSettings.DATACITE_USERNAME, value = "test", varArgs ="dc1") +@JvmSetting(key = JvmSettings.DATACITE_PASSWORD, value = "changeme", varArgs ="dc1") +//Datacite 2 +@JvmSetting(key = JvmSettings.PID_PROVIDER_LABEL, value = "dataCite 2", varArgs = "dc2") +@JvmSetting(key = JvmSettings.PID_PROVIDER_TYPE, value = DataCiteDOIProvider.TYPE, varArgs = "dc2") +@JvmSetting(key = JvmSettings.PID_PROVIDER_AUTHORITY, value = "10.5072", varArgs = "dc2") +@JvmSetting(key = JvmSettings.PID_PROVIDER_SHOULDER, value = "FK3", varArgs = "dc2") +@JvmSetting(key = JvmSettings.DATACITE_MDS_API_URL, value = "https://mds.test.datacite.org/", varArgs = "dc2") +@JvmSetting(key = JvmSettings.DATACITE_REST_API_URL, value = "https://api.test.datacite.org", varArgs ="dc2") +@JvmSetting(key = JvmSettings.DATACITE_USERNAME, value = "test2", varArgs ="dc2") +@JvmSetting(key = JvmSettings.DATACITE_PASSWORD, value = "changeme2", varArgs ="dc2") +//EZID 1 +@JvmSetting(key = JvmSettings.PID_PROVIDER_LABEL, value = "EZId 1", varArgs = "ez1") +@JvmSetting(key = JvmSettings.PID_PROVIDER_TYPE, value = EZIdDOIProvider.TYPE, varArgs = "ez1") +@JvmSetting(key = JvmSettings.PID_PROVIDER_AUTHORITY, value = "10.5072", varArgs = "ez1") +@JvmSetting(key = JvmSettings.PID_PROVIDER_SHOULDER, value = "FK2", varArgs = "ez1") +@JvmSetting(key = JvmSettings.EZID_API_URL, value = "https://ezid.cdlib.org/", varArgs = "ez1") +@JvmSetting(key = JvmSettings.EZID_USERNAME, value = "apitest", varArgs ="ez1") +@JvmSetting(key = JvmSettings.EZID_PASSWORD, value = "apitest", varArgs ="ez1") +//FAKE 1 +@JvmSetting(key = JvmSettings.PID_PROVIDER_LABEL, value = "FAKE 1", varArgs = "fake1") +@JvmSetting(key = JvmSettings.PID_PROVIDER_TYPE, value = FakeDOIProvider.TYPE, varArgs = "fake1") +@JvmSetting(key = JvmSettings.PID_PROVIDER_AUTHORITY, value = "10.5074", varArgs = "fake1") +@JvmSetting(key = JvmSettings.PID_PROVIDER_SHOULDER, value = "FK", varArgs = "fake1") +@JvmSetting(key = JvmSettings.PID_PROVIDER_MANAGED_LIST, value = "doi:10.5073/FK3ABCDEF", varArgs ="fake1") + +//HANDLE 1 +@JvmSetting(key = JvmSettings.PID_PROVIDER_LABEL, value = "HDL 1", varArgs = "hdl1") +@JvmSetting(key = JvmSettings.PID_PROVIDER_TYPE, value = HandlePidProvider.TYPE, varArgs = "hdl1") +@JvmSetting(key = JvmSettings.PID_PROVIDER_AUTHORITY, value = "20.500.1234", varArgs = "hdl1") +@JvmSetting(key = JvmSettings.PID_PROVIDER_SHOULDER, value = "", varArgs = "hdl1") +@JvmSetting(key = JvmSettings.PID_PROVIDER_MANAGED_LIST, value = "hdl:20.20.20/FK2ABCDEF", varArgs ="hdl1") +@JvmSetting(key = JvmSettings.HANDLENET_AUTH_HANDLE, value = "20.500.1234/ADMIN", varArgs ="hdl1") +@JvmSetting(key = JvmSettings.HANDLENET_INDEPENDENT_SERVICE, value = "true", varArgs ="hdl1") +@JvmSetting(key = JvmSettings.HANDLENET_INDEX, value = "1", varArgs ="hdl1") +@JvmSetting(key = JvmSettings.HANDLENET_KEY_PASSPHRASE, value = "passphrase", varArgs ="hdl1") +@JvmSetting(key = JvmSettings.HANDLENET_KEY_PATH, value = "/tmp/cred", varArgs ="hdl1") + +//List to instantiate +@JvmSetting(key = JvmSettings.PID_PROVIDERS, value = "perma1, perma2, dc1, dc2, ez1, fake1, hdl1") + public class PidUtilTest { + @Mock private SettingsServiceBean settingsServiceBean; - @InjectMocks - private PermaLinkPidProviderServiceBean p = new PermaLinkPidProviderServiceBean(); - + @BeforeAll + //FWIW @JvmSetting doesn't appear to work with @BeforeAll + public static void setUpClass() throws Exception { + + //This mimics the initial config in the PidProviderFactoryBean.loadProviderFactories method - could potentially be used to mock that bean at some point + Map pidProviderFactoryMap = new HashMap<>(); + pidProviderFactoryMap.put(PermaLinkPidProvider.TYPE, new PermaLinkProviderFactory()); + pidProviderFactoryMap.put(DataCiteDOIProvider.TYPE, new DataCiteProviderFactory()); + pidProviderFactoryMap.put(HandlePidProvider.TYPE, new HandleProviderFactory()); + pidProviderFactoryMap.put(FakeDOIProvider.TYPE, new FakeProviderFactory()); + pidProviderFactoryMap.put(EZIdDOIProvider.TYPE, new EZIdProviderFactory()); + + PidUtil.clearPidProviders(); + + //Read list of providers to add + List providers = Arrays.asList(JvmSettings.PID_PROVIDERS.lookup().split(",\\s")); + //Iterate through the list of providers and add them using the PidProviderFactory of the appropriate type + for (String providerId : providers) { + System.out.println("Loading provider: " + providerId); + String type = JvmSettings.PID_PROVIDER_TYPE.lookup(providerId); + PidProviderFactory factory = pidProviderFactoryMap.get(type); + PidUtil.addToProviderList(factory.createPidProvider(providerId)); + } + PidUtil.addAllToUnmanagedProviderList(Arrays.asList(new UnmanagedDOIProvider(), + new UnmanagedHandlePidProvider(), new UnmanagedPermaLinkPidProvider())); + } + + @AfterAll + public static void tearDownClass() throws Exception { + PidUtil.clearPidProviders(); + } + @BeforeEach public void initMocks() { MockitoAnnotations.initMocks(this); - Mockito.when(settingsServiceBean.getValueForKey(SettingsServiceBean.Key.Protocol)).thenReturn("perma"); - Mockito.when(settingsServiceBean.getValueForKey(SettingsServiceBean.Key.Authority)).thenReturn("DANSLINK"); - p.reInit(); +// Mockito.when(settingsServiceBean.getValueForKey(SettingsServiceBean.Key.Protocol)).thenReturn("perma"); +// Mockito.when(settingsServiceBean.getValueForKey(SettingsServiceBean.Key.Authority)).thenReturn("DANSLINK"); } + /** + * Useful for testing but requires DataCite credentials, etc. + */ @Disabled @Test public void testGetDoi() throws IOException { String username = System.getenv("DataCiteUsername"); String password = System.getenv("DataCitePassword"); String baseUrl = "https://api.test.datacite.org"; - GlobalId pid = new GlobalId(DOIServiceBean.DOI_PROTOCOL,"10.70122","QE5A-XN55", "/", DOIServiceBean.DOI_RESOLVER_URL, null); + GlobalId pid = new GlobalId(AbstractDOIProvider.DOI_PROTOCOL,"10.70122","QE5A-XN55", "/", AbstractDOIProvider.DOI_RESOLVER_URL, null); try { JsonObjectBuilder result = PidUtil.queryDoi(pid, baseUrl, username, password); String out = JsonUtil.prettyPrint(result.build()); @@ -58,23 +179,291 @@ public void testGetDoi() throws IOException { System.out.println("ex: " + ex); } } + @Test - public void testGetPermaLink() throws IOException { - List list = new ArrayList(); + public void testFactories() throws IOException { + PidProvider p = PidUtil.getPidProvider("perma1"); + assertEquals("perma 1", p.getLabel()); + assertEquals(PermaLinkPidProvider.PERMA_PROTOCOL, p.getProtocol()); + assertEquals("DANSLINK", p.getAuthority()); + assertEquals("QE", p.getShoulder()); + assertEquals("-", p.getSeparator()); + assertTrue(p.getUrlPrefix().startsWith(SystemConfig.getDataverseSiteUrlStatic())); + p = PidUtil.getPidProvider("perma2"); + assertTrue(p.getUrlPrefix().startsWith("https://example.org/123")); + p = PidUtil.getPidProvider("dc2"); + assertEquals("FK3", p.getShoulder()); + } + + @Test + public void testPermaLinkParsing() throws IOException { + //Verify that we can parse a valid perma link associated with perma1 + String pid1String = "perma:DANSLINK-QE-5A-XN55"; + GlobalId pid2 = PidUtil.parseAsGlobalID(pid1String); + assertEquals(pid1String, pid2.asString()); + //Check that it was parsed by perma1 and that the URL is correct, etc + assertEquals("perma1", pid2.getProviderId()); + assertEquals(SystemConfig.getDataverseSiteUrlStatic() + "/citation?persistentId=" + pid1String, pid2.asURL()); + assertEquals("DANSLINK", pid2.getAuthority()); + assertEquals(PermaLinkPidProvider.PERMA_PROTOCOL, pid2.getProtocol()); + + //Verify that parsing the URL form works + GlobalId pid3 = PidUtil.parseAsGlobalID(pid2.asURL()); + assertEquals(pid1String, pid3.asString()); + assertEquals("perma1", pid3.getProviderId()); - list.add(p); - PidUtil.addAllToProviderList(list); - GlobalId pid = new GlobalId(PermaLinkPidProviderServiceBean.PERMA_PROTOCOL,"DANSLINK","QE5A-XN55", "", p.getUrlPrefix(), PermaLinkPidProviderServiceBean.PERMA_PROVIDER_NAME); - System.out.println(pid.asString()); - System.out.println(pid.asURL()); + //Repeat the basics with a permalink associated with perma2 + String pid4String = "perma:DANSLINK/QE-5A-XN55"; + GlobalId pid5 = PidUtil.parseAsGlobalID(pid4String); + assertEquals("perma2", pid5.getProviderId()); + assertEquals(pid4String, pid5.asString()); + assertEquals("https://example.org/123/citation?persistentId=" + pid4String, pid5.asURL()); + + } + + @Test + public void testDOIParsing() throws IOException { - GlobalId pid2 = PidUtil.parseAsGlobalID(pid.asString()); - assertEquals(pid.asString(), pid2.asString()); - GlobalId pid3 = PidUtil.parseAsGlobalID(pid.asURL()); - assertEquals(pid.asString(), pid3.asString()); + String pid1String = "doi:10.5073/FK2ABCDEF"; + GlobalId pid2 = PidUtil.parseAsGlobalID(pid1String); + assertEquals(pid1String, pid2.asString()); + assertEquals("dc1", pid2.getProviderId()); + assertEquals("https://doi.org/" + pid2.getAuthority() + PidUtil.getPidProvider(pid2.getProviderId()).getSeparator() + pid2.getIdentifier(),pid2.asURL()); + assertEquals("10.5073", pid2.getAuthority()); + assertEquals(AbstractDOIProvider.DOI_PROTOCOL, pid2.getProtocol()); + GlobalId pid3 = PidUtil.parseAsGlobalID(pid2.asURL()); + assertEquals(pid1String, pid3.asString()); + assertEquals("dc1", pid3.getProviderId()); + + String pid4String = "doi:10.5072/FK3ABCDEF"; + GlobalId pid4 = PidUtil.parseAsGlobalID(pid4String); + assertEquals(pid4String, pid4.asString()); + assertEquals("dc2", pid4.getProviderId()); + + String pid5String = "doi:10.5072/FK2ABCDEF"; + GlobalId pid5 = PidUtil.parseAsGlobalID(pid5String); + assertEquals(pid5String, pid5.asString()); + assertEquals("ez1", pid5.getProviderId()); + String pid6String = "doi:10.5074/FKABCDEF"; + GlobalId pid6 = PidUtil.parseAsGlobalID(pid6String); + assertEquals(pid6String, pid6.asString()); + assertEquals("fake1", pid6.getProviderId()); + + + } + + @Test + public void testHandleParsing() throws IOException { + + String pid1String = "hdl:20.500.1234/10052"; + GlobalId pid2 = PidUtil.parseAsGlobalID(pid1String); + assertEquals(pid1String, pid2.asString()); + assertEquals("hdl1", pid2.getProviderId()); + assertEquals("https://hdl.handle.net/" + pid2.getAuthority() + PidUtil.getPidProvider(pid2.getProviderId()).getSeparator() + pid2.getIdentifier(),pid2.asURL()); + assertEquals("20.500.1234", pid2.getAuthority()); + assertEquals(HandlePidProvider.HDL_PROTOCOL, pid2.getProtocol()); + GlobalId pid3 = PidUtil.parseAsGlobalID(pid2.asURL()); + assertEquals(pid1String, pid3.asString()); + assertEquals("hdl1", pid3.getProviderId()); } + @Test + public void testUnmanagedParsing() throws IOException { + // A handle managed not managed in the hdl1 provider + String pid1String = "hdl:20.500.3456/10052"; + GlobalId pid2 = PidUtil.parseAsGlobalID(pid1String); + assertEquals(pid1String, pid2.asString()); + //Only parsed by the unmanaged provider + assertEquals(UnmanagedHandlePidProvider.ID, pid2.getProviderId()); + assertEquals(HandlePidProvider.HDL_RESOLVER_URL + pid2.getAuthority() + PidUtil.getPidProvider(pid2.getProviderId()).getSeparator() + pid2.getIdentifier(),pid2.asURL()); + assertEquals("20.500.3456", pid2.getAuthority()); + assertEquals(HandlePidProvider.HDL_PROTOCOL, pid2.getProtocol()); + GlobalId pid3 = PidUtil.parseAsGlobalID(pid2.asURL()); + assertEquals(pid1String, pid3.asString()); + assertEquals(UnmanagedHandlePidProvider.ID, pid3.getProviderId()); + + //Same for DOIs + String pid5String = "doi:10.6083/FK2ABCDEF"; + GlobalId pid5 = PidUtil.parseAsGlobalID(pid5String); + assertEquals(pid5String, pid5.asString()); + assertEquals(UnmanagedDOIProvider.ID, pid5.getProviderId()); + + //And Permalinks + String pid6String = "perma:NOTDANSQEABCDEF"; + GlobalId pid6 = PidUtil.parseAsGlobalID(pid6String); + assertEquals(pid6String, pid6.asString()); + assertEquals(UnmanagedPermaLinkPidProvider.ID, pid6.getProviderId()); + + } + + @Test + public void testExcludedSetParsing() throws IOException { + + String pid1String = "doi:10.5073/FK2123456"; + GlobalId pid2 = PidUtil.parseAsGlobalID(pid1String); + assertEquals(pid1String, pid2.asString()); + assertEquals(UnmanagedDOIProvider.ID, pid2.getProviderId()); + assertEquals("https://doi.org/" + pid2.getAuthority() + PidUtil.getPidProvider(pid2.getProviderId()).getSeparator() + pid2.getIdentifier(),pid2.asURL()); + assertEquals("10.5073", pid2.getAuthority()); + assertEquals(AbstractDOIProvider.DOI_PROTOCOL, pid2.getProtocol()); + GlobalId pid3 = PidUtil.parseAsGlobalID(pid2.asURL()); + assertEquals(pid1String, pid3.asString()); + assertEquals(UnmanagedDOIProvider.ID, pid3.getProviderId()); + + String pid4String = "perma:bad"; + GlobalId pid4 = PidUtil.parseAsGlobalID(pid4String); + assertEquals(pid4String, pid4.asString()); + assertEquals(UnmanagedPermaLinkPidProvider.ID, pid4.getProviderId()); + + String pid5String = "perma:DANSLINKQE123456"; + GlobalId pid5 = PidUtil.parseAsGlobalID(pid5String); + assertEquals(pid5String, pid5.asString()); + assertEquals(UnmanagedPermaLinkPidProvider.ID, pid5.getProviderId()); + + String pid6String = "perma:LINKIT123456"; + GlobalId pid6 = PidUtil.parseAsGlobalID(pid6String); + assertEquals(pid6String, pid6.asString()); + assertEquals(UnmanagedPermaLinkPidProvider.ID, pid6.getProviderId()); + + + } + + @Test + public void testManagedSetParsing() throws IOException { + + String pid1String = "doi:10.5073/FK3ABCDEF"; + GlobalId pid2 = PidUtil.parseAsGlobalID(pid1String); + assertEquals(pid1String, pid2.asString()); + assertEquals("fake1", pid2.getProviderId()); + assertEquals("https://doi.org/" + pid2.getAuthority() + PidUtil.getPidProvider(pid2.getProviderId()).getSeparator() + pid2.getIdentifier(),pid2.asURL()); + assertEquals("10.5073", pid2.getAuthority()); + assertEquals(AbstractDOIProvider.DOI_PROTOCOL, pid2.getProtocol()); + GlobalId pid3 = PidUtil.parseAsGlobalID(pid2.asURL()); + assertEquals(pid1String, pid3.asString()); + assertEquals("fake1", pid3.getProviderId()); + assertFalse(PidUtil.getPidProvider(pid3.getProviderId()).canCreatePidsLike(pid3)); + + String pid4String = "hdl:20.20.20/FK2ABCDEF"; + GlobalId pid4 = PidUtil.parseAsGlobalID(pid4String); + assertEquals(pid4String, pid4.asString()); + assertEquals("hdl1", pid4.getProviderId()); + assertFalse(PidUtil.getPidProvider(pid4.getProviderId()).canCreatePidsLike(pid4)); + + String pid5String = "perma:LINKIT/FK2ABCDEF"; + GlobalId pid5 = PidUtil.parseAsGlobalID(pid5String); + assertEquals(pid5String, pid5.asString()); + assertEquals("perma2", pid5.getProviderId()); + assertFalse(PidUtil.getPidProvider(pid5.getProviderId()).canCreatePidsLike(pid5)); + } + + @Test + public void testFindingPidGenerators() throws IOException { + + Dataset dataset1 = new Dataset(); + Dataverse dataverse1 = new Dataverse(); + dataset1.setOwner(dataverse1); + String pidGeneratorSpecs = Json.createObjectBuilder().add("protocol", AbstractDOIProvider.DOI_PROTOCOL).add("authority","10.5072").add("shoulder", "FK2").build().toString(); + //Set a PID generator on the parent + dataverse1.setPidGeneratorSpecs(pidGeneratorSpecs); + assertEquals(pidGeneratorSpecs, dataverse1.getPidGeneratorSpecs()); + //Verify that the parent's PID generator is the effective one + assertEquals("ez1", dataverse1.getEffectivePidGenerator().getId()); + assertEquals("ez1", dataset1.getEffectivePidGenerator().getId()); + //Change dataset to have a provider and verify that it is used instead of any effective one + dataset1.setAuthority("10.5073"); + dataset1.setProtocol(AbstractDOIProvider.DOI_PROTOCOL); + dataset1.setIdentifier("FK2ABCDEF"); + //Reset to get rid of cached @transient value + dataset1.setPidGenerator(null); + assertEquals("dc1", dataset1.getGlobalId().getProviderId()); + assertEquals("dc1", dataset1.getEffectivePidGenerator().getId()); + assertTrue(PidUtil.getPidProvider(dataset1.getEffectivePidGenerator().getId()).canCreatePidsLike(dataset1.getGlobalId())); + + dataset1.setPidGenerator(null); + //Now set identifier so that the provider has this one in it's managed list (and therefore we can't mint new PIDs in the same auth/shoulder) and therefore we get the effective pid generator + dataset1.setIdentifier("FK3ABCDEF"); + assertEquals("fake1", dataset1.getGlobalId().getProviderId()); + assertEquals("ez1", dataset1.getEffectivePidGenerator().getId()); + + + + } + + @Test + @JvmSetting(key = JvmSettings.LEGACY_DATACITE_MDS_API_URL, value = "https://mds.test.datacite.org/") + @JvmSetting(key = JvmSettings.LEGACY_DATACITE_REST_API_URL, value = "https://api.test.datacite.org") + @JvmSetting(key = JvmSettings.LEGACY_DATACITE_USERNAME, value = "test2") + @JvmSetting(key = JvmSettings.LEGACY_DATACITE_PASSWORD, value = "changeme2") + public void testLegacyConfig() throws IOException { + MockitoAnnotations.openMocks(this); + Mockito.when(settingsServiceBean.getValueForKey(SettingsServiceBean.Key.DoiProvider)).thenReturn("DataCite"); + Mockito.when(settingsServiceBean.getValueForKey(SettingsServiceBean.Key.Shoulder)).thenReturn("FK2"); + + Mockito.when(settingsServiceBean.getValueForKey(SettingsServiceBean.Key.Protocol)).thenReturn("doi"); + Mockito.when(settingsServiceBean.getValueForKey(SettingsServiceBean.Key.Authority)).thenReturn("10.5075"); + + + + String protocol = settingsServiceBean.getValueForKey(SettingsServiceBean.Key.Protocol); + String authority = settingsServiceBean.getValueForKey(SettingsServiceBean.Key.Authority); + String shoulder = settingsServiceBean.getValueForKey(SettingsServiceBean.Key.Shoulder); + String provider = settingsServiceBean.getValueForKey(SettingsServiceBean.Key.DoiProvider); + + if (protocol != null && authority != null && shoulder != null && provider != null) { + // This line is different than in PidProviderFactoryBean because here we've + // already added the unmanaged providers, so we can't look for null + if (!PidUtil.getPidProvider(protocol, authority, shoulder).canManagePID()) { + PidProvider legacy = null; + // Try to add a legacy provider + String identifierGenerationStyle = settingsServiceBean + .getValueForKey(SettingsServiceBean.Key.IdentifierGenerationStyle, "random"); + String dataFilePidFormat = settingsServiceBean.getValueForKey(SettingsServiceBean.Key.DataFilePIDFormat, + "DEPENDENT"); + switch (provider) { + case "EZID": + /* + * String baseUrl = JvmSettings.PID_EZID_BASE_URL.lookup(String.class); String + * username = JvmSettings.PID_EZID_USERNAME.lookup(String.class); String + * password = JvmSettings.PID_EZID_PASSWORD.lookup(String.class); + * legacy = new EZIdDOIProvider("legacy", "legacy", authority, + * shoulder, identifierGenerationStyle, dataFilePidFormat, "", "", baseUrl, + * username, password); + */ + break; + case "DataCite": + String mdsUrl = JvmSettings.LEGACY_DATACITE_MDS_API_URL.lookup(String.class); + String restUrl = JvmSettings.LEGACY_DATACITE_REST_API_URL.lookup(String.class); + String dcUsername = JvmSettings.LEGACY_DATACITE_USERNAME.lookup(String.class); + String dcPassword = JvmSettings.LEGACY_DATACITE_PASSWORD.lookup(String.class); + if (mdsUrl != null && restUrl != null && dcUsername != null && dcPassword != null) { + legacy = new DataCiteDOIProvider("legacy", "legacy", authority, shoulder, + identifierGenerationStyle, dataFilePidFormat, "", "", mdsUrl, restUrl, dcUsername, + dcPassword); + } + break; + case "FAKE": + System.out.println("Legacy FAKE found"); + legacy = new FakeDOIProvider("legacy", "legacy", authority, shoulder, + identifierGenerationStyle, dataFilePidFormat, "", ""); + break; + } + if (legacy != null) { + // Not testing parts that require this bean + legacy.setPidProviderServiceBean(null); + PidUtil.addToProviderList(legacy); + } + } else { + System.out.println("Legacy PID provider settings found - ignored since a provider for the same protocol, authority, shoulder has been registered"); + } + + } + + String pid1String = "doi:10.5075/FK2ABCDEF"; + GlobalId pid2 = PidUtil.parseAsGlobalID(pid1String); + assertEquals(pid1String, pid2.asString()); + assertEquals("legacy", pid2.getProviderId()); + } } diff --git a/src/test/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DataCiteProviderTest.java b/src/test/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DataCiteProviderTest.java new file mode 100644 index 00000000000..572fc722272 --- /dev/null +++ b/src/test/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DataCiteProviderTest.java @@ -0,0 +1,187 @@ +package edu.harvard.iq.dataverse.pidproviders.doi.datacite; + +import edu.harvard.iq.dataverse.Dataset; +import edu.harvard.iq.dataverse.DatasetField; +import edu.harvard.iq.dataverse.DatasetFieldConstant; +import edu.harvard.iq.dataverse.DatasetFieldType; +import edu.harvard.iq.dataverse.DatasetVersion; +import edu.harvard.iq.dataverse.DatasetVersion.VersionState; +import edu.harvard.iq.dataverse.DataverseServiceBean; +import edu.harvard.iq.dataverse.GlobalId; +import edu.harvard.iq.dataverse.branding.BrandingUtil; +import edu.harvard.iq.dataverse.pidproviders.PidProviderFactoryBean; +import edu.harvard.iq.dataverse.pidproviders.PidUtil; +import edu.harvard.iq.dataverse.settings.JvmSettings; +import edu.harvard.iq.dataverse.settings.SettingsServiceBean; +import edu.harvard.iq.dataverse.util.SystemConfig; +import edu.harvard.iq.dataverse.util.testing.JvmSetting; +import edu.harvard.iq.dataverse.util.testing.LocalJvmSettings; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.extension.ExtendWith; + +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; + +@ExtendWith(MockitoExtension.class) +@LocalJvmSettings +@JvmSetting(key = JvmSettings.SITE_URL, value = "https://example.com") + +public class DataCiteProviderTest { + + static DataverseServiceBean dataverseSvc; + static SettingsServiceBean settingsSvc; + static PidProviderFactoryBean pidService; + static final String DEFAULT_NAME = "LibraScholar"; + + @BeforeAll + public static void setupMocks() { + dataverseSvc = Mockito.mock(DataverseServiceBean.class); + settingsSvc = Mockito.mock(SettingsServiceBean.class); + BrandingUtil.injectServices(dataverseSvc, settingsSvc); + + // initial values (needed here for other tests where this method is reused!) + Mockito.when(settingsSvc.getValueForKey(SettingsServiceBean.Key.InstallationName)).thenReturn(DEFAULT_NAME); + Mockito.when(dataverseSvc.getRootDataverseName()).thenReturn(DEFAULT_NAME); + + pidService = Mockito.mock(PidProviderFactoryBean.class); + Mockito.when(pidService.isGlobalIdLocallyUnique(any(GlobalId.class))).thenReturn(true); + Mockito.when(pidService.getProducer()).thenReturn("RootDataverse"); + + } + + /** + * Useful for testing but requires DataCite credentials, etc. + * + * To run the test: + * export DataCiteUsername=test2 + * export DataCitePassword=changeme2 + * export DataCiteAuthority=10.5072 + * export DataCiteShoulder=FK2 + * + * then run mvn test -Dtest=DataCiteProviderTest + * + * For each run of the test, one test DOI will be created and will remain in the registered state, as visible on Fabrica at doi.test.datacite.org + * (two DOIs are created, but one is deleted after being created in the draft state and never made findable.) + */ + @Test + @Disabled + public void testDoiLifecycle() throws IOException { + String username = System.getenv("DataCiteUsername"); + String password = System.getenv("DataCitePassword"); + String authority = System.getenv("DataCiteAuthority"); + String shoulder = System.getenv("DataCiteShoulder"); + DataCiteDOIProvider provider = new DataCiteDOIProvider("test", "test", authority, shoulder, "randomString", + SystemConfig.DataFilePIDFormat.DEPENDENT.toString(), "", "", "https://mds.test.datacite.org", + "https://api.test.datacite.org", username, password); + + provider.setPidProviderServiceBean(pidService); + + PidUtil.addToProviderList(provider); + + Dataset d = new Dataset(); + DatasetVersion dv = new DatasetVersion(); + DatasetFieldType primitiveDSFType = new DatasetFieldType(DatasetFieldConstant.title, + DatasetFieldType.FieldType.TEXT, false); + DatasetField testDatasetField = new DatasetField(); + + dv.setVersionState(VersionState.DRAFT); + + testDatasetField.setDatasetVersion(dv); + testDatasetField.setDatasetFieldType(primitiveDSFType); + testDatasetField.setSingleValue("First Title"); + List fields = new ArrayList<>(); + fields.add(testDatasetField); + dv.setDatasetFields(fields); + ArrayList dsvs = new ArrayList<>(); + dsvs.add(0, dv); + d.setVersions(dsvs); + + assertEquals(d.getCurrentName(), "First Title"); + + provider.generatePid(d); + assertEquals(d.getProtocol(), "doi"); + assertEquals(d.getAuthority(), authority); + assertTrue(d.getIdentifier().startsWith(shoulder)); + d.getGlobalId(); + + try { + provider.createIdentifier(d); + d.setIdentifierRegistered(true); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + assertEquals(DataCiteDOIProvider.DRAFT, provider.getPidStatus(d)); + Map mdMap = provider.getIdentifierMetadata(d); + assertEquals("First Title", mdMap.get("datacite.title")); + + testDatasetField.setSingleValue("Second Title"); + + //Modify called for a draft dataset shouldn't update DataCite (given current code) + try { + provider.modifyIdentifierTargetURL(d); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + //Verify the title hasn't changed + mdMap = provider.getIdentifierMetadata(d); + assertEquals("First Title", mdMap.get("datacite.title")); + //Check our local status + assertEquals(DataCiteDOIProvider.DRAFT, provider.getPidStatus(d)); + //Now delete the identifier + provider.deleteIdentifier(d); + //Causes a 404 and a caught exception that prints a stack trace. + mdMap = provider.getIdentifierMetadata(d); + // And verify the record is gone (no title, should be no entries at all) + assertEquals(null, mdMap.get("datacite.title")); + + //Now recreate and publicize in one step + assertTrue(provider.publicizeIdentifier(d)); + d.getLatestVersion().setVersionState(VersionState.RELEASED); + + //Verify the title hasn't changed + mdMap = provider.getIdentifierMetadata(d); + assertEquals("Second Title", mdMap.get("datacite.title")); + //Check our local status + assertEquals(DataCiteDOIProvider.FINDABLE, provider.getPidStatus(d)); + + //Verify that modify does update a published/findable record + testDatasetField.setSingleValue("Third Title"); + + try { + provider.modifyIdentifierTargetURL(d); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + mdMap = provider.getIdentifierMetadata(d); + assertEquals("Third Title", mdMap.get("datacite.title")); + + //Now delete the identifier . Once it's been findable, this should just flip the record to registered + //Not sure that can be easily verified in the test, but it will be visible in Fabrica + provider.deleteIdentifier(d); + d.getLatestVersion().setVersionState(VersionState.DEACCESSIONED); + + mdMap = provider.getIdentifierMetadata(d); + assertEquals("This item has been removed from publication", mdMap.get("datacite.title")); + + //Check our local status - just uses the version state + assertEquals(DataCiteDOIProvider.REGISTERED, provider.getPidStatus(d)); + + // provider.registerWhenPublished() + } + +} diff --git a/src/test/java/edu/harvard/iq/dataverse/search/IndexServiceBeanTest.java b/src/test/java/edu/harvard/iq/dataverse/search/IndexServiceBeanTest.java index adf48e05f09..92b06e5936f 100644 --- a/src/test/java/edu/harvard/iq/dataverse/search/IndexServiceBeanTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/search/IndexServiceBeanTest.java @@ -4,6 +4,7 @@ import edu.harvard.iq.dataverse.Dataverse.DataverseType; import edu.harvard.iq.dataverse.branding.BrandingUtil; import edu.harvard.iq.dataverse.mocks.MocksFactory; +import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider; import edu.harvard.iq.dataverse.settings.JvmSettings; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import edu.harvard.iq.dataverse.util.SystemConfig; @@ -134,7 +135,7 @@ private DatasetField constructBoundingBoxValue(String datasetFieldTypeName, Stri private IndexableDataset createIndexableDataset() { final Dataset dataset = MocksFactory.makeDataset(); - dataset.setGlobalId(new GlobalId(DOIServiceBean.DOI_PROTOCOL,"10.666", "FAKE/fake", "/", DOIServiceBean.DOI_RESOLVER_URL, null)); + dataset.setGlobalId(new GlobalId(AbstractDOIProvider.DOI_PROTOCOL,"10.666", "FAKE/fake", "/", AbstractDOIProvider.DOI_RESOLVER_URL, null)); final DatasetVersion datasetVersion = dataset.getCreateVersion(null); DatasetField field = createCVVField("language", "English", false); datasetVersion.getDatasetFields().add(field); diff --git a/src/test/java/edu/harvard/iq/dataverse/settings/JvmSettingsTest.java b/src/test/java/edu/harvard/iq/dataverse/settings/JvmSettingsTest.java index 6b03f20fc41..f4494b7116e 100644 --- a/src/test/java/edu/harvard/iq/dataverse/settings/JvmSettingsTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/settings/JvmSettingsTest.java @@ -17,22 +17,15 @@ void lookupSetting() { } @Test - @SystemProperty(key = "doi.username", value = "test") - void lookupSettingViaAlias() { - assertEquals("test", JvmSettings.DATACITE_USERNAME.lookup()); + @SystemProperty(key = "dataverse.pid.datacite.datacite.username", value = "test") + void lookupPidProviderSetting() { + assertEquals("test", JvmSettings.DATACITE_USERNAME.lookup("datacite")); } @Test - @SystemProperty(key = "doi.baseurlstring", value = "test") + @SystemProperty(key = "dataverse.ingest.rserve.port", value = "1234") void lookupSettingViaAliasWithDefaultInMPCFile() { - assertEquals("test", JvmSettings.DATACITE_MDS_API_URL.lookup()); - } - - @Test - @SystemProperty(key = "doi.dataciterestapiurlstring", value = "foo") - @SystemProperty(key = "doi.mdcbaseurlstring", value = "bar") - void lookupSettingViaAliasWithDefaultInMPCFileAndTwoAliases() { - assertEquals("foo", JvmSettings.DATACITE_REST_API_URL.lookup()); + assertEquals("1234", JvmSettings.RSERVE_PORT.lookup()); } } \ No newline at end of file diff --git a/src/test/java/edu/harvard/iq/dataverse/sitemap/SiteMapUtilTest.java b/src/test/java/edu/harvard/iq/dataverse/sitemap/SiteMapUtilTest.java index 41032ffa811..310bec72c2e 100644 --- a/src/test/java/edu/harvard/iq/dataverse/sitemap/SiteMapUtilTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/sitemap/SiteMapUtilTest.java @@ -1,11 +1,11 @@ package edu.harvard.iq.dataverse.sitemap; -import edu.harvard.iq.dataverse.DOIServiceBean; import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.DatasetVersion; import edu.harvard.iq.dataverse.Dataverse; import edu.harvard.iq.dataverse.GlobalId; import edu.harvard.iq.dataverse.harvest.client.HarvestingClient; +import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider; import edu.harvard.iq.dataverse.util.xml.XmlPrinter; import edu.harvard.iq.dataverse.util.xml.XmlValidator; import java.io.File; @@ -66,14 +66,14 @@ void testUpdateSiteMap() throws IOException, ParseException, SAXException { List datasets = new ArrayList<>(); Dataset published = new Dataset(); - published.setGlobalId(new GlobalId(DOIServiceBean.DOI_PROTOCOL, "10.666", "FAKE/published1", null, DOIServiceBean.DOI_RESOLVER_URL, null)); + published.setGlobalId(new GlobalId(AbstractDOIProvider.DOI_PROTOCOL, "10.666", "FAKE/published1", null, AbstractDOIProvider.DOI_RESOLVER_URL, null)); String publishedPid = published.getGlobalId().asString(); published.setPublicationDate(new Timestamp(new Date().getTime())); published.setModificationTime(new Timestamp(new Date().getTime())); datasets.add(published); Dataset unpublished = new Dataset(); - unpublished.setGlobalId(new GlobalId(DOIServiceBean.DOI_PROTOCOL, "10.666", "FAKE/unpublished1", null, DOIServiceBean.DOI_RESOLVER_URL, null)); + unpublished.setGlobalId(new GlobalId(AbstractDOIProvider.DOI_PROTOCOL, "10.666", "FAKE/unpublished1", null, AbstractDOIProvider.DOI_RESOLVER_URL, null)); String unpublishedPid = unpublished.getGlobalId().asString(); Timestamp nullPublicationDateToIndicateNotPublished = null; @@ -81,14 +81,14 @@ void testUpdateSiteMap() throws IOException, ParseException, SAXException { datasets.add(unpublished); Dataset harvested = new Dataset(); - harvested.setGlobalId(new GlobalId(DOIServiceBean.DOI_PROTOCOL, "10.666", "FAKE/harvested1", null, DOIServiceBean.DOI_RESOLVER_URL, null)); + harvested.setGlobalId(new GlobalId(AbstractDOIProvider.DOI_PROTOCOL, "10.666", "FAKE/harvested1", null, AbstractDOIProvider.DOI_RESOLVER_URL, null)); String harvestedPid = harvested.getGlobalId().asString(); harvested.setPublicationDate(new Timestamp(new Date().getTime())); harvested.setHarvestedFrom(new HarvestingClient()); datasets.add(harvested); Dataset deaccessioned = new Dataset(); - deaccessioned.setGlobalId(new GlobalId(DOIServiceBean.DOI_PROTOCOL, "10.666", "FAKE/deaccessioned1", null, DOIServiceBean.DOI_RESOLVER_URL, null)); + deaccessioned.setGlobalId(new GlobalId(AbstractDOIProvider.DOI_PROTOCOL, "10.666", "FAKE/deaccessioned1", null, AbstractDOIProvider.DOI_RESOLVER_URL, null)); String deaccessionedPid = deaccessioned.getGlobalId().asString(); deaccessioned.setPublicationDate(new Timestamp(new Date().getTime())); diff --git a/src/test/java/edu/harvard/iq/dataverse/util/UrlTokenUtilTest.java b/src/test/java/edu/harvard/iq/dataverse/util/UrlTokenUtilTest.java index d70a108e7c6..15905c2971b 100644 --- a/src/test/java/edu/harvard/iq/dataverse/util/UrlTokenUtilTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/util/UrlTokenUtilTest.java @@ -1,12 +1,12 @@ package edu.harvard.iq.dataverse.util; -import edu.harvard.iq.dataverse.DOIServiceBean; import edu.harvard.iq.dataverse.DataFile; import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.DatasetVersion; import edu.harvard.iq.dataverse.FileMetadata; import edu.harvard.iq.dataverse.GlobalId; import edu.harvard.iq.dataverse.authorization.users.ApiToken; +import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider; import edu.harvard.iq.dataverse.settings.JvmSettings; import edu.harvard.iq.dataverse.util.testing.JvmSetting; import edu.harvard.iq.dataverse.util.testing.LocalJvmSettings; @@ -32,7 +32,7 @@ void testGetToolUrlWithOptionalQueryParameters() { DatasetVersion dv = new DatasetVersion(); Dataset ds = new Dataset(); ds.setId(50L); - ds.setGlobalId(new GlobalId(DOIServiceBean.DOI_PROTOCOL,"10.5072","FK2ABCDEF",null, DOIServiceBean.DOI_RESOLVER_URL, null)); + ds.setGlobalId(new GlobalId(AbstractDOIProvider.DOI_PROTOCOL,"10.5072","FK2ABCDEF",null, AbstractDOIProvider.DOI_RESOLVER_URL, null)); dv.setDataset(ds); fmd.setDatasetVersion(dv); List fmdl = new ArrayList<>(); From 4716c7ae18e89d9a3fe602e411953b23c981d5b3 Mon Sep 17 00:00:00 2001 From: luddaniel <83018819+luddaniel@users.noreply.github.com> Date: Wed, 6 Mar 2024 15:38:47 +0100 Subject: [PATCH 135/141] Returning to author now requires a reason that is sent by email to the author (#10137) * #3702 - Returning to author now requires a commented reason that is sent by email to the author * Update src/main/java/propertyFiles/Bundle.properties Co-authored-by: Philip Durbin * #3702 - Increased maxlength of message to 2000 + Added email contacts of collection in return to author email * #3702 - Added test on null or empty comment for ReturnDatasetToAuthorCommand * #3702 fixed Unit Tests errors * #3702 - Code commentary to be removed * #3702 - Adding release note * #3702 - Adding last Bundle.properties corrections * #3702 - Updated release note and guide --------- Co-authored-by: Philip Durbin --- doc/release-notes/3702-return-to-author.md | 4 +++ doc/sphinx-guides/source/api/native-api.rst | 3 +- .../edu/harvard/iq/dataverse/DatasetPage.java | 13 ++++++-- .../harvard/iq/dataverse/MailServiceBean.java | 26 ++++++++++------ .../harvard/iq/dataverse/api/Datasets.java | 3 +- .../iq/dataverse/api/Notifications.java | 1 - .../impl/ReturnDatasetToAuthorCommand.java | 5 +++ src/main/java/propertyFiles/Bundle.properties | 13 +++++--- src/main/webapp/dataset.xhtml | 31 ++++++++++--------- src/main/webapp/dataverseuser.xhtml | 3 -- .../ReturnDatasetToAuthorCommandTest.java | 31 +++++++++---------- 11 files changed, 78 insertions(+), 55 deletions(-) create mode 100644 doc/release-notes/3702-return-to-author.md diff --git a/doc/release-notes/3702-return-to-author.md b/doc/release-notes/3702-return-to-author.md new file mode 100644 index 00000000000..aa7dd9feaef --- /dev/null +++ b/doc/release-notes/3702-return-to-author.md @@ -0,0 +1,4 @@ +### Return to author + +Popup for returning to author now requires a reason that will be sent by email to the author. +Please note that you can still type a creative and meaningful comment such as "The author would like to modify his dataset", "Files are missing", "Nothing to report" or "A curation report with comments and suggestions/instructions will follow in another email" that suits your situation. \ No newline at end of file diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index 7f048f96eb9..70d73ae3c98 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -2126,7 +2126,8 @@ The fully expanded example above (without environment variables) looks like this curl -H "X-Dataverse-key: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X POST "https://demo.dataverse.org/api/datasets/:persistentId/returnToAuthor?persistentId=doi:10.5072/FK2/J8SJZB" -H "Content-type: application/json" -d @reason-for-return.json -The review process can sometimes resemble a tennis match, with the authors submitting and resubmitting the dataset over and over until the curators are satisfied. Each time the curators send a "reason for return" via API, that reason is persisted into the database, stored at the dataset version level. +The review process can sometimes resemble a tennis match, with the authors submitting and resubmitting the dataset over and over until the curators are satisfied. Each time the curators send a "reason for return" via API, that reason is sent by email and is persisted into the database, stored at the dataset version level. +The reason is required, please note that you can still type a creative and meaningful comment such as "The author would like to modify his dataset", "Files are missing", "Nothing to report" or "A curation report with comments and suggestions/instructions will follow in another email" that suits your situation. The :ref:`send-feedback` API call may be useful as a way to move the conversation to email. However, note that these emails go to contacts (versus authors) and there is no database record of the email contents. (:ref:`dataverse.mail.cc-support-on-contact-email` will send a copy of these emails to the support email address which would provide a record.) diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java b/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java index 88b1f4f49bc..0641039e433 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java @@ -709,6 +709,16 @@ public void setNumberOfFilesToShow(Long numberOfFilesToShow) { this.numberOfFilesToShow = numberOfFilesToShow; } + private String returnReason = ""; + + public String getReturnReason() { + return returnReason; + } + + public void setReturnReason(String returnReason) { + this.returnReason = returnReason; + } + public void showAll(){ setNumberOfFilesToShow(new Long(fileMetadatasSearch.size())); } @@ -2653,8 +2663,7 @@ public void edit(EditMode editMode) { public String sendBackToContributor() { try { - //FIXME - Get Return Comment from sendBackToContributor popup - Command cmd = new ReturnDatasetToAuthorCommand(dvRequestService.getDataverseRequest(), dataset, ""); + Command cmd = new ReturnDatasetToAuthorCommand(dvRequestService.getDataverseRequest(), dataset, returnReason); dataset = commandEngine.submit(cmd); JsfHelper.addSuccessMessage(BundleUtil.getStringFromBundle("dataset.reject.success")); } catch (CommandException ex) { diff --git a/src/main/java/edu/harvard/iq/dataverse/MailServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/MailServiceBean.java index 72fc6ee6d64..4b591d240bd 100644 --- a/src/main/java/edu/harvard/iq/dataverse/MailServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/MailServiceBean.java @@ -466,18 +466,24 @@ public String getMessageTextBasedOnNotification(UserNotification userNotificatio case RETURNEDDS: version = (DatasetVersion) targetObject; pattern = BundleUtil.getStringFromBundle("notification.email.wasReturnedByReviewer"); - String optionalReturnReason = ""; - /* - FIXME - Setting up to add single comment when design completed - optionalReturnReason = "."; - if (comment != null && !comment.isEmpty()) { - optionalReturnReason = ".\n\n" + BundleUtil.getStringFromBundle("wasReturnedReason") + "\n\n" + comment; - } - */ + String[] paramArrayReturnedDataset = {version.getDataset().getDisplayName(), getDatasetDraftLink(version.getDataset()), - version.getDataset().getOwner().getDisplayName(), getDataverseLink(version.getDataset().getOwner()), optionalReturnReason}; + version.getDataset().getOwner().getDisplayName(), getDataverseLink(version.getDataset().getOwner())}; messageText += MessageFormat.format(pattern, paramArrayReturnedDataset); + + if (comment != null && !comment.isEmpty()) { + messageText += "\n\n" + MessageFormat.format(BundleUtil.getStringFromBundle("notification.email.wasReturnedByReviewerReason"), comment); + } + + Dataverse d = (Dataverse) version.getDataset().getOwner(); + List contactEmailList = new ArrayList(); + for (DataverseContact dc : d.getDataverseContacts()) { + contactEmailList.add(dc.getContactEmail()); + } + if (!contactEmailList.isEmpty()) { + String contactEmails = String.join(", ", contactEmailList); + messageText += "\n\n" + MessageFormat.format(BundleUtil.getStringFromBundle("notification.email.wasReturnedByReviewer.collectionContacts"), contactEmails); + } return messageText; case WORKFLOW_SUCCESS: diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java b/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java index e312d6ec15b..ad66fb468f4 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Datasets.java @@ -2145,9 +2145,8 @@ public Response returnToAuthor(@Context ContainerRequestContext crc, @PathParam( Dataset dataset = findDatasetOrDie(idSupplied); String reasonForReturn = null; reasonForReturn = json.getString("reasonForReturn"); - // TODO: Once we add a box for the curator to type into, pass the reason for return to the ReturnDatasetToAuthorCommand and delete this check and call to setReturnReason on the API side. if (reasonForReturn == null || reasonForReturn.isEmpty()) { - return error(Response.Status.BAD_REQUEST, "You must enter a reason for returning a dataset to the author(s)."); + return error(Response.Status.BAD_REQUEST, BundleUtil.getStringFromBundle("dataset.reject.datasetNotInReview")); } AuthenticatedUser authenticatedUser = getRequestAuthenticatedUserOrDie(crc); Dataset updatedDataset = execCommand(new ReturnDatasetToAuthorCommand(createDataverseRequest(authenticatedUser), dataset, reasonForReturn )); diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Notifications.java b/src/main/java/edu/harvard/iq/dataverse/api/Notifications.java index 37c894d3071..df172f36973 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Notifications.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Notifications.java @@ -55,7 +55,6 @@ public Response getAllNotificationsForUser(@Context ContainerRequestContext crc) notificationObjectBuilder.add("id", notification.getId()); notificationObjectBuilder.add("type", type.toString()); /* FIXME - Re-add reasons for return if/when they are added to the notifications page. - if (Type.RETURNEDDS.equals(type) || Type.SUBMITTEDDS.equals(type)) { JsonArrayBuilder reasons = getReasonsForReturn(notification); for (JsonValue reason : reasons.build()) { diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ReturnDatasetToAuthorCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ReturnDatasetToAuthorCommand.java index caf37ad4de1..f3b33f82524 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ReturnDatasetToAuthorCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ReturnDatasetToAuthorCommand.java @@ -25,6 +25,11 @@ public class ReturnDatasetToAuthorCommand extends AbstractDatasetCommand
    You may contact us for support at {0}.

    Thank you,
    {1} notification.email.assignRole=You are now {0} for the {1} "{2}" (view at {3} ). @@ -1476,7 +1478,7 @@ dataset.submit.failure.inReview=You cannot submit this dataset for review becaus dataset.status.failure.notallowed=Status update failed - label not allowed dataset.status.failure.disabled=Status labeling disabled for this dataset dataset.status.failure.isReleased=Latest version of dataset is already released. Status can only be set on draft versions -dataset.rejectMessage=Return this dataset to contributor for modification. +dataset.rejectMessage=Return this dataset to contributor for modification. The reason for return entered below will be sent by email to the author. dataset.rejectMessage.label=Return to Author Reason dataset.rejectWatermark=Please enter a reason for returning this dataset to its author(s). dataset.reject.enterReason.error=Reason for return to author is required. @@ -1484,6 +1486,7 @@ dataset.reject.success=This dataset has been sent back to the contributor. dataset.reject.failure=Dataset Submission Return Failed - {0} dataset.reject.datasetNull=Cannot return the dataset to the author(s) because it is null. dataset.reject.datasetNotInReview=This dataset cannot be return to the author(s) because the latest version is not In Review. The author(s) needs to click Submit for Review first. +dataset.reject.commentNull=You must enter a reason for returning a dataset to the author(s). dataset.publish.tip=Are you sure you want to publish this dataset? Once you do so it must remain published. dataset.publish.terms.tip=This version of the dataset will be published with the following terms: dataset.publish.terms.help.tip=To change the terms for this version, click the Cancel button and go to the Terms tab for this dataset. diff --git a/src/main/webapp/dataset.xhtml b/src/main/webapp/dataset.xhtml index 4bb1ec869f6..34c6d3dcbea 100644 --- a/src/main/webapp/dataset.xhtml +++ b/src/main/webapp/dataset.xhtml @@ -1843,27 +1843,30 @@

    #{bundle['dataset.rejectMessage']}

    - - - - -

    - -

    - -
    + + +

    + +

    + + +
    - + + +
    - + diff --git a/src/main/webapp/dataverseuser.xhtml b/src/main/webapp/dataverseuser.xhtml index 2426cf980d3..9ed8b5209b6 100644 --- a/src/main/webapp/dataverseuser.xhtml +++ b/src/main/webapp/dataverseuser.xhtml @@ -178,9 +178,6 @@ #{DataverseUserPage.getRequestorEmail(item)} - - #{DataverseUserPage.getReasonForReturn(item.theObject)} - diff --git a/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/ReturnDatasetToAuthorCommandTest.java b/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/ReturnDatasetToAuthorCommandTest.java index 23cc4547bc4..fc52abecaf2 100644 --- a/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/ReturnDatasetToAuthorCommandTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/ReturnDatasetToAuthorCommandTest.java @@ -155,7 +155,7 @@ public void testReleasedDataset() { String actual = null; Dataset updatedDataset = null; try { - updatedDataset = testEngine.submit(new ReturnDatasetToAuthorCommand(dataverseRequest, dataset, "")); + updatedDataset = testEngine.submit(new ReturnDatasetToAuthorCommand(dataverseRequest, dataset, "Update Your Files, Dummy")); } catch (CommandException ex) { actual = ex.getMessage(); } @@ -171,36 +171,33 @@ public void testNotInReviewDataset() { String actual = null; Dataset updatedDataset = null; try { - updatedDataset = testEngine.submit(new ReturnDatasetToAuthorCommand(dataverseRequest, dataset, "")); + updatedDataset = testEngine.submit(new ReturnDatasetToAuthorCommand(dataverseRequest, dataset, "Update Your Files, Dummy")); } catch (CommandException ex) { actual = ex.getMessage(); } assertEquals(expected, actual); } - /* - FIXME - Empty Comments won't be allowed in future @Test - public void testEmptyComments(){ - - dataset.setIdentifier("DUMMY"); + public void testEmptyOrNullComment(){ dataset.getLatestVersion().setVersionState(DatasetVersion.VersionState.DRAFT); - dataset.getLatestVersion().setInReview(true); - dataset.getLatestVersion().setReturnReason(null); + Dataset updatedDataset = null; String expected = "You must enter a reason for returning a dataset to the author(s)."; String actual = null; - Dataset updatedDataset = null; try { - - updatedDataset = testEngine.submit(new ReturnDatasetToAuthorCommand(dataverseRequest, dataset)); - } catch (CommandException ex) { + testEngine.submit( new AddLockCommand(dataverseRequest, dataset, + new DatasetLock(DatasetLock.Reason.InReview, dataverseRequest.getAuthenticatedUser()))); + + assertThrowsExactly(IllegalArgumentException.class, + () -> new ReturnDatasetToAuthorCommand(dataverseRequest, dataset, null), expected); + assertThrowsExactly(IllegalArgumentException.class, + () -> new ReturnDatasetToAuthorCommand(dataverseRequest, dataset, ""), expected); + updatedDataset = testEngine.submit(new ReturnDatasetToAuthorCommand(dataverseRequest, dataset, "")); + } catch (IllegalArgumentException | CommandException ex) { actual = ex.getMessage(); } - assertEquals(expected, actual); - - + assertEquals(expected, actual); } - */ @Test public void testAllGood() { From 3417751a376a04a84432b92e5dfd579e51e06344 Mon Sep 17 00:00:00 2001 From: Juan Pablo Tosca Villanueva Date: Wed, 6 Mar 2024 10:27:31 -0500 Subject: [PATCH 136/141] flyway script bump --- ...id-providers.sql => V6.1.0.5__3623-multiple-pid-providers.sql} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/resources/db/migration/{V6.1.0.4__3623-multiple-pid-providers.sql => V6.1.0.5__3623-multiple-pid-providers.sql} (100%) diff --git a/src/main/resources/db/migration/V6.1.0.4__3623-multiple-pid-providers.sql b/src/main/resources/db/migration/V6.1.0.5__3623-multiple-pid-providers.sql similarity index 100% rename from src/main/resources/db/migration/V6.1.0.4__3623-multiple-pid-providers.sql rename to src/main/resources/db/migration/V6.1.0.5__3623-multiple-pid-providers.sql From 38d54bc8f3147e83b254ae72f7cbeaab219ee9c6 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Wed, 6 Mar 2024 11:23:00 -0600 Subject: [PATCH 137/141] no-op update to pom.xml to force Docker image build As described in .github/workflows/maven_unit_test.yml we need to touch Java files or pom.xml for this action (which pushes Docker images) to run. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index aaa2b49eaae..8b2850e1df9 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ In case the dependency is both transitive and direct (e. g. some common lib for logging), manage the version above and add the direct dependency here WITHOUT version tag, too. --> - +