diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000000..b16f8e5a010 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,4 @@ +# These are supported funding model platforms + +github: [osgeo] +cusotm: ['https://github.com/geonetwork/core-geonetwork/wiki#financial-support','https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=LDTWEL3XKUVU8&source=url','https://www.osgeo.org/about/how-to-become-a-sponsor/'] diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000000..e4f7920f8c5 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,27 @@ + + + + + +# Checklist + +- [ ] I have read the [contribution guidelines](https://github.com/geonetwork/core-geonetwork/blob/main/CONTRIBUTING.md) +- [ ] *Pull request* provided for `main` branch, backports managed with label +- [ ] *Good housekeeping* of code, cleaning up comments, tests, and documentation +- [ ] *Clean commit history* broken into understandable chucks, avoiding big commits with hundreds of files, cautious of reformatting and whitespace changes +- [ ] *Clean commit message*s, longer verbose messages are encouraged +- [ ] *API Changes* are identified in commit messages +- [ ] *Testing* provided for features or enhancements using [automatic tests](https://github.com/geonetwork/core-geonetwork/blob/main/software_development/TESTING.md) +- [ ] *User documentation* provided for new features or enhancements in [manual](https://github.com/geonetwork/core-geonetwork/tree/main/docs/manual) +- [ ] *Build documentation* provided for development instructions in `README.md` files +- [ ] *Library management* using `pom.xml` dependency management. Update build documentation with intended library use and library tutorials or documentation + + + + + diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml new file mode 100644 index 00000000000..272cd05d974 --- /dev/null +++ b/.github/workflows/backport.yml @@ -0,0 +1,25 @@ +name: ♻ Backport +on: + pull_request_target: + types: + - closed + - labeled + +permissions: + contents: read + +jobs: + backport: + permissions: + contents: write + pull-requests: write + issues: write + runs-on: ubuntu-20.04 + name: Backport + steps: + - name: Backport Bot + id: backport + if: github.event.pull_request.merged && ( ( github.event.action == 'closed' && contains( join( github.event.pull_request.labels.*.name ), 'backport') ) || contains( github.event.label.name, 'backport' ) ) + uses: m-kuhn/backport@v1.2.7 + with: + github_token: ${{ secrets.GH_TOKEN_BOT }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 582ede07080..36dcfa3ff48 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -38,12 +38,14 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 - + uses: actions/checkout@v4 + with: + show-progress: 'false' + - name: Setup Java JDK - uses: actions/setup-java@v3.10.0 + uses: actions/setup-java@v4.2.1 with: - java-version: 8 + java-version: 11 # Java distribution. See the list of supported distributions in README file distribution: temurin # The package type (jdk, jre, jdk+fx, jre+fx) @@ -53,7 +55,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -64,7 +66,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -78,11 +80,8 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 - name: Remove SNAPSHOT jars from repository run: | find ~/.m2/repository -name "*SNAPSHOT*" -type d | xargs rm -rf {} - - name: Remove Schema 3.8 jars from repository - run: | - find ~/.m2/repository -name "*3.8*" -type d | xargs rm -rf {} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000000..0d596bc06df --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,41 @@ +name: Documentation + +on: + push: + branches: + - main + paths: + - "docs/manual/**" + pull_request: + branches: + - main + paths: + - "docs/manual/**" + workflow_dispatch: + +jobs: + deploy-docs: + runs-on: ubuntu-latest + steps: + - name: Checkout GeoNetwork + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install Python + uses: actions/setup-python@v5 + with: + python-version: 3.x + - name: mkdocs install + run: pip install --upgrade pip && pip install -r docs/manual/requirements.txt + - name: git configuration + run: git config user.name 'github-actions[bot]' && git config user.email 'github-actions[bot]@users.noreply.github.com' + - name: build docs without publishing them + if: ${{ github.event_name == 'pull_request' }} + working-directory: docs/manual + run: | + mike deploy --title "4.4" --alias-type=copy --update-aliases 4.4 latest + - name: deploy latest docs to gh-pages branch + if: ${{ github.event_name != 'pull_request' }} + working-directory: docs/manual + run: | + mike deploy --push --title "4.4" --alias-type=copy --update-aliases 4.4 latest diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 1fcc8cfa395..4d1d6d27eb1 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -3,7 +3,7 @@ name: Linux GitHub CI on: [pull_request,push,workflow_dispatch] env: - MAVEN_OPTS: -Dmaven.wagon.httpconnectionManager.ttlSeconds=25 -Dmaven.wagon.http.retryHandler.count=3 -Xmx512m -Dorg.slf4j.simpleLogger.showDateTime=true -Dorg.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss,SSS + MAVEN_OPTS: -Dmaven.wagon.httpconnectionManager.ttlSeconds=25 -Dmaven.wagon.http.retryHandler.count=3 -Xmx512m -Dorg.slf4j.simpleLogger.showDateTime=true -Dorg.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss,SSS -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn TAKARI_SMART_BUILDER_VERSION: 0.6.1 jobs: @@ -13,57 +13,61 @@ jobs: matrix: include: - os: ubuntu-22.04 - jdk: 8 + jdk: 11 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: # 500 commits, set to 0 to get all fetch-depth: 500 submodules: 'recursive' + show-progress: 'false' - name: Set up JDK - uses: actions/setup-java@v3.10.0 + uses: actions/setup-java@v4.2.1 with: distribution: 'temurin' java-version: ${{ matrix.jdk }} cache: 'maven' + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: 3.x + - name: mkdocs install + working-directory: docs/manual + run: pip install --upgrade pip && pip install -r requirements.txt - name: Set up Maven - uses: stCarolas/setup-maven@v4 + uses: stCarolas/setup-maven@v5 with: - maven-version: 3.6.3 + maven-version: 3.8.3 - name: Build with Maven - run: mvn -B -V install -DskipTests=true -Dmaven.javadoc.skip=true + run: | + mvn -B -ntp -V install -DskipTests=true -Dmaven.javadoc.skip=true -Drelease -Pwith-doc - name: Remove SNAPSHOT jars from repository run: | find ~/.m2/repository -name "*SNAPSHOT*" -type d | xargs rm -rf {} - - name: Remove Schema 3.8 jars from repository - run: | - find ~/.m2/repository -name "*3.8*" -type d | xargs rm -rf {} QA: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: # 500 commits, set to 0 to get all fetch-depth: 500 submodules: 'recursive' + show-progress: 'false' - name: Set up JDK - uses: actions/setup-java@v3.10.0 + uses: actions/setup-java@v4.2.1 with: distribution: 'temurin' - java-version: 8 + java-version: 11 cache: 'maven' - name: Set up Maven - uses: stCarolas/setup-maven@v4 + uses: stCarolas/setup-maven@v5 with: - maven-version: 3.6.3 + maven-version: 3.8.3 - name: Test with maven run: | - mvn resources:resources@copy-index-schema-to-source -f web - mvn -B -V -fae verify -Pit + mvn -B resources:resources@copy-index-schema-to-source -f web + mvn -B -ntp -V -fae verify -Drelesae -Pit - name: Remove SNAPSHOT jars from repository run: | find ~/.m2/repository -name "*SNAPSHOT*" -type d | xargs rm -rf {} - - name: Remove Schema 3.8 jars from repository - run: | - find ~/.m2/repository -name "*3.8*" -type d | xargs rm -rf {} diff --git a/.github/workflows/mvn-dep-tree.yml b/.github/workflows/mvn-dep-tree.yml index 4b807118189..75b02b2fc57 100644 --- a/.github/workflows/mvn-dep-tree.yml +++ b/.github/workflows/mvn-dep-tree.yml @@ -12,20 +12,22 @@ on: jobs: update-maven-dep-tree: runs-on: ubuntu-latest - + steps: - name: Checkout repository - uses: actions/checkout@v3 - + uses: actions/checkout@v4 + with: + show-progress: 'false' + - name: Setup Java JDK - uses: actions/setup-java@v3.10.0 + uses: actions/setup-java@v4.2.1 with: - java-version: 8 + java-version: 11 # Java distribution. See the list of supported distributions in README file distribution: temurin # The package type (jdk, jre, jdk+fx, jre+fx) java-package: jdk cache: maven - + - name: Submit Dependency Snapshot - uses: advanced-security/maven-dependency-submission-action@v3 + uses: advanced-security/maven-dependency-submission-action@v4 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml new file mode 100644 index 00000000000..98cf13704c4 --- /dev/null +++ b/.github/workflows/scorecard.yml @@ -0,0 +1,72 @@ +# This workflow uses actions that are not certified by GitHub. They are provided +# by a third-party and are governed by separate terms of service, privacy +# policy, and support documentation. + +name: Scorecard supply-chain security +on: + # For Branch-Protection check. Only the default branch is supported. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection + branch_protection_rule: + # To guarantee Maintained check is occasionally updated. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained + schedule: + - cron: '26 10 * * 5' + push: + branches: [ "main" ] + +# Declare default permissions as read only. +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + # Needed to publish results and get a badge (see publish_results below). + id-token: write + # Uncomment the permissions below if installing in a private repository. + # contents: read + # actions: read + + steps: + - name: "Checkout code" + uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1 + with: + results_file: results.sarif + results_format: sarif + # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: + # - you want to enable the Branch-Protection check on a *public* repository, or + # - you are installing Scorecard on a *private* repository + # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. + # repo_token: ${{ secrets.SCORECARD_TOKEN }} + + # Public repositories: + # - Publish results to OpenSSF REST API for easy access by consumers + # - Allows the repository to include the Scorecard badge. + # - See https://github.com/ossf/scorecard-action#publishing-results. + # For private repositories: + # - `publish_results` will always be set to `false`, regardless + # of the value entered here. + publish_results: true + + # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF + # format to the repository Actions tab. + - name: "Upload artifact" + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # Upload the results to GitHub's code scanning dashboard. + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@17573ee1cc1b9d061760f3a006fc4aac4f944fd5 # v2.2.4 + with: + sarif_file: results.sarif diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 72c61694603..6f1285d3e23 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -3,8 +3,6 @@ on: push: branches: - main - - 4.0.x - - 3.12.x pull_request: types: [opened, synchronize, reopened] jobs: @@ -15,33 +13,32 @@ jobs: # https://github.community/t/how-to-detect-a-pull-request-from-a-fork/18363/4 if: github.event.pull_request.head.repo.fork != true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis submodules: 'recursive' - # For building GeoNetwork, JDK8 is necessary, but for running - # the SonarQube plugin, JDK11 is necessary. - # So, first install JDK 8, build GeoNetwork, then install JDK11 - # and run SonarQube: - - name: Set up JDK 8 - uses: actions/setup-java@v3.10.0 + show-progress: 'false' + - name: Set up JDK 11 + uses: actions/setup-java@v4.2.1 with: - java-version: 8 distribution: 'temurin' + java-version: '11' cache: 'maven' - name: Cache SonarCloud packages - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.sonar/cache key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar - name: Build GN run: mvn -B package -DskipTests - - name: Set up JDK 11 - uses: actions/setup-java@v3.10.0 + + - name: Set up JDK 21 # Sonarcloud analyzer needs at least JDK 17 + uses: actions/setup-java@v4.2.1 with: distribution: 'temurin' - java-version: '11' + java-version: '21' + cache: 'maven' - name: Analyze with Sonar env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any diff --git a/.gitignore b/.gitignore index 19dce805080..84f282d0af7 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,8 @@ git*.properties */*/target/ */target/ .*/ -GeoNetwork* +!.github +#GeoNetwork* /geonetwork* camel-harvesters/wfsfeature-harvester/logs changes-* @@ -27,6 +28,7 @@ eclipse/ es/elasticsearch-* es/es-dashboards/kibana-* es/es-dashboards/data/nodes/ +es/es-dashboards/data/index/ harvesters/harvester_*.log idea/ jcs_caching/ @@ -38,7 +40,12 @@ release/jetty/* schemas/*/doc/*/*.rst schematrons/.build target/ + +# build and release transifex/transifex-format/ +build/ +web-ui/LICENSE +web-ui/tx # web-app, clear using: mvn -f web/pom.xml clean:clean@reset @@ -57,17 +64,14 @@ web/src/main/webapp/META-INF/MANIFEST.MF web/src/main/webapp/WEB-INF/data/0* web/src/main/webapp/WEB-INF/data/config/encryptor.properties web/src/main/webapp/WEB-INF/data/config/index/records.json -web/src/main/webapp/WEB-INF/data/config/schema_plugins/*/schematron/schematron*.xsl -web/src/main/webapp/WEB-INF/data/config/schema_plugins/csw-record -web/src/main/webapp/WEB-INF/data/config/schema_plugins/dublin-core -web/src/main/webapp/WEB-INF/data/config/schema_plugins/iso19* -web/src/main/webapp/WEB-INF/data/config/schema_plugins/schemaplugin-uri-catalog.xml +web/src/main/webapp/WEB-INF/data/config/schema_plugins/* web/src/main/webapp/WEB-INF/data/config/schemaplugin-uri-catalog.xml web/src/main/webapp/WEB-INF/data/data/backup web/src/main/webapp/WEB-INF/data/data/metadata_data web/src/main/webapp/WEB-INF/data/data/metadata_subversion web/src/main/webapp/WEB-INF/data/data/resources/htmlcache web/src/main/webapp/WEB-INF/data/data/resources/images +web/src/main/webapp/WEB-INF/data/data/resources/schemapublication web/src/main/webapp/WEB-INF/data/data/resources/xml web/src/main/webapp/WEB-INF/data/data/upload/ web/src/main/webapp/WEB-INF/data/harvester_* @@ -79,8 +83,8 @@ web/src/main/webapp/WEB-INF/data/wro4j*.db web/src/main/webapp/WEB-INF/data/wro4j-cache* web/src/main/webapp/WEB-INF/data_* web/src/main/webapp/WEB-INF/metadata_subversion/ -web/src/main/webapp/WEB-INF/server.prop web/src/main/webapp/WEB-INF/prebuilt web/src/main/webapp/data/ web/src/main/webapp/doc/en web/src/main/webapp/doc/fr +web/src/main/webapp/WEB-INF/data/data/resources/schemapublication diff --git a/.gitmodules b/.gitmodules index 67303aee7df..ec6788d718c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,6 +7,3 @@ [submodule "web-ui/src/main/resources/catalog/lib/bootstrap-table"] path = web-ui/src/main/resources/catalog/lib/bootstrap-table url = https://github.com/wenzhixin/bootstrap-table.git -[submodule "docs/manuals"] - path = docs/manuals - url = https://github.com/geonetwork/doc.git diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 00000000000..1cdaa3768cf --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,88 @@ +# This CITATION.cff file was generated with cffinit. +# Visit https://bit.ly/cffinit to generate yours today! + +cff-version: 1.2.0 +title: GeoNetwork opensource +message: >- + If you use this software, please cite it using the + metadata from this file. +type: software +authors: + - given-names: François + family-names: Prunayre + affiliation: Titellus + - given-names: Jose + family-names: García + affiliation: GeoCat BV + - given-names: Jeroen + family-names: Ticheler + affiliation: GeoCat BV + orcid: 'https://orcid.org/0009-0003-3896-0437' + email: jeroen.ticheler@geocat.net + - given-names: Florent + family-names: Gravin + affiliation: CamptoCamp + - given-names: Simon + family-names: Pigot + affiliation: CSIRO Australia + - name: GeoCat BV + address: Veenderweg 13 + city: Bennekom + country: NL + post-code: 6721 WD + tel: +31 (0) 318 416 664 + website: 'https://www.geocat.net/' + email: info@geocat.net + - name: Titellus + address: 321 Route de la Mollière + city: Saint Pierre de Genebroz + country: FR + post-code: 73360 + website: 'https://titellus.net/' + email: fx.prunayre@titellus.net + - name: CamptoCamp + address: QG Center Rte de la Chaux 4 + city: Bussigny + country: CH + post-code: 1030 + tel: +41 (21) 619 10 10 + website: 'https://camptocamp.com/' + email: info@camptocamp.com + - name: Open Source Geospatial Foundation - OSGeo + address: '9450 SW Gemini Dr. #42523' + location: Beaverton + region: Oregon + post-code: '97008' + country: US + email: info@osgeo.org + website: 'https://www.osgeo.org/' +repository-code: 'http://github.com/geonetwork/core-geonetwork' +url: 'https://geonetwork-opensource.org' +repository-artifact: >- + https://sourceforge.net/projects/geonetwork/files/GeoNetwork_opensource/ +abstract: >- + GeoNetwork is a catalog application to manage spatial and + non-spatial resources. It is compliant with critical + international standards from ISO, OGC and INSPIRE. It + provides powerful metadata editing and search functions as + well as an interactive web map viewer. +keywords: + - catalog + - gis + - sdi + - spatial data infrastructure + - dataspace + - search + - open data + - standards + - spatial + - CSW + - OGCAPI Records + - DCAT + - GeoDCAT-AP + - Catalog Service + - OGC + - open geospatial consortium + - osgeo + - open source geospatial foundation +license: GPL-2.0 diff --git a/CNAME b/CNAME new file mode 100644 index 00000000000..41e7b2c784f --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +docs.geonetwork-opensource.org \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 698871368c3..1bff3df03f5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,25 +1,31 @@ # Contributing -Thank you for contributing to GeoNetwork: +Thank you for contributing to GeoNetwork! * Free-software: GeoNetwork is free-software, using the [GNU GENERAL PUBLIC LICENSE](LICENSE.md). Contributions provided by you, or your employer, are required to be compatible with this free-software license. * Pull-request: GeoNetwork uses a pull-request workflow to review and accept changes. Pull-requests must be submitted against the *main* branch first, and may be back ported as required. # Pull requests -* Pull request is required, even if you have commit access, so the tests are run and other developer can check your code. +* Pull request is required, even if you have commit access, so the tests are run and another developer can check your code. * Pull requests must be applied to `main`, before being backported. -* Good housekeeping: Anytime you commit, try and clean the code around it to latest style guide. If you improve a function without comments: add comments. If you modify functionality that does not have tests: write a test. If you fix functionality without documentation: add documentation. +* Before merging a pull request, the following properties should be defined: + + - Milestone to include the change. + - Add the label `changelog` when the change is relevant to be added to the release changelog file. + - Add `backport ` to indicate when the change is a bug fix or when it is a small improvement that is relevant to be backported. + +* Good housekeeping: Anytime you commit, try and clean the code around it according to the latest style guide. If you improve a function without comments: _add comments!!_ If you modify functionality that does not have tests: _write a test!!_ If you fix functionality without documentation: _add documentation!!_ -* History: Clean commit messages and history: avoid big commits with hundreds of files, break commits commits up into understandable chunks, longer verbose commit messages are encouraged. Beware of reformatting and needless whitespace changes. +* History: Clean commit messages and history. Avoid big commits with hundreds of files, break commits up into understandable chunks. Longer, verbose commit messages are encouraged. Avoid reformatting and needless whitespace changes. -* Draft: Use pull request *Draft** (or even the text "WIP") to identify work in progress. +* Draft: Use pull request **Draft** (or even the text "WIP") to identify _Work In Progress_. -* Rebase: No merge commits with current branch: use rebase! +* Rebase / Squash and merge: Do not merge commits with the current branch, use Rebase or Squash and merge! -* API Change: Please identify any API change or behavior changes in commit messages. +* API Changes: Please identify any API change or behavior changes in commit messages. Also make sure that a [process for deprecation](PROCESS_FOR_DEPRECATION.md) of a feature is carefully dealt with. * Review: Review is required by another person, or more than one! Don't be shy asking for help or reviewing. @@ -29,6 +35,6 @@ Thank you for contributing to GeoNetwork: * Build documentation: All build and development instructions managed in repository `README.md` files. -* New libraries: Do not commit jars, use maven `pom.xml` to declare dependencies where needed, and `src/pom.xml` dependency management to manage version numbers. Document what the library does in GeoNetwork, how it interacts or extends GeoNetwork, with references to official library tutorials or documentation. +* New libraries: Do not commit jars, use maven `pom.xml` to declare dependencies where needed, and `src/pom.xml` dependency management to manage version numbers. Use build documentation to share what the library does in GeoNetwork, how it interacts or extends GeoNetwork, with references to official library tutorials or documentation. For more information see [How to contribute](https://github.com/geonetwork/core-geonetwork/wiki/How-to-contribute) (wiki). diff --git a/PROCESS_FOR_DEPRECATION.md b/PROCESS_FOR_DEPRECATION.md new file mode 100644 index 00000000000..f80f7086c3f --- /dev/null +++ b/PROCESS_FOR_DEPRECATION.md @@ -0,0 +1,6 @@ +* Proposal for a Process for Deprecation (draft) + +# Feature deprecation process + +This page describes considerations and steps to take when removing a product feature. This is the process of depreciation or 'deprecating a feature'. + diff --git a/README.md b/README.md index 6e2d522512e..65f57590c6a 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,35 @@ -# GeoNetwork Open-source +# GeoNetwork opensource -# Build Health +## Build Health [![Build Status](https://github.com/geonetwork/core-geonetwork/actions/workflows/linux.yml/badge.svg?branch=main)](https://github.com/geonetwork/core-geonetwork/actions/workflows/linux.yml?query=branch%3Amain) -# Features +## Features * Immediate search access to local and distributed geospatial catalogues * Uploading and downloading of data, graphics, documents, pdf files and any other content type * An interactive Web Map Viewer to combine Web Map Services from distributed servers around the world * Online editing of metadata with a powerful template system * Scheduled harvesting and synchronization of metadata between distributed catalogs -* Support for OGC-CSW 2.0.2 ISO Profile, OAI-PMH, SRU protocols +* Support for OGC-CSW 2.0.2, ISO 1911x and DCAT-AP metadata profiles, OAI-PMH, SRU protocols * Fine-grained access control with group and user management * Multi-lingual user interface -# Documentation +## Documentation -User documentation is managed in the [geonetwork/doc](https://github.com/geonetwork/doc) repository covering all releases of GeoNetwork. +The GeoNetwork Manual and Online Help are included in the `docs/manual` folder. This content is compiled into html pages during a release for a publishing on docs.geonetwork-opensource.org website. -The `docs` folder includes [geonetwork/doc](https://github.com/geonetwork/doc) as a git submodule. This documentation is compiled into html pages during a release for publishing on the [geonetwork-opensource.org](http://geonetwork-opensource.org) website. +* [docs.geonetwork-opensource.org](https://docs.geonetwork-opensource.org) -Developer documentation located in README.md files in the code-base: +The online help is compiled into html pages during a release and is included in the `war` web archive. -* General documentation for the project as a whole is in this README.md -* [Software Development Documentation](/software_development/) provides instructions for setting up a development environment, building Geonetwork, compiling user documentation, and making a releases -* Module specific documentation can be found in each module (assuming there is module specific documentation required) +## Developer Documentation +Developer documentation located in ``README.md`` files in the code-base: + +* General documentation for the project as a whole is in this [README.md](README.md) +* [Software Development Documentation](/software_development/) provides instructions for setting up a development environment, building GeoNetwork, compiling user documentation, and making a releases. +* Module specific documentation can be found in each module: + +## Open Source Security Foundation (OpenSSF) best practices status +[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/8626/badge)](https://www.bestpractices.dev/projects/8626) diff --git a/SECURITY.md b/SECURITY.md index 35bf244af02..8ca2726ee51 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,20 +2,20 @@ The GeoNetwork community takes the security of the software and all services based on the software product seriously. On this page you can find the versions for which the community provides security patches. -If you believe you have found a security vulnerability in the software or an implementation of the software, please report it to geonetwork@osgeo.org as described below. Do not publish the vulnerability in any public forums (such as twitter, email list or issue tracker). +If you believe you have found a security vulnerability in the software or an implementation of the software, please report it [here](https://github.com/geonetwork/core-geonetwork/security/advisories/new) as described below. Do not publish the vulnerability in any public forums (such as Twitter/X, email list or issue tracker). ## Supported Versions Each GeoNetwork release is supported with bug fixes for a limited period, with patch releases made approximately every three to six months. -- We recommend to update to latest incremental release as soon as possible to address security vulnarabilities. +- We recommend to update to latest incremental release as soon as possible to address security vulnerabilities. - Some overlap is provided when major versions are announced with both a current version and a maintenance version being made available to provide time for organizations to upgrade. -| Version | Supported | Comment | -| ----------- | ------------------ |------------------------ | -| 4.2.x | :white_check_mark: | Current version | -| 4.0.x | :white_check_mark: | Maintenance version | -| 3.12.x | :white_check_mark: | Maintenance version | +| Version | Supported | Comment | +|---------|--------------------|---------------------------------------------| +| 4.4.x | :white_check_mark: | Latest version | +| 4.2.x | :white_check_mark: | Stable version | +| 3.12.x | ❌ | End Of Life 2024-03-31 | If your organisation is making use of a GeoNetwork version that is no longer in use by the community all is not lost. You can volunteer on the developer list to make additional releases, or engage with one of our [Commercial Support](https://www.osgeo.org/service-providers/?p=geonetwork) providers. @@ -23,8 +23,8 @@ If your organisation is making use of a GeoNetwork version that is no longer in If you encounter a security vulnerability in GeoNetwork please take care to report in a responsible fashion: -* Keep exploit details out of mailing list and issue tracker (send details to the Project Steering Committee via geonetwork@osgeo.org) +* Keep exploit details out of mailing list and issue tracker (instead provide details to the Project Steering Committee via the GitHub [Report a vulnerability](https://github.com/geonetwork/core-geonetwork/security/advisories/new) option link at the top of this page or send an email to geonetwork@osgeo.org) * Be prepared to work with community members on a solution -* Keep in mind community members are volunteers and an extensive fix may require fundraising / resources +* Keep in mind that community members are volunteers and an extensive fix may require fundraising / resources For more information see [How to contribute](https://github.com/geonetwork/core-geonetwork/wiki/How-to-contribute). diff --git a/add-schema.sh b/add-schema.sh index 2a268428530..4f1ecc8c92d 100755 --- a/add-schema.sh +++ b/add-schema.sh @@ -83,7 +83,7 @@ then ${insertLine} a\\ \ \\ \ org.geonetwork-opensource.schemas\\ -\ schema-${schema}\\ +\ gn-schema-${schema}\\ \ ${gnSchemasVersion}\\ \ SED_SCRIPT @@ -103,7 +103,7 @@ SED_SCRIPT \ \\ \ \\ \ org.geonetwork-opensource.schemas\\ -\ schema-${schema}\\ +\ gn-schema-${schema}\\ \ ${gnSchemasVersion}\\ \ \\ \ \\ @@ -121,7 +121,7 @@ SED_SCRIPT \ \\ \ \\ \ org.geonetwork-opensource.schemas\\ -\ schema-${schema}\\ +\ gn-schema-${schema}\\ \ zip\\ \ false\\ \ \$\{schema-plugins.dir\}\\ @@ -138,7 +138,7 @@ SED_SCRIPT fi # Add schema resources in service/pom.xml with test scope for unit tests -line=$(grep -n "schema-${schema}" services/pom.xml | cut -d: -f1) +line=$(grep -n "gn-schema-${schema}" services/pom.xml | cut -d: -f1) if [ ! $line ] then @@ -154,7 +154,7 @@ then ${finalLine} a\\ \ \\ \ ${projectGroupId}\\ -\ schema-${schema}\\ +\ gn-schema-${schema}\\ \ ${gnSchemasVersion}\\ \ test\\ \ diff --git a/cachingxslt/pom.xml b/cachingxslt/pom.xml index d1cbec2581d..897ff970754 100644 --- a/cachingxslt/pom.xml +++ b/cachingxslt/pom.xml @@ -31,7 +31,7 @@ org.geonetwork-opensource geonetwork - 4.2.4-SNAPSHOT + 4.4.7-SNAPSHOT diff --git a/code_quality/README.md b/code_quality/README.md index fcea5269fb3..5c708c35aea 100644 --- a/code_quality/README.md +++ b/code_quality/README.md @@ -1,3 +1,3 @@ The files in this directory are used for configuring IDEs or are used by the build tool to make certain code quality checks. -For example findbugs-ecludes is used by both the build tool's findbugs implementation as well as IDES for running findbugs. \ No newline at end of file +For example, findbugs-excludes is used by both the build tool's findbugs implementation as well as IDES for running findbugs. diff --git a/code_quality/findbugs-excludes.xml b/code_quality/findbugs-excludes.xml index d04d3b14941..6e225396aef 100644 --- a/code_quality/findbugs-excludes.xml +++ b/code_quality/findbugs-excludes.xml @@ -230,15 +230,6 @@ - - - - - - - - - diff --git a/common/pom.xml b/common/pom.xml index f798046d326..2c2e9083ba9 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -31,7 +31,7 @@ org.geonetwork-opensource geonetwork - 4.2.4-SNAPSHOT + 4.4.7-SNAPSHOT @@ -85,6 +85,10 @@ org.apache.jcs jcs + + xalan + serializer + net.sf.saxon saxon @@ -171,13 +175,19 @@ org.json json - 20140107 - compile org.bitbucket.cowwoc diff-match-patch + + javax.annotation + javax.annotation-api + + + javax.xml.bind + jaxb-api + diff --git a/common/src/main/java/org/fao/geonet/Logger.java b/common/src/main/java/org/fao/geonet/Logger.java index 920d13e548f..76590b8d698 100644 --- a/common/src/main/java/org/fao/geonet/Logger.java +++ b/common/src/main/java/org/fao/geonet/Logger.java @@ -23,8 +23,6 @@ package org.fao.geonet; -//============================================================================= - import org.apache.logging.log4j.core.appender.FileAppender; /** @@ -37,35 +35,52 @@ public interface Logger { * * @return check if debug logging is enabled */ - public boolean isDebugEnabled(); + boolean isDebugEnabled(); /** * Log debug message used indicate module troubleshoot module activity. * * @param message debug message used to provide in */ - public void debug(String message); + void debug(String message); + + void debug(String message, Throwable throwable); + + void debug(String message, Object... object); /** * Log information message indicating module progress. * * @param message information message indicating progress */ - public void info(String message); + void info(String message); + + void info(String message, Throwable throwable); - /** Log warning message indicating potentially harmful situation, module + void info(String message, Object... object); + + /** + * Log warning message indicating potentially harmful situation, module * will continue to try and complete current activity. * * @param message Warning message indicating potentially harmful situation */ - public void warning(String message); + void warning(String message); + + void warning(String message, Throwable throwable); + + void warning(String message, Object... object); /** * Log error message indicating module cannot continue current activity. * * @param message Error message */ - public void error(String message); + void error(String message); + + void error(String message, Throwable throwable); + + void error(String message, Object... object); /** * Log error message using provided throwable, indicating module cannot continue @@ -73,51 +88,49 @@ public interface Logger { * * @param ex Cause of error condition. */ - public void error(Throwable ex); + void error(Throwable ex); /** * Log severe message, indicating application cannot continue to operate. * * @param message severe message */ - public void fatal(String message); + void fatal(String message); /** * Functional module used for logging messages (for example {@code jeeves.engine}). * * @return functional module used for logging messages. */ - public String getModule(); + String getModule(); /** * Configure logger with log4j {@link FileAppender}, used for output. - * + *

* The file appender is also responsible for log file location provided by {@link #getFileAppender()}. * * @param fileAppender Log4j FileAppender */ - public void setAppender(FileAppender fileAppender); + void setAppender(FileAppender fileAppender); /** * The log file name from the file appender for this module. - * + *

* Note both module and fallback module are provided allowing providing a better opportunity * to learn the log file location. Harvesters use the log file name parent directory as a good * location to create {@code /harvester_logs/} folder. - * + *

* Built-in configuration uses log file location {@code logs/geonetwork.log} relative to the current directory, or relative to system property {@code log_file}. * * @return logfile location of {@code logs/geonetwork.log} file */ - public String getFileAppender(); + String getFileAppender(); /** * Access to omodule logging level, providing + * * @return */ - public org.apache.logging.log4j.Level getThreshold(); + org.apache.logging.log4j.Level getThreshold(); } - -//============================================================================= - diff --git a/common/src/main/java/org/fao/geonet/utils/AbstractHttpRequest.java b/common/src/main/java/org/fao/geonet/utils/AbstractHttpRequest.java index 457842d0a4e..9d4f92adc13 100644 --- a/common/src/main/java/org/fao/geonet/utils/AbstractHttpRequest.java +++ b/common/src/main/java/org/fao/geonet/utils/AbstractHttpRequest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2016 Food and Agriculture Organization of the + * Copyright (C) 2001-2023 Food and Agriculture Organization of the * United Nations (FAO-UN), United Nations World Food Programme (WFP) * and United Nations Environment Programme (UNEP) * @@ -83,7 +83,7 @@ public class AbstractHttpRequest { private boolean useProxy; private String proxyHost; private int proxyPort; - private ArrayList alSimpleParams = new ArrayList(); + private ArrayList alSimpleParams = new ArrayList<>(); private String postData; private boolean preemptiveBasicAuth; private HttpClientContext httpClientContext; @@ -303,9 +303,9 @@ protected HttpRequestBase setupHttpMethod() throws IOException { } if (host == null || protocol == null) { - throw new IllegalStateException(String.format(getClass().getSimpleName() + " is not ready to be executed: \n\tprotocol: '%s' " + + throw new IllegalStateException(String.format("%s is not ready to be executed: \n\tprotocol: '%s' " + "\n\tuserinfo: '%s'\n\thost: '%s' \n\tport: '%s' \n\taddress: '%s'\n\tquery '%s'" + - "\n\tfragment: '%s'", protocol, userInfo, host, port, address, query, fragment)); + "\n\tfragment: '%s'", getClass().getSimpleName(), protocol, userInfo, host, port, address, query, fragment)); } HttpRequestBase httpMethod; @@ -352,25 +352,25 @@ protected HttpRequestBase setupHttpMethod() throws IOException { protected String getSentData(HttpRequestBase httpMethod) { URI uri = httpMethod.getURI(); - StringBuilder sentData = new StringBuilder(httpMethod.getMethod()).append(" ").append(uri.getPath()); + StringBuilder sentDataValue = new StringBuilder(httpMethod.getMethod()).append(" ").append(uri.getPath()); if (uri.getQuery() != null) { - sentData.append("?" + uri.getQuery()); + sentDataValue.append("?" + uri.getQuery()); } - sentData.append("\r\n"); + sentDataValue.append("\r\n"); for (Header h : httpMethod.getAllHeaders()) { - sentData.append(h); + sentDataValue.append(h); } - sentData.append("\r\n"); + sentDataValue.append("\r\n"); if (httpMethod instanceof HttpPost) { - sentData.append(postData); + sentDataValue.append(postData); } - return sentData.toString(); + return sentDataValue.toString(); } private Element soapEmbed(Element elem) { @@ -393,7 +393,7 @@ protected Element soapUnembed(Element envelope) throws BadSoapResponseEx { List list = body.getChildren(); - if (list.size() == 0) + if (list.isEmpty()) throw new BadSoapResponseEx(envelope); return list.get(0); diff --git a/common/src/main/java/org/fao/geonet/utils/Env.java b/common/src/main/java/org/fao/geonet/utils/Env.java new file mode 100644 index 00000000000..bc80bf7a131 --- /dev/null +++ b/common/src/main/java/org/fao/geonet/utils/Env.java @@ -0,0 +1,56 @@ +//============================================================================= +//=== Copyright (C) 2001-2023 Food and Agriculture Organization of the +//=== United Nations (FAO-UN), United Nations World Food Programme (WFP) +//=== and United Nations Environment Programme (UNEP) +//=== +//=== This program is free software; you can redistribute it and/or modify +//=== it under the terms of the GNU General Public License as published by +//=== the Free Software Foundation; either version 2 of the License, or (at +//=== your option) any later version. +//=== +//=== This program is distributed in the hope that it will be useful, but +//=== WITHOUT ANY WARRANTY; without even the implied warranty of +//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//=== General Public License for more details. +//=== +//=== You should have received a copy of the GNU General Public License +//=== along with this program; if not, write to the Free Software +//=== Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//=== +//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, +//=== Rome - Italy. email: geonetwork@osgeo.org +//============================================================================== + +package org.fao.geonet.utils; + +import org.apache.commons.lang.StringUtils; + +public final class Env { + + /** + * Retrieves an environment variable with this priority: + * - Java environment variable. + * - System environment variable. + * - Default value provided as parameter. + * + * @param propertyName + * @param defaultValue + * @return + */ + public static String getPropertyFromEnv(String propertyName, String defaultValue) { + // Check if provided in Java environment variable + String propertyValue = System.getProperty(propertyName); + + if (StringUtils.isEmpty(propertyValue)) { + // System environment variable + propertyValue = System.getenv(propertyName.toUpperCase().replace('.', '_')); + } + + if (StringUtils.isEmpty(propertyValue)) { + propertyValue = defaultValue; + } + + return propertyValue; + } + +} diff --git a/common/src/main/java/org/fao/geonet/utils/GeonetHttpRequestFactory.java b/common/src/main/java/org/fao/geonet/utils/GeonetHttpRequestFactory.java index 7ba666fd2a9..bd548561c05 100644 --- a/common/src/main/java/org/fao/geonet/utils/GeonetHttpRequestFactory.java +++ b/common/src/main/java/org/fao/geonet/utils/GeonetHttpRequestFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2016 Food and Agriculture Organization of the + * Copyright (C) 2001-2023 Food and Agriculture Organization of the * United Nations (FAO-UN), United Nations World Food Programme (WFP) * and United Nations Environment Programme (UNEP) * @@ -200,6 +200,7 @@ public HttpClientBuilder getDefaultHttpClientBuilder() { final HttpClientBuilder builder = HttpClientBuilder.create(); builder.setRedirectStrategy(new LaxRedirectStrategy()); builder.disableContentCompression(); + builder.useSystemProperties(); synchronized (this) { if (connectionManager == null) { @@ -249,40 +250,40 @@ public void closeIdleConnections(long idleTimeout, TimeUnit tunit) { private static class AdaptingResponse extends AbstractClientHttpResponse { - private final CloseableHttpResponse _response; - private final CloseableHttpClient _client; + private final CloseableHttpResponse response; + private final CloseableHttpClient client; public AdaptingResponse(CloseableHttpClient client, CloseableHttpResponse response) { - this._response = response; - this._client = client; + this.response = response; + this.client = client; } @Override public int getRawStatusCode() throws IOException { - return _response.getStatusLine().getStatusCode(); + return response.getStatusLine().getStatusCode(); } @Override public String getStatusText() throws IOException { - return _response.getStatusLine().getReasonPhrase(); + return response.getStatusLine().getReasonPhrase(); } @Override public void close() { - IOUtils.closeQuietly(_response); - IOUtils.closeQuietly(_client); + IOUtils.closeQuietly(response); + IOUtils.closeQuietly(client); } @Override public InputStream getBody() throws IOException { - return _response.getEntity().getContent(); + return response.getEntity().getContent(); } @Override public HttpHeaders getHeaders() { final HttpHeaders httpHeaders = new HttpHeaders(); - final Header[] headers = _response.getAllHeaders(); + final Header[] headers = response.getAllHeaders(); for (Header header : headers) { final HeaderElement[] elements = header.getElements(); diff --git a/common/src/main/java/org/fao/geonet/utils/Log.java b/common/src/main/java/org/fao/geonet/utils/Log.java index 5521672ab02..df0269aaf14 100644 --- a/common/src/main/java/org/fao/geonet/utils/Log.java +++ b/common/src/main/java/org/fao/geonet/utils/Log.java @@ -24,22 +24,18 @@ package org.fao.geonet.utils; -import org.apache.log4j.Priority; import org.apache.log4j.bridge.AppenderWrapper; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.appender.FileAppender; import org.apache.logging.log4j.core.appender.RollingFileAppender; -import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.LoggerConfig; import java.io.File; -import java.util.Enumeration; - -//============================================================================= /** * Jeeves logging integration, defining functional logger categories by module @@ -105,6 +101,16 @@ public final class Log { public static final String TRANSFORMER_FACTORY = JEEVES + ".transformerFactory"; + /** + * This is the name of the RollingFileAppender in your log4j2.xml configuration file. + *

+ * LogConfig uses this name to lookup RollingFileAppender to check configuration in + * case a custom log file location has been used. + */ + private static final String FILE_APPENDER_NAME = "File"; + + public static final String GEONETWORK_MODULE = "geonetwork"; + /** * Default constructor. Builds a Log. */ @@ -115,8 +121,12 @@ public static void debug(String module, Object message) { LogManager.getLogger(module).debug(message); } - public static void debug(String module, Object message, Exception e) { - LogManager.getLogger(module).debug(message, e); + public static void debug(String module, String message, Object... objects) { + LogManager.getLogger(module).debug(message, objects); + } + + public static void debug(String module, String message, Throwable throwable) { + LogManager.getLogger(module).debug(message, throwable); } public static boolean isDebugEnabled(String module) { @@ -147,10 +157,15 @@ public static void info(String module, Object message) { LogManager.getLogger(module).info(message); } - public static void info(String module, Object message, Throwable t) { - LogManager.getLogger(module).info(message, t); + public static void info(String module, String message, Object... objects) { + LogManager.getLogger(module).info(message, objects); } + public static void info(String module, String message, Throwable throwable) { + LogManager.getLogger(module).info(message, throwable); + } + + //--------------------------------------------------------------------------- public static void warning(String module, Object message) { @@ -172,6 +187,14 @@ public static void error(String module, Object message, Throwable t) { LogManager.getLogger(module).error(message, t); } + public static void error(String module, String message, Object... objects) { + LogManager.getLogger(module).error(message, objects); + } + + public static void error(String module, String message, Throwable throwable) { + LogManager.getLogger(module).error(message, throwable); + } + //--------------------------------------------------------------------------- public static void fatal(String module, Object message) { @@ -215,18 +238,58 @@ public void debug(String message) { Log.debug(module, message); } + @Override + public void debug(String message, Throwable throwable) { + Log.debug(module, message, throwable); + } + + @Override + public void debug(String message, Object... object) { + Log.debug(module, message, object); + } + public void info(String message) { Log.info(module, message); } + @Override + public void info(String message, Throwable throwable) { + Log.info(module, message, throwable); + } + + @Override + public void info(String message, Object... object) { + Log.info(module, message, object); + } + public void warning(String message) { Log.warning(module, message); } + @Override + public void warning(String message, Throwable throwable) { + Log.warning(module, message, throwable); + } + + @Override + public void warning(String message, Object... object) { + + } + public void error(String message) { Log.error(module, message); } + @Override + public void error(String message, Throwable throwable) { + Log.error(module, message, throwable); + } + + @Override + public void error(String message, Object... object) { + Log.error(module, message, object); + } + public void fatal(String message) { Log.fatal(module, message); } @@ -269,7 +332,7 @@ public String getFileAppender() { } } LoggerConfig fallbackConfig = configuration.getLoggers().get(fallbackModule); - if( fallbackConfig != null) { + if (fallbackConfig != null) { for (Appender appender : fallbackConfig.getAppenders().values()) { File file = toLogFile(appender); if (file != null && file.exists()) { @@ -331,4 +394,62 @@ public static File toLogFile(Appender appender) { return null; } + public static File getLogfile() { + // Appender is supplied by LogUtils based on parsing log4j2.xml file indicated + // by database settings + + // First, try the fileappender from the logger named "geonetwork" + org.apache.log4j.Appender appender = org.apache.log4j.Logger.getLogger(GEONETWORK_MODULE).getAppender(FILE_APPENDER_NAME); + // If still not found, try the one from the logger named "jeeves" + if (appender == null) { + appender = org.apache.log4j.Logger.getLogger(Log.JEEVES).getAppender(FILE_APPENDER_NAME); + } + if (appender != null) { + if (appender instanceof AppenderWrapper) { + AppenderWrapper wrapper = (AppenderWrapper) appender; + org.apache.logging.log4j.core.Appender appender2 = wrapper.getAppender(); + + if (appender2 instanceof FileAppender) { + FileAppender fileAppender = (FileAppender) appender2; + String logFileName = fileAppender.getFileName(); + if (logFileName != null) { + File logFile = new File(logFileName); + if (logFile.exists()) { + return logFile; + } + } + } + if (appender2 instanceof RollingFileAppender) { + RollingFileAppender fileAppender = (RollingFileAppender) appender2; + String logFileName = fileAppender.getFileName(); + if (logFileName != null) { + File logFile = new File(logFileName); + if (logFile.exists()) { + return logFile; + } + } + } + } + } + Log.warning(GEONETWORK_MODULE, "Error when getting logger file for the " + "appender named '" + FILE_APPENDER_NAME + "'. " + + "Check your log configuration file. " + + "A FileAppender or RollingFileAppender is required to return last activity to the user interface." + + "Appender file not found."); + + if (System.getProperties().containsKey("log_dir")) { + File logDir = new File(System.getProperty("log_dir")); + if (logDir.exists() && logDir.isDirectory()) { + File logFile = new File(logDir, "logs/geonetwork.log"); + if (logFile.exists()) { + return logFile; + } + } + } else { + File logFile = new File("logs/geonetwork.log"); + if (logFile.exists()) { + return logFile; + } + } + return null; // unavailable + } } diff --git a/common/src/main/java/org/fao/geonet/utils/Xml.java b/common/src/main/java/org/fao/geonet/utils/Xml.java index 03a0934e2cf..9e0b20ee6fd 100644 --- a/common/src/main/java/org/fao/geonet/utils/Xml.java +++ b/common/src/main/java/org/fao/geonet/utils/Xml.java @@ -31,27 +31,15 @@ import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.FeatureKeys; -import org.apache.commons.io.IOUtils; import org.apache.fop.apps.Fop; import org.apache.fop.apps.FopFactory; import org.apache.fop.apps.MimeConstants; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.DefaultHttpClient; import org.apache.xml.resolver.tools.CatalogResolver; import org.fao.geonet.exceptions.XSDValidationErrorEx; import org.fao.geonet.utils.nio.NioPathAwareEntityResolver; import org.fao.geonet.utils.nio.NioPathHolder; import org.fao.geonet.utils.nio.PathStreamSource; -import org.jdom.Attribute; -import org.jdom.Content; -import org.jdom.DocType; -import org.jdom.Document; -import org.jdom.Element; -import org.jdom.JDOMException; -import org.jdom.Namespace; -import org.jdom.Text; +import org.jdom.*; import org.jdom.filter.ElementFilter; import org.jdom.input.SAXBuilder; import org.jdom.output.Format; @@ -69,27 +57,14 @@ import javax.xml.XMLConstants; import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; -import javax.xml.transform.Result; -import javax.xml.transform.Source; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.URIResolver; +import javax.xml.transform.*; import javax.xml.transform.sax.SAXResult; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import javax.xml.validation.ValidatorHandler; -import java.io.BufferedOutputStream; -import java.io.ByteArrayInputStream; -import java.io.DataInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintStream; -import java.io.StringReader; +import java.io.*; import java.net.HttpURLConnection; import java.net.URI; import java.net.URISyntaxException; @@ -100,19 +75,11 @@ import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; -import java.nio.charset.StandardCharsets; import java.nio.file.FileSystemNotFoundException; import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; +import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -399,6 +366,9 @@ public static Object unmarshall(Element xml, Class clazz) throws Exception { public static Element transform(Element xml, Path styleSheetPath, Map params) throws Exception { JDOMResult resXml = new JDOMResult(); transform(xml, styleSheetPath, resXml, params); + if (resXml.getDocument() == null) { + throw new NullPointerException("Failed to create a Document for " + resXml.getResult()); + } return (Element) resXml.getDocument().getRootElement().detach(); } //-------------------------------------------------------------------------- @@ -406,22 +376,16 @@ public static Element transform(Element xml, Path styleSheetPath, Map params, OutputStream out) throws Exception { StreamResult resStream = new StreamResult(out); - transform(xml, styleSheetPath, resStream, null); + transform(xml, styleSheetPath, resStream, params); out.flush(); } - - public static void transformXml(Element xml, Path styleSheetPath, OutputStream out) throws Exception { - StreamResult resStream = new StreamResult(out); - Map map = new HashMap<>(); - map.put("geonet-force-xml", "xml"); - transform(xml, styleSheetPath, resStream, map); - out.flush(); + public static void transform(Element xml, Path styleSheetPath, OutputStream out) throws Exception { + transform(xml, styleSheetPath, new HashMap<>(), out); } - //-------------------------------------------------------------------------- /** * Transforms an xml tree putting the result to a stream - no parameters. @@ -487,6 +451,9 @@ protected static Path resolvePath(Source s) throws URISyntaxException { /** * Transforms an xml tree putting the result to a stream with optional parameters. + *

+ * Add a geonet-force-xml parameter to force the formatting to be xml. + * The preferred method is to define it using xsl:output. */ public static void transform(Element xml, Path styleSheetPath, Result result, Map params) throws Exception { @@ -518,13 +485,13 @@ protected static Path resolvePath(Source s) throws URISyntaxException { t.setParameter(param.getKey(), param.getValue()); } - if (params.containsKey("geonet-force-xml")) { - ((Controller) t).setOutputProperty("indent", "yes"); - ((Controller) t).setOutputProperty("method", "xml"); - ((Controller) t).setOutputProperty("{http://saxon.sf.net/}indent-spaces", "3"); + if (params.containsKey("geonet-force-xml")) { + ((Controller) t).setOutputProperty("indent", "yes"); + ((Controller) t).setOutputProperty("method", "xml"); + ((Controller) t).setOutputProperty("{http://saxon.sf.net/}indent-spaces", "2"); + } } - } t.transform(srcXml, result); } } diff --git a/common/src/main/java/org/fao/geonet/utils/XmlRequest.java b/common/src/main/java/org/fao/geonet/utils/XmlRequest.java index 7b6a3b69c59..cba8608a556 100644 --- a/common/src/main/java/org/fao/geonet/utils/XmlRequest.java +++ b/common/src/main/java/org/fao/geonet/utils/XmlRequest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2016 Food and Agriculture Organization of the + * Copyright (C) 2001-2024 Food and Agriculture Organization of the * United Nations (FAO-UN), United Nations World Food Programme (WFP) * and United Nations Environment Programme (UNEP) * @@ -124,13 +124,13 @@ protected final Element executeAndReadResponse(HttpRequestBase httpMethod) throw " -- Response Code: " + httpResponse.getRawStatusCode()); } - byte[] data = null; + byte[] data; try { data = IOUtils.toByteArray(httpResponse.getBody()); return Xml.loadStream(new ByteArrayInputStream(data)); } catch (JDOMException e) { - throw new BadXmlResponseEx("Response: '" + new String(data, "UTF8") + "' (from URI " + httpMethod.getURI() + ")"); + throw new BadXmlResponseEx("Invalid XML document from URI: " + httpMethod.getURI()); } finally { httpMethod.releaseConnection(); diff --git a/common/src/test/java/org/fao/geonet/ZipUtilTest.java b/common/src/test/java/org/fao/geonet/ZipUtilTest.java index 4874094f461..6c47d4cb447 100644 --- a/common/src/test/java/org/fao/geonet/ZipUtilTest.java +++ b/common/src/test/java/org/fao/geonet/ZipUtilTest.java @@ -127,10 +127,10 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO assertEquals(7, allFiles.size()); assertTrue(allFiles.toString(), allFiles.contains("/")); - assertTrue(allFiles.toString(), allFiles.contains("/zipfile/")); + assertTrue(allFiles.toString(), allFiles.contains("/zipfile") || allFiles.contains("/zipfile/")); assertTrue(allFiles.toString(), allFiles.contains("/zipfile/file1.txt")); assertTrue(allFiles.toString(), allFiles.contains("/zipfile/file2.txt")); - assertTrue(allFiles.toString(), allFiles.contains("/zipfile/dir/")); + assertTrue(allFiles.toString(), allFiles.contains("/zipfile/dir") || allFiles.contains("/zipfile/dir/")); assertTrue(allFiles.toString(), allFiles.contains("/zipfile/dir/file4.txt")); assertTrue(allFiles.toString(), allFiles.contains("/file3.txt")); } diff --git a/core/README.md b/core/README.md index f9d23d22e6f..cc99498e812 100644 --- a/core/README.md +++ b/core/README.md @@ -1,9 +1,9 @@ -The core module contains the core Geonetwork classes. For example SearchManager for searching the metadata index, DataManager for saving +The core module contains the core Geonetwork classes. For example, EsSearchManager for searching the metadata index, DataManager for saving and loading Metadata. -Services, Harvesters, etc... that are are plugins will usually depend on core and will make use of these core classes to implement their +Services, Harvesters, etc... that are plugins will usually depend on core and will make use of these core classes to implement their services. -Geonetwork is wired together via Spring-Dependency-Injection. The critical classes (DataManager, SchemaManager, SearchManager, etc...) are +Geonetwork is wired together via Spring-Dependency-Injection. The critical classes (DataManager, SchemaManager, EsSearchManager, etc...) are all singleton beans in the application context and can be either injected into other beans or obtained via the ServiceContext.getBean -method (or ServiceContext.getApplicationContext()). \ No newline at end of file +method (or ServiceContext.getApplicationContext()). diff --git a/core/pom.xml b/core/pom.xml index 93a660921cd..7b724db211c 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -27,7 +27,7 @@ geonetwork org.geonetwork-opensource - 4.2.4-SNAPSHOT + 4.4.7-SNAPSHOT 4.0.0 @@ -52,6 +52,10 @@ xalan xalan + + xalan + serializer + net.sf.saxon saxon-dom @@ -336,10 +340,6 @@ org.apache.xmlgraphics xmlgraphics-commons - - commons-fileupload - commons-fileupload - commons-collections commons-collections @@ -395,30 +395,6 @@ ${project.version} - - org.apache.jclouds - jclouds-all - 2.2.1 - - - - org.apache.chemistry.opencmis - chemistry-opencmis-client-api - 1.1.0 - - - - org.apache.chemistry.opencmis - chemistry-opencmis-client-impl - 1.1.0 - - - xml-resolver - xml-resolver - - - - org.tmatesoft.svnkit svnkit @@ -478,6 +454,10 @@ xalan xalan + + xalan + serializer + org.apache.xmlgraphics batik-transcoder @@ -511,6 +491,12 @@ gn-schema-iso19139 ${project.version} + + org.geonetwork-opensource.schemas + gn-schema-iso19115-3.2018 + ${project.version} + test + ${project.groupId} gn-dummy-api @@ -566,7 +552,7 @@ org.owasp.esapi esapi - 2.4.0.0 + 2.5.4.0 log4j @@ -593,15 +579,12 @@ spring-test compile + - org.elasticsearch.client - elasticsearch-rest-high-level-client - - - com.amazonaws - aws-java-sdk-s3 - 1.12.261 + co.elastic.clients + elasticsearch-java + org.jasypt jasypt @@ -713,6 +696,7 @@ test 9300 9200 + -Xmx2g diff --git a/core/src/main/java/jeeves/config/springutil/JeevesContextLoaderListener.java b/core/src/main/java/jeeves/config/springutil/JeevesContextLoaderListener.java index a02a4b0298b..74838de6b02 100644 --- a/core/src/main/java/jeeves/config/springutil/JeevesContextLoaderListener.java +++ b/core/src/main/java/jeeves/config/springutil/JeevesContextLoaderListener.java @@ -52,11 +52,6 @@ public void contextInitialized(final ServletContextEvent sce) { final Pattern nodeNamePattern = Pattern.compile("[a-zA-Z0-9_\\-]+"); final ServletContext servletContext = sce.getServletContext(); - String javaVersion = System.getProperty("java.version"); - if(!javaVersion.startsWith("1.8")){ - // GeoNetwork does not support Java 11 at this time - throw new RuntimeException("Java 8 required, cannot start with \""+javaVersion+"\""); - } File node = new File(servletContext.getRealPath("/WEB-INF/config-node/srv.xml")); diff --git a/core/src/main/java/jeeves/config/springutil/JeevesNodeAwareLogoutSuccessHandler.java b/core/src/main/java/jeeves/config/springutil/JeevesNodeAwareLogoutSuccessHandler.java index e1c0aec9692..8442c90959a 100644 --- a/core/src/main/java/jeeves/config/springutil/JeevesNodeAwareLogoutSuccessHandler.java +++ b/core/src/main/java/jeeves/config/springutil/JeevesNodeAwareLogoutSuccessHandler.java @@ -26,11 +26,15 @@ import org.fao.geonet.NodeInfo; import org.fao.geonet.kernel.setting.SettingManager; import org.fao.geonet.kernel.setting.Settings; +import org.fao.geonet.constants.Geonet; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.AbstractAuthenticationTargetUrlRequestHandler; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; +import org.apache.commons.lang3.StringUtils; +import org.fao.geonet.kernel.setting.SettingInfo; + import java.io.IOException; import java.net.MalformedURLException; @@ -84,8 +88,10 @@ protected String determineTargetUrl(HttpServletRequest request, HttpServletRespo String siteHost = settingManager.getValue(Settings.SYSTEM_SERVER_HOST); String siteProtocol = settingManager.getValue(Settings.SYSTEM_SERVER_PROTOCOL); - int sitePort = settingManager.getValueAsInt(Settings.SYSTEM_SERVER_PORT); - + + // some conditional logic to handle the case where there's no port in the settings + SettingInfo si = new SettingInfo(); + int sitePort = si.getSitePort(); if (!hostName.equalsIgnoreCase(siteHost) || !protocol.equalsIgnoreCase(siteProtocol) || diff --git a/core/src/main/java/jeeves/guiservices/profiles/Get.java b/core/src/main/java/jeeves/guiservices/profiles/Get.java deleted file mode 100644 index 32beb02a690..00000000000 --- a/core/src/main/java/jeeves/guiservices/profiles/Get.java +++ /dev/null @@ -1,59 +0,0 @@ -//============================================================================= -//=== Copyright (C) 2001-2005 Food and Agriculture Organization of the -//=== United Nations (FAO-UN), United Nations World Food Programme (WFP) -//=== and United Nations Environment Programme (UNEP) -//=== -//=== This library is free software; you can redistribute it and/or -//=== modify it under the terms of the GNU Lesser General Public -//=== License as published by the Free Software Foundation; either -//=== version 2.1 of the License, or (at your option) any later version. -//=== -//=== This library is distributed in the hope that it will be useful, -//=== but WITHOUT ANY WARRANTY; without even the implied warranty of -//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -//=== Lesser General Public License for more details. -//=== -//=== You should have received a copy of the GNU Lesser General Public -//=== License along with this library; if not, write to the Free Software -//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -//=== -//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, -//=== Rome - Italy. email: geonetwork@osgeo.org -//============================================================================== - -package jeeves.guiservices.profiles; - -import jeeves.interfaces.Service; -import jeeves.server.ServiceConfig; -import jeeves.server.context.ServiceContext; - -import org.fao.geonet.domain.Profile; -import org.jdom.Element; - -import java.nio.file.Path; - -//============================================================================= - -/** - * A simple service that returns all user profiles in the system - */ - -public class Get implements Service { - public void init(Path appPath, ServiceConfig params) throws Exception { - } - - //-------------------------------------------------------------------------- - //--- - //--- Service - //--- - //-------------------------------------------------------------------------- - - public Element exec(Element params, ServiceContext context) throws Exception { - Profile profile = context.getUserSession().getProfile(); - - return (Element) context.getProfileManager().getProfilesElement(profile); - } -} - -//============================================================================= - diff --git a/core/src/main/java/jeeves/server/context/BasicContext.java b/core/src/main/java/jeeves/server/context/BasicContext.java index da210ed0ecf..00d1769b4c6 100644 --- a/core/src/main/java/jeeves/server/context/BasicContext.java +++ b/core/src/main/java/jeeves/server/context/BasicContext.java @@ -143,21 +143,61 @@ public void debug(final String message) { logger.debug(message); } + @Override + public void debug(String message, Throwable throwable) { + logger.debug(message, throwable); + } + + @Override + public void debug(String message, Object... object) { + logger.debug(message, object); + } + @Override public void info(final String message) { logger.info(message); } + @Override + public void info(String message, Throwable throwable) { + logger.info(message, throwable); + } + + @Override + public void info(String message, Object... object) { + logger.info(message, object); + } + @Override public void warning(final String message) { logger.warning(message); } + @Override + public void warning(String message, Throwable throwable) { + logger.warning(message, throwable); + } + + @Override + public void warning(String message, Object... object) { + logger.warning(message, object); + } + @Override public void error(final String message) { logger.error(message); } + @Override + public void error(String message, Throwable throwable) { + logger.error(message, throwable); + } + + @Override + public void error(String message, Object... object) { + logger.error(message, object); + } + @Override public void error(Throwable ex) { logger.error(ex); @@ -200,6 +240,3 @@ public String getNodeId() { return NodeInfo.DEFAULT_NODE; } } - -//============================================================================= - diff --git a/core/src/main/java/jeeves/services/Ping.java b/core/src/main/java/jeeves/services/Ping.java deleted file mode 100644 index c975bfdd22c..00000000000 --- a/core/src/main/java/jeeves/services/Ping.java +++ /dev/null @@ -1,52 +0,0 @@ -//============================================================================= -//=== Copyright (C) 2001-2005 Food and Agriculture Organization of the -//=== United Nations (FAO-UN), United Nations World Food Programme (WFP) -//=== and United Nations Environment Programme (UNEP) -//=== -//=== This library is free software; you can redistribute it and/or -//=== modify it under the terms of the GNU Lesser General Public -//=== License as published by the Free Software Foundation; either -//=== version 2.1 of the License, or (at your option) any later version. -//=== -//=== This library is distributed in the hope that it will be useful, -//=== but WITHOUT ANY WARRANTY; without even the implied warranty of -//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -//=== Lesser General Public License for more details. -//=== -//=== You should have received a copy of the GNU Lesser General Public -//=== License along with this library; if not, write to the Free Software -//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -//=== -//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, -//=== Rome - Italy. email: geonetwork@osgeo.org -//============================================================================== - -package jeeves.services; - -import jeeves.interfaces.Service; -import jeeves.server.ServiceConfig; -import jeeves.server.context.ServiceContext; - -import org.jdom.Element; - -import java.nio.file.Path; - -//============================================================================= - -public class Ping implements Service { - public void init(Path appPath, ServiceConfig params) throws Exception { - } - - //-------------------------------------------------------------------------- - //--- - //--- Service - //--- - //-------------------------------------------------------------------------- - - public Element exec(Element params, ServiceContext context) throws Exception { - return (Element) params.clone(); - } -} - -//============================================================================= - diff --git a/core/src/main/java/jeeves/services/RegExpReplace.java b/core/src/main/java/jeeves/services/RegExpReplace.java deleted file mode 100644 index a172f82c4e5..00000000000 --- a/core/src/main/java/jeeves/services/RegExpReplace.java +++ /dev/null @@ -1,141 +0,0 @@ -//============================================================================= -//=== Copyright (C) 2001-2005 Food and Agriculture Organization of the -//=== United Nations (FAO-UN), United Nations World Food Programme (WFP) -//=== and United Nations Environment Programme (UNEP) -//=== -//=== This library is free software; you can redistribute it and/or -//=== modify it under the terms of the GNU Lesser General Public -//=== License as published by the Free Software Foundation; either -//=== version 2.1 of the License, or (at your option) any later version. -//=== -//=== This library is distributed in the hope that it will be useful, -//=== but WITHOUT ANY WARRANTY; without even the implied warranty of -//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -//=== Lesser General Public License for more details. -//=== -//=== You should have received a copy of the GNU Lesser General Public -//=== License along with this library; if not, write to the Free Software -//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -//=== -//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, -//=== Rome - Italy. email: geonetwork@osgeo.org -//============================================================================== - -package jeeves.services; - -import jeeves.constants.Jeeves; -import jeeves.interfaces.Service; -import jeeves.server.ServiceConfig; -import jeeves.server.context.ServiceContext; - -import org.fao.geonet.utils.Xml; -import org.jdom.Element; - -import java.nio.file.Path; -import java.util.Iterator; -import java.util.List; -import java.util.StringTokenizer; -import java.util.Vector; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -//============================================================================= - -/** - * This service reads a configuration xml file containing pattern-replacement pairs and - * applies all the pairs to each text element of the output. The configuration is read from - * xml/regexp.xml and is formatted: - */ - -public class RegExpReplace implements Service { - private Vector patterns; - private Vector replacements; - - //-------------------------------------------------------------------------- - //--- - //--- Init - //--- - //-------------------------------------------------------------------------- - - @SuppressWarnings("unchecked") - public void init(Path appPath, ServiceConfig params) throws Exception { - String file = params.getMandatoryValue(Jeeves.Config.FILE); - Element config = Xml.loadFile(appPath.resolve(file)); - - patterns = new Vector(); - replacements = new Vector(); - - // read all pattern-replacement pairs - for (Element expr : (List) config.getChildren()) { - String pattern = expr.getAttributeValue(Jeeves.Attr.PATTERN); - String replacement = expr.getAttributeValue(Jeeves.Attr.REPLACEMENT); - - patterns.add(Pattern.compile(pattern)); - replacements.add(getRealText(replacement)); - } - } - - //-------------------------------------------------------------------------- - //--- - //--- Service - //--- - //-------------------------------------------------------------------------- - - public Element exec(Element params, ServiceContext context) throws Exception { - replaceInElement(params); - - return params; - } - - //-------------------------------------------------------------------------- - //--- replace some entities - - private String getRealText(String text) { - String noLt = replace(text, "<", "<"); - String noGt = replace(noLt, ">", ">"); - String noAmp = replace(noGt, "&", "&"); - - return noAmp; - } - - //-------------------------------------------------------------------------- - - private String replace(String text, String delim, String replacement) { - StringBuffer result = new StringBuffer(); - StringTokenizer st = new StringTokenizer(text, delim, true); - - while (st.hasMoreTokens()) { - String token = st.nextToken(); - - if (token.equals(delim)) result.append(replacement); - else result.append(token); - } - - return result.toString(); - } - - //-------------------------------------------------------------------------- - //--- apply all pattern-replacement pairs - - @SuppressWarnings("unchecked") - private void replaceInElement(Element e) { - if (e.getChildren().size() != 0) - for (Iterator iter = e.getChildren().iterator(); iter.hasNext(); ) - replaceInElement(iter.next()); - else { - String text = e.getText(); - - for (int i = 0; i < patterns.size(); i++) { - Pattern pattern = (Pattern) patterns.get(i); - String replacement = (String) replacements.get(i); - Matcher matcher = pattern.matcher(text); - - text = matcher.replaceAll(replacement); - } - e.setText(text); - } - } -} - -//============================================================================= - diff --git a/core/src/main/java/jeeves/services/db/Select.java b/core/src/main/java/jeeves/services/db/Select.java deleted file mode 100644 index f1bf4a206d1..00000000000 --- a/core/src/main/java/jeeves/services/db/Select.java +++ /dev/null @@ -1,396 +0,0 @@ -//============================================================================= -//=== Copyright (C) 2001-2005 Food and Agriculture Organization of the -//=== United Nations (FAO-UN), United Nations World Food Programme (WFP) -//=== and United Nations Environment Programme (UNEP) -//=== -//=== This library is free software; you can redistribute it and/or -//=== modify it under the terms of the GNU Lesser General Public -//=== License as published by the Free Software Foundation; either -//=== version 2.1 of the License, or (at your option) any later version. -//=== -//=== This library is distributed in the hope that it will be useful, -//=== but WITHOUT ANY WARRANTY; without even the implied warranty of -//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -//=== Lesser General Public License for more details. -//=== -//=== You should have received a copy of the GNU Lesser General Public -//=== License along with this library; if not, write to the Free Software -//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -//=== -//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, -//=== Rome - Italy. email: geonetwork@osgeo.org -//============================================================================== - -package jeeves.services.db; - -import jeeves.constants.Jeeves; -import jeeves.interfaces.Service; -import jeeves.server.ServiceConfig; -import jeeves.server.context.ServiceContext; - -import org.fao.geonet.utils.Xml; -import org.jdom.Element; - -import javax.sql.DataSource; - -import java.io.StringReader; -import java.nio.file.Path; -import java.sql.*; -import java.text.DecimalFormat; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.Date; - -//============================================================================= - -/** - * Performs a generic query - */ - -public class Select implements Service { - private static final String DEFAULT_DATE_FORMAT = "dd-MM-yyyy"; - private static final String DEFAULT_TIME_FORMAT = "HH:mm:ss"; - private static final String DEFAULT_TIMESTAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ss"; - - //-------------------------------------------------------------------------- - //--- - //--- Init - //--- - //-------------------------------------------------------------------------- - private String query; - - //-------------------------------------------------------------------------- - //--- - //--- Service - //--- - //-------------------------------------------------------------------------- - private Vector inFields; - private Vector outFields; - - public static Vector scanInFields(Element params, Vector inFields, Element result, ServiceContext context) throws Exception { - // build argument list - Vector vArgs = new Vector(); - - for (Element field : inFields) { - // extract field attributes and value - String name = field.getAttributeValue(Jeeves.Attr.NAME); - String mandatory = field.getAttributeValue(Jeeves.Attr.MANDATORY); - String nullText = field.getAttributeValue(Jeeves.Attr.NULL); - String format = field.getAttributeValue(Jeeves.Attr.FORMAT); - String sqlValue = field.getAttributeValue(Jeeves.Attr.VALUE); - String forward = field.getAttributeValue(Jeeves.Attr.FORWARD); - String value = params.getChildText(name); - - // check if field name is defined - if (name == null) - throw new IllegalArgumentException("undefined field name: " + Xml.getString(field)); - - // get value from sqlValue if needed - if (sqlValue != null) { - Element el = select(context, sqlValue); - value = el.getChild(Jeeves.Elem.RECORD).getChildText(name); - } - // check if mandatory fields are present - boolean mFlag; - if (mandatory == null || mandatory.equals(Jeeves.Text.FALSE)) - mFlag = false; - else if (mandatory.equals(Jeeves.Text.TRUE)) - mFlag = true; - else - throw new IllegalArgumentException("bad mandatory attribute value: " + mandatory); - if (mFlag && value == null) - throw new IllegalArgumentException("mandatory parameter missing: " + name); - - // add field to select arguments - if (value == null || (nullText != null && nullText.equals(value))) - vArgs.add(null); - else { - // forward field to output if needed - boolean fFlag; - if (forward == null || forward.equals(Jeeves.Text.FALSE)) - fFlag = false; - else if (forward.equals(Jeeves.Text.TRUE)) - fFlag = true; - else - throw new IllegalArgumentException("bad forward attribute value: " + forward); - if (fFlag && result != null) - result.addContent(new Element(name).setText(value)); - - String type = field.getAttributeValue(Jeeves.Attr.TYPE); - - if (type == null || type.equals(Jeeves.Attr.Type.STRING)) - vArgs.add(value); - - else if (type.equals(Jeeves.Attr.Type.INT)) { - if (format == null) - vArgs.add(Integer.valueOf(value)); - else { - DecimalFormat df = new DecimalFormat(format); - Number n = df.parse(value); - vArgs.add(Integer.valueOf(n.intValue())); - } - } else if (type.equals(Jeeves.Attr.Type.DOUBLE)) { - if (format == null) - vArgs.add(new Double(value)); - else { - DecimalFormat df = new DecimalFormat(format); - Number n = df.parse(value); - vArgs.add(new Double(n.doubleValue())); - } - } else if (type.equals(Jeeves.Attr.Type.DATE)) { - SimpleDateFormat df = (format == null) ? new SimpleDateFormat(DEFAULT_DATE_FORMAT) : new SimpleDateFormat(format); - Date date = df.parse(value); - vArgs.add(new java.sql.Date(date.getTime())); // directly passing date does not work, at least with MySql - } else - throw new IllegalArgumentException("bad field type: " + type); - } - } - return vArgs; - } - - /* ************************** Methods for simplifying JPA migration ****************************************** */ - - public static Hashtable scanOutFields(Vector outFields) throws Exception { - Hashtable formats = new Hashtable(); - - // scan fields info - for (Element field : outFields) { - // build Field - String name = field.getAttributeValue(Jeeves.Attr.NAME); - if (name == null) - throw new IllegalArgumentException("undefined field name: " + Xml.getString(field)); - - String format = field.getAttributeValue(Jeeves.Attr.FORMAT); - if (format != null) - formats.put(name, format); - } - return formats; - } - - /** - * This method is taken from the old Dbms class to allow reading as Element like a lot of xsl - * require. This is to ease the migration to all JPA database access. - */ - public static Element select(ServiceContext context, String query) - throws SQLException { - return selectFull(context, query, Collections.emptyMap()); - } - - /** - * This method is taken from the old Dbms class to allow reading as Element like a lot of xsl - * require. This is to ease the migration to all JPA database access. - */ - public static Element selectFull(ServiceContext context, String query, Map formats, Object... args) - throws SQLException { - - DataSource datasource = context.getBean(DataSource.class); - - Connection conn = null; - PreparedStatement stmt = null; - ResultSet resultSet = null; - - try { - conn = datasource.getConnection(); - stmt = conn.prepareStatement(query); - if (args != null) { - for (int i = 0; i < args.length; i++) { - setObject(stmt, i, args[i]); - } - } - resultSet = stmt.executeQuery(); - - Element result = buildResponse(resultSet, formats); - - return result; - } finally { - try { - if (resultSet != null) { - resultSet.close(); - } - } finally { - try { - if (stmt != null) { - stmt.close(); - } - } finally { - if (conn != null) { - conn.close(); - } - } - } - } - } - - private static void setObject(PreparedStatement stmt, int i, Object obj) throws SQLException { - if (obj instanceof String) { - String s = (String) obj; - - if (s.length() < 4000) - stmt.setString(i + 1, s); - else - stmt.setCharacterStream(i + 1, new StringReader(s), s.length()); - } else - stmt.setObject(i + 1, obj); - } - - private static Element buildResponse(ResultSet rs, Map formats) throws SQLException { - ResultSetMetaData md = rs.getMetaData(); - - int colNum = md.getColumnCount(); - - // --- retrieve name and type of fields - - Vector vHeaders = new Vector(); - Vector vTypes = new Vector(); - - for (int i = 0; i < colNum; i++) { - vHeaders.add(md.getColumnLabel(i + 1).toLowerCase()); - vTypes.add(Integer.valueOf(md.getColumnType(i + 1))); - } - - // --- build the jdom tree - - Element root = new Element(Jeeves.Elem.RESPONSE); - - while (rs.next()) { - Element record = new Element(Jeeves.Elem.RECORD); - - for (int i = 0; i < colNum; i++) { - String name = vHeaders.get(i).toString(); - int type = ((Integer) vTypes.get(i)).intValue(); - record.addContent(buildElement(rs, i, name, type, formats)); - } - root.addContent(record); - } - return root; - } - - private static Element buildElement(ResultSet rs, int col, String name, int type, Map formats) throws SQLException { - String value = null; - - switch (type) { - case Types.DATE: - Date date = rs.getDate(col + 1); - if (date == null) value = null; - else { - String format = formats.get(name); - SimpleDateFormat df = (format == null) ? new SimpleDateFormat(DEFAULT_DATE_FORMAT) : new SimpleDateFormat(format); - value = df.format(date); - } - break; - - case Types.TIME: - Time time = rs.getTime(col + 1); - if (time == null) value = null; - else { - String format = formats.get(name); - SimpleDateFormat df = (format == null) ? new SimpleDateFormat(DEFAULT_TIME_FORMAT) : new SimpleDateFormat(format); - value = df.format(time); - } - break; - - case Types.TIMESTAMP: - Timestamp timestamp = rs.getTimestamp(col + 1); - if (timestamp == null) value = null; - else { - String format = formats.get(name); - SimpleDateFormat df = (format == null) ? new SimpleDateFormat(DEFAULT_TIMESTAMP_FORMAT) : new SimpleDateFormat(format); - value = df.format(timestamp); - } - break; - - case Types.TINYINT: - case Types.SMALLINT: - case Types.INTEGER: - case Types.BIGINT: - long l = rs.getLong(col + 1); - if (rs.wasNull()) value = null; - else { - String format = formats.get(name); - if (format == null) value = l + ""; - else { - DecimalFormat df = new DecimalFormat(format); - value = df.format(l); - } - } - break; - - case Types.DECIMAL: - case Types.FLOAT: - case Types.DOUBLE: - case Types.REAL: - case Types.NUMERIC: - double n = rs.getDouble(col + 1); - - if (rs.wasNull()) - value = null; - else { - String format = formats.get(name); - - if (format == null) { - value = n + ""; - - //--- this fix is mandatory for oracle - //--- that shit returns integers like xxx.0 - - if (value.endsWith(".0")) - value = value.substring(0, value.length() - 2); - } else { - DecimalFormat df = new DecimalFormat(format); - value = df.format(n); - } - } - break; - - default: - value = rs.getString(col + 1); - if (value != null) { - value = stripIllegalChars(value); - } - - break; - } - return new Element(name).setText(value); - } - - private static String stripIllegalChars(String input) { - String output = input; - for (int i = 127; i < 160; i++) { - String c = String.valueOf((char) i); - if (output.contains(c)) { - output = output.replaceAll(c, ""); - } - } - - return output; - } - - public void init(Path appPath, ServiceConfig params) throws Exception { - query = params.getMandatoryValue(Jeeves.Config.QUERY); - List inList = params.getChildren(Jeeves.Config.IN_FIELDS, Jeeves.Config.FIELD); - - inFields = new Vector(); - if (inList != null) { - for (Element field : inList) { - inFields.add(field); - } - } - - List outList = params.getChildren(Jeeves.Config.OUT_FIELDS, Jeeves.Config.FIELD); - outFields = new Vector(); - if (outList != null) { - for (Element field : outList) { - outFields.add(field); - } - } - } - - public Element exec(Element params, ServiceContext context) throws Exception { - Vector vArgs = scanInFields(params, inFields, null, context); - Hashtable formats = scanOutFields(outFields); - return selectFull(context, query, formats, vArgs.toArray()); - } -} - -//============================================================================= - diff --git a/core/src/main/java/jeeves/services/http/Get.java b/core/src/main/java/jeeves/services/http/Get.java deleted file mode 100644 index c33fe4f87af..00000000000 --- a/core/src/main/java/jeeves/services/http/Get.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2001-2016 Food and Agriculture Organization of the - * United Nations (FAO-UN), United Nations World Food Programme (WFP) - * and United Nations Environment Programme (UNEP) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * - * Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, - * Rome - Italy. email: geonetwork@osgeo.org - */ - -//============================================================================= - -package jeeves.services.http; - -import jeeves.interfaces.Service; -import jeeves.server.ServiceConfig; -import jeeves.server.context.ServiceContext; - -import org.fao.geonet.Constants; -import org.fao.geonet.utils.Xml; -import org.jdom.Element; - -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLEncoder; -import java.nio.file.Path; -import java.util.List; - -//============================================================================= - -/** - * Returns a specific record given its id - */ - -public class Get implements Service { - public static final String URL_PARAM_NAME = "url"; - - private String configUrl; - - //-------------------------------------------------------------------------- - //--- - //--- Init - //--- - //-------------------------------------------------------------------------- - - public void init(Path appPath, ServiceConfig params) throws Exception { - configUrl = params.getValue(URL_PARAM_NAME); - } - - //-------------------------------------------------------------------------- - //--- - //--- Service - //--- - //-------------------------------------------------------------------------- - - @SuppressWarnings("unchecked") - public Element exec(Element params, ServiceContext context) throws Exception { - // read url - String sUrl = params.getChildText(URL_PARAM_NAME); - if (sUrl == null) sUrl = configUrl; - if (sUrl == null) - throw new IllegalArgumentException("The '" + URL_PARAM_NAME + "' configuration parameter is missing"); - - // add other parameters to HTTP request - boolean first = new URL(sUrl).getQuery() == null; - StringBuffer sb = new StringBuffer(sUrl); - for (Element child : (List) params.getChildren()) { - // skip the url parameter - if (child.getName().equals(URL_PARAM_NAME)) continue; - - if (first) { - first = false; - sb.append('?'); - } else { - sb.append('&'); - } - sb.append(child.getName()).append('=').append(URLEncoder.encode(child.getText(), Constants.ENCODING)); - } - URL url = new URL(sb.toString()); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - InputStream input = conn.getInputStream(); - - return Xml.loadStream(input); - - /* FIXME: use this instead of previous line to dump HTTP response body - ByteArrayOutputStream output = new ByteArrayOutputStream(); - byte buffer[] = new byte[BUFSIZE]; - for (int nRead; (nRead = input.read(buffer, 0, BUFSIZE)) > 0; ) - output.write(buffer, 0, nRead); - output.close(); - conn.disconnect(); - String sResult = output.toString(); - System.out.println("HTTP response body:\n" + sResult); - Element result = Xml.loadString(sResult, false); // do not validate - return result; - */ - } -} - diff --git a/core/src/main/java/jeeves/services/session/Put.java b/core/src/main/java/jeeves/services/session/Put.java deleted file mode 100644 index 5f82970b320..00000000000 --- a/core/src/main/java/jeeves/services/session/Put.java +++ /dev/null @@ -1,92 +0,0 @@ -//============================================================================= -//=== Copyright (C) 2001-2005 Food and Agriculture Organization of the -//=== United Nations (FAO-UN), United Nations World Food Programme (WFP) -//=== and United Nations Environment Programme (UNEP) -//=== -//=== This library is free software; you can redistribute it and/or -//=== modify it under the terms of the GNU Lesser General Public -//=== License as published by the Free Software Foundation; either -//=== version 2.1 of the License, or (at your option) any later version. -//=== -//=== This library is distributed in the hope that it will be useful, -//=== but WITHOUT ANY WARRANTY; without even the implied warranty of -//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -//=== Lesser General Public License for more details. -//=== -//=== You should have received a copy of the GNU Lesser General Public -//=== License along with this library; if not, write to the Free Software -//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -//=== -//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, -//=== Rome - Italy. email: geonetwork@osgeo.org -//============================================================================== - -package jeeves.services.session; - -import jeeves.constants.Jeeves; -import jeeves.interfaces.Service; -import jeeves.server.ServiceConfig; -import jeeves.server.UserSession; -import jeeves.server.context.ServiceContext; - -import org.jdom.Element; - -import java.nio.file.Path; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.List; - -//============================================================================= - -/** - * Stores input fields in the session - */ - -public class Put implements Service { - String groupName; - HashSet inFields; - - //-------------------------------------------------------------------------- - //--- - //--- Init - //--- - //-------------------------------------------------------------------------- - - public void init(Path appPath, ServiceConfig params) throws Exception { - groupName = params.getMandatoryValue(Jeeves.Config.GROUP); - List l = params.getChildren(Jeeves.Config.IN_FIELDS, Jeeves.Config.FIELD); - if (l != null) { - inFields = new HashSet(); - for (Element field : l) { - inFields.add(field.getName()); - } - } - } - - //-------------------------------------------------------------------------- - //--- - //--- Service - //--- - //-------------------------------------------------------------------------- - - @SuppressWarnings("unchecked") - public Element exec(Element params, ServiceContext context) throws Exception { - UserSession session = context.getUserSession(); - - Hashtable group = (Hashtable) session.getProperty(groupName); - if (group == null) { - group = new Hashtable(); - } - for (Element child : (List) params.getChildren()) { - if (inFields == null || inFields.contains(child.getName())) { - group.put(child.getName(), child); - } - } - session.setProperty(groupName, group); - - return params; - } -} - -//============================================================================= - diff --git a/core/src/main/java/org/fao/geonet/analytics/WebAnalyticsConfiguration.java b/core/src/main/java/org/fao/geonet/analytics/WebAnalyticsConfiguration.java new file mode 100644 index 00000000000..d9c2799076e --- /dev/null +++ b/core/src/main/java/org/fao/geonet/analytics/WebAnalyticsConfiguration.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2001-2023 Food and Agriculture Organization of the + * United Nations (FAO-UN), United Nations World Food Programme (WFP) + * and United Nations Environment Programme (UNEP) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, + * Rome - Italy. email: geonetwork@osgeo.org + */ + +package org.fao.geonet.analytics; + +public class WebAnalyticsConfiguration { + private String service; + private String javascriptCode; + + public String getService() { + return service; + } + + public void setService(String service) { + this.service = service; + } + + public String getJavascriptCode() { + return javascriptCode; + } + + public void setJavascriptCode(String javascriptCode) { + this.javascriptCode = javascriptCode; + } +} diff --git a/core/src/main/java/org/fao/geonet/api/records/attachments/AbstractStore.java b/core/src/main/java/org/fao/geonet/api/records/attachments/AbstractStore.java index dfcd55a1b51..168e4e2a63c 100644 --- a/core/src/main/java/org/fao/geonet/api/records/attachments/AbstractStore.java +++ b/core/src/main/java/org/fao/geonet/api/records/attachments/AbstractStore.java @@ -1,6 +1,6 @@ /* * ============================================================================= - * === Copyright (C) 2019 Food and Agriculture Organization of the + * === Copyright (C) 2024 Food and Agriculture Organization of the * === United Nations (FAO-UN), United Nations World Food Programme (WFP) * === and United Nations Environment Programme (UNEP) * === @@ -44,12 +44,16 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Base64; import java.util.List; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; public abstract class AbstractStore implements Store { + protected static final String RESOURCE_MANAGEMENT_EXTERNAL_PROPERTIES_SEPARATOR = ":"; + protected static final String RESOURCE_MANAGEMENT_EXTERNAL_PROPERTIES_ESCAPED_SEPARATOR = "\\:"; + @Override public final List getResources(final ServiceContext context, final String metadataUuid, final Sort sort, final String filter) throws Exception { @@ -97,7 +101,7 @@ public final ResourceHolder getResource(ServiceContext context, String metadataU } protected static AccessManager getAccessManager(final ServiceContext context) { - return context.getBean(AccessManager.class); + return ApplicationContextHolder.get().getBean(AccessManager.class); } public static int getAndCheckMetadataId(String metadataUuid, Boolean approved) throws Exception { @@ -202,6 +206,12 @@ public String delResources(final ServiceContext context, final String metadataUu return delResources(context, metadataUuid, true); } + @Override + public String delResources(final ServiceContext context, final String metadataUuid, Boolean approved) throws Exception { + int metadataId = canEdit(context, metadataUuid, approved); + return delResources(context, metadataId); + } + @Override public String delResource(final ServiceContext context, final String metadataUuid, final String resourceId) throws Exception { return delResource(context, metadataUuid, resourceId, true); @@ -273,4 +283,28 @@ public String toString() { } }; } + + private String escapeResourceManagementExternalProperties(String value) { + return value.replace(RESOURCE_MANAGEMENT_EXTERNAL_PROPERTIES_SEPARATOR, RESOURCE_MANAGEMENT_EXTERNAL_PROPERTIES_ESCAPED_SEPARATOR); +} + + /** + * Create an encoded base 64 object id contains the following fields to uniquely identify the resource + * The fields are separated by a colon ":" + * @param type to identify type of storage - document/folder + * @param visibility of the resource public/private + * @param metadataId internal metadata id + * @param version identifier which can be used to directly get this version. + * @param resourceId or filename of the resource + * @return based 64 object id + */ + protected String getResourceManagementExternalPropertiesObjectId(final String type, final MetadataResourceVisibility visibility, final Integer metadataId, final String version, + final String resourceId) { + return Base64.getEncoder().encodeToString( + ((type + RESOURCE_MANAGEMENT_EXTERNAL_PROPERTIES_SEPARATOR + + escapeResourceManagementExternalProperties(visibility == null ? "" : visibility.toString().toLowerCase()) + RESOURCE_MANAGEMENT_EXTERNAL_PROPERTIES_SEPARATOR + + metadataId + RESOURCE_MANAGEMENT_EXTERNAL_PROPERTIES_SEPARATOR + + escapeResourceManagementExternalProperties(version == null ? "" : version) + RESOURCE_MANAGEMENT_EXTERNAL_PROPERTIES_SEPARATOR + + escapeResourceManagementExternalProperties(resourceId)).getBytes())); + } } diff --git a/core/src/main/java/org/fao/geonet/api/records/attachments/FilesystemStore.java b/core/src/main/java/org/fao/geonet/api/records/attachments/FilesystemStore.java index 4f2c16ec739..469bfc296ea 100644 --- a/core/src/main/java/org/fao/geonet/api/records/attachments/FilesystemStore.java +++ b/core/src/main/java/org/fao/geonet/api/records/attachments/FilesystemStore.java @@ -229,25 +229,31 @@ private Path getPath(ServiceContext context, int metadataId, MetadataResourceVis } @Override - public String delResources(ServiceContext context, String metadataUuid, Boolean approved) throws Exception { - int metadataId = canEdit(context, metadataUuid, approved); + public String delResources(ServiceContext context, int metadataId) throws Exception { Path metadataDir = Lib.resource.getMetadataDir(getDataDirectory(context), metadataId); try { + Log.info(Geonet.RESOURCES, String.format("Deleting all files from metadataId '%d'", metadataId)); IO.deleteFileOrDirectory(metadataDir, true); - return String.format("Metadata '%s' directory removed.", metadataId); + Log.info(Geonet.RESOURCES, + String.format("Metadata '%d' directory removed.", metadataId)); + return String.format("Metadata '%d' directory removed.", metadataId); } catch (Exception e) { - return String.format("Unable to remove metadata '%s' directory.", metadataId); + return String.format("Unable to remove metadata '%d' directory.", metadataId); } } @Override public String delResource(ServiceContext context, String metadataUuid, String resourceId, Boolean approved) throws Exception { - canEdit(context, metadataUuid, approved); + int metadataId = canEdit(context, metadataUuid, approved); try (ResourceHolder filePath = getResource(context, metadataUuid, resourceId, approved)) { Files.deleteIfExists(filePath.getPath()); - return String.format("MetadataResource '%s' removed.", resourceId); + Log.info(Geonet.RESOURCES, + String.format("Resource '%s' removed for metadata %d (%s).", resourceId, metadataId, metadataUuid)); + return String.format("Metadata resource '%s' removed.", resourceId); } catch (IOException e) { + Log.warning(Geonet.RESOURCES, + String.format("Unable to remove resource '%s' for metadata %d (%s). %s", resourceId, metadataId, metadataUuid, e.getMessage())); return String.format("Unable to remove resource '%s'.", resourceId); } } @@ -255,12 +261,16 @@ public String delResource(ServiceContext context, String metadataUuid, String re @Override public String delResource(final ServiceContext context, final String metadataUuid, final MetadataResourceVisibility visibility, final String resourceId, Boolean approved) throws Exception { - canEdit(context, metadataUuid, approved); + int metadataId = canEdit(context, metadataUuid, approved); try (ResourceHolder filePath = getResource(context, metadataUuid, visibility, resourceId, approved)) { Files.deleteIfExists(filePath.getPath()); - return String.format("MetadataResource '%s' removed.", resourceId); + Log.info(Geonet.RESOURCES, + String.format("Resource '%s' removed for metadata %d (%s).", resourceId, metadataId, metadataUuid)); + return String.format("Metadata resource '%s' removed.", resourceId); } catch (IOException e) { + Log.warning(Geonet.RESOURCES, + String.format("Unable to remove resource '%s' for metadata %d (%s). %s", resourceId, metadataId, metadataUuid, e.getMessage())); return String.format("Unable to remove resource '%s'.", resourceId); } } diff --git a/core/src/main/java/org/fao/geonet/api/records/attachments/JCloudStore.java b/core/src/main/java/org/fao/geonet/api/records/attachments/JCloudStore.java deleted file mode 100644 index d7ed09b1837..00000000000 --- a/core/src/main/java/org/fao/geonet/api/records/attachments/JCloudStore.java +++ /dev/null @@ -1,550 +0,0 @@ -/* - * ============================================================================= - * === Copyright (C) 2001-2016 Food and Agriculture Organization of the - * === United Nations (FAO-UN), United Nations World Food Programme (WFP) - * === and United Nations Environment Programme (UNEP) - * === - * === This program is free software; you can redistribute it and/or modify - * === it under the terms of the GNU General Public License as published by - * === the Free Software Foundation; either version 2 of the License, or (at - * === your option) any later version. - * === - * === This program is distributed in the hope that it will be useful, but - * === WITHOUT ANY WARRANTY; without even the implied warranty of - * === MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * === General Public License for more details. - * === - * === You should have received a copy of the GNU General Public License - * === along with this program; if not, write to the Free Software - * === Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * === - * === Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, - * === Rome - Italy. email: geonetwork@osgeo.org - * ============================================================================== - */ -package org.fao.geonet.api.records.attachments; - - -import static org.jclouds.blobstore.options.PutOptions.Builder.multipart; - -import jeeves.server.context.ServiceContext; - -import org.apache.commons.lang.StringUtils; -import org.fao.geonet.api.exception.ResourceNotFoundException; -import org.fao.geonet.constants.Geonet; -import org.fao.geonet.domain.MetadataResource; -import org.fao.geonet.domain.MetadataResourceContainer; -import org.fao.geonet.domain.MetadataResourceExternalManagementProperties; -import org.fao.geonet.domain.MetadataResourceVisibility; -import org.fao.geonet.kernel.GeonetworkDataDirectory; -import org.fao.geonet.kernel.setting.SettingManager; -import org.fao.geonet.languages.IsoLanguagesMapper; -import org.fao.geonet.lib.Lib; -import org.fao.geonet.resources.JCloudConfiguration; -import org.fao.geonet.utils.IO; -import org.fao.geonet.utils.Log; -import org.jclouds.blobstore.ContainerNotFoundException; -import org.jclouds.blobstore.domain.*; -import org.jclouds.blobstore.options.CopyOptions; -import org.jclouds.blobstore.options.ListContainerOptions; -import org.springframework.beans.factory.annotation.Autowired; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.PathMatcher; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import javax.annotation.Nullable; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; - -public class JCloudStore extends AbstractStore { - - private Path baseMetadataDir = null; - - @Autowired - JCloudConfiguration jCloudConfiguration; - - @Autowired - SettingManager settingManager; - - @Override - public List getResources(final ServiceContext context, final String metadataUuid, - final MetadataResourceVisibility visibility, String filter, Boolean approved) throws Exception { - final int metadataId = canDownload(context, metadataUuid, visibility, approved); - - final String resourceTypeDir = getMetadataDir(context, metadataId) + jCloudConfiguration.getFolderDelimiter() + visibility.toString() + jCloudConfiguration.getFolderDelimiter(); - - List resourceList = new ArrayList<>(); - if (filter == null) { - filter = FilesystemStore.DEFAULT_FILTER; - } - - PathMatcher matcher = - FileSystems.getDefault().getPathMatcher("glob:" + filter); - - ListContainerOptions opts = new ListContainerOptions(); - opts.delimiter(jCloudConfiguration.getFolderDelimiter()).prefix(resourceTypeDir);; - - // Page through the data - String marker = null; - do { - if (marker != null) { - opts.afterMarker(marker); - } - - PageSet page = jCloudConfiguration.getClient().getBlobStore().list(jCloudConfiguration.getContainerName(), opts); - - for (StorageMetadata storageMetadata : page) { - // Only add to the list if it is a blob and it matches the filter. - Path keyPath = new File(storageMetadata.getName()).toPath().getFileName(); - if (storageMetadata.getType() == StorageType.BLOB && matcher.matches(keyPath)){ - final String filename = getFilename(storageMetadata.getName()); - MetadataResource resource = createResourceDescription(context, metadataUuid, visibility, filename, storageMetadata, metadataId, approved); - resourceList.add(resource); - } - } - marker = page.getNextMarker(); - } while (marker != null); - - - resourceList.sort(MetadataResourceVisibility.sortByFileName); - - return resourceList; - } - - private MetadataResource createResourceDescription(final ServiceContext context, final String metadataUuid, - final MetadataResourceVisibility visibility, final String resourceId, - StorageMetadata storageMetadata, int metadataId, boolean approved) { - String filename = getFilename(metadataUuid, resourceId); - - String versionValue = null; - if (jCloudConfiguration.isVersioningEnabled()) { - versionValue = storageMetadata.getETag(); - } - - MetadataResourceExternalManagementProperties metadataResourceExternalManagementProperties = - getMetadataResourceExternalManagementProperties(context, metadataId, metadataUuid, visibility, resourceId, filename, storageMetadata.getETag(), storageMetadata.getType()); - - return new FilesystemStoreResource(metadataUuid, metadataId, filename, - settingManager.getNodeURL() + "api/records/", visibility, storageMetadata.getSize(), storageMetadata.getLastModified(), versionValue, metadataResourceExternalManagementProperties, approved); - } - - private static String getFilename(final String key) { - final String[] splittedKey = key.split("/"); - return splittedKey[splittedKey.length - 1]; - } - - @Override - public ResourceHolder getResource(final ServiceContext context, final String metadataUuid, final MetadataResourceVisibility visibility, - final String resourceId, Boolean approved) throws Exception { - // Those characters should not be allowed by URL structure - int metadataId = canDownload(context, metadataUuid, visibility, approved); - try { - final Blob object = jCloudConfiguration.getClient().getBlobStore().getBlob( - jCloudConfiguration.getContainerName(), getKey(context, metadataUuid, metadataId, visibility, resourceId)); - return new ResourceHolderImpl(object, createResourceDescription(context, metadataUuid, visibility, resourceId, - object.getMetadata(), metadataId, approved)); - } catch (ContainerNotFoundException e) { - throw new ResourceNotFoundException( - String.format("Metadata resource '%s' not found for metadata '%s'", resourceId, metadataUuid)) - .withMessageKey("exception.resourceNotFound.resource", new String[]{resourceId}) - .withDescriptionKey("exception.resourceNotFound.resource.description", new String[]{resourceId, metadataUuid}); - } - } - - @Override - public ResourceHolder getResourceInternal(String metadataUuid, MetadataResourceVisibility visibility, String resourceId, Boolean approved) throws Exception { - throw new UnsupportedOperationException("JCloud does not support getResourceInternal."); - } - - private String getKey(final ServiceContext context, String metadataUuid, int metadataId, MetadataResourceVisibility visibility, String resourceId) { - checkResourceId(resourceId); - final String metadataDir = getMetadataDir(context, metadataId); - return metadataDir + jCloudConfiguration.getFolderDelimiter() + visibility.toString() + jCloudConfiguration.getFolderDelimiter() + getFilename(metadataUuid, resourceId); - } - - @Override - public MetadataResource putResource(final ServiceContext context, final String metadataUuid, final String filename, - final InputStream is, @Nullable final Date changeDate, final MetadataResourceVisibility visibility, Boolean approved) - throws Exception { - final int metadataId = canEdit(context, metadataUuid, approved); - String key = getKey(context, metadataUuid, metadataId, visibility, filename); - - // Todo - jcloud does not seem to allow setting the last modified date. May need to investigate to see if there are other options. - //if (changeDate != null) { - // metadata.setLastModified(changeDate); - - Blob blob = jCloudConfiguration.getClient().getBlobStore().blobBuilder(key) - .payload(is) - .contentLength(is.available()) - .build(); - // Upload the Blob in multiple chunks to supports large files. - jCloudConfiguration.getClient().getBlobStore().putBlob(jCloudConfiguration.getContainerName(), blob, multipart()); - Blob blobResults = jCloudConfiguration.getClient().getBlobStore().getBlob(jCloudConfiguration.getContainerName(), key); - - return createResourceDescription(context, metadataUuid, visibility, filename, blobResults.getMetadata(), metadataId, approved); - - } - - @Override - public MetadataResource patchResourceStatus(final ServiceContext context, final String metadataUuid, final String resourceId, - final MetadataResourceVisibility visibility, Boolean approved) throws Exception { - int metadataId = canEdit(context, metadataUuid, approved); - - String sourceKey = null; - StorageMetadata storageMetadata = null; - for (MetadataResourceVisibility sourceVisibility : MetadataResourceVisibility.values()) { - final String key = getKey(context, metadataUuid, metadataId, sourceVisibility, resourceId); - try { - storageMetadata = jCloudConfiguration.getClient().getBlobStore().blobMetadata(jCloudConfiguration.getContainerName(), key); - if (storageMetadata != null) { - if (sourceVisibility != visibility) { - sourceKey = key; - break; - } else { - // already the good visibility - return createResourceDescription(context, metadataUuid, visibility, resourceId, storageMetadata, metadataId, approved); - } - } - } catch (ContainerNotFoundException ignored) { - // ignored - } - } - if (sourceKey != null) { - final String destKey = getKey(context, metadataUuid, metadataId, visibility, resourceId); - - jCloudConfiguration.getClient().getBlobStore().copyBlob(jCloudConfiguration.getContainerName(), sourceKey, jCloudConfiguration.getContainerName(), destKey, CopyOptions.NONE); - jCloudConfiguration.getClient().getBlobStore().removeBlob(jCloudConfiguration.getContainerName(), sourceKey); - - Blob blobResults = jCloudConfiguration.getClient().getBlobStore().getBlob(jCloudConfiguration.getContainerName(), destKey); - - return createResourceDescription(context, metadataUuid, visibility, resourceId, blobResults.getMetadata(), metadataId, approved); - } else { - Log.warning(Geonet.RESOURCES, - String.format("Could not update permissions. Metadata resource '%s' not found for metadata '%s'", resourceId, metadataUuid)); - throw new ResourceNotFoundException( - String.format("Could not update permissions. Metadata resource '%s' not found for metadata '%s'", resourceId, metadataUuid)); - } - } - - @Override - public String delResources(final ServiceContext context, final String metadataUuid, Boolean approved) throws Exception { - int metadataId = canEdit(context, metadataUuid, approved); - try { - ListContainerOptions opts = new ListContainerOptions(); - opts.prefix(getMetadataDir(context, metadataId) + jCloudConfiguration.getFolderDelimiter()).recursive(); - - // Page through the data - String marker = null; - do { - if (marker != null) { - opts.afterMarker(marker); - } - - PageSet page = jCloudConfiguration.getClient().getBlobStore().list(jCloudConfiguration.getContainerName(), opts); - - for (StorageMetadata storageMetadata : page) { - if (storageMetadata.getType() == StorageType.BLOB) { - jCloudConfiguration.getClient().getBlobStore().removeBlob(jCloudConfiguration.getContainerName(), storageMetadata.getName()); - } - } - marker = page.getNextMarker(); - } while (marker != null); - return String.format("Metadata '%s' directory removed.", metadataId); - } catch (ContainerNotFoundException e) { - Log.warning(Geonet.RESOURCES, - String.format("Unable to located metadata '%s' directory to be removed.", metadataId)); - return String.format("Unable to located metadata '%s' directory to be removed.", metadataId); - } - } - - @Override - public String delResource(final ServiceContext context, final String metadataUuid, final String resourceId, Boolean approved) - throws Exception { - int metadataId = canEdit(context, metadataUuid, approved); - - for (MetadataResourceVisibility visibility : MetadataResourceVisibility.values()) { - if (tryDelResource(context, metadataUuid, metadataId, visibility, resourceId)) { - return String.format("MetadataResource '%s' removed.", resourceId); - } - } - return String.format("Unable to remove resource '%s'.", resourceId); - } - - @Override - public String delResource(final ServiceContext context, final String metadataUuid, final MetadataResourceVisibility visibility, - final String resourceId, Boolean approved) throws Exception { - int metadataId = canEdit(context, metadataUuid, approved); - if (tryDelResource(context, metadataUuid, metadataId, visibility, resourceId)) { - return String.format("MetadataResource '%s' removed.", resourceId); - } - return String.format("Unable to remove resource '%s'.", resourceId); - } - - private boolean tryDelResource(final ServiceContext context, final String metadataUuid, final int metadataId, final MetadataResourceVisibility visibility, - final String resourceId) throws Exception { - final String key = getKey(context, metadataUuid, metadataId, visibility, resourceId); - - if (jCloudConfiguration.getClient().getBlobStore().blobExists(jCloudConfiguration.getContainerName(), key)) { - jCloudConfiguration.getClient().getBlobStore().removeBlob(jCloudConfiguration.getContainerName(), key); - return true; - } - return false; - } - - @Override - public MetadataResource getResourceDescription(final ServiceContext context, final String metadataUuid, - final MetadataResourceVisibility visibility, final String filename, Boolean approved) throws Exception { - int metadataId = getAndCheckMetadataId(metadataUuid, approved); - final String key = getKey(context, metadataUuid, metadataId, visibility, filename); - try { - final Blob object = jCloudConfiguration.getClient().getBlobStore().getBlob(jCloudConfiguration.getContainerName(), key); - if (object == null) { - return null; - } else { - final StorageMetadata metadata = object.getMetadata(); - return createResourceDescription(context, metadataUuid, visibility, filename, metadata, metadataId, approved); - } - } catch (ContainerNotFoundException e) { - return null; - } - } - - @Override - public MetadataResourceContainer getResourceContainerDescription(ServiceContext context, String metadataUuid, Boolean approved) throws Exception { - - int metadataId = getAndCheckMetadataId(metadataUuid, approved); - - return new FilesystemStoreResourceContainer(metadataUuid, metadataId, metadataUuid, settingManager.getNodeURL() + "api/records/", approved); - } - - private String getMetadataDir(ServiceContext context, final int metadataId) { - - Path metadataFullDir = Lib.resource.getMetadataDir(getDataDirectory(context), metadataId); - Path baseMetadataDir = getBaseMetadataDir(context, metadataFullDir); - Path metadataDir; - if (baseMetadataDir.toString().equals(".")) { - metadataDir = Paths.get(jCloudConfiguration.getBaseFolder()).resolve(metadataFullDir); - } else { - metadataDir = Paths.get(jCloudConfiguration.getBaseFolder()).resolve(baseMetadataDir.relativize(metadataFullDir)); - } - - String key; - // For windows it may be "\" in which case we need to change it to folderDelimiter which is normally "/" - if (metadataDir.getFileSystem().getSeparator().equals(jCloudConfiguration.getFolderDelimiter())) { - key = metadataDir.toString(); - } else { - key = metadataDir.toString().replace(metadataDir.getFileSystem().getSeparator(), jCloudConfiguration.getFolderDelimiter()); - } - - // For Windows, the pathString may start with // so remove one if this is the case. - if (key.startsWith("//")) { - key = key.substring(1); - } - - // Make sure the key that is returns does not starts with "/" as it is already assumed to be relative to the container. - if (key.startsWith(jCloudConfiguration.getFolderDelimiter())) { - return key.substring(1); - } else { - return key; - } - } - - private Path getBaseMetadataDir(ServiceContext context, Path metadataFullDir) { - //If we not already figured out the base metadata dir then lets figure it out. - if (baseMetadataDir == null) { - Path systemFullDir = getDataDirectory(context).getSystemDataDir(); - - // If the metadata full dir is relative from the system dir then use system dir as the base dir. - if (metadataFullDir.toString().startsWith(systemFullDir.toString())) { - baseMetadataDir = systemFullDir; - } else { - // If the metadata full dir is an absolute folder then use that as the base dir. - if (getDataDirectory(context).getMetadataDataDir().isAbsolute()) { - baseMetadataDir = metadataFullDir.getRoot(); - } else { - // use it as a relative url. - baseMetadataDir = Paths.get("."); - } - } - } - return baseMetadataDir; - } - - private GeonetworkDataDirectory getDataDirectory(ServiceContext context) { - return context.getBean(GeonetworkDataDirectory.class); - } - - /** - * get external resource management for the supplied resource. - * Replace the following - * {id} resource id - * {type:folder:document} // If the type is folder then type "folder" will be displayed else if document then "document" will be displayed - * {uuid} metadatauuid - * {metadataid} metadataid - * {visibility} visibility - * {filename} filename - * {version} version - * {lang} ISO639-1 2 char language - * {iso3lang} ISO 639-2/T language - *

- * Sample url for custom app - * http://localhost:8080/artifact?filename={filename}&version={version}&lang={lang} - */ - - private MetadataResourceExternalManagementProperties getMetadataResourceExternalManagementProperties(ServiceContext context, - int metadataId, - final String metadataUuid, - final MetadataResourceVisibility visibility, - final String resourceId, - String filename, - String version, - StorageType type - ) { - String metadataResourceExternalManagementPropertiesUrl = jCloudConfiguration.getExternalResourceManagementUrl(); - if (!StringUtils.isEmpty(metadataResourceExternalManagementPropertiesUrl)) { - // {id} id - if (metadataResourceExternalManagementPropertiesUrl.contains("{id}")) { - metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("(\\{id\\})", resourceId); - } - // {type:folder:document} // If the type is folder then type "folder" will be displayed else if document then "document" will be displayed - if (metadataResourceExternalManagementPropertiesUrl.contains("{type:")) { - metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("\\{type:([a-zA-Z0-9]*?):([a-zA-Z0-9]*?)\\}", - (type==null?"":(StorageType.FOLDER.equals(type)?"$1":"$2"))); - } - - // {uuid} metadatauuid - if (metadataResourceExternalManagementPropertiesUrl.contains("{uuid}")) { - metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("(\\{uuid\\})", (metadataUuid==null?"":metadataUuid)); - } - // {metadataid} metadataid - if (metadataResourceExternalManagementPropertiesUrl.contains("{metadataid}")) { - metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("(\\{metadataid\\})", String.valueOf(metadataId)); - } - // {visibility} visibility - if (metadataResourceExternalManagementPropertiesUrl.contains("{visibility}")) { - metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("(\\{visibility\\})", (visibility==null?"":visibility.toString().toLowerCase())); - } - // {filename} filename - if (metadataResourceExternalManagementPropertiesUrl.contains("{filename}")) { - metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("(\\{filename\\})", (filename==null?"":filename)); - } - // {version} version - if (metadataResourceExternalManagementPropertiesUrl.contains("{version}")) { - metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("(\\{version\\})", (version==null?"":version)); - } - - if (metadataResourceExternalManagementPropertiesUrl.contains("{lang}") || metadataResourceExternalManagementPropertiesUrl.contains("{ISO3lang}")) { - final IsoLanguagesMapper mapper = context.getBean(IsoLanguagesMapper.class); - String contextLang = context.getLanguage() == null ? Geonet.DEFAULT_LANGUAGE : context.getLanguage(); - String lang; - String iso3Lang; - - if (contextLang.length() == 2) { - lang = contextLang; - iso3Lang = mapper.iso639_1_to_iso639_2(contextLang); - } else { - lang = mapper.iso639_2_to_iso639_1(contextLang); - iso3Lang = contextLang; - } - // {lang} ISO639-1 2 char language - if (metadataResourceExternalManagementPropertiesUrl.contains("{lang}")) { - metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("(\\{lang\\})", lang); - } - // {iso3lang} ISO 639-2/T language - if (metadataResourceExternalManagementPropertiesUrl.contains("{iso3lang}")) { - metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("(\\{iso3lang\\})", iso3Lang); - } - } - } - - MetadataResourceExternalManagementProperties metadataResourceExternalManagementProperties - = new MetadataResourceExternalManagementProperties(resourceId, metadataResourceExternalManagementPropertiesUrl, MetadataResourceExternalManagementProperties.ValidationStatus.UNKNOWN); - - return metadataResourceExternalManagementProperties; - } - - public ResourceManagementExternalProperties getResourceManagementExternalProperties() { - return new ResourceManagementExternalProperties() { - @Override - public boolean isEnabled() { - // Return true if we have an external management url - return !StringUtils.isEmpty(jCloudConfiguration.getExternalResourceManagementUrl()); - } - - @Override - public String getWindowParameters() { - return jCloudConfiguration.getExternalResourceManagementWindowParameters(); - } - - @Override - public boolean isModal() { - return jCloudConfiguration.isExternalResourceManagementModalEnabled(); - } - - @Override - public boolean isFolderEnabled() { - return isEnabled() && jCloudConfiguration.isExternalResourceManagementFolderEnabled(); - } - - @Override - public String toString() { - try { - return new ObjectMapper().writeValueAsString(this); - } catch (JsonProcessingException e) { - throw new RuntimeException("Error converting ResourceManagementExternalProperties to json", e); - } - } - }; - } - - private static class ResourceHolderImpl implements ResourceHolder { - private Path tempFolderPath; - private Path path; - private final MetadataResource metadataResource; - - public ResourceHolderImpl(final Blob object, MetadataResource metadataResource) throws IOException { - // Preserve filename by putting the files into a temporary folder and using the same filename. - tempFolderPath = Files.createTempDirectory("gn-meta-res-" + String.valueOf(metadataResource.getMetadataId() + "-")); - tempFolderPath.toFile().deleteOnExit(); - path = tempFolderPath.resolve(getFilename(object.getMetadata().getName())); - this.metadataResource = metadataResource; - try (InputStream in = object.getPayload().openStream()) { - Files.copy(in, path, StandardCopyOption.REPLACE_EXISTING); - } - } - - @Override - public Path getPath() { - return path; - } - - @Override - public MetadataResource getMetadata() { - return metadataResource; - } - - @Override - public void close() throws IOException { - // Delete temporary file and folder. - IO.deleteFileOrDirectory(tempFolderPath, true); - path=null; - tempFolderPath = null; - } - - @Override - protected void finalize() throws Throwable { - close(); - super.finalize(); - } - } -} diff --git a/core/src/main/java/org/fao/geonet/api/records/attachments/ResourceLoggerStore.java b/core/src/main/java/org/fao/geonet/api/records/attachments/ResourceLoggerStore.java index 75876ab95ff..14d9e74ce56 100644 --- a/core/src/main/java/org/fao/geonet/api/records/attachments/ResourceLoggerStore.java +++ b/core/src/main/java/org/fao/geonet/api/records/attachments/ResourceLoggerStore.java @@ -125,6 +125,13 @@ public String delResources(ServiceContext context, String metadataUuid, Boolean return null; } + public String delResources(ServiceContext context, int metadataId) throws Exception { + if (decoratedStore != null) { + return decoratedStore.delResources(context, metadataId); + } + return null; + } + @Override public String delResource(ServiceContext context, String metadataUuid, String resourceId, Boolean approved) throws Exception { if (decoratedStore != null) { diff --git a/core/src/main/java/org/fao/geonet/api/records/attachments/Store.java b/core/src/main/java/org/fao/geonet/api/records/attachments/Store.java index 3e6ad03011a..41dc645b0d1 100644 --- a/core/src/main/java/org/fao/geonet/api/records/attachments/Store.java +++ b/core/src/main/java/org/fao/geonet/api/records/attachments/Store.java @@ -278,12 +278,24 @@ MetadataResource putResource(ServiceContext context, String metadataUuid, String /** * Delete all resources for a metadata * + * @deprecated it is possible that the metadata draft was deleted during the transaction. Use + * String delResources(ServiceContext context, int metadataId) throws Exception; instead. + * * @param context * @param metadataUuid The metadata UUID * @param approved Return the approved version or not */ + @Deprecated String delResources(ServiceContext context, String metadataUuid, Boolean approved) throws Exception; + /** + * Delete all resources for a metadata + * + * @param context + * @param metadataId The metadata ID + */ + String delResources(ServiceContext context, int metadataId) throws Exception; + /** * Delete a resource from the metadata store * diff --git a/core/src/main/java/org/fao/geonet/api/standards/StandardsUtils.java b/core/src/main/java/org/fao/geonet/api/standards/StandardsUtils.java index 1866f4e5858..fa238266cee 100644 --- a/core/src/main/java/org/fao/geonet/api/standards/StandardsUtils.java +++ b/core/src/main/java/org/fao/geonet/api/standards/StandardsUtils.java @@ -114,8 +114,25 @@ public static Element getHelp(SchemaManager scm, String fileName, String schema, return result; } + /** + * Loop in the schema entries to find a match. + * + * If requireContextMatch = false, try to find a match a standard default with no context defined. + * + * @param scm + * @param schema + * @param entries + * @param context + * @param name + * @param isoType + * @param displayIf + * @param requireContextMatch + * @return + * @throws OperationAbortedEx + */ private static Element checkEntries(SchemaManager scm, String schema, Element entries, String context, String name, String isoType, String displayIf, boolean requireContextMatch) throws OperationAbortedEx { + Element tentativeElement = null; for (Object o : entries.getChildren()) { Element currElem = (Element) o; @@ -168,13 +185,18 @@ private static Element checkEntries(SchemaManager scm, String schema, Element en return (Element) currElem.clone(); } if (!requireContextMatch && displayIfAttribute == null) { - // Return an element not matching any context attribute - // or displayIf condition. Usually the default value of the standard. - return (Element) currElem.clone(); + if (currContext != null) { + // Keep tentative, in case there is a standard default with no context defined. + tentativeElement = (Element) currElem.clone(); + } else { + // Return an element not matching any context attribute + // or displayIf condition. Usually the default value of the standard. + return (Element) currElem.clone(); + } } } - return null; // no match found + return tentativeElement; } diff --git a/core/src/main/java/org/fao/geonet/api/tools/i18n/TranslationPackBuilder.java b/core/src/main/java/org/fao/geonet/api/tools/i18n/TranslationPackBuilder.java index 3d301ab938d..8f14052ab05 100644 --- a/core/src/main/java/org/fao/geonet/api/tools/i18n/TranslationPackBuilder.java +++ b/core/src/main/java/org/fao/geonet/api/tools/i18n/TranslationPackBuilder.java @@ -136,12 +136,21 @@ public Map getPack( ); } else if (config[0].equals(TranslationType.standards.name()) && config.length == 4) { - // standards/iso19115-3.2018/codelists/cit:CI_DateTypeCode+... String[] codelistKeys = config[3].split(LIST_SEPARATOR); - translations.putAll( - self.getStandardCodelist( - language, config[1], Arrays.asList(codelistKeys), context) - ); + + if ("labels".equals(config[2])) { + // standards/iso19139/labels/gmd:DQ_AbsoluteExternalPositionalAccuracy+gmd + translations.putAll( + self.getStandardLabel( + language, config[1], Arrays.asList(codelistKeys), context) + ); + } else { + // standards/iso19115-3.2018/codelists/cit:CI_DateTypeCode+... + translations.putAll( + self.getStandardCodelist( + language, config[1], Arrays.asList(codelistKeys), context) + ); + } } else { throw new IllegalArgumentException( String.format( @@ -193,6 +202,28 @@ public Map getStandardCodelist( return translations; } + @Cacheable(value = "translations", + cacheManager = "cacheManager", + key = "{#schema, #language, #label}") + public Map getStandardLabel( + String language, String schema, List label, + ServiceContext context) { + Map translations = new HashMap<>(); + context.setLanguage(language); + + for (String c : label) { + Element e = null; + try { + e = StandardsUtils.getLabel(c, schemaManager, + schema, null, null, null, null, context); + translations.put(c.split(":")[1], e.getChildText("label")); + } catch (Exception exception) { + exception.printStackTrace(); + } + } + return translations; + } + @Cacheable(value = "translations", cacheManager = "cacheManager") public Map getDbTranslation(String language, List type) { Map translations = new HashMap<>(); @@ -201,72 +232,59 @@ public Map getDbTranslation(String language, List type) if (type == null || type.contains("StatusValue")) { List valueList = statusValueRepository.findAll(); - Iterator valueIterator = valueList.iterator(); - while (valueIterator.hasNext()) { - StatusValue entity = valueIterator.next(); - translations.put("status-" + entity.getId() + "", - getLabelOrKey(entity, language, entity.getId() + "")); + for (StatusValue entity : valueList) { + String label = getLabelOrKey(entity, language, entity.getId() + ""); + translations.put("status-" + entity.getId(), label); + translations.put("status-" + entity.getName(), label); } } if (type == null || type.contains("MetadataCategory")) { List metadataCategoryList = categoryRepository.findAll(); - Iterator metadataCategoryIterator = metadataCategoryList.iterator(); - while (metadataCategoryIterator.hasNext()) { - MetadataCategory entity = metadataCategoryIterator.next(); - translations.put("cat-" + entity.getName() + "", + for (MetadataCategory entity : metadataCategoryList) { + translations.put("cat-" + entity.getName(), getLabelOrKey(entity, language, entity.getName())); } } if (type == null || type.contains("Group")) { List groupList = groupRepository.findAll(); - Iterator groupIterator = groupList.iterator(); - while (groupIterator.hasNext()) { - Group entity = groupIterator.next(); - translations.put("group-" + entity.getId() + "", + for (Group entity : groupList) { + translations.put("group-" + entity.getId(), getLabelOrKey(entity, language, entity.getName())); } } if (type == null || type.contains("Operation")) { List operationList = operationRepository.findAll(); - Iterator operationIterator = operationList.iterator(); - while (operationIterator.hasNext()) { - Operation entity = operationIterator.next(); - translations.put("op-" + entity.getId() + "", - getLabelOrKey(entity, language, entity.getId() + "")); - translations.put("op-" + entity.getName() + "", + for (Operation entity : operationList) { + translations.put("op-" + entity.getId(), + getLabelOrKey(entity, language, String.valueOf(entity.getId()))); + translations.put("op-" + entity.getName(), getLabelOrKey(entity, language, entity.getName())); } } if (type == null || type.contains("Source")) { List sourceList = sourceRepository.findAll(); - Iterator sourceIterator = sourceList.iterator(); - while (sourceIterator.hasNext()) { - Source entity = sourceIterator.next(); - translations.put("source-" + entity.getUuid() + "", + for (Source entity : sourceList) { + translations.put("source-" + entity.getUuid(), getLabelOrKey(entity, language, entity.getUuid())); } } if (type == null || type.contains("Schematron")) { List schematronList = schematronRepository.findAll(); - Iterator schematronIterator = schematronList.iterator(); - while (schematronIterator.hasNext()) { - Schematron entity = schematronIterator.next(); - translations.put("sch-" + entity.getRuleName() + "", + for (Schematron entity : schematronList) { + translations.put("sch-" + entity.getRuleName(), getLabelOrKey(entity, language, entity.getRuleName())); } } if (type == null || type.contains("IsoLanguage")) { List isoLanguageList = isoLanguageRepository.findAll(); - Iterator isoLanguageIterator = isoLanguageList.iterator(); - while (isoLanguageIterator.hasNext()) { - IsoLanguage entity = isoLanguageIterator.next(); - translations.put("lang-" + entity.getCode() + "", + for (IsoLanguage entity : isoLanguageList) { + translations.put("lang-" + entity.getCode(), getLabelOrKey(entity, language, entity.getCode())); } } diff --git a/core/src/main/java/org/fao/geonet/constants/Edit.java b/core/src/main/java/org/fao/geonet/constants/Edit.java index d3e6faecc26..5f9560f75e9 100644 --- a/core/src/main/java/org/fao/geonet/constants/Edit.java +++ b/core/src/main/java/org/fao/geonet/constants/Edit.java @@ -74,6 +74,7 @@ public static final class Elem { public static final String TITLE = "title"; public static final String IS_HARVESTED = "isHarvested"; public static final String HARVEST_INFO = "harvestInfo"; + public static final String OWNERID = "ownerId"; public static final String OWNERNAME = "ownername"; public static final String GROUPOWNERNAME = "groupOwnerName"; public static final String POPULARITY = "popularity"; diff --git a/core/src/main/java/org/fao/geonet/constants/Geonet.java b/core/src/main/java/org/fao/geonet/constants/Geonet.java index 41e3f76a4d1..057626e6940 100644 --- a/core/src/main/java/org/fao/geonet/constants/Geonet.java +++ b/core/src/main/java/org/fao/geonet/constants/Geonet.java @@ -535,6 +535,7 @@ public static final class SortBy { */ public static final class Config { public static final String HTMLCACHE_DIR = "htmlCacheDir"; + public static final String SCHEMAPUBLICATION_DIR = "schemaPublicationDir"; public static final String INDEX_CONFIG_DIR = "indexConfigDir"; /** * Profiles of languages for autodetection using https://code.google.com/p/language-detection/. @@ -629,7 +630,7 @@ public static final class Namespaces { public static class IndexFieldNames { public static final String HASXLINKS = "_hasxlinks"; - public static final String XLINK = "_xlink"; + public static final String XLINK = "xlink"; public static final String ROOT = "_root"; public static final String SCHEMA = "documentStandard"; public static final String DATABASE_CREATE_DATE = "createDate"; @@ -660,6 +661,8 @@ public static class IndexFieldNames { public static final String ANY = "any"; public static final String LOCALE = "locale"; public static final String IS_PUBLISHED_TO_ALL = "isPublishedToAll"; + public static final String IS_PUBLISHED_TO_INTRANET = "isPublishedToIntranet"; + public static final String IS_PUBLISHED_TO_GUEST = "isPublishedToGuest"; public static final String FEEDBACKCOUNT = "feedbackCount"; public static final String DRAFT = "draft"; public static final String DRAFT_ID = "draftId"; diff --git a/core/src/main/java/org/fao/geonet/kernel/AbstractSchematronValidator.java b/core/src/main/java/org/fao/geonet/kernel/AbstractSchematronValidator.java index 324895f4f4e..d8ad4b2df54 100644 --- a/core/src/main/java/org/fao/geonet/kernel/AbstractSchematronValidator.java +++ b/core/src/main/java/org/fao/geonet/kernel/AbstractSchematronValidator.java @@ -47,7 +47,7 @@ public class AbstractSchematronValidator { protected void runSchematron(String lang, Path schemaDir, List validations, Element schemaTronXmlOut, - int metadataId, Element md, ApplicableSchematron applicable) { + int metadataId, Element md, ApplicableSchematron applicable) { final ConfigurableApplicationContext applicationContext = ApplicationContextHolder.get(); ThesaurusManager thesaurusManager = applicationContext.getBean(ThesaurusManager.class); @@ -61,6 +61,9 @@ protected void runSchematron(String lang, Path schemaDir, List params = new HashMap(); params.put("lang", lang); @@ -74,28 +77,33 @@ protected void runSchematron(String lang, Path schemaDir, List i = xmlReport.getDescendants(new ElementFilter("fired-rule", Geonet.Namespaces.SVRL)); - int firedRules = Iterators.size(i); + firedRules = Iterators.size(i); i = xmlReport.getDescendants(new ElementFilter("failed-assert", Geonet.Namespaces.SVRL)); - int invalidRules = Iterators.size(i); + invalidRules = Iterators.size(i); - if (validations != null) { - validations.add(new MetadataValidation(). - setId(new MetadataValidationId(metadataId, ruleId)). - setStatus(invalidRules != 0 ? MetadataValidationStatus.INVALID : MetadataValidationStatus.VALID). - setRequired(requirement == SchematronRequirement.REQUIRED). - setNumTests(firedRules). - setNumFailures(invalidRules)); - - } + metadataValidationStatus = invalidRules != 0 ? MetadataValidationStatus.INVALID : MetadataValidationStatus.VALID; } } catch (Exception e) { Log.error(Geonet.DATA_MANAGER, "WARNING: schematron xslt " + ruleId + " failed", e); // If an error occurs that prevents to verify schematron rules, add to show in report Element errorReport = new Element("schematronVerificationError", Edit.NAMESPACE); - errorReport.addContent("Schematron error ocurred, rules could not be verified: " + e.getMessage()); + errorReport.addContent("Schematron error occurred, rules could not be verified: " + e.getMessage()); report.addContent(errorReport); + + // As the validation failed due to an exception lets identify the metadata as never validated. + metadataValidationStatus = MetadataValidationStatus.NEVER_CALCULATED; + } finally { + if (metadataValidationStatus != null && validations != null) { + validations.add(new MetadataValidation(). + setId(new MetadataValidationId(metadataId, ruleId)). + setStatus(metadataValidationStatus). + setRequired(requirement == SchematronRequirement.REQUIRED). + setNumTests(firedRules). + setNumFailures(invalidRules)); + + } } // -- append report to main XML report. diff --git a/core/src/main/java/org/fao/geonet/kernel/AllThesaurus.java b/core/src/main/java/org/fao/geonet/kernel/AllThesaurus.java index 971e1c072a0..361c7fc816b 100644 --- a/core/src/main/java/org/fao/geonet/kernel/AllThesaurus.java +++ b/core/src/main/java/org/fao/geonet/kernel/AllThesaurus.java @@ -27,15 +27,13 @@ import com.google.common.base.Function; import com.google.common.collect.Lists; import com.google.common.collect.Maps; - -import org.locationtech.jts.util.Assert; - import org.fao.geonet.Constants; import org.fao.geonet.constants.Geonet; import org.fao.geonet.exceptions.TermNotFoundException; import org.fao.geonet.kernel.search.keyword.KeywordRelation; import org.fao.geonet.languages.IsoLanguagesMapper; import org.fao.geonet.utils.Log; +import org.locationtech.jts.util.Assert; import org.openrdf.model.GraphException; import org.openrdf.model.URI; import org.openrdf.sesame.config.AccessDeniedException; @@ -46,6 +44,8 @@ import org.openrdf.sesame.repository.local.LocalRepository; import org.springframework.beans.factory.annotation.Autowired; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; @@ -59,9 +59,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - /** * @author Jesse on 2/27/2015. */ @@ -221,8 +218,7 @@ public synchronized URI addElement(KeywordBean keyword) throws IOException, Acce } @Override - public synchronized Thesaurus removeElement(KeywordBean keyword) throws MalformedQueryException, QueryEvaluationException, - IOException, AccessDeniedException { + public synchronized Thesaurus removeElement(KeywordBean keyword) throws AccessDeniedException { throw new UnsupportedOperationException(); } @@ -237,8 +233,7 @@ public synchronized Thesaurus removeElement(String uri) throws AccessDeniedExcep } @Override - public synchronized URI updateElement(KeywordBean keyword, boolean replace) throws AccessDeniedException, IOException, - MalformedQueryException, QueryEvaluationException, GraphException { + public synchronized URI updateElement(KeywordBean keyword, boolean replace) throws AccessDeniedException { throw new UnsupportedOperationException(); } @@ -266,12 +261,12 @@ public Thesaurus updateCode(KeywordBean bean, String newcode) throws AccessDenie } @Override - public synchronized Thesaurus updateCode(String namespace, String oldcode, String newcode) throws AccessDeniedException, IOException { + public synchronized Thesaurus updateCode(String namespace, String oldcode, String newcode) throws AccessDeniedException { throw new UnsupportedOperationException(); } @Override - public synchronized Thesaurus updateCodeByURI(String olduri, String newuri) throws AccessDeniedException, IOException { + public synchronized Thesaurus updateCodeByURI(String olduri, String newuri) throws AccessDeniedException { throw new UnsupportedOperationException(); } @@ -287,8 +282,7 @@ public IsoLanguagesMapper getIsoLanguageMapper() { } @Override - public synchronized void addRelation(String subject, KeywordRelation related, String relatedSubject) throws AccessDeniedException, - IOException, MalformedQueryException, QueryEvaluationException, GraphException { + public synchronized void addRelation(String subject, KeywordRelation related, String relatedSubject) throws AccessDeniedException { throw new UnsupportedOperationException(); } diff --git a/core/src/main/java/org/fao/geonet/kernel/DataManager.java b/core/src/main/java/org/fao/geonet/kernel/DataManager.java index 0ee36b1774e..4605016efd2 100644 --- a/core/src/main/java/org/fao/geonet/kernel/DataManager.java +++ b/core/src/main/java/org/fao/geonet/kernel/DataManager.java @@ -3,7 +3,7 @@ //=== DataManager //=== //============================================================================= -//=== Copyright (C) 2001-2007 Food and Agriculture Organization of the +//=== Copyright (C) 2001-2023 Food and Agriculture Organization of the //=== United Nations (FAO-UN), United Nations World Food Programme (WFP) //=== and United Nations Environment Programme (UNEP) //=== @@ -143,11 +143,6 @@ public void init(ServiceContext context, Boolean force) throws Exception { } } - @Deprecated - public synchronized void rebuildIndexXLinkedMetadata(final ServiceContext context) throws Exception { - metadataIndexer.rebuildIndexXLinkedMetadata(context); - } - @Deprecated public synchronized void rebuildIndexForSelection(final ServiceContext context, String bucket, boolean clearXlink) throws Exception { metadataIndexer.rebuildIndexForSelection(context, bucket, clearXlink); diff --git a/core/src/main/java/org/fao/geonet/kernel/EditLib.java b/core/src/main/java/org/fao/geonet/kernel/EditLib.java index c08322ec61a..873b9c3bcdf 100644 --- a/core/src/main/java/org/fao/geonet/kernel/EditLib.java +++ b/core/src/main/java/org/fao/geonet/kernel/EditLib.java @@ -33,23 +33,16 @@ import java.io.IOException; import java.io.StringReader; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.BitSet; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.Vector; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.jxpath.ri.parser.Token; import org.apache.commons.jxpath.ri.parser.XPathParser; import org.apache.commons.jxpath.ri.parser.XPathParserConstants; +import org.apache.commons.lang.StringUtils; import org.fao.geonet.constants.Edit; import org.fao.geonet.constants.Geonet; import org.fao.geonet.domain.Pair; @@ -271,7 +264,7 @@ private void addChildToParent(MetadataSchema mdSchema, Element targetElement, El // remove everything and then, depending on removeExisting // readd all children to the element and assure a correct position for the new one: at the end of the others // or just add the new one - List existingAllType = new ArrayList(targetElement.getChildren()); + List existingAllType = new ArrayList(targetElement.getChildren()); targetElement.removeContent(); for (String singleType: type.getAlElements()) { List existingForThisType = filterOnQname(existingAllType, singleType); @@ -282,9 +275,22 @@ private void addChildToParent(MetadataSchema mdSchema, Element targetElement, El LOGGER_ADD_ELEMENT.debug("#### - add child {}", existingChild.toString()); } } - if (qname.equals(singleType)) + if (qname.equals(singleType)) { targetElement.addContent(childToAdd); + } + + filterOnQname(existingAllType, "geonet:child") + .stream() + .filter(gnChild -> (gnChild.getAttributeValue("prefix") + ":" + gnChild.getAttributeValue("name")).equals(singleType)) + .findFirst() + .ifPresent(targetElement::addContent); } + + Stream.concat( + filterOnQname(existingAllType, "geonet:element").stream(), + filterOnQname(existingAllType, "geonet:attribute").stream() + ).forEach(targetElement::addContent); + } public void addXMLFragments(String schema, Element md, Map xmlInputs) throws Exception { @@ -583,7 +589,10 @@ public boolean addElementOrFragmentFromXpath(Element metadataRecord, } } else if (propNode instanceof Attribute) { Element parent = ((Attribute) propNode).getParent(); - parent.removeAttribute(((Attribute) propNode).getName()); + Attribute targetAttribute = (Attribute) propNode; + parent.removeAttribute( + targetAttribute.getName(), + targetAttribute.getNamespace()); } } else { // Update element content with node @@ -736,6 +745,7 @@ private boolean createAndAddFromXPath(Element metadataRecord, MetadataSchema met boolean isAttribute = false; String currentElementName = ""; String currentElementNamespacePrefix = ""; + String currentAttributeNamespacePrefix = ""; // Stop when token is null, start of an expression is found ie. "[" // @@ -758,10 +768,15 @@ private boolean createAndAddFromXPath(Element metadataRecord, MetadataSchema met isAttribute = true; } // Match namespace prefix - if (currentToken.kind == XPathParserLocalConstants.TEXT && previousToken.kind == XPathParserConstants.SLASH) { + if (currentToken.kind == XPathParserLocalConstants.TEXT && + previousToken.kind == XPathParserConstants.SLASH) { // get element namespace if element is text and previous was / // means qualified name only is supported currentElementNamespacePrefix = currentToken.image; + } else if (isAttribute && + previousToken.kind == XPathParserLocalConstants.TEXT && + currentToken.kind == XPathParserLocalConstants.NAMESPACE_SEP) { + currentAttributeNamespacePrefix = previousToken.image; } else if (currentToken.kind == XPathParserLocalConstants.TEXT && previousToken.kind == XPathParserLocalConstants.NAMESPACE_SEP) { // get element name if element is text and previous was / @@ -788,7 +803,9 @@ private boolean createAndAddFromXPath(Element metadataRecord, MetadataSchema met } else { LOGGER_ADD_ELEMENT.debug(" > add new node {} inserted in {}", qualifiedName, currentNode.getName()); - if (metadataSchema.getElementValues(qualifiedName, currentNode.getQualifiedName()) != null) { + if (isAttribute) { + existingElement = false; // Attribute is created and set after. + } else if (metadataSchema.getElementValues(qualifiedName, currentNode.getQualifiedName()) != null) { currentNode = addElement(metadataSchema, currentNode, qualifiedName); existingElement = false; } else { @@ -833,7 +850,15 @@ private boolean createAndAddFromXPath(Element metadataRecord, MetadataSchema met doAddFragmentFromXpath(metadataSchema, value.getNodeValue(), currentNode); } else { if (isAttribute) { - currentNode.setAttribute(previousToken.image, value.getStringValue()); + if (StringUtils.isNotEmpty(currentAttributeNamespacePrefix)) { + currentNode.setAttribute(previousToken.image, + value.getStringValue(), + Namespace.getNamespace(currentAttributeNamespacePrefix, + metadataSchema.getNS(currentAttributeNamespacePrefix))); + } else { + currentNode.setAttribute(previousToken.image, value.getStringValue()); + } + } else { currentNode.setText(value.getStringValue()); } diff --git a/core/src/main/java/org/fao/geonet/kernel/GeonetworkDataDirectory.java b/core/src/main/java/org/fao/geonet/kernel/GeonetworkDataDirectory.java index 8df08f2bedf..cc5296232bd 100644 --- a/core/src/main/java/org/fao/geonet/kernel/GeonetworkDataDirectory.java +++ b/core/src/main/java/org/fao/geonet/kernel/GeonetworkDataDirectory.java @@ -25,15 +25,13 @@ import jeeves.server.ServiceConfig; import jeeves.server.sources.http.JeevesServlet; -import org.apache.log4j.Appender; -import org.apache.log4j.Logger; -import org.apache.log4j.bridge.AppenderWrapper; -import org.apache.logging.log4j.core.appender.FileAppender; -import org.apache.logging.log4j.core.appender.RollingFileAppender; import org.fao.geonet.ApplicationContextHolder; import org.fao.geonet.constants.Geonet; +import org.fao.geonet.exceptions.BadParameterEx; +import org.fao.geonet.utils.FilePathChecker; import org.fao.geonet.utils.IO; import org.fao.geonet.utils.Log; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationEvent; import org.springframework.context.ConfigurableApplicationContext; @@ -68,6 +66,9 @@ public class GeonetworkDataDirectory { */ public static final String GEONETWORK_BEAN_KEY = "GeonetworkDataDirectory"; + @Autowired + SchemaManager schemaManager; + private Path webappDir; private Path systemDataDir; private Path indexConfigDir; @@ -79,6 +80,7 @@ public class GeonetworkDataDirectory { private Path metadataRevisionDir; private Path resourcesDir; private Path htmlCacheDir; + private Path schemaPublicationDir; private Path uploadDir; private Path formatterDir; private Path nodeLessFiles; @@ -124,15 +126,6 @@ public void init(final String webappName, final Path webappDir, Path systemDataD this.init(webappName, webappDir, handlerConfig, jeevesServlet); } - - /** - * This is the name of the RollingFileAppender in your log4j2.xml configuration file. - *

- * LogConfig uses this name to lookup RollingFileAppender to check configuration in - * case a custom log file location has been used. - */ - private static final String FILE_APPENDER_NAME = "File"; - /** * Logfile location as determined from appender, or system property, or default. *

@@ -141,62 +134,7 @@ public void init(final String webappName, final Path webappDir, Path systemDataD * @return logfile location, or {@code null} if unable to determine */ public static File getLogfile() { - // Appender is supplied by LogUtils based on parsing log4j2.xml file indicated - // by database settings - - // First, try the fileappender from the logger named "geonetwork" - Appender appender = Logger.getLogger(Geonet.GEONETWORK).getAppender(FILE_APPENDER_NAME); - // If still not found, try the one from the logger named "jeeves" - if (appender == null) { - appender = Logger.getLogger(Log.JEEVES).getAppender(FILE_APPENDER_NAME); - } - if (appender != null) { - if (appender instanceof AppenderWrapper) { - AppenderWrapper wrapper = (AppenderWrapper) appender; - org.apache.logging.log4j.core.Appender appender2 = wrapper.getAppender(); - - if (appender2 instanceof FileAppender) { - FileAppender fileAppender = (FileAppender) appender2; - String logFileName = fileAppender.getFileName(); - if (logFileName != null) { - File logFile = new File(logFileName); - if (logFile.exists()) { - return logFile; - } - } - } - if (appender2 instanceof RollingFileAppender) { - RollingFileAppender fileAppender = (RollingFileAppender) appender2; - String logFileName = fileAppender.getFileName(); - if (logFileName != null) { - File logFile = new File(logFileName); - if (logFile.exists()) { - return logFile; - } - } - } - } - } - Log.warning(Geonet.GEONETWORK, "Error when getting logger file for the " + "appender named '" + FILE_APPENDER_NAME + "'. " - + "Check your log configuration file. " - + "A FileAppender or RollingFileAppender is required to return last activity to the user interface." - + "Appender file not found."); - - if (System.getProperties().containsKey("log_dir")) { - File logDir = new File(System.getProperty("log_dir")); - if (logDir.exists() && logDir.isDirectory()) { - File logFile = new File(logDir, "logs/geonetwork.log"); - if (logFile.exists()) { - return logFile; - } - } - } else { - File logFile = new File("logs/geonetwork.log"); - if (logFile.exists()) { - return logFile; - } - } - return null; // unavailable + return Log.getLogfile(); } /** @@ -371,10 +309,12 @@ private Path setDataDirectory(JeevesServlet jeevesServlet, String webappName, ); formatterDir = setDir(jeevesServlet, webappName, handlerConfig, formatterDir, ".formatter" + KEY_SUFFIX, Geonet.Config.FORMATTER_PATH, "data", "formatter"); - htmlCacheDir = setDir(jeevesServlet, webappName, handlerConfig, htmlCacheDir, ".htmlcache" + KEY_SUFFIX, Geonet.Config.HTMLCACHE_DIR, handlerConfig.getValue(Geonet.Config.RESOURCES_DIR), "htmlcache" ); + schemaPublicationDir = setDir(jeevesServlet, webappName, handlerConfig, schemaPublicationDir, + ".schemapublication" + KEY_SUFFIX, Geonet.Config.SCHEMAPUBLICATION_DIR, handlerConfig.getValue(Geonet.Config.RESOURCES_DIR), "schemapublication" + ); backupDir = setDir(jeevesServlet, webappName, handlerConfig, backupDir, ".backup" + KEY_SUFFIX, Geonet.Config.BACKUP_DIR, "data", "backup" ); @@ -458,6 +398,29 @@ private void initDataDirectory() throws IOException { } } + Path resourcesConfigDir = this.resourcesDir.resolve("config"); + if (!Files.exists(resourcesConfigDir) || IO.isEmptyDir(resourcesConfigDir)) { + Log.info(Geonet.DATA_DIRECTORY, " - Copying config ..."); + try { + Files.createDirectories(resourcesConfigDir); + final Path fromDir = getDefaultDataDir(webappDir).resolve("data").resolve("resources").resolve("config"); + + if (Files.exists(fromDir)) { + try (DirectoryStream paths = Files.newDirectoryStream(fromDir)) { + for (Path path : paths) { + final Path relativePath = fromDir.relativize(path); + final Path dest = resourcesConfigDir.resolve(relativePath.toString()); + if (!Files.exists(dest)) { + IO.copyDirectoryOrFile(path, dest, false); + } + } + } + } + } catch (IOException e) { + Log.error(Geonet.DATA_DIRECTORY, " - Config copy failed: " + e.getMessage(), e); + } + } + logoDir = this.resourcesDir.resolve("images").resolve("harvesting"); if (!Files.exists(logoDir) || IO.isEmptyDir(logoDir)) { Log.info(Geonet.DATA_DIRECTORY, " - Copying logos ..."); @@ -765,6 +728,23 @@ public void setHtmlCacheDir(Path htmlCacheDir) { this.htmlCacheDir = htmlCacheDir; } + /** + * Get directory for publishing schemas and making them publicly available. + * + * @return directory for publishing schemas and making them publicly available. + */ + public Path getSchemaPublicationDir() { + return schemaPublicationDir; + } + + /** + * Set directory for publishing schemas and making them publicly available. + * @param schemaPublicationDir + */ + public void setSchemaPublicationDir(Path schemaPublicationDir) { + this.schemaPublicationDir = schemaPublicationDir; + } + /** * Get directory for caching where uploaded files go. * @@ -823,11 +803,18 @@ public Path getXsltConversion(String conversionId) { if (conversionId.startsWith(IMPORT_STYLESHEETS_SCHEMA_PREFIX)) { String[] pathToken = conversionId.split(":"); if (pathToken.length == 3) { + String schema = pathToken[1]; + if (!schemaManager.existsSchema(schema)) { + throw new BadParameterEx(String.format( + "Conversion not found. Schema '%s' is not registered in this catalog.", schema)); + } + FilePathChecker.verify(pathToken[2]); return this.getSchemaPluginsDir() .resolve(pathToken[1]) .resolve(pathToken[2] + ".xsl"); } } else { + FilePathChecker.verify(conversionId); return this.getWebappDir().resolve(Geonet.Path.IMPORT_STYLESHEETS). resolve(conversionId + ".xsl"); } diff --git a/core/src/main/java/org/fao/geonet/kernel/GeonetworkOverridingWKTFactory.java b/core/src/main/java/org/fao/geonet/kernel/GeonetworkOverridingWKTFactory.java index 463ea1363aa..c27dbd8bc4b 100644 --- a/core/src/main/java/org/fao/geonet/kernel/GeonetworkOverridingWKTFactory.java +++ b/core/src/main/java/org/fao/geonet/kernel/GeonetworkOverridingWKTFactory.java @@ -32,7 +32,7 @@ import org.geotools.util.factory.Hints; import org.geotools.referencing.factory.epsg.FactoryUsingWKT; -import org.opengis.referencing.operation.CoordinateOperationAuthorityFactory; +import org.geotools.api.referencing.operation.CoordinateOperationAuthorityFactory; /** diff --git a/core/src/main/java/org/fao/geonet/kernel/SchemaManager.java b/core/src/main/java/org/fao/geonet/kernel/SchemaManager.java index 1489c367132..18742c86494 100644 --- a/core/src/main/java/org/fao/geonet/kernel/SchemaManager.java +++ b/core/src/main/java/org/fao/geonet/kernel/SchemaManager.java @@ -1,29 +1,25 @@ -//============================================================================= -//=== -//=== SchemaManager -//=== -//============================================================================= -//=== Copyright (C) 2001-2011 Food and Agriculture Organization of the -//=== United Nations (FAO-UN), United Nations World Food Programme (WFP) -//=== and United Nations Environment Programme (UNEP) -//=== -//=== This program is free software; you can redistribute it and/or modify -//=== it under the terms of the GNU General Public License as published by -//=== the Free Software Foundation; either version 2 of the License, or (at -//=== your option) any later version. -//=== -//=== This program is distributed in the hope that it will be useful, but -//=== WITHOUT ANY WARRANTY; without even the implied warranty of -//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -//=== General Public License for more details. -//=== -//=== You should have received a copy of the GNU General Public License -//=== along with this program; if not, write to the Free Software -//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA -//=== -//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, -//=== Rome - Italy. email: geonetwork@osgeo.org -//============================================================================== +/* + * Copyright (C) 2001-2024 Food and Agriculture Organization of the + * United Nations (FAO-UN), United Nations World Food Programme (WFP) + * and United Nations Environment Programme (UNEP) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, + * Rome - Italy. email: geonetwork@osgeo.org + */ package org.fao.geonet.kernel; @@ -42,6 +38,7 @@ import org.fao.geonet.exceptions.OperationAbortedEx; import org.fao.geonet.exceptions.SchemaMatchConflictException; import org.fao.geonet.kernel.schema.MetadataSchema; +import org.fao.geonet.kernel.schema.MetadataSchemaOperationFilter; import org.fao.geonet.kernel.schema.SchemaLoader; import org.fao.geonet.kernel.schema.SchemaPlugin; import org.fao.geonet.kernel.setting.SettingInfo; @@ -79,6 +76,7 @@ import java.util.Map; import java.util.Set; import java.util.regex.Pattern; +import java.util.stream.Collectors; /** * Class that handles all functions relating to metadata schemas. This includes @@ -107,8 +105,9 @@ public class SchemaManager { * Active writers count */ private static int activeWriters = 0; - private Map hmSchemas = new HashMap(); - private Map hmSchemasTypenames = new HashMap(); + private Map hmSchemas = new HashMap<>(); + private Map hmSchemasTypenames = new HashMap<>(); + private Map cswOutputSchemas = new HashMap<>(); private String[] fnames = {"labels.xml", "codelists.xml", "strings.xml"}; private Path schemaPluginsDir; private Path schemaPluginsCat; @@ -117,6 +116,7 @@ public class SchemaManager { private String defaultSchema; private Path basePath; private Path resourcePath; + private Path schemaPublicationDir; private int numberOfCoreSchemasAdded = 0; public static Path registerXmlCatalogFiles(Path webappDir, Path schemapluginUriCatalog) { @@ -177,6 +177,7 @@ public static SchemaPlugin getSchemaPlugin(String schemaIdentifier) { public void configureFrom(SchemaManager schemaManager, Path basePath, GeonetworkDataDirectory dataDir) { this.basePath = basePath; this.resourcePath = dataDir.getResourcesDir(); + this.schemaPublicationDir = dataDir.getSchemaPublicationDir(); this.schemaPluginsDir = dataDir.getSchemaPluginsDir(); this.schemaPluginsCat = schemaPluginsDir.resolve("schemaplugin-uri-catalog.xml"); this.defaultLang = schemaManager.defaultLang; @@ -203,19 +204,29 @@ private void addResolverRewriteDirectives(GeonetworkDataDirectory dataDir) { /** * initialize and configure schema manager. should only be on startup. * - * @param basePath the web app base path - * @param schemaPluginsCat the schema catalogue file - * @param sPDir the schema plugin directory - * @param defaultLang the default language (taken from context) - * @param defaultSchema the default schema (taken from config.xml) - */ - public void configure(ApplicationContext applicationContext, Path basePath, Path resourcePath, Path schemaPluginsCat, - Path sPDir, String defaultLang, String defaultSchema, boolean createOrUpdateSchemaCatalog) throws Exception { + * @param basePath the web app base path + * @param resourcePath the resource folder (eg. images, logo) + * @param schemaPublicationDir the schema publication folder (ie. schema plugin XSDs) + * @param schemaPluginsCat the schema catalogue file (ie. schemaplugin-uri-catalog.xml) + * @param sPDir the schema plugin directory + * @param defaultLang the default language (taken from context) + * @param defaultSchema the default schema (taken from config.xml) + */ + public void configure(ApplicationContext applicationContext, + Path basePath, + Path resourcePath, + Path schemaPublicationDir, + Path schemaPluginsCat, + Path sPDir, + String defaultLang, + String defaultSchema, + boolean createOrUpdateSchemaCatalog) throws Exception { hmSchemas.clear(); this.basePath = basePath; this.resourcePath = resourcePath; + this.schemaPublicationDir = schemaPublicationDir; this.schemaPluginsDir = sPDir; this.schemaPluginsCat = schemaPluginsCat; this.defaultLang = defaultLang; @@ -271,11 +282,11 @@ public MetadataSchema getSchema(String name) { try { Schema schema = hmSchemas.get(name); - if (schema == null) + if (schema == null) { throw new IllegalArgumentException("Schema not registered : " + name); + } - final MetadataSchema mds = schema.getMetadataSchema(); - return mds; + return schema.getMetadataSchema(); } finally { afterRead(); } @@ -288,7 +299,7 @@ public MetadataSchema getSchema(String name) { */ public Set getDependencies(String name) { - Set dependencies = new HashSet(); + Set dependencies = new HashSet<>(); beforeRead(); try { @@ -541,7 +552,7 @@ public List getConversionElements(String name) throws Exception { try { Schema schema = hmSchemas.get(name); List childs = schema.getConversionElements(); - List dChilds = new ArrayList(); + List dChilds = new ArrayList<>(); for (Element child : childs) { if (child != null) dChilds.add((Element) child.clone()); } @@ -712,40 +723,35 @@ public String autodetectSchema(Element md, String defaultSchema) throws SchemaMa // -- specific test first, then in order of increasing generality, // -- first match wins schema = compareElementsAndAttributes(md, MODE_ATTRIBUTEWITHVALUE); - if (schema != null) { - if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) - Log.debug(Geonet.SCHEMA_MANAGER, " => Found schema " + schema + " using AUTODETECT(attributes) examination"); + if (schema != null && Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) { + Log.debug(Geonet.SCHEMA_MANAGER, " => Found schema " + schema + " using AUTODETECT(attributes) examination"); } if (schema == null) { schema = compareElementsAndAttributes(md, MODE_NEEDLEWITHVALUE); - if (schema != null) { - if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) - Log.debug(Geonet.SCHEMA_MANAGER, " => Found schema " + schema + " using AUTODETECT(elements with value) examination"); + if (schema != null && Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) { + Log.debug(Geonet.SCHEMA_MANAGER, " => Found schema " + schema + " using AUTODETECT(elements with value) examination"); } } if (schema == null) { schema = compareElementsAndAttributes(md, MODE_NEEDLE); - if (schema != null) { - if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) - Log.debug(Geonet.SCHEMA_MANAGER, " => Found schema " + schema + " using AUTODETECT(elements) examination"); + if (schema != null && Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) { + Log.debug(Geonet.SCHEMA_MANAGER, " => Found schema " + schema + " using AUTODETECT(elements) examination"); } } if (schema == null) { schema = compareElementsAndAttributes(md, MODE_ROOT); - if (schema != null) { - if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) - Log.debug(Geonet.SCHEMA_MANAGER, " => Found schema " + schema + " using AUTODETECT(elements with root) examination"); + if (schema != null && Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) { + Log.debug(Geonet.SCHEMA_MANAGER, " => Found schema " + schema + " using AUTODETECT(elements with root) examination"); } } if (schema == null) { schema = compareElementsAndAttributes(md, MODE_NAMESPACE); - if (schema != null) { - if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) - Log.debug(Geonet.SCHEMA_MANAGER, " => Found schema " + schema + " using AUTODETECT(namespaces) examination"); + if (schema != null && Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) { + Log.debug(Geonet.SCHEMA_MANAGER, " => Found schema " + schema + " using AUTODETECT(namespaces) examination"); } } @@ -789,8 +795,9 @@ private String checkNamespace(Element md, String schema) { MetadataSchema mds = getSchema(schema); if (mds != null) { String primeNs = mds.getPrimeNS(); - if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) + if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) { Log.debug(Geonet.SCHEMA_MANAGER, " primeNs " + primeNs + " for schema " + schema); + } if (md.getNamespace().getURI().equals(primeNs)) { result = schema; } else { @@ -800,8 +807,9 @@ private String checkNamespace(Element md, String schema) { Schema sch = hmSchemas.get(schema); List dependsList = sch.getDependElements(); for (Element depends : dependsList) { - if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) + if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) { Log.debug(Geonet.SCHEMA_MANAGER, " checkNamespace for dependency: " + depends.getText()); + } return checkNamespace(md, depends.getText()); } } @@ -869,7 +877,7 @@ private void realDeletePluginSchema(String name, boolean doDependencies) throws if (schema != null) { if (doDependencies) { List dependsOnMe = getSchemasThatDependOnMe(name); - if (dependsOnMe.size() > 0) { + if (!dependsOnMe.isEmpty()) { String errStr = "Cannot remove schema " + name + " because the following schemas list it as a dependency: " + dependsOnMe; Log.error(Geonet.SCHEMA_MANAGER, errStr); throw new OperationAbortedEx(errStr); @@ -952,6 +960,7 @@ private void addSchema(ApplicationContext applicationContext, Path schemaDir, El if (mds.getSchemaPlugin() != null && mds.getSchemaPlugin().getCswTypeNames() != null) { hmSchemasTypenames.putAll(mds.getSchemaPlugin().getCswTypeNames()); + cswOutputSchemas.putAll(mds.getSchemaPlugin().getOutputSchemas()); } // -- add cached xml files (schema codelists and label files) @@ -959,19 +968,21 @@ private void addSchema(ApplicationContext applicationContext, Path schemaDir, El final String schemaName = schemaDir.getFileName().toString(); Path locBase = schemaDir.resolve("loc"); - Map xfMap = new HashMap(); + Map xfMap = new HashMap<>(); for (String fname : fnames) { Path filePath = path.resolve("loc").resolve(defaultLang).resolve(fname); - if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) + if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) { Log.debug(Geonet.SCHEMA_MANAGER, "Searching for " + filePath); + } if (Files.exists(filePath)) { Element config = new Element("xml"); config.setAttribute("name", schemaName); config.setAttribute("base", locBase.toUri().toString()); config.setAttribute("file", fname); - if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) + if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) { Log.debug(Geonet.SCHEMA_MANAGER, "Adding XmlFile " + Xml.getString(config)); + } XmlFile xf = new XmlFile(config, defaultLang, true); xfMap.put(fname, xf); } else { @@ -1078,8 +1089,9 @@ private Element deleteSchemaFromPluginCatalog(String name, Element root) throws else continue; // skip this if (!uri.getName().equals("uri") || !uri.getNamespace().equals(Namespaces.OASIS_CATALOG)) { - if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) + if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) { Log.debug(Geonet.SCHEMA_MANAGER, "Skipping element " + uri.getQualifiedName() + ":" + uri.getNamespace()); + } continue; } @@ -1113,8 +1125,9 @@ private int getHighestSchemaPluginCatalogId(String name, Element root) throws Ex else continue; // skip this if (!uri.getName().equals("rewriteURI") || !uri.getNamespace().equals(Namespaces.OASIS_CATALOG)) { - if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) + if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) { Log.debug(Geonet.SCHEMA_MANAGER, "Skipping element " + uri.getQualifiedName() + ":" + uri.getNamespace()); + } continue; } @@ -1122,8 +1135,9 @@ private int getHighestSchemaPluginCatalogId(String name, Element root) throws Ex if (uri.getAttributeValue("rewritePrefix").equals(ourUri.toString())) return -1; String nameAttr = uri.getAttributeValue("uriStartString"); - if (nameAttr.startsWith(Geonet.File.METADATA_BLANK)) { - if (nameAttr.compareTo(baseBlank) > 0) baseBlank = nameAttr; + if (nameAttr.startsWith(Geonet.File.METADATA_BLANK) && + nameAttr.compareTo(baseBlank) > 0) { + baseBlank = nameAttr; } } @@ -1260,7 +1274,7 @@ private void removeSchemaDir(Path schemaDir, String name) { } deleteDir(schemaDir); - Path pubSchemaDir = resourcePath.resolve(Geonet.Path.SCHEMAS).resolve(name); + Path pubSchemaDir = schemaPublicationDir.resolve(Geonet.Path.SCHEMAS).resolve(name); if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) { Log.debug(Geonet.SCHEMA_MANAGER, "Removing published schemas directory " + pubSchemaDir); } @@ -1318,17 +1332,17 @@ private void processSchema(ApplicationContext applicationContext, Path schemasDi * Check dependencies for all schemas - remove those that fail. */ private void checkDependencies(Element schemaPluginCatRoot) throws Exception { - List removes = new ArrayList(); + List removes = new ArrayList<>(); // process each schema to see whether its dependencies are present - for (String schemaName : hmSchemas.keySet()) { - Schema schema = hmSchemas.get(schemaName); + for (Map.Entry schemaInfo : hmSchemas.entrySet()) { + Schema schema = schemaInfo.getValue(); try { - checkDepends(schemaName, schema.getDependElements()); + checkDepends(schemaInfo.getKey(), schema.getDependElements()); } catch (Exception e) { Log.error(Geonet.SCHEMA_MANAGER, "check dependencies failed: " + e.getMessage()); // add the schema to list for removal - removes.add(schemaName); + removes.add(schemaInfo.getKey()); } } @@ -1341,7 +1355,7 @@ private void checkDependencies(Element schemaPluginCatRoot) throws Exception { } private void checkAppSupported(Element schemaPluginCatRoot) throws Exception { - List removes = new ArrayList(); + List removes = new ArrayList<>(); final SystemInfo systemInfo = ApplicationContextHolder.get().getBean(SystemInfo.class); @@ -1349,17 +1363,17 @@ private void checkAppSupported(Element schemaPluginCatRoot) throws Exception { Version appVersion = Version.parseVersionNumber(version); // process each schema to see whether its dependencies are present - for (String schemaName : hmSchemas.keySet()) { - Schema schema = hmSchemas.get(schemaName); + for (Map.Entry schemaInfo : hmSchemas.entrySet()) { + Schema schema = schemaInfo.getValue(); String minorAppVersionSupported = schema.getMetadataSchema().getAppMinorVersionSupported(); Version schemaMinorAppVersion = Version.parseVersionNumber(minorAppVersionSupported); if (appVersion.compareTo(schemaMinorAppVersion) < 0) { - Log.error(Geonet.SCHEMA_MANAGER, "Schema " + schemaName + + Log.error(Geonet.SCHEMA_MANAGER, "Schema " + schemaInfo.getKey() + " requires min Geonetwork version: " + minorAppVersionSupported + ", current is: " + version + ". Skip load schema."); - removes.add(schemaName); + removes.add(schemaInfo.getKey()); continue; } @@ -1368,11 +1382,10 @@ private void checkAppSupported(Element schemaPluginCatRoot) throws Exception { Version schemaMajorAppVersion = Version.parseVersionNumber(majorAppVersionSupported); if (appVersion.compareTo(schemaMajorAppVersion) > 0) { - Log.error(Geonet.SCHEMA_MANAGER, "Schema " + schemaName + + Log.error(Geonet.SCHEMA_MANAGER, "Schema " + schemaInfo.getKey() + " requires max Geonetwork version: " + majorAppVersionSupported + ", current is: " + version + ". Skip load schema."); - removes.add(schemaName); - continue; + removes.add(schemaInfo.getKey()); } } @@ -1396,17 +1409,17 @@ private void checkAppSupported(Element schemaPluginCatRoot) throws Exception { */ public List getSchemasThatDependOnMe(String schemaName) { - List myDepends = new ArrayList(); + List myDepends = new ArrayList<>(); // process each schema to see whether its dependencies are present - for (String schemaNameToTest : hmSchemas.keySet()) { - if (schemaNameToTest.equals(schemaName)) continue; + for (Map.Entry schemaInfoToTest : hmSchemas.entrySet()) { + if (schemaInfoToTest.getKey().equals(schemaName)) continue; - Schema schema = hmSchemas.get(schemaNameToTest); + Schema schema = schemaInfoToTest.getValue(); List dependsList = schema.getDependElements(); for (Element depends : dependsList) { if (depends.getText().equals(schemaName)) { - myDepends.add(schemaNameToTest); + myDepends.add(schemaInfoToTest.getKey()); } } } @@ -1424,7 +1437,7 @@ private void checkDepends(String thisSchema, List dependsList) throws E // process each dependency to see whether it is present for (Element depends : dependsList) { String schema = depends.getText(); - if (schema.length() > 0) { + if (StringUtils.isNotBlank(schema)) { if (!hmSchemas.containsKey(schema)) { throw new IllegalArgumentException("Schema " + thisSchema + " depends on " + schema + ", but that schema is not loaded"); } @@ -1444,7 +1457,7 @@ private List extractDepends(Path xmlIdFile) throws Exception { // get list of depends elements from schema-ident.xml List dependsList = root.getChildren("depends", GEONET_SCHEMA_NS); - if (dependsList.size() == 0) { + if (dependsList.isEmpty()) { dependsList = root.getChildren("depends", GEONET_SCHEMA_PREFIX_NS); } return dependsList; @@ -1502,11 +1515,11 @@ private Map getSchemaIdentMultilingualProperty(Element root, Str * true if schema requires to synch the uuid column schema info with the uuid in the metadata * record (updated on editing or in UFO). */ - private Map> extractOperationFilters(Path xmlIdFile) throws Exception { + private Map extractOperationFilters(Path xmlIdFile) throws Exception { Element root = Xml.loadFile(xmlIdFile); Element filters = root.getChild("filters", GEONET_SCHEMA_NS); - Map> filterRules = - new HashMap>(); + Map filterRules = + new HashMap<>(); if (filters == null) { return filterRules; } else { @@ -1514,11 +1527,14 @@ private Map> extractOperationFilters(Path xmlIdFil if (rule instanceof Element) { Element ruleElement = (Element) rule; String xpath = ruleElement.getAttributeValue("xpath"); + String jsonpath = ruleElement.getAttributeValue("jsonpath"); String ifNotOperation = ruleElement.getAttributeValue("ifNotOperation"); Element markedElement = ruleElement.getChild("keepMarkedElement", GEONET_SCHEMA_NS); + if (StringUtils.isNotBlank(ifNotOperation) && StringUtils.isNotBlank(xpath)) { - filterRules.put(ifNotOperation, Pair.read(xpath, markedElement)); + MetadataSchemaOperationFilter filter = new MetadataSchemaOperationFilter(xpath, jsonpath, ifNotOperation, markedElement); + filterRules.put(ifNotOperation, filter); } } } @@ -1574,11 +1590,12 @@ private List extractConvElements(Path xmlConvFile) throws Exception { if (!Files.exists(xmlConvFile)) { if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) Log.debug(Geonet.SCHEMA_MANAGER, "Schema conversions file not present"); - return new ArrayList(); + return new ArrayList<>(); } else { Element root = Xml.loadFile(xmlConvFile); - if (root.getName() != "conversions") + if (!root.getName().equals("conversions")) { throw new IllegalArgumentException("Schema conversions file " + xmlConvFile + " is invalid, no root element"); + } @SuppressWarnings("unchecked") List result = root.getChildren(); return result; @@ -1609,8 +1626,9 @@ private String compareElementsAndAttributes(Element md, int mode) throws SchemaM Set allSchemas = getSchemas(); List matches = new ArrayList<>(); - if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) + if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) { Log.debug(Geonet.SCHEMA_MANAGER, "Schema autodetection starting on " + md.getName() + " (Namespace: " + md.getNamespace() + ") using mode: " + mode + "..."); + } for (String schemaName : allSchemas) { if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) @@ -1619,8 +1637,9 @@ private String compareElementsAndAttributes(Element md, int mode) throws SchemaM List adElems = schema.getAutodetectElements(); for (Element elem : adElems) { - if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) + if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) { Log.debug(Geonet.SCHEMA_MANAGER, " Checking autodetect element " + Xml.getString(elem) + " with name " + elem.getName()); + } @SuppressWarnings("unchecked") List elemKids = elem.getChildren(); @@ -1629,12 +1648,13 @@ private String compareElementsAndAttributes(Element md, int mode) throws SchemaM Attribute type = elem.getAttribute("type"); // --- try and find the attribute and value in md - if (mode == MODE_ATTRIBUTEWITHVALUE && elem.getName() == "attributes") { + if (mode == MODE_ATTRIBUTEWITHVALUE && elem.getName().equals("attributes")) { @SuppressWarnings("unchecked") List atts = elem.getAttributes(); for (Attribute searchAtt : atts) { - if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) + if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) { Log.debug(Geonet.SCHEMA_MANAGER, " Finding attribute " + searchAtt.toString()); + } if (isMatchingAttributeInMetadata(searchAtt, md)) { match = true; @@ -1649,8 +1669,9 @@ private String compareElementsAndAttributes(Element md, int mode) throws SchemaM @SuppressWarnings("unchecked") List nss = elem.getAdditionalNamespaces(); for (Namespace ns : nss) { - if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) + if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) { Log.debug(Geonet.SCHEMA_MANAGER, " Finding namespace " + ns.toString()); + } if (isMatchingNamespaceInMetadata(ns, md)) { match = true; @@ -1664,8 +1685,9 @@ private String compareElementsAndAttributes(Element md, int mode) throws SchemaM // --- is the kid the same as the root of the md if (mode == MODE_ROOT && type != null && "root".equals(type.getValue())) { - if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) + if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) { Log.debug(Geonet.SCHEMA_MANAGER, " Comparing " + Xml.getString(kid) + " with " + md.getName() + " with namespace " + md.getNamespace() + " : " + (kid.getName().equals(md.getName()) && kid.getNamespace().equals(md.getNamespace()))); + } if (kid.getName().equals(md.getName()) && kid.getNamespace().equals(md.getNamespace())) { match = true; @@ -1675,8 +1697,9 @@ private String compareElementsAndAttributes(Element md, int mode) throws SchemaM } // --- try and find the kid in the md (kid only, not value) } else if (mode == MODE_NEEDLE && type != null && "search".equals(type.getValue())) { - if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) + if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) { Log.debug(Geonet.SCHEMA_MANAGER, " Comparing " + Xml.getString(kid) + " with " + md.getName() + " with namespace " + md.getNamespace() + " : " + (kid.getName().equals(md.getName()) && kid.getNamespace().equals(md.getNamespace()))); + } if (isMatchingElementInMetadata(kid, md, false)) { match = true; @@ -1720,8 +1743,9 @@ private boolean isMatchingAttributeInMetadata(Attribute needle, Element haystack @SuppressWarnings("unchecked") Iterator haystackIterator = haystack.getDescendants(new ElementFilter()); - if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) + if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) { Log.debug(Geonet.SCHEMA_MANAGER, "Matching " + needle.toString()); + } while (haystackIterator.hasNext()) { Element tempElement = haystackIterator.next(); @@ -1742,8 +1766,9 @@ private boolean isMatchingAttributeInMetadata(Attribute needle, Element haystack * @param haystack the XML metadata record we are searching */ private boolean isMatchingNamespaceInMetadata(Namespace needle, Element haystack) { - if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) + if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) { Log.debug(Geonet.SCHEMA_MANAGER, "Matching " + needle.toString()); + } if (checkNamespacesOnElement(needle, haystack)) return true; @@ -1797,8 +1822,9 @@ private boolean isMatchingElementInMetadata(Element needle, Element haystack, bo if (tempElement.getName().equals(needleName) && tempElement.getNamespace().equals(needleNS)) { if (checkValue) { - if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) + if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) { Log.debug(Geonet.SCHEMA_MANAGER, " Searching value for element: " + tempElement.getName()); + } String needleVal = StringUtils.deleteWhitespace(needle.getValue()); String tempVal = StringUtils.deleteWhitespace(tempElement.getValue()); @@ -1857,7 +1883,7 @@ public String getDefaultSchema() { * @param schemaPluginDir the directory containing the schema plugin */ private void copySchemaXSDsToWebApp(String name, Path schemaPluginDir) throws Exception { - Path schemasDir = resourcePath.resolve(Geonet.Path.SCHEMAS); + Path schemasDir = schemaPublicationDir.resolve(Geonet.Path.SCHEMAS); Files.createDirectories(schemasDir); Path webAppDirSchemaXSD = schemasDir.resolve(name); @@ -1877,7 +1903,7 @@ public boolean accept(Path entry) throws IOException { try (DirectoryStream schemaplugins = Files.newDirectoryStream(schemaPluginDir, xsdFilter)) { boolean missingXsdFiles = true; for (Path schemaplugin : schemaplugins) { - IO.copyDirectoryOrFile(schemaplugin, webAppDirSchemaXSD.resolve(schemaplugin), false); + IO.copyDirectoryOrFile(schemaplugin, webAppDirSchemaXSD.resolve(schemaplugin.getFileName()), false); missingXsdFiles = false; } @@ -1902,17 +1928,17 @@ public Map getHmSchemasTypenames() { } /** - * Return the list of namespace URI of all typenames declared in all schema plugins. + * Return the list of outputSchema declared in all schema plugins. + */ + public Map getOutputSchemas() { + return cswOutputSchemas; + } + + /** + * Return the list of namespace URI of all outputSchema declared in all schema plugins. */ public List getListOfOutputSchemaURI() { - Iterator iterator = hmSchemasTypenames.keySet().iterator(); - List listOfSchemaURI = new ArrayList<>(); - while (iterator.hasNext()) { - String typeLocalName = iterator.next(); - Namespace ns = hmSchemasTypenames.get(typeLocalName); - listOfSchemaURI.add(ns.getURI()); - } - return listOfSchemaURI; + return new ArrayList<>(cswOutputSchemas.values()); } /** @@ -1923,7 +1949,6 @@ public List getListOfTypeNames() { List listOfTypenames = new ArrayList<>(); while (iterator.hasNext()) { String typeName = iterator.next(); - Namespace ns = hmSchemasTypenames.get(typeName); listOfTypenames.add(typeName); } return listOfTypenames; diff --git a/core/src/main/java/org/fao/geonet/kernel/SelectionManager.java b/core/src/main/java/org/fao/geonet/kernel/SelectionManager.java index cd400331964..a42a9e982e9 100644 --- a/core/src/main/java/org/fao/geonet/kernel/SelectionManager.java +++ b/core/src/main/java/org/fao/geonet/kernel/SelectionManager.java @@ -23,13 +23,14 @@ package org.fao.geonet.kernel; +import co.elastic.clients.elasticsearch.core.SearchResponse; +import co.elastic.clients.elasticsearch.core.search.Hit; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import jeeves.server.UserSession; import jeeves.server.context.ServiceContext; import org.apache.commons.lang.StringUtils; -import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.search.SearchHit; import org.fao.geonet.ApplicationContextHolder; import org.fao.geonet.constants.Edit; import org.fao.geonet.constants.Geonet; @@ -248,8 +249,9 @@ public void selectAll(String type, ServiceContext context, UserSession session) EsSearchManager searchManager = context.getBean(EsSearchManager.class); searchResponse = searchManager.query(request.get("query"), FIELDLIST_UUID, 0, maxhits); List uuidList = new ArrayList(); - for (SearchHit h : Arrays.asList(searchResponse.getHits().getHits())) { - uuidList.add((String) h.getSourceAsMap().get(Geonet.IndexFieldNames.UUID)); + ObjectMapper objectMapper = new ObjectMapper(); + for (Hit h : (List) searchResponse.hits().hits()) { + uuidList.add((String) objectMapper.convertValue(h.source(), Map.class).get(Geonet.IndexFieldNames.UUID)); } if (selection != null) { diff --git a/core/src/main/java/org/fao/geonet/kernel/SpringLocalServiceInvoker.java b/core/src/main/java/org/fao/geonet/kernel/SpringLocalServiceInvoker.java index 87da11f4888..fa3711cb858 100644 --- a/core/src/main/java/org/fao/geonet/kernel/SpringLocalServiceInvoker.java +++ b/core/src/main/java/org/fao/geonet/kernel/SpringLocalServiceInvoker.java @@ -22,8 +22,6 @@ */ package org.fao.geonet.kernel; -import org.fao.geonet.NodeInfo; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpSession; @@ -43,16 +41,19 @@ public class SpringLocalServiceInvoker { - @Autowired - public RequestMappingHandlerMapping requestMappingHandlerMapping; + public final RequestMappingHandlerMapping requestMappingHandlerMapping; - @Autowired - public RequestMappingHandlerAdapter requestMappingHandlerAdapter; + public final RequestMappingHandlerAdapter requestMappingHandlerAdapter; private HandlerMethodArgumentResolverComposite argumentResolvers; private HandlerMethodReturnValueHandlerComposite returnValueHandlers; private DefaultDataBinderFactory webDataBinderFactory; + public SpringLocalServiceInvoker(RequestMappingHandlerMapping requestMappingHandlerMapping, RequestMappingHandlerAdapter requestMappingHandlerAdapter) { + this.requestMappingHandlerMapping = requestMappingHandlerMapping; + this.requestMappingHandlerAdapter = requestMappingHandlerAdapter; + } + public void init() { argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(requestMappingHandlerAdapter.getArgumentResolvers()); returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(requestMappingHandlerAdapter.getReturnValueHandlers()); diff --git a/core/src/main/java/org/fao/geonet/kernel/Thesaurus.java b/core/src/main/java/org/fao/geonet/kernel/Thesaurus.java index 5c5ed93ec5a..a9f2d57230f 100644 --- a/core/src/main/java/org/fao/geonet/kernel/Thesaurus.java +++ b/core/src/main/java/org/fao/geonet/kernel/Thesaurus.java @@ -76,6 +76,7 @@ public class Thesaurus { private static final String DEFAULT_THESAURUS_NAMESPACE = "http://custom.shared.obj.ch/concept#"; private static final String RDF_NAMESPACE = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; + private static final String RDF_SCHEMA_NAMESPACE = "http://www.w3.org/2000/01/rdf-schema#"; private static final String SKOS_NAMESPACE = "http://www.w3.org/2004/02/skos/core#"; @@ -99,6 +100,12 @@ public class Thesaurus { private String date; + private String createdDate; + + private String issuedDate; + + private String modifiedDate; + private String defaultNamespace; private String downloadUrl; @@ -114,7 +121,7 @@ public class Thesaurus { // map of lang -> dictionary of values // key is a dublinCore element (i.e. https://guides.library.ucsc.edu/c.php?g=618773&p=4306386) // see #retrieveDublinCore() for example - private Map> dublinCoreMultilingual = new Hashtable<>(); + private Map> dublinCoreMultilingual = new Hashtable<>(); private Cache THESAURUS_SEARCH_CACHE; @@ -126,14 +133,15 @@ protected Thesaurus() { } /** - * @param fname file name - * @param dname category/domain name of thesaurus + * @param fname file name + * @param dname category/domain name of thesaurus * @param thesaurusCacheMaxSize */ public Thesaurus(IsoLanguagesMapper isoLanguageMapper, String fname, String type, String dname, Path thesaurusFile, String siteUrl, int thesaurusCacheMaxSize) { this(isoLanguageMapper, fname, null, null, type, dname, thesaurusFile, siteUrl, false, thesaurusCacheMaxSize); } + public Thesaurus(IsoLanguagesMapper isoLanguageMapper, String fname, String tname, String tnamespace, String type, String dname, Path thesaurusFile, String siteUrl, boolean ignoreMissingError, int thesaurusCacheMaxSize) { this(isoLanguageMapper, fname, null, null, null, type, dname, thesaurusFile, siteUrl, false, thesaurusCacheMaxSize); } @@ -145,9 +153,9 @@ public Thesaurus(IsoLanguagesMapper isoLanguageMapper, String fname, super(); THESAURUS_SEARCH_CACHE = CacheBuilder.newBuilder() - .maximumSize(thesaurusCacheMaxSize) - .expireAfterAccess(25, TimeUnit.HOURS) - .build(); + .maximumSize(thesaurusCacheMaxSize) + .expireAfterAccess(25, TimeUnit.HOURS) + .build(); this.isoLanguageMapper = isoLanguageMapper; this.fname = fname; @@ -186,7 +194,6 @@ public Thesaurus(IsoLanguagesMapper isoLanguageMapper, String fname, } /** - * * @param fname * @param type * @param dname @@ -204,7 +211,7 @@ public Map getMultilingualTitles() { return Collections.unmodifiableMap(this.multilingualTitles); } - public Map> getDublinCoreMultilingual() { + public Map> getDublinCoreMultilingual() { return Collections.unmodifiableMap(this.dublinCoreMultilingual); } @@ -258,6 +265,18 @@ public String getDate() { return date; } + public String getCreatedDate() { + return createdDate; + } + + public String getIssuedDate() { + return issuedDate; + } + + public String getModifiedDate() { + return modifiedDate; + } + @Nonnull public FileTime getLastModifiedTime() { FileTime lastModified; @@ -313,7 +332,7 @@ public synchronized Thesaurus initRepository() throws ConfigurationException, IO SailConfig syncSail = new SailConfig("org.openrdf.sesame.sailimpl.sync.SyncRdfSchemaRepository"); SailConfig memSail = new org.openrdf.sesame.sailimpl.memory.RdfSchemaRepositoryConfig(getFile().toString(), - RDFFormat.RDFXML); + RDFFormat.RDFXML); repConfig.addSail(syncSail); repConfig.addSail(memSail); repConfig.setWorldReadable(true); @@ -325,7 +344,7 @@ public synchronized Thesaurus initRepository() throws ConfigurationException, IO } public synchronized QueryResultsTable performRequest(String query) throws IOException, MalformedQueryException, - QueryEvaluationException, AccessDeniedException { + QueryEvaluationException, AccessDeniedException { if (Log.isDebugEnabled(Geonet.THESAURUS)) Log.debug(Geonet.THESAURUS, "Query : " + query); @@ -335,14 +354,15 @@ public synchronized QueryResultsTable performRequest(String query) throws IOExce public boolean hasConceptScheme(String uri) { String query = "SELECT conceptScheme" - + " FROM {conceptScheme} rdf:type {skos:ConceptScheme}" - + " WHERE conceptScheme = <" + uri + ">" - + " USING NAMESPACE skos = "; + + " FROM {conceptScheme} rdf:type {skos:ConceptScheme}" + + " WHERE conceptScheme = <" + uri + ">" + + " USING NAMESPACE skos = "; try { return performRequest(query).getRowCount() > 0; } catch (Exception e) { - Log.error(Geonet.THESAURUS_MAN, "Error retrieving concept scheme for " + thesaurusFile + ". Error is: " + e.getMessage()); + Log.error(Geonet.THESAURUS_MAN, + String.format("Error retrieving concept scheme for %s. Error is: %s", thesaurusFile, e.getMessage())); throw new RuntimeException(e); } } @@ -350,8 +370,8 @@ public boolean hasConceptScheme(String uri) { public List getConceptSchemes() { String query = "SELECT conceptScheme" - + " FROM {conceptScheme} rdf:type {skos:ConceptScheme}" - + " USING NAMESPACE skos = "; + + " FROM {conceptScheme} rdf:type {skos:ConceptScheme}" + + " USING NAMESPACE skos = "; try { List ret = new ArrayList<>(); @@ -362,7 +382,8 @@ public List getConceptSchemes() { } return ret; } catch (Exception e) { - Log.error(Geonet.THESAURUS_MAN, "Error retrieving concept schemes for " + thesaurusFile + ". Error is: " + e.getMessage()); + Log.error(Geonet.THESAURUS_MAN, String.format( + "Error retrieving concept schemes for %s. Error is: %s", thesaurusFile, e.getMessage())); return Collections.emptyList(); } } @@ -385,34 +406,28 @@ public synchronized URI addElement(KeywordBean keyword) throws IOException, Acce URI mySubject = myFactory.createURI(keyword.getUriCode()); URI skosClass = myFactory.createURI(SKOS_NAMESPACE, "Concept"); + URI rdfType = myFactory.createURI(org.openrdf.vocabulary.RDF.TYPE); + mySubject.addProperty(rdfType, skosClass); + URI predicatePrefLabel = myFactory - .createURI(SKOS_NAMESPACE, "prefLabel"); + .createURI(SKOS_NAMESPACE, "prefLabel"); URI predicateScopeNote = myFactory - .createURI(SKOS_NAMESPACE, "scopeNote"); - - URI predicateBoundedBy = myFactory.createURI(namespaceGml, "BoundedBy"); - URI predicateEnvelope = myFactory.createURI(namespaceGml, "Envelope"); - URI predicateSrsName = myFactory.createURI(namespaceGml, "srsName"); - URI srsNameURI = myFactory - .createURI("http://www.opengis.net/gml/srs/epsg.xml#epsg:4326"); - BNode gmlNode = myFactory.createBNode(); - URI predicateLowerCorner = myFactory.createURI(namespaceGml, - "lowerCorner"); - URI predicateUpperCorner = myFactory.createURI(namespaceGml, - "upperCorner"); - - Literal lowerCorner = myFactory.createLiteral(keyword.getCoordWest() + " " + keyword.getCoordSouth()); - Literal upperCorner = myFactory.createLiteral(keyword.getCoordEast() + " " + keyword.getCoordNorth()); + .createURI(SKOS_NAMESPACE, "scopeNote"); + + URI predicateInScheme = myFactory + .createURI(SKOS_NAMESPACE, "inScheme"); + myGraph.add(mySubject, + predicateInScheme, + myFactory.createURI(this.getDefaultNamespace())); - mySubject.addProperty(rdfType, skosClass); Set> values = keyword.getValues().entrySet(); for (Entry entry : values) { String language = toiso639_1_Lang(entry.getKey()); Value valueObj = myFactory.createLiteral(entry.getValue(), language); myGraph.add(mySubject, predicatePrefLabel, valueObj); - } + Set> definitions = keyword.getDefinitions().entrySet(); for (Entry entry : definitions) { String language = toiso639_1_Lang(entry.getKey()); @@ -420,12 +435,29 @@ public synchronized URI addElement(KeywordBean keyword) throws IOException, Acce myGraph.add(mySubject, predicateScopeNote, definitionObj); } - myGraph.add(mySubject, predicateBoundedBy, gmlNode); - gmlNode.addProperty(rdfType, predicateEnvelope); - myGraph.add(gmlNode, predicateLowerCorner, lowerCorner); - myGraph.add(gmlNode, predicateUpperCorner, upperCorner); - myGraph.add(gmlNode, predicateSrsName, srsNameURI); + if (!(keyword.getCoordEast() + keyword.getCoordNorth() + keyword.getCoordWest() + keyword.getCoordSouth()).trim().isEmpty()) { + URI predicateBoundedBy = myFactory.createURI(namespaceGml, "BoundedBy"); + URI predicateEnvelope = myFactory.createURI(namespaceGml, "Envelope"); + URI predicateSrsName = myFactory.createURI(namespaceGml, "srsName"); + URI srsNameURI = myFactory + .createURI("http://www.opengis.net/gml/srs/epsg.xml#epsg:4326"); + BNode gmlNode = myFactory.createBNode(); + URI predicateLowerCorner = myFactory.createURI(namespaceGml, + "lowerCorner"); + URI predicateUpperCorner = myFactory.createURI(namespaceGml, + "upperCorner"); + + Literal lowerCorner = myFactory.createLiteral(keyword.getCoordWest() + " " + keyword.getCoordSouth()); + Literal upperCorner = myFactory.createLiteral(keyword.getCoordEast() + " " + keyword.getCoordNorth()); + + myGraph.add(mySubject, predicateBoundedBy, gmlNode); + + gmlNode.addProperty(rdfType, predicateEnvelope); + myGraph.add(gmlNode, predicateLowerCorner, lowerCorner); + myGraph.add(gmlNode, predicateUpperCorner, upperCorner); + myGraph.add(gmlNode, predicateSrsName, srsNameURI); + } repository.addGraph(myGraph); return mySubject; @@ -434,8 +466,7 @@ public synchronized URI addElement(KeywordBean keyword) throws IOException, Acce /** * Remove keyword from thesaurus. */ - public synchronized Thesaurus removeElement(KeywordBean keyword) throws MalformedQueryException, - QueryEvaluationException, IOException, AccessDeniedException { + public synchronized Thesaurus removeElement(KeywordBean keyword) throws AccessDeniedException { String namespace = keyword.getNameSpaceCode(); String code = keyword.getRelativeCode(); @@ -465,7 +496,7 @@ public synchronized Thesaurus removeElement(String uri) throws AccessDeniedExcep } private Thesaurus removeElement(Graph myGraph, URI subject) - throws AccessDeniedException { + throws AccessDeniedException { StatementIterator iter = myGraph.getStatements(subject, null, null); while (iter.hasNext()) { AtomicReference st = new AtomicReference(iter.next()); @@ -484,8 +515,8 @@ private Thesaurus removeElement(Graph myGraph, URI subject) private String toiso639_1_Lang(String lang) { String defaultCode = getIsoLanguageMapper().iso639_2_to_iso639_1( - Geonet.DEFAULT_LANGUAGE, - Geonet.DEFAULT_LANGUAGE.substring(0, 2)); + Geonet.DEFAULT_LANGUAGE, + Geonet.DEFAULT_LANGUAGE.substring(0, 2)); return getIsoLanguageMapper().iso639_2_to_iso639_1(lang, defaultCode); } @@ -500,8 +531,7 @@ private String toiso639_1_Lang(String lang) { * languages) and the coordinates will only be updated if they are non-empty * strings. */ - public synchronized URI updateElement(KeywordBean keyword, boolean replace) throws AccessDeniedException, IOException, - MalformedQueryException, QueryEvaluationException, GraphException { + public synchronized URI updateElement(KeywordBean keyword, boolean replace) throws AccessDeniedException { THESAURUS_SEARCH_CACHE.invalidateAll(); // Get thesaurus graph @@ -529,15 +559,14 @@ public synchronized URI updateElement(KeywordBean keyword, boolean replace) thro String language = toiso639_1_Lang(entry.getKey()); Value valueObj = myFactory.createLiteral(entry.getValue(), language); myGraph.add(subject, predicatePrefLabel, valueObj); - } + // add updated Definitions/Notes Set> definitions = keyword.getDefinitions().entrySet(); for (Entry entry : definitions) { String language = toiso639_1_Lang(entry.getKey()); Value definitionObj = myFactory.createLiteral(entry.getValue(), language); myGraph.add(subject, predicateScopeNote, definitionObj); - } // update bbox @@ -643,7 +672,7 @@ public Thesaurus updateCode(KeywordBean bean, String newcode) throws AccessDenie * Update concept code by creating URI from namespace and code. This is recommended when * thesaurus concept identifiers contains # eg. http://vocab.nerc.ac.uk/collection/P07/current#CFV13N44 */ - public synchronized Thesaurus updateCode(String namespace, String oldcode, String newcode) throws AccessDeniedException, IOException { + public synchronized Thesaurus updateCode(String namespace, String oldcode, String newcode) throws AccessDeniedException { Graph myGraph = repository.getGraph(); ValueFactory myFactory = myGraph.getValueFactory(); @@ -658,10 +687,10 @@ public synchronized Thesaurus updateCode(String namespace, String oldcode, Strin /** * Update concept code using its URI. This is recommended when concept identifier may not be * based on thesaurus namespace and does not contains #. - * + *

* eg. http://vocab.nerc.ac.uk/collection/P07/current/CFV13N44/ */ - public synchronized Thesaurus updateCodeByURI(String olduri, String newuri) throws AccessDeniedException, IOException { + public synchronized Thesaurus updateCodeByURI(String olduri, String newuri) throws AccessDeniedException { Graph myGraph = repository.getGraph(); ValueFactory myFactory = myGraph.getValueFactory(); @@ -710,13 +739,13 @@ public void createConceptScheme(String thesaurusTitle, Graph myGraph = new org.openrdf.model.impl.GraphImpl(); writeConceptScheme(myGraph, - thesaurusTitle, - multilingualTitles, - thesaurusDescription, - multilingualDescriptions, - identifier, - type, - namespace); + thesaurusTitle, + multilingualTitles, + thesaurusDescription, + multilingualDescriptions, + identifier, + type, + namespace); repository.addGraph(myGraph); } @@ -736,13 +765,13 @@ public void updateConceptScheme(String thesaurusTitle, removeElement(getConceptSchemes().get(0)); writeConceptScheme(myGraph, - thesaurusTitle, - multilingualTitles, - thesaurusDescription, - multilingualDescriptions, - identifier, - type, - namespace); + thesaurusTitle, + multilingualTitles, + thesaurusDescription, + multilingualDescriptions, + identifier, + type, + namespace); } public void writeConceptScheme(Graph myGraph, String thesaurusTitle, @@ -804,9 +833,6 @@ public void writeConceptScheme(Graph myGraph, String thesaurusTitle, } - - - private void addElement(String name, String value, Graph myGraph, ValueFactory myFactory, URI mySubject) { if (StringUtils.isNotEmpty(value)) { URI uri = myFactory.createURI(DC_NAMESPACE, name); @@ -842,22 +868,22 @@ private void addElement(String name, String value, Graph myGraph, ValueFactory m private void retrieveDublinCore(Element thesaurusEl) { List theNSs = getThesaurusNamespaces(); - Namespace xmlNS = Namespace.getNamespace("xml","http://www.w3.org/XML/1998/namespace"); + Namespace xmlNS = Namespace.getNamespace("xml", "http://www.w3.org/XML/1998/namespace"); try { List multiLingualTitles = (List) Xml.selectNodes(thesaurusEl, - "skos:ConceptScheme/dc:*[@xml:lang]|skos:ConceptScheme/dcterms:*[@xml:lang]", theNSs); + "skos:ConceptScheme/dc:*[@xml:lang]|skos:ConceptScheme/dcterms:*[@xml:lang]", theNSs); dublinCoreMultilingual.clear(); - for (Element el: multiLingualTitles) { + for (Element el : multiLingualTitles) { String lang = isoLanguageMapper.iso639_2_to_iso639_1(el.getAttribute("lang", xmlNS).getValue()); String value = el.getTextTrim(); String name = el.getName(); if (!dublinCoreMultilingual.containsKey(lang)) { - dublinCoreMultilingual.put(lang,new HashMap<>()); + dublinCoreMultilingual.put(lang, new HashMap<>()); } - dublinCoreMultilingual.get(lang).put(name,value); + dublinCoreMultilingual.get(lang).put(name, value); } } catch (Exception e) { - Log.warning(Geonet.THESAURUS,"error extracting multilingual dublin core items from thesaurus",e); + Log.warning(Geonet.THESAURUS, "error extracting multilingual dublin core items from thesaurus", e); } } @@ -876,11 +902,15 @@ private void retrieveDublinCore(Element thesaurusEl) { // } private void retrieveMultiLingualTitles(Element thesaurusEl) { try { - String xpathTitles = "skos:ConceptScheme/dc:title[@xml:lang]|skos:ConceptScheme/dcterms:title[@xml:lang]|rdf:Description[rdf:type/@rdf:resource = 'http://www.w3.org/2004/02/skos/core#ConceptScheme']/dc:title[@xml:lang]"; + String xpathTitles = "skos:ConceptScheme/dc:title[@xml:lang]" + + "|skos:ConceptScheme/dcterms:title[@xml:lang]" + + "|skos:ConceptScheme/rdfs:label[@xml:lang]" + + "|skos:ConceptScheme/skos:prefLabel[@xml:lang]" + + "|rdf:Description[rdf:type/@rdf:resource = 'http://www.w3.org/2004/02/skos/core#ConceptScheme']/dc:title[@xml:lang]"; multilingualTitles.clear(); multilingualTitles.putAll(retrieveMultilingualField(thesaurusEl, xpathTitles)); } catch (Exception e) { - Log.warning(Geonet.THESAURUS,"error extracting multilingual titles from thesaurus",e); + Log.warning(Geonet.THESAURUS, "error extracting multilingual titles from thesaurus", e); } } @@ -890,19 +920,19 @@ private void retrieveMultiLingualDescriptions(Element thesaurusEl) { multilingualDescriptions.clear(); multilingualDescriptions.putAll(retrieveMultilingualField(thesaurusEl, xpathDescriptions)); } catch (Exception e) { - Log.warning(Geonet.THESAURUS,"error extracting multilingual descriptions from thesaurus",e); + Log.warning(Geonet.THESAURUS, "error extracting multilingual descriptions from thesaurus", e); } } private Map retrieveMultilingualField(Element thesaurusEl, String xpath) throws JDOMException { List theNSs = getThesaurusNamespaces(); - Namespace xmlNS = Namespace.getNamespace("xml","http://www.w3.org/XML/1998/namespace"); + Namespace xmlNS = Namespace.getNamespace("xml", "http://www.w3.org/XML/1998/namespace"); Map multilingualValues = new HashMap<>(); List multilingualValuesEl = (List) Xml.selectNodes(thesaurusEl, - xpath, theNSs); - for (Element el: multilingualValuesEl) { + xpath, theNSs); + for (Element el : multilingualValuesEl) { String lang = isoLanguageMapper.iso639_2_to_iso639_1(el.getAttribute("lang", xmlNS).getValue()); String titleValue = el.getTextTrim(); multilingualValues.put(lang, titleValue); @@ -913,7 +943,7 @@ private Map retrieveMultilingualField(Element thesaurusEl, Strin /** * Retrieves the thesaurus information from rdf file. - * + *

* Used to set the thesaurusName and thesaurusDate for keywords. */ private void retrieveThesaurusInformation(Path thesaurusFile, String defaultTitle, boolean ignoreMissingError) { @@ -926,34 +956,32 @@ private void retrieveThesaurusInformation(Path thesaurusFile, String defaultTitl try { Element thesaurusEl = Xml.loadFile(thesaurusFile); - List theNSs = new ArrayList<>(); - Namespace rdfNamespace = Namespace.getNamespace("rdf", RDF_NAMESPACE); - theNSs.add(rdfNamespace); - theNSs.add(Namespace.getNamespace("skos", SKOS_NAMESPACE)); - theNSs.add(Namespace.getNamespace("dc", DC_NAMESPACE)); - theNSs.add(Namespace.getNamespace("dcterms", DCTERMS_NAMESPACE)); + List theNSs = getThesaurusNamespaces(); this.defaultNamespace = null; retrieveMultiLingualTitles(thesaurusEl); retrieveDublinCore(thesaurusEl); Element titleEl = Xml.selectElement(thesaurusEl, - "skos:ConceptScheme/dc:title|skos:ConceptScheme/dcterms:title|" + - "skos:Collection/dc:title|skos:Collection/dcterms:title|" + - "rdf:Description/dc:title|rdf:Description/dcterms:title", theNSs); + "skos:ConceptScheme/dc:title|skos:ConceptScheme/dcterms:title" + + "|skos:ConceptScheme/rdfs:label|skos:ConceptScheme/skos:prefLabel" + + "|skos:Collection/dc:title|skos:Collection/dcterms:title" + + "|rdf:Description/dc:title|rdf:Description/dcterms:title", theNSs); if (titleEl != null) { this.title = titleEl.getValue(); - this.defaultNamespace = titleEl.getParentElement().getAttributeValue("about", rdfNamespace); + this.defaultNamespace = titleEl + .getParentElement() + .getAttributeValue("about", Namespace.getNamespace("rdf", RDF_NAMESPACE)); } else { this.title = defaultTitle; this.defaultNamespace = DEFAULT_THESAURUS_NAMESPACE; } Element descriptionEl = Xml.selectElement(thesaurusEl, - "skos:ConceptScheme/dc:description|skos:ConceptScheme/dcterms:description|" + - "skos:Collection/dc:description|skos:Collection/dcterms:description|" + - "rdf:Description/dc:description|rdf:Description/dcterms:description", theNSs); + "skos:ConceptScheme/dc:description|skos:ConceptScheme/dcterms:description|" + + "skos:Collection/dc:description|skos:Collection/dcterms:description|" + + "rdf:Description/dc:description|rdf:Description/dcterms:description", theNSs); this.description = descriptionEl != null ? descriptionEl.getValue() : ""; @@ -965,8 +993,17 @@ private void retrieveThesaurusInformation(Path thesaurusFile, String defaultTitl this.defaultNamespace = DEFAULT_THESAURUS_NAMESPACE; } - Element dateEl = Xml.selectElement(thesaurusEl, "skos:ConceptScheme/dcterms:issued|skos:Collection/dc:date", theNSs); + Element issuedDateEl = Xml.selectElement(thesaurusEl, "skos:ConceptScheme/dcterms:issued", theNSs); + this.issuedDate = issuedDateEl == null ? "" : issuedDateEl.getText(); + + Element modifiedDateEl = Xml.selectElement(thesaurusEl, "skos:ConceptScheme/dcterms:modified", theNSs); + this.modifiedDate = modifiedDateEl == null ? "" : modifiedDateEl.getText(); + Element createdDateEl = Xml.selectElement(thesaurusEl, "skos:ConceptScheme/dcterms:created", theNSs); + this.createdDate = createdDateEl == null ? "" : createdDateEl.getText(); + + // Default date + Element dateEl = Xml.selectElement(thesaurusEl, "skos:ConceptScheme/dcterms:issued|skos:Collection/dc:date", theNSs); Date thesaususDate = parseThesaurusDate(dateEl); if (thesaususDate == null) { @@ -1000,11 +1037,13 @@ private void retrieveThesaurusInformation(Path thesaurusFile, String defaultTitl } if (Log.isDebugEnabled(Geonet.THESAURUS_MAN)) { - Log.debug(Geonet.THESAURUS_MAN, "Thesaurus information: " + this.title + " (" + this.date + ")"); + Log.debug(Geonet.THESAURUS_MAN, String.format( + "Thesaurus information: %s (%s)", this.title, this.date)); } } catch (Exception ex) { if (!ignoreMissingError) - Log.error(Geonet.THESAURUS_MAN, "Error getting thesaurus info for " + thesaurusFile + ". Error is: " + ex.getMessage()); + Log.error(Geonet.THESAURUS_MAN, String.format( + "Error getting thesaurus info for %s. Error is: %s", thesaurusFile, ex.getMessage())); } } @@ -1027,15 +1066,16 @@ private Date parseThesaurusDate(Element dateEl) { dfList.add(new SimpleDateFormat("EEE MMM d HH:mm:ss z yyyy")); dfList.add(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); dfList.add(new SimpleDateFormat("yyyy-MM-dd")); + dfList.add(new SimpleDateFormat("yyyy-MM")); + dfList.add(new SimpleDateFormat("yyyy")); StringBuffer errorMsg = new StringBuffer("Error parsing the thesaurus date value: "); errorMsg.append(dateVal); - boolean success = false; for (SimpleDateFormat df : dfList) { try { thesaurusDate = df.parse(dateVal); - success = true; + return thesaurusDate; } catch (Exception ex) { // Ignore the exception and try next format errorMsg.append("\n * with format: "); @@ -1045,11 +1085,9 @@ private Date parseThesaurusDate(Element dateEl) { } } // Report error if no success - if (!success) { - errorMsg.append("\nCheck thesaurus date in "); - errorMsg.append(this.fname); - Log.error(Geonet.THESAURUS_MAN, errorMsg.toString()); - } + errorMsg.append("\nCheck thesaurus date in "); + errorMsg.append(this.fname); + Log.error(Geonet.THESAURUS_MAN, errorMsg.toString()); return thesaurusDate; } @@ -1073,8 +1111,7 @@ public IsoLanguagesMapper getIsoLanguageMapper() { * @param subject the keyword that is related to the other keyword * @param related the relation between the two keywords */ - public synchronized void addRelation(String subject, KeywordRelation related, String relatedSubject) throws AccessDeniedException, IOException, - MalformedQueryException, QueryEvaluationException, GraphException { + public synchronized void addRelation(String subject, KeywordRelation related, String relatedSubject) throws AccessDeniedException { THESAURUS_SEARCH_CACHE.invalidateAll(); Graph myGraph = repository.getGraph(); @@ -1097,7 +1134,7 @@ public synchronized void addRelation(String subject, KeywordRelation related, St * @return keyword */ public KeywordBean getKeyword(String uri, String... languages) { - String cacheKey = "getKeyword" + uri + Arrays.stream(languages).collect(Collectors.joining("")); + String cacheKey = "getKeyword" + uri + String.join("", languages); Object cacheValue = THESAURUS_SEARCH_CACHE.getIfPresent(cacheKey); if (cacheValue != null) { return (KeywordBean) cacheValue; @@ -1107,9 +1144,9 @@ public KeywordBean getKeyword(String uri, String... languages) { try { Query query = QueryBuilder - .keywordQueryBuilder(getIsoLanguageMapper(), languages) - .where(Wheres.ID(uri)) - .build(); + .keywordQueryBuilder(getIsoLanguageMapper(), languages) + .where(Wheres.ID(uri)) + .build(); keywords = query.execute(this); } catch (Exception e) { @@ -1135,9 +1172,9 @@ public List getTopConcepts(String... languages) { try { Query query = QueryBuilder - .keywordQueryBuilder(getIsoLanguageMapper(), languages) - .select(Selectors.TOPCONCEPTS, true) - .build(); + .keywordQueryBuilder(getIsoLanguageMapper(), languages) + .select(Selectors.TOPCONCEPTS, true) + .build(); keywords = query.execute(this); } catch (Exception e) { @@ -1205,9 +1242,9 @@ public boolean hasBroader(String uri) { */ public List getRelated(String uri, KeywordRelation request, String... languages) { Query query = QueryBuilder - .keywordQueryBuilder(getIsoLanguageMapper(), languages) - .select(Selectors.related(uri, request), true) - .build(); + .keywordQueryBuilder(getIsoLanguageMapper(), languages) + .select(Selectors.related(uri, request), true) + .build(); try { return query.execute(this); @@ -1242,9 +1279,9 @@ public boolean hasKeywordWithLabel(String label, String langCode) { */ public KeywordBean getKeywordWithLabel(String label, String langCode) { Query query = QueryBuilder - .keywordQueryBuilder(getIsoLanguageMapper(), langCode) - .where(Wheres.prefLabel(langCode, label)) - .build(); + .keywordQueryBuilder(getIsoLanguageMapper(), langCode) + .where(Wheres.prefLabel(langCode, label)) + .build(); List matchingKeywords; @@ -1274,7 +1311,7 @@ public Map getTitles(ApplicationContext context) throws JDOMExce return LangUtils.translate(context, getKey()); } - public List getKeywordHierarchy(String keywordLabel, String langCode) { + public List getKeywordHierarchy(String keywordLabel, String langCode) { String cacheKey = "getKeywordHierarchy" + keywordLabel + langCode; Object cacheValue = THESAURUS_SEARCH_CACHE.getIfPresent(cacheKey); if (cacheValue != null) { @@ -1282,26 +1319,26 @@ public List getKeywordHierarchy(String keywordLabel, String langCode) { } boolean isUri = keywordLabel.startsWith("http"); KeywordBean term = - isUri - ? this.getKeyword(keywordLabel, langCode) - : this.getKeywordWithLabel(keywordLabel, langCode); + isUri + ? this.getKeyword(keywordLabel, langCode) + : this.getKeywordWithLabel(keywordLabel, langCode); - List> result = this.classify(term, langCode); + List> result = this.classify(term, langCode); - List hierarchies = new ArrayList<>(); - for ( List hierachy : result) { + List hierarchies = new ArrayList<>(); + for (List hierachy : result) { String path = hierachy.stream() - .map(k -> isUri ? k.getUriCode() : k.getPreferredLabel(langCode)) - .collect(Collectors.joining("^")); + .map(k -> isUri ? k.getUriCode() : k.getPreferredLabel(langCode)) + .collect(Collectors.joining("^")); hierarchies.add(path); } THESAURUS_SEARCH_CACHE.put(cacheKey, hierarchies); return hierarchies; } - public List> classify(KeywordBean term, String langCode) { + public List> classify(KeywordBean term, String langCode) { - List> result = new ArrayList<>(); + List> result = new ArrayList<>(); if (this.hasBroader(term.getUriCode())) { result.addAll(classifyTermWithBroaderTerms(term, langCode)); } else { @@ -1310,16 +1347,16 @@ public List> classify(KeywordBean term, String langCode) return result; } - private List> classifyTermWithBroaderTerms(KeywordBean term, String langCode) { - List> result = new ArrayList<>(); - for (ArrayList stringToBroaderTerm : classifyBroaderTerms(term, langCode)) { + private List> classifyTermWithBroaderTerms(KeywordBean term, String langCode) { + List> result = new ArrayList<>(); + for (ArrayList stringToBroaderTerm : classifyBroaderTerms(term, langCode)) { stringToBroaderTerm.add(term); result.add(stringToBroaderTerm); } return result; } - private List> classifyBroaderTerms(KeywordBean term, String langCode) { + private List> classifyBroaderTerms(KeywordBean term, String langCode) { List> result = new ArrayList<>(); List narrowerList = this.getNarrower(term.getUriCode(), langCode); for (KeywordBean broaderTerm : this.getBroader(term.getUriCode(), langCode)) { @@ -1331,8 +1368,8 @@ private List> classifyBroaderTerms(KeywordBean term, Str return result; } - private ArrayList classifyTermWithNoBroaderTerms(KeywordBean term) { - ArrayList list = new ArrayList <>(); + private ArrayList classifyTermWithNoBroaderTerms(KeywordBean term) { + ArrayList list = new ArrayList<>(); list.add(term); return list; } @@ -1341,6 +1378,7 @@ private ArrayList classifyTermWithNoBroaderTerms(KeywordBean term) private List getThesaurusNamespaces() { List theNSs = new ArrayList<>(); theNSs.add(Namespace.getNamespace("rdf", RDF_NAMESPACE)); + theNSs.add(Namespace.getNamespace("rdfs", RDF_SCHEMA_NAMESPACE)); theNSs.add(Namespace.getNamespace("skos", SKOS_NAMESPACE)); theNSs.add(Namespace.getNamespace("dc", DC_NAMESPACE)); theNSs.add(Namespace.getNamespace("dcterms", DCTERMS_NAMESPACE)); diff --git a/core/src/main/java/org/fao/geonet/kernel/ThesaurusManager.java b/core/src/main/java/org/fao/geonet/kernel/ThesaurusManager.java index 62d7a83bcfd..a48563dc3d2 100644 --- a/core/src/main/java/org/fao/geonet/kernel/ThesaurusManager.java +++ b/core/src/main/java/org/fao/geonet/kernel/ThesaurusManager.java @@ -551,6 +551,18 @@ public Element buildResultfromThTable(ServiceContext context) throws SQLExceptio String date = currentTh.getDate(); elDate.addContent(date); + Element elCreatedDate = new Element("createdDate"); + String createdDate = currentTh.getCreatedDate(); + elCreatedDate.addContent(createdDate); + + Element elIssuedDate = new Element("issuedDate"); + String issuedDate = currentTh.getIssuedDate(); + elIssuedDate.addContent(issuedDate); + + Element elModifiedDate = new Element("modifiedDate"); + String modifiedDate = currentTh.getModifiedDate(); + elModifiedDate.addContent(modifiedDate); + Element elUrl = new Element("url"); String url = currentTh.getDownloadUrl(); elUrl.addContent(url); @@ -568,6 +580,9 @@ public Element buildResultfromThTable(ServiceContext context) throws SQLExceptio elLoop.addContent(elDublinCoreMultilingual); elLoop.addContent(elMultilingualDescriptions); elLoop.addContent(elDate); + elLoop.addContent(elCreatedDate); + elLoop.addContent(elIssuedDate); + elLoop.addContent(elModifiedDate); elLoop.addContent(elUrl); elLoop.addContent(elDefaultURI); elLoop.addContent(elType); diff --git a/core/src/main/java/org/fao/geonet/kernel/WatchListNotifier.java b/core/src/main/java/org/fao/geonet/kernel/WatchListNotifier.java index 7291dd8ff8b..09a17638f1a 100644 --- a/core/src/main/java/org/fao/geonet/kernel/WatchListNotifier.java +++ b/core/src/main/java/org/fao/geonet/kernel/WatchListNotifier.java @@ -30,9 +30,13 @@ import org.fao.geonet.domain.Selection; import org.fao.geonet.domain.User; import org.fao.geonet.kernel.setting.SettingManager; +import org.fao.geonet.languages.FeedbackLanguages; import org.fao.geonet.repository.SelectionRepository; import org.fao.geonet.repository.UserRepository; import org.fao.geonet.repository.UserSavedSelectionRepository; +import org.fao.geonet.util.LocalizedEmail; +import org.fao.geonet.util.LocalizedEmailParameter; +import org.fao.geonet.util.LocalizedEmailComponent; import org.fao.geonet.util.MailUtil; import org.fao.geonet.utils.Log; import org.quartz.JobExecutionContext; @@ -44,6 +48,10 @@ import java.util.*; import static org.fao.geonet.kernel.setting.Settings.SYSTEM_USER_LASTNOTIFICATIONDATE; +import static org.fao.geonet.util.LocalizedEmailComponent.ComponentType.*; +import static org.fao.geonet.util.LocalizedEmailComponent.KeyType; +import static org.fao.geonet.util.LocalizedEmailComponent.ReplacementType.*; +import static org.fao.geonet.util.LocalizedEmailParameter.ParameterType; /** * Task checking on a regular basis the list of records @@ -53,15 +61,13 @@ public class WatchListNotifier extends QuartzJobBean { private String lastNotificationDate; private String nextLastNotificationDate; - private String subject; - private String message; - private String recordMessage; private String updatedRecordPermalink; private String language = "eng"; private SettingManager settingManager; private ApplicationContext appContext; private UserSavedSelectionRepository userSavedSelectionRepository; private UserRepository userRepository; + private FeedbackLanguages feedbackLanguages; @Value("${usersavedselection.watchlist.searchurl}") private String permalinkApp = "catalog.search#/search?_uuid={{filter}}"; @@ -92,20 +98,7 @@ public WatchListNotifier() { protected void executeInternal(JobExecutionContext jobContext) throws JobExecutionException { appContext = ApplicationContextHolder.get(); settingManager = appContext.getBean(SettingManager.class); - - ResourceBundle messages = ResourceBundle.getBundle("org.fao.geonet.api.Messages", - new Locale( - language - )); - - try { - subject = messages.getString("user_watchlist_subject"); - message = messages.getString("user_watchlist_message"); - recordMessage = messages.getString("user_watchlist_message_record"). - replace("{{link}}", - settingManager.getNodeURL() + permalinkRecordApp); - } catch (Exception e) { - } + feedbackLanguages = appContext.getBean(FeedbackLanguages.class); updatedRecordPermalink = settingManager.getSiteURL(language); @@ -166,6 +159,9 @@ protected void executeInternal(JobExecutionContext jobContext) throws JobExecuti } private void notify(Integer selectionId, Integer userId) { + + Locale[] feedbackLocales = feedbackLanguages.getLocales(new Locale(language)); + // Get metadata with changes since last notification // TODO: Could be relevant to get versionning system info once available // and report deleted records too. @@ -188,27 +184,51 @@ private void notify(Integer selectionId, Integer userId) { // TODO: We should send email depending on user language Optional user = userRepository.findById(userId); if (user.isPresent() && StringUtils.isNotEmpty(user.get().getEmail())) { + String url = updatedRecordPermalink + + permalinkApp.replace("{{filter}}", String.join(" or ", updatedRecords)); - // Build message - StringBuffer listOfUpdateMessage = new StringBuffer(); - for (String record : updatedRecords) { - try { - listOfUpdateMessage.append( - MailUtil.compileMessageWithIndexFields(recordMessage, record, this.language) - ); - } catch (Exception e) { - Log.error(Geonet.USER_WATCHLIST, e.getMessage(), e); + LocalizedEmailComponent emailSubjectComponent = new LocalizedEmailComponent(SUBJECT, "user_watchlist_subject", KeyType.MESSAGE_KEY, POSITIONAL_FORMAT); + LocalizedEmailComponent emailMessageComponent = new LocalizedEmailComponent(MESSAGE, "user_watchlist_message", KeyType.MESSAGE_KEY, POSITIONAL_FORMAT); + + for (Locale feedbackLocale : feedbackLocales) { + + // Build message + StringBuffer listOfUpdateMessage = new StringBuffer(); + for (String record : updatedRecords) { + LocalizedEmailComponent recordMessageComponent = new LocalizedEmailComponent(NESTED, "user_watchlist_message_record", KeyType.MESSAGE_KEY, NAMED_FORMAT); + recordMessageComponent.enableCompileWithIndexFields(record); + recordMessageComponent.enableReplaceLinks(true); + try { + listOfUpdateMessage.append( + recordMessageComponent.parseMessage(feedbackLocale) + ); + } catch (Exception e) { + Log.error(Geonet.USER_WATCHLIST, e.getMessage(), e); + } } + + emailSubjectComponent.addParameters( + feedbackLocale, + new LocalizedEmailParameter(ParameterType.RAW_VALUE, 1, settingManager.getSiteName()), + new LocalizedEmailParameter(ParameterType.RAW_VALUE, 2, updatedRecords.size()), + new LocalizedEmailParameter(ParameterType.RAW_VALUE, 3, lastNotificationDate) + ); + + emailMessageComponent.addParameters( + feedbackLocale, + new LocalizedEmailParameter(ParameterType.RAW_VALUE, 1, listOfUpdateMessage.toString()), + new LocalizedEmailParameter(ParameterType.RAW_VALUE, 2, lastNotificationDate), + new LocalizedEmailParameter(ParameterType.RAW_VALUE, 3, url), + new LocalizedEmailParameter(ParameterType.RAW_VALUE, 4, url) + ); + } - String url = updatedRecordPermalink + - permalinkApp.replace("{{filter}}", String.join(" or ", updatedRecords)); - String mailSubject = String.format(subject, - settingManager.getSiteName(), updatedRecords.size(), lastNotificationDate); - String htmlMessage = String.format(message, - listOfUpdateMessage.toString(), - lastNotificationDate, - url, url); + LocalizedEmail localizedEmail = new LocalizedEmail(true); + localizedEmail.addComponents(emailSubjectComponent, emailMessageComponent); + + String mailSubject = localizedEmail.getParsedSubject(feedbackLocales); + String htmlMessage = localizedEmail.getParsedMessage(feedbackLocales); if (Log.isDebugEnabled(Geonet.USER_WATCHLIST)) { Log.debug(Geonet.USER_WATCHLIST, String.format( diff --git a/core/src/main/java/org/fao/geonet/kernel/XmlSerializer.java b/core/src/main/java/org/fao/geonet/kernel/XmlSerializer.java index 4e0840d5a68..fd22881c373 100644 --- a/core/src/main/java/org/fao/geonet/kernel/XmlSerializer.java +++ b/core/src/main/java/org/fao/geonet/kernel/XmlSerializer.java @@ -36,6 +36,7 @@ import org.fao.geonet.kernel.datamanager.IMetadataManager; import org.fao.geonet.kernel.datamanager.IMetadataUtils; import org.fao.geonet.kernel.schema.MetadataSchema; +import org.fao.geonet.kernel.schema.MetadataSchemaOperationFilter; import org.fao.geonet.kernel.setting.SettingManager; import org.fao.geonet.kernel.setting.Settings; import org.fao.geonet.utils.Log; @@ -53,34 +54,19 @@ * (id, data, lastChangeDate). */ public abstract class XmlSerializer { - private static InheritableThreadLocal configThreadLocal = new InheritableThreadLocal(); - - public static ThreadLocalConfiguration getThreadLocal(boolean setIfNotPresent) { - ThreadLocalConfiguration config = configThreadLocal.get(); - if (config == null && setIfNotPresent) { - config = new ThreadLocalConfiguration(); - configThreadLocal.set(config); - } - - return config; - } - - public static void clearThreadLocal() { - configThreadLocal.set(null); - } - public static void removeFilteredElement(Element metadata, - final Pair xPathAndMarkedElement, + final MetadataSchemaOperationFilter filter, List namespaces) throws JDOMException { // xPathAndMarkedElement seem can be null in some schemas like dublin core - if (xPathAndMarkedElement == null) return; + if (filter == null) return; - String xpath = xPathAndMarkedElement.one(); - Element mark = xPathAndMarkedElement.two(); + String xpath = filter.getXpath(); + Element mark = filter.getMarkedElement(); List nodes = Xml.selectNodes(metadata, xpath, namespaces); + for (Object object : nodes) { if (object instanceof Element) { Element element = (Element) object; @@ -89,13 +75,13 @@ public static void removeFilteredElement(Element metadata, // Remove attributes @SuppressWarnings("unchecked") - List atts = new ArrayList(element.getAttributes()); + List atts = new ArrayList<>(element.getAttributes()); for (Attribute attribute : atts) { attribute.detach(); } // Insert attributes or children element of the mark - List markAtts = new ArrayList(mark.getAttributes()); + List markAtts = new ArrayList<>(mark.getAttributes()); for (Attribute attribute : markAtts) { element.setAttribute((Attribute) attribute.clone()); } @@ -124,7 +110,7 @@ public boolean resolveXLinks() { return false; } - String xlR = _settingManager.getValue(Settings.SYSTEM_XLINKRESOLVER_ENABLE); + String xlR = _settingManager.getValue(Settings.SYSTEM_XLINKRESOLVER_ENABLE); if (xlR != null) { boolean isEnabled = xlR.equals("true"); if (isEnabled) Log.debug(Geonet.DATA_MANAGER, "XLink Resolver enabled."); @@ -182,33 +168,43 @@ public Element removeHiddenElements(boolean isIndexingTask, AbstractMetadata met // Check if a filter is defined for this schema // for the editing operation ie. user who can not edit // will not see those elements. - Pair editXpathFilter = mds.getOperationFilter(ReservedOperation.editing); - boolean filterEditOperationElements = editXpathFilter != null; + MetadataSchemaOperationFilter editFilter = mds.getOperationFilter(ReservedOperation.editing); + boolean filterEditOperationElements = editFilter != null; List namespaces = mds.getNamespaces(); if (context != null) { - if (editXpathFilter != null) { + if (editFilter != null) { boolean canEdit = accessManager.canEdit(context, id); if (canEdit) { filterEditOperationElements = false; } } - Pair downloadXpathFilter = mds.getOperationFilter(ReservedOperation.download); - if (downloadXpathFilter != null) { + + MetadataSchemaOperationFilter authenticatedFilter = mds.getOperationFilter("authenticated"); + if (authenticatedFilter != null) { + boolean isAuthenticated = context.getUserSession().isAuthenticated(); + if (!isAuthenticated) { + removeFilteredElement(metadataXml, authenticatedFilter, namespaces); + } + } + + MetadataSchemaOperationFilter downloadFilter = mds.getOperationFilter(ReservedOperation.download); + if (downloadFilter != null) { boolean canDownload = accessManager.canDownload(context, id); if (!canDownload) { - removeFilteredElement(metadataXml, downloadXpathFilter, namespaces); + removeFilteredElement(metadataXml, downloadFilter, namespaces); } } - Pair dynamicXpathFilter = mds.getOperationFilter(ReservedOperation.dynamic); - if (dynamicXpathFilter != null) { + MetadataSchemaOperationFilter dynamicFilter = mds.getOperationFilter(ReservedOperation.dynamic); + if (dynamicFilter != null) { boolean canDynamic = accessManager.canDynamic(context, id); if (!canDynamic) { - removeFilteredElement(metadataXml, dynamicXpathFilter, namespaces); + removeFilteredElement(metadataXml, dynamicFilter, namespaces); } } } - if (filterEditOperationElements || (getThreadLocal(false) != null && getThreadLocal(false).forceFilterEditOperation)) { - removeFilteredElement(metadataXml, editXpathFilter, namespaces); + + if (filterEditOperationElements) { + removeFilteredElement(metadataXml, editFilter, namespaces); } } return metadataXml; @@ -282,7 +278,7 @@ protected void deleteDb(String id) throws Exception { public abstract void delete(String id, ServiceContext context) throws Exception; - /* API to be overridden by extensions */ + /* API to be overridden by extensions */ public abstract void update(String id, Element xml, String changeDate, boolean updateDateStamp, String uuid, ServiceContext context) @@ -300,16 +296,4 @@ public abstract AbstractMetadata insert(AbstractMetadata metadata, Element dataX public abstract Element selectNoXLinkResolver(String id, boolean isIndexingTask, boolean applyOperationsFilters) throws Exception; - - public static class ThreadLocalConfiguration { - private boolean forceFilterEditOperation = false; - - public boolean isForceFilterEditOperation() { - return forceFilterEditOperation; - } - - public void setForceFilterEditOperation(boolean forceFilterEditOperation) { - this.forceFilterEditOperation = forceFilterEditOperation; - } - } } diff --git a/core/src/main/java/org/fao/geonet/kernel/datamanager/IMetadataIndexer.java b/core/src/main/java/org/fao/geonet/kernel/datamanager/IMetadataIndexer.java index 3ee6843f0e2..f7ef10c9c7c 100644 --- a/core/src/main/java/org/fao/geonet/kernel/datamanager/IMetadataIndexer.java +++ b/core/src/main/java/org/fao/geonet/kernel/datamanager/IMetadataIndexer.java @@ -1,5 +1,5 @@ //============================================================================= -//=== Copyright (C) 2001-2011 Food and Agriculture Organization of the +//=== Copyright (C) 2001-2023 Food and Agriculture Organization of the //=== United Nations (FAO-UN), United Nations World Food Programme (WFP) //=== and United Nations Environment Programme (UNEP) //=== @@ -24,11 +24,9 @@ package org.fao.geonet.kernel.datamanager; import java.io.IOException; -import java.util.Calendar; import java.util.List; import org.fao.geonet.domain.AbstractMetadata; -import org.fao.geonet.kernel.search.ISearchManager; import org.fao.geonet.kernel.search.IndexingMode; import org.jdom.Element; import org.springframework.data.jpa.domain.Specification; @@ -65,11 +63,6 @@ public interface IMetadataIndexer { */ int batchDeleteMetadataAndUpdateIndex(Specification specification) throws Exception; - /** - * Search for all records having XLinks (ie. indexed with _hasxlinks flag), clear the cache and reindex all records found. - */ - void rebuildIndexXLinkedMetadata(ServiceContext context) throws Exception; - /** * Reindex all records in current selection. */ diff --git a/core/src/main/java/org/fao/geonet/kernel/datamanager/IMetadataManager.java b/core/src/main/java/org/fao/geonet/kernel/datamanager/IMetadataManager.java index 512d8810618..83c4b8d05d9 100644 --- a/core/src/main/java/org/fao/geonet/kernel/datamanager/IMetadataManager.java +++ b/core/src/main/java/org/fao/geonet/kernel/datamanager/IMetadataManager.java @@ -62,6 +62,9 @@ public interface IMetadataManager { /** * Removes the record with the id metadataId + * from the database and index without sending events. + * + * This is useful for harvesting tasks. * * @param context * @param metadataId @@ -69,6 +72,17 @@ public interface IMetadataManager { */ void deleteMetadata(ServiceContext context, String metadataId) throws Exception; + /** + * Delete the record with the id metadataId + * from the database and index + * and additionally take care of cleaning up resources, send events, ... + * + * @param context + * @param metadataId + * @throws Exception + */ + void purgeMetadata(ServiceContext context, String metadataId, boolean withBackup) throws Exception; + /** * Removes a record without notifying. * diff --git a/core/src/main/java/org/fao/geonet/kernel/datamanager/IMetadataStatus.java b/core/src/main/java/org/fao/geonet/kernel/datamanager/IMetadataStatus.java index 89fa4efd6dc..16cfc9719ae 100644 --- a/core/src/main/java/org/fao/geonet/kernel/datamanager/IMetadataStatus.java +++ b/core/src/main/java/org/fao/geonet/kernel/datamanager/IMetadataStatus.java @@ -69,11 +69,14 @@ public interface IMetadataStatus { MetadataStatus setStatusExt(ServiceContext context, int id, int status, ISODate changeDate, String changeMessage) throws Exception; /** - * Set status of metadata id and do not reindex metadata id afterwards. + * Set status of metadata id and reindex metadata id afterwards based on updateIndex flag + * + * @param status metadata status to set + * @param updateIndex index update flag * * @return the saved status entity object */ - MetadataStatus setStatusExt(MetadataStatus status) throws Exception; + MetadataStatus setStatusExt(MetadataStatus status, boolean updateIndex) throws Exception; /** * Set status of metadata id and reindex metadata id afterwards. @@ -100,6 +103,15 @@ public interface IMetadataStatus { */ MetadataStatus getStatus(int metadataId) throws Exception; + /** + * Given a metadata id, return the previous status of the metadata + * + * @param metadataId + * @return + * @throws Exception + */ + MetadataStatus getPreviousStatus(int metadataId) throws Exception; + /** * Given a metadata id, return the status of the metadata * diff --git a/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataIndexer.java b/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataIndexer.java index 261d9a442a3..9b39ce6118b 100644 --- a/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataIndexer.java +++ b/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataIndexer.java @@ -29,12 +29,10 @@ import jeeves.monitor.MonitorManager; import jeeves.monitor.timer.IndexingRecordMeter; import jeeves.monitor.timer.IndexingRecordTimer; -import jeeves.monitor.timer.ServiceManagerXslOutputTransformTimer; import jeeves.server.UserSession; import jeeves.server.context.ServiceContext; import jeeves.xlink.Processor; import org.apache.commons.lang.StringUtils; -import org.eclipse.jetty.util.ConcurrentHashSet; import org.fao.geonet.ApplicationContextHolder; import org.fao.geonet.api.records.attachments.Store; import org.fao.geonet.constants.Geonet; @@ -74,6 +72,7 @@ import java.io.IOException; import java.nio.file.Path; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicInteger; @@ -146,7 +145,7 @@ public void setMetadataManager(IMetadataManager metadataManager) { Set waitForIndexing = new HashSet(); Set indexing = new HashSet(); - Set batchIndex = new ConcurrentHashSet(); + Set batchIndex = ConcurrentHashMap.newKeySet(); @Override public void forceIndexChanges() throws IOException { @@ -201,31 +200,6 @@ public int batchDeleteMetadataAndUpdateIndex(Specification toIndex = searchManager.getDocsWithXLinks(); - - if (Log.isDebugEnabled(Geonet.DATA_MANAGER)) - Log.debug(Geonet.DATA_MANAGER, "Will index " + toIndex.size() + " records with XLinks"); - if (toIndex.size() > 0) { - // clean XLink Cache so that cache and index remain in sync - Processor.clearCache(); - - ArrayList stringIds = new ArrayList(); - for (Integer id : toIndex) { - stringIds.add(id.toString()); - } - // execute indexing operation - batchIndexInThreadPool(context, stringIds); - } - } - /** * Reindex all records in current selection. */ @@ -351,9 +325,9 @@ public void indexMetadata(final String metadataId, List xlinks = Processor.getXLinks(md); if (xlinks.size() > 0) { fields.put(Geonet.IndexFieldNames.HASXLINKS, true); - StringBuilder sb = new StringBuilder(); for (Attribute xlink : xlinks) { fields.put(Geonet.IndexFieldNames.XLINK, xlink.getValue()); + fields.put(Geonet.IndexFieldNames.XLINK, xlink.getValue().replaceAll("local://srv/api/registries/entries/(.*)\\?.*", "$1")); } Processor.detachXLink(md, getServiceContext()); } else { @@ -409,14 +383,14 @@ public void indexMetadata(final String metadataId, if (!schemaManager.existsSchema(schema)) { fields.put(IndexFields.DRAFT, "n"); fields.put(IndexFields.INDEXING_ERROR_FIELD, true); - fields.put(IndexFields.INDEXING_ERROR_MSG, String.format( - "Schema '%s' is not registerd in this catalog. Install it or remove those records", - schema - )); + fields.put(IndexFields.INDEXING_ERROR_MSG, + searchManager.createIndexingErrorMsgObject("indexingErrorMsg-schemaNotRegistered", + "error", + Map.of("record", metadataId, "schema", schema))); searchManager.index(null, md, indexKey, fields, metadataType, forceRefreshReaders, indexingMode); Log.error(Geonet.DATA_MANAGER, String.format( - "Record %s / Schema '%s' is not registerd in this catalog. Install it or remove those records. Record is indexed indexing error flag.", + "Record %s / Schema '%s' is not registered in this catalog. Install it or remove those records. Record is indexed indexing error flag.", metadataId, schema)); } else { @@ -527,7 +501,11 @@ public void indexMetadata(final String metadataId, // TODO: Check if ignore INSPIRE validation? if (!type.equalsIgnoreCase("inspire")) { - if (status == MetadataValidationStatus.INVALID && vi.isRequired()) { + // If never validated and required then set status to never validated. + if (status == MetadataValidationStatus.NEVER_CALCULATED && vi.isRequired()) { + isValid = "-1"; + } + if (status == MetadataValidationStatus.INVALID && vi.isRequired() && isValid != "-1") { isValid = "0"; } } else { @@ -571,6 +549,7 @@ public void indexMetadata(final String metadataId, metadataId, indexingMode, System.currentTimeMillis() - start)); } + @Override public void indexMetadataPrivileges(String uuid, int id) throws Exception { Set operationFields = new HashSet<>(); @@ -585,6 +564,8 @@ private Multimap buildFieldsForPrivileges(int recordId) { List operationsAllowed = operationAllowedRepository.findAllById_MetadataId(recordId); Multimap privilegesFields = ArrayListMultimap.create(); boolean isPublishedToAll = false; + boolean isPublishedToIntranet = false; + boolean isPublishedToGuest = false; for (OperationAllowed operationAllowed : operationsAllowed) { OperationAllowedId operationAllowedId = operationAllowed.getId(); @@ -601,6 +582,10 @@ private Multimap buildFieldsForPrivileges(int recordId) { if (g.get().getId() == ReservedGroup.all.getId()) { isPublishedToAll = true; + } else if (g.get().getId() == ReservedGroup.intranet.getId()) { + isPublishedToIntranet = true; + } else if (g.get().getId() == ReservedGroup.guest.getId()) { + isPublishedToGuest = true; } } } @@ -611,6 +596,19 @@ private Multimap buildFieldsForPrivileges(int recordId) { } else { privilegesFields.put(Geonet.IndexFieldNames.IS_PUBLISHED_TO_ALL, false); } + + if (isPublishedToIntranet) { + privilegesFields.put(Geonet.IndexFieldNames.IS_PUBLISHED_TO_INTRANET, true); + } else { + privilegesFields.put(Geonet.IndexFieldNames.IS_PUBLISHED_TO_INTRANET, false); + } + + if (isPublishedToGuest) { + privilegesFields.put(Geonet.IndexFieldNames.IS_PUBLISHED_TO_GUEST, true); + } else { + privilegesFields.put(Geonet.IndexFieldNames.IS_PUBLISHED_TO_GUEST, false); + } + return privilegesFields; } diff --git a/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataManager.java b/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataManager.java index ba128b9c033..7464a267735 100644 --- a/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataManager.java +++ b/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataManager.java @@ -34,21 +34,25 @@ import jeeves.xlink.Processor; import org.apache.commons.lang.StringUtils; import org.fao.geonet.ApplicationContextHolder; +import org.fao.geonet.api.records.attachments.Store; import org.fao.geonet.constants.Edit; import org.fao.geonet.constants.Geonet; import org.fao.geonet.constants.Params; import org.fao.geonet.domain.*; +import org.fao.geonet.events.history.RecordDeletedEvent; +import org.fao.geonet.events.md.MetadataPreRemove; import org.fao.geonet.exceptions.UnAuthorizedException; import org.fao.geonet.kernel.*; import org.fao.geonet.kernel.datamanager.*; +import org.fao.geonet.kernel.mef.MEFLib; import org.fao.geonet.kernel.schema.MetadataSchema; import org.fao.geonet.kernel.schema.SchemaPlugin; import org.fao.geonet.kernel.search.EsSearchManager; import org.fao.geonet.kernel.search.IndexingMode; -import org.fao.geonet.kernel.search.MetaSearcher; import org.fao.geonet.kernel.search.index.BatchOpsMetadataReindexer; import org.fao.geonet.kernel.setting.SettingManager; import org.fao.geonet.kernel.setting.Settings; +import org.fao.geonet.kernel.setting.SettingInfo; import org.fao.geonet.lib.Lib; import org.fao.geonet.repository.*; import org.fao.geonet.repository.specification.MetadataFileUploadSpecs; @@ -345,6 +349,36 @@ public void deleteMetadata(ServiceContext context, String metadataId) throws Exc // _entityManager.clear(); } + /** + * Delete the record with the id metadataId and additionally take care of cleaning up resources, send events, ... + */ + @Override + public void purgeMetadata(ServiceContext context, String metadataId, boolean withBackup) throws Exception { + AbstractMetadata metadata = metadataUtils.findOne(metadataId); + Store store = context.getBean("resourceStore", Store.class); + + MetadataPreRemove preRemoveEvent = new MetadataPreRemove(metadata); + ApplicationContextHolder.get().publishEvent(preRemoveEvent); + + if (metadata.getDataInfo().getType() != MetadataType.SUB_TEMPLATE + && metadata.getDataInfo().getType() != MetadataType.TEMPLATE_OF_SUB_TEMPLATE && withBackup) { + MEFLib.backupRecord(metadata, context); + } + + boolean approved = true; + if (metadata instanceof MetadataDraft) { + approved = false; + } + + store.delResources(context, metadata.getUuid(), approved); + + RecordDeletedEvent recordDeletedEvent = new RecordDeletedEvent( + metadata.getId(), metadata.getUuid(), new LinkedHashMap<>(), + context.getUserSession().getUserIdAsInt(), metadata.getData()); + deleteMetadata(context, metadataId); + recordDeletedEvent.publish(ApplicationContextHolder.get()); + } + /** * @param context * @param metadataId @@ -372,8 +406,7 @@ public String createMetadata(ServiceContext context, String templateId, String g } /** - * Creates a new metadata duplicating an existing template with an specified - * uuid. + * Creates a new metadata duplicating an existing template with a specified uuid. * * @param isTemplate * @param fullRightsForGroup @@ -400,7 +433,7 @@ public String createMetadata(ServiceContext context, String templateId, String g xml = duplicateMetadata(schema, xml, context); } else if (type == MetadataType.SUB_TEMPLATE - || type == MetadataType.TEMPLATE_OF_SUB_TEMPLATE) { + || type == MetadataType.TEMPLATE_OF_SUB_TEMPLATE) { xml.setAttribute("uuid", uuid); } @@ -494,7 +527,7 @@ private void setMetadataTitle(String schema, Element xml, String language, boole * @param createDate date of creation * @param changeDate date of modification * @param ufo whether to apply automatic changes - * @param indexingMode whether to index this metadata + * @param indexingMode whether to index this metadata * @return id, as a string * @throws Exception hmm */ @@ -549,7 +582,11 @@ public AbstractMetadata insertMetadata(ServiceContext context, AbstractMetadata // Check if the schema is allowed by settings String mdImportSetting = settingManager.getValue(Settings.METADATA_IMPORT_RESTRICT); - if (mdImportSetting != null && !mdImportSetting.equals("")) { + if (mdImportSetting != null) { + // Remove spaces from the list so that "iso19115-3.2018, dublin-core" will also work + mdImportSetting = mdImportSetting.replace(" ", ""); + } + if (!StringUtils.isBlank(mdImportSetting)) { if (!newMetadata.getHarvestInfo().isHarvested() && !Arrays.asList(mdImportSetting.split(",")).contains(schema)) { throw new IllegalArgumentException("The system setting '" + Settings.METADATA_IMPORT_RESTRICT + "' doesn't allow to import " + schema @@ -696,7 +733,7 @@ public void apply(@Nonnull Metadata entity) { */ @Override public synchronized AbstractMetadata updateMetadata(final ServiceContext context, final String metadataId, final Element md, - final boolean validate, final boolean ufo, final String lang, final String changeDate, + final boolean validate, final boolean ufo, final String lang, String changeDate, final boolean updateDateStamp, final IndexingMode indexingMode) throws Exception { Log.trace(Geonet.DATA_MANAGER, "Update record with id " + metadataId); @@ -709,13 +746,22 @@ public synchronized AbstractMetadata updateMetadata(final ServiceContext context } String schema = metadataSchemaUtils.getMetadataSchema(metadataId); + final AbstractMetadata metadata = metadataUtils.findOne(metadataId); + + if (updateDateStamp) { + if (StringUtils.isEmpty(changeDate)) { + changeDate = new ISODate().toString(); + metadata.getDataInfo().setChangeDate(new ISODate()); + } else { + metadata.getDataInfo().setChangeDate(new ISODate(changeDate)); + } + } + String uuidBeforeUfo = null; if (ufo) { String parentUuid = null; Integer intId = Integer.valueOf(metadataId); - final AbstractMetadata metadata = metadataUtils.findOne(metadataId); - uuidBeforeUfo = findUuid(metadataXml, schema, metadata); metadataXml = updateFixedInfo(schema, Optional.of(intId), uuidBeforeUfo, metadataXml, parentUuid, @@ -725,9 +771,6 @@ public synchronized AbstractMetadata updateMetadata(final ServiceContext context // --- force namespace prefix for iso19139 metadata setNamespacePrefixUsingSchemas(schema, metadataXml); - // Notifies the metadata change to metatada notifier service - final AbstractMetadata metadata = metadataUtils.findOne(metadataId); - String uuid = findUuid(metadataXml, schema, metadata); metadataUtils.checkMetadataWithSameUuidExist(uuid, metadata.getId()); @@ -828,6 +871,7 @@ private Element buildInfoElem(ServiceContext context, String id, String version) // add owner name java.util.Optional user = userRepository.findById(Integer.parseInt(owner)); if (user.isPresent()) { + addElement(info, Edit.Info.Elem.OWNERID, user.get().getId()); String ownerName = user.get().getName(); addElement(info, Edit.Info.Elem.OWNERNAME, ownerName); } @@ -875,15 +919,8 @@ private Element buildInfoElem(ServiceContext context, String id, String version) } // add baseUrl of this site (from settings) - String protocol = settingManager.getValue(Settings.SYSTEM_SERVER_PROTOCOL); - String host = settingManager.getValue(Settings.SYSTEM_SERVER_HOST); - String port = settingManager.getValue(Settings.SYSTEM_SERVER_PORT); - if (port.equals("80")) { - port = ""; - } else { - port = ":" + port; - } - addElement(info, Edit.Info.Elem.BASEURL, protocol + "://" + host + port + context.getBaseUrl()); + SettingInfo si = new SettingInfo(); + addElement(info, Edit.Info.Elem.BASEURL, si.getSiteUrl() + context.getBaseUrl()); addElement(info, Edit.Info.Elem.LOCSERV, "/srv/en"); return info; } @@ -930,8 +967,7 @@ public Element updateFixedInfo(String schema, Optional metadataId, Stri if (metadata != null) { changeDate = metadata.getDataInfo().getChangeDate().getDateAndTime(); createDate = metadata.getDataInfo().getCreateDate().getDateAndTime(); - } - else { + } else { createDate = new ISODate().toString(); } env.addContent(new Element("changeDate").setText(changeDate)); @@ -986,8 +1022,8 @@ public Element updateFixedInfo(String schema, Optional metadataId, Stri Path styleSheet = metadataSchemaUtils.getSchemaDir(schema).resolve( metadata != null && ( - metadata.getDataInfo().getType() == MetadataType.SUB_TEMPLATE - || metadata.getDataInfo().getType() == MetadataType.TEMPLATE_OF_SUB_TEMPLATE)? + metadata.getDataInfo().getType() == MetadataType.SUB_TEMPLATE + || metadata.getDataInfo().getType() == MetadataType.TEMPLATE_OF_SUB_TEMPLATE) ? Geonet.File.UPDATE_FIXED_INFO_SUBTEMPLATE : Geonet.File.UPDATE_FIXED_INFO); result = Xml.transform(result, styleSheet); @@ -1201,13 +1237,13 @@ private void setNamespacePrefixUsingSchemas(String schema, Element md) throws Ex * Applies a xslt process when duplicating a metadata, typically to remove identifiers * or other information like DOI (Digital Object Identifiers) and returns the updated metadata. * - * @param schema Metadata schema. - * @param md Metadata to duplicate. + * @param schema Metadata schema. + * @param md Metadata to duplicate. * @param srvContext - * @return If the xslt process exists, the metadata processed, otherwise the original metadata. + * @return If the xslt process exists, the metadata processed, otherwise the original metadata. * @throws Exception */ - private Element duplicateMetadata(String schema, Element md, ServiceContext srvContext) throws Exception { + private Element duplicateMetadata(String schema, Element md, ServiceContext srvContext) throws Exception { Path styleSheet = metadataSchemaUtils.getSchemaDir(schema).resolve( Geonet.File.DUPLICATE_METADATA); @@ -1310,8 +1346,8 @@ public boolean isValid(Integer id) { } boolean hasReferencingMetadata(ServiceContext context, AbstractMetadata metadata) throws Exception { - StringBuilder query = new StringBuilder(String.format("xlink:*%s*", metadata.getUuid())); - return this.searchManager.query(query.toString(), null, 0, 0).getHits().getTotalHits().value > 0; + StringBuilder query = new StringBuilder(String.format("xlink:\"%s\"", metadata.getUuid())); + return this.searchManager.query(query.toString(), null, 0, 0).hits().total().value() > 0; } } diff --git a/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataOperations.java b/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataOperations.java index 5d57875291d..47cfe3b5342 100644 --- a/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataOperations.java +++ b/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataOperations.java @@ -1,5 +1,5 @@ //============================================================================= -//=== Copyright (C) 2001-2011 Food and Agriculture Organization of the +//=== Copyright (C) 2001-2024 Food and Agriculture Organization of the //=== United Nations (FAO-UN), United Nations World Food Programme (WFP) //=== and United Nations Environment Programme (UNEP) //=== @@ -167,7 +167,7 @@ public boolean setOperation(ServiceContext context, int mdId, int grpId, int opI */ @Override public boolean forceSetOperation(ServiceContext context, int mdId, int grpId, int opId) throws Exception { - Optional opAllowed = _getOperationAllowedToAdd(context, mdId, grpId, opId, false); + Optional opAllowed = getOperationAllowedToAddInternal(context, mdId, grpId, opId, false); if (opAllowed.isPresent()) { Log.trace(Geonet.DATA_MANAGER, "Operation is allowed"); @@ -199,11 +199,11 @@ public boolean forceSetOperation(ServiceContext context, int mdId, int grpId, in @Override public Optional getOperationAllowedToAdd(final ServiceContext context, final int mdId, final int grpId, final int opId) { - return _getOperationAllowedToAdd(context, mdId, grpId, opId, true); + return getOperationAllowedToAddInternal(context, mdId, grpId, opId, true); } - private Optional _getOperationAllowedToAdd(final ServiceContext context, final int mdId, final int grpId, - final int opId, boolean shouldCheckPermission) { + private Optional getOperationAllowedToAddInternal(final ServiceContext context, final int mdId, final int grpId, + final int opId, boolean shouldCheckPermission) { Log.trace(Geonet.DATA_MANAGER, "_getOperationAllowedToAdd(" + mdId + ", " + grpId + ", " + opId + ", " + shouldCheckPermission + ")"); final OperationAllowed operationAllowed = opAllowedRepo.findOneById_GroupIdAndId_MetadataIdAndId_OperationId(grpId, mdId, opId); @@ -340,14 +340,12 @@ public void copyDefaultPrivForGroup(ServiceContext context, String id, String gr setOperation(context, id, groupId, ReservedOperation.view); setOperation(context, id, groupId, ReservedOperation.notify); + setOperation(context, id, groupId, ReservedOperation.download); + setOperation(context, id, groupId, ReservedOperation.dynamic); // - // Restrictive: new and inserted records should not be editable, - // their resources can't be downloaded and any interactive maps can't be - // displayed by users in the same group + // Restrictive: new and inserted records should not be editable by users in the same group, if (fullRightsForGroup) { setOperation(context, id, groupId, ReservedOperation.editing); - setOperation(context, id, groupId, ReservedOperation.download); - setOperation(context, id, groupId, ReservedOperation.dynamic); } // Ultimately this should be configurable elsewhere } diff --git a/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataStatus.java b/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataStatus.java index ee0300922fd..cf5f7fc972d 100644 --- a/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataStatus.java +++ b/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataStatus.java @@ -96,6 +96,21 @@ public MetadataStatus getStatus(int metadataId) throws Exception { } } + /** + * Return previous workflow status for the metadata id + */ + @Override + public MetadataStatus getPreviousStatus(int metadataId) throws Exception { + String sortField = SortUtils.createPath(MetadataStatus_.id, MetadataStatus_.changeDate); + List metadataStatusList = metadataStatusRepository.findAllByMetadataIdAndByType( + metadataId, StatusValueType.workflow, Sort.by(Sort.Direction.DESC, sortField)); + if (metadataStatusList.isEmpty() || metadataStatusList.size() == 1) { + return null; + } else { + return metadataStatusList.get(1); + } + } + /** * Return all status for the metadata id */ @@ -145,9 +160,11 @@ public MetadataStatus setStatus(ServiceContext context, int id, int status, ISOD } @Override - public MetadataStatus setStatusExt(MetadataStatus metatatStatus) throws Exception { + public MetadataStatus setStatusExt(MetadataStatus metatatStatus, boolean updateIndex) throws Exception { metadataStatusRepository.save(metatatStatus); - metadataIndexer.indexMetadata(metatatStatus.getMetadataId() + "", true, IndexingMode.full); + if (updateIndex) { + metadataIndexer.indexMetadata(metatatStatus.getMetadataId() + "", true, IndexingMode.full); + } return metatatStatus; } diff --git a/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataUtils.java b/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataUtils.java index a07a3acf3d0..ad4dde213b4 100644 --- a/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataUtils.java +++ b/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataUtils.java @@ -51,6 +51,7 @@ import org.fao.geonet.repository.specification.OperationAllowedSpecs; import org.fao.geonet.utils.Log; import org.fao.geonet.utils.Xml; +import org.fao.geonet.web.DefaultLanguage; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.Namespace; @@ -107,6 +108,9 @@ public class BaseMetadataUtils implements IMetadataUtils { @Autowired(required = false) protected XmlSerializer xmlSerializer; + @Autowired + private DefaultLanguage defaultLanguage; + private Path stylePath; protected IMetadataManager metadataManager; @@ -261,15 +265,15 @@ public String extractUUID(String schema, Element md) throws Exception { @Override public String extractDefaultLanguage(String schema, Element md) throws Exception { Path styleSheet = metadataSchemaUtils.getSchemaDir(schema).resolve(Geonet.File.EXTRACT_DEFAULT_LANGUAGE); - String defaultLanguage = Xml.transform(md, styleSheet).getText().trim(); + String defaultLanguageValue = Xml.transform(md, styleSheet).getText().trim(); if (Log.isDebugEnabled(Geonet.DATA_MANAGER)) - Log.debug(Geonet.DATA_MANAGER, "Extracted default language '" + defaultLanguage + "' for schema '" + schema + "'"); + Log.debug(Geonet.DATA_MANAGER, "Extracted default language '" + defaultLanguageValue + "' for schema '" + schema + "'"); // --- needed to detach md from the document md.detach(); - return defaultLanguage; + return defaultLanguageValue; } /** @@ -347,10 +351,7 @@ public String getPermalink(String uuid, String language) { public String getDefaultUrl(String uuid, String language) { String dynamicAppLinkUrl = settingManager.getValue(METADATA_URL_DYNAMICAPPLINKURL); if ("all".equals(language)) { - Language defaultLanguage = languageRepository.findOneByDefaultLanguage(); - if (defaultLanguage != null) { - language = defaultLanguage.getId(); - } + language = defaultLanguage.getLanguage(); } String defaultLink = settingManager.getNodeURL() + language + "/catalog.search#/metadata/" + uuid; String url = buildUrl(uuid, language, dynamicAppLinkUrl); @@ -359,17 +360,20 @@ public String getDefaultUrl(String uuid, String language) { private String buildUrl(String uuid, String language, String url) { if (StringUtils.isNotEmpty(url)) { + String upperCaseUrl = url.toUpperCase(); Map substitutions = new HashMap<>(); substitutions.put("{{UUID}}", uuid); substitutions.put("{{LANG}}", StringUtils.isEmpty(language) ? "" : language); - try { - String resourceId = getResourceIdentifier(uuid); - substitutions.put("{{RESOURCEID}}", StringUtils.isEmpty(resourceId) ? "" : resourceId); - } catch (Exception e) { - // No resource identifier xpath defined in schema + if (upperCaseUrl.contains("{{RESOURCEID}}")) { + try { + String resourceId = getResourceIdentifier(uuid); + substitutions.put("{{RESOURCEID}}", StringUtils.isEmpty(resourceId) ? "" : resourceId); + } catch (Exception e) { + // No resource identifier xpath defined in schema + } } for (Map.Entry s : substitutions.entrySet()) { - if (url.toUpperCase().contains(s.getKey())) { + if (upperCaseUrl.contains(s.getKey())) { url = url.replaceAll("(?i)" + Pattern.quote(s.getKey()), s.getValue()); } } @@ -513,12 +517,9 @@ public void setTemplate(final int id, final MetadataType type, final String titl @Override public void setTemplateExt(final int id, final MetadataType metadataType) throws Exception { - metadataRepository.update(id, new Updater() { - @Override - public void apply(@Nonnull Metadata metadata) { - final MetadataDataInfo dataInfo = metadata.getDataInfo(); - dataInfo.setType(metadataType); - } + metadataRepository.update(id, metadata -> { + final MetadataDataInfo dataInfo = metadata.getDataInfo(); + dataInfo.setType(metadataType); }); } @@ -538,14 +539,11 @@ public void setHarvested(int id, String harvestUuid) throws Exception { */ @Override public void setSubtemplateTypeAndTitleExt(final int id, String title) throws Exception { - metadataRepository.update(id, new Updater() { - @Override - public void apply(@Nonnull Metadata metadata) { - final MetadataDataInfo dataInfo = metadata.getDataInfo(); - dataInfo.setType(MetadataType.SUB_TEMPLATE); - if (title != null) { - dataInfo.setTitle(title); - } + metadataRepository.update(id, metadata -> { + final MetadataDataInfo dataInfo = metadata.getDataInfo(); + dataInfo.setType(MetadataType.SUB_TEMPLATE); + if (title != null) { + dataInfo.setTitle(title); } }); } @@ -558,14 +556,11 @@ public void setHarvestedExt(int id, String harvestUuid) throws Exception { @Override public void setHarvestedExt(final int id, final String harvestUuid, final Optional harvestUri) throws Exception { - metadataRepository.update(id, new Updater() { - @Override - public void apply(Metadata metadata) { - MetadataHarvestInfo harvestInfo = metadata.getHarvestInfo(); - harvestInfo.setUuid(harvestUuid); - harvestInfo.setHarvested(harvestUuid != null); - harvestInfo.setUri(harvestUri.orNull()); - } + metadataRepository.update(id, metadata -> { + MetadataHarvestInfo harvestInfo = metadata.getHarvestInfo(); + harvestInfo.setUuid(harvestUuid); + harvestInfo.setHarvested(harvestUuid != null); + harvestInfo.setUri(harvestUri.orNull()); }); } @@ -576,12 +571,7 @@ public void apply(Metadata metadata) { */ @Override public void updateDisplayOrder(final String id, final String displayOrder) throws Exception { - metadataRepository.update(Integer.valueOf(id), new Updater() { - @Override - public void apply(Metadata entity) { - entity.getDataInfo().setDisplayOrder(Integer.parseInt(displayOrder)); - } - }); + metadataRepository.update(Integer.valueOf(id), entity -> entity.getDataInfo().setDisplayOrder(Integer.parseInt(displayOrder))); } /** @@ -592,14 +582,9 @@ public void increasePopularity(ServiceContext srvContext, String id) throws Exce // READONLYMODE if (!srvContext.getBean(NodeInfo.class).isReadOnly()) { int iId = Integer.parseInt(id); - metadataRepository.update(iId, new Updater() { - @Override - public void apply(Metadata entity) { - entity.getDataInfo().setPopularity( - entity.getDataInfo().getPopularity() + 1 - ); - } - }); + metadataRepository.update(iId, entity -> entity.getDataInfo().setPopularity( + entity.getDataInfo().getPopularity() + 1 + )); final java.util.Optional metadata = metadataRepository.findById(iId); if (metadata.isPresent()) { @@ -639,12 +624,7 @@ public int rateMetadata(final int metadataId, final String ipAddress, final int if (Log.isDebugEnabled(Geonet.DATA_MANAGER)) Log.debug(Geonet.DATA_MANAGER, "Setting rating for id:" + metadataId + " --> rating is:" + newRating); - metadataRepository.update(metadataId, new Updater() { - @Override - public void apply(Metadata entity) { - entity.getDataInfo().setRating(newRating); - } - }); + metadataRepository.update(metadataId, entity -> entity.getDataInfo().setRating(newRating)); // And register the metadata to be indexed in the near future indexingList.add(metadataId); @@ -671,7 +651,7 @@ public Element removeMetadataInfo(Element md) throws Exception { // Drop Geonet namespace declaration. It may be contained // multiple times, so loop on all. - final List additionalNamespaces = new ArrayList(md.getAdditionalNamespaces()); + final List additionalNamespaces = new ArrayList<>(md.getAdditionalNamespaces()); for (Namespace n : additionalNamespaces) { if (Edit.NAMESPACE.getURI().equals(n.getURI())) { md.removeNamespaceDeclaration(Edit.NAMESPACE); diff --git a/core/src/main/java/org/fao/geonet/kernel/datamanager/draft/DraftMetadataIndexer.java b/core/src/main/java/org/fao/geonet/kernel/datamanager/draft/DraftMetadataIndexer.java index d3982a75830..65d3a794f15 100644 --- a/core/src/main/java/org/fao/geonet/kernel/datamanager/draft/DraftMetadataIndexer.java +++ b/core/src/main/java/org/fao/geonet/kernel/datamanager/draft/DraftMetadataIndexer.java @@ -86,17 +86,17 @@ protected Multimap addExtraFields(AbstractMetadata fullMd) { List statuses = statusRepository.findAllByMetadataIdAndByType(fullMd.getId(), StatusValueType.workflow, statusSort); if (!statuses.isEmpty()) { MetadataStatus stat = statuses.get(0); - status = String.valueOf(stat.getStatusValue().getId()); + status = String.valueOf(stat.getStatusValue().getName()); } // get status of draft statuses = statusRepository.findAllByMetadataIdAndByType(metadataDraft.getId(), StatusValueType.workflow, statusSort); if (!statuses.isEmpty()) { MetadataStatus stat = statuses.get(0); - statusDraft = String.valueOf(stat.getStatusValue().getId()); + statusDraft = String.valueOf(stat.getStatusValue().getName()); } - extraFields.put(Geonet.IndexFieldNames.STATUS_WORKFLOW, status + statusDraft); + extraFields.put(Geonet.IndexFieldNames.STATUS_WORKFLOW, status + "-" + statusDraft); } else { Log.trace(Geonet.DATA_MANAGER, @@ -109,8 +109,8 @@ protected Multimap addExtraFields(AbstractMetadata fullMd) { List statuses = statusRepository.findAllByMetadataIdAndByType(fullMd.getId(), StatusValueType.workflow, statusSort); if (!statuses.isEmpty()) { MetadataStatus stat = statuses.get(0); - String status = String.valueOf(stat.getStatusValue().getId()); - extraFields.put(Geonet.IndexFieldNames.STATUS_WORKFLOW, status); + String status = String.valueOf(stat.getStatusValue().getName()); + extraFields.put(Geonet.IndexFieldNames.STATUS_WORKFLOW, status); } } } diff --git a/core/src/main/java/org/fao/geonet/kernel/datamanager/draft/DraftMetadataManager.java b/core/src/main/java/org/fao/geonet/kernel/datamanager/draft/DraftMetadataManager.java index 9872a5476bf..07db4799fe2 100644 --- a/core/src/main/java/org/fao/geonet/kernel/datamanager/draft/DraftMetadataManager.java +++ b/core/src/main/java/org/fao/geonet/kernel/datamanager/draft/DraftMetadataManager.java @@ -93,6 +93,7 @@ public void deleteMetadata(ServiceContext context, String metadataId) throws Exc // _entityManager.flush(); // _entityManager.clear(); } + /** * For update of owner info. */ diff --git a/core/src/main/java/org/fao/geonet/kernel/datamanager/draft/DraftMetadataUtils.java b/core/src/main/java/org/fao/geonet/kernel/datamanager/draft/DraftMetadataUtils.java index a71d64f7315..21cf26e85bd 100644 --- a/core/src/main/java/org/fao/geonet/kernel/datamanager/draft/DraftMetadataUtils.java +++ b/core/src/main/java/org/fao/geonet/kernel/datamanager/draft/DraftMetadataUtils.java @@ -24,6 +24,7 @@ package org.fao.geonet.kernel.datamanager.draft; import com.google.common.base.Optional; +import com.google.common.collect.Sets; import jeeves.server.context.ServiceContext; import org.eclipse.jetty.io.RuntimeIOException; import org.fao.geonet.api.records.attachments.StoreUtils; @@ -88,6 +89,7 @@ public class DraftMetadataUtils extends BaseMetadataUtils { IMetadataUtils metadataUtils; private ServiceContext context; + private Set listOfStatusToTriggerDraftCreation = Sets.newHashSet(StatusValue.Status.APPROVED); public void init(ServiceContext context, Boolean force) throws Exception { this.context = context; @@ -235,7 +237,7 @@ public AbstractMetadata findOne(int id) { java.util.Optional md = metadataDraftRepository.findById(id); - return md.isPresent()?md.get():null; + return md.isPresent() ? md.get() : null; } @Override @@ -407,7 +409,7 @@ public List findAllIdsBy(Specification spec /** * Start an editing session. This will record the original metadata record in * the session under the - * {@link org.fao.geonet.constants.Geonet.Session#METADATA_BEFORE_ANY_CHANGES} + + * {@link Geonet.Session#METADATA_BEFORE_ANY_CHANGES} + * id session property. *

* The record contains geonet:info element. @@ -433,7 +435,9 @@ public Integer startEditingSession(ServiceContext context, String id) throws Exc Log.trace(Geonet.DATA_MANAGER, "Editing draft with id " + id); } else if (isMdWorkflowEnable && (context.getBean(IMetadataManager.class) instanceof DraftMetadataManager) - && metadataStatus.getCurrentStatus(Integer.valueOf(id)).equals(StatusValue.Status.APPROVED)) { + && listOfStatusToTriggerDraftCreation.contains( + metadataStatus.getCurrentStatus(Integer.parseInt(id))) + ) { id = createDraft(context, id, md); Log.trace(Geonet.DATA_MANAGER, "Creating draft with id " + id + " to edit."); @@ -568,6 +572,10 @@ protected String createDraft(ServiceContext context, String templateId, String g Integer status = Integer.valueOf(StatusValue.Status.DRAFT); java.util.Optional statusValue = statusValueRepository.findById(status); + String lang = context.getLanguage(); + ResourceBundle messages = ResourceBundle.getBundle("org.fao.geonet.api.Messages", + new Locale(lang)); + if (statusValue.isPresent()) { for (Integer mdId : metadataIds) { MetadataStatus metadataStatus = new MetadataStatus(); @@ -576,12 +584,12 @@ protected String createDraft(ServiceContext context, String templateId, String g metadataStatus.setChangeDate(new ISODate()); metadataStatus.setUserId(author); metadataStatus.setStatusValue(statusValue.get()); - metadataStatus.setChangeMessage("Editing instance created"); + metadataStatus.setChangeMessage(messages.getString("metadata_status_editing_instance_created_text")); metadataStatus.setTitles(metadataUtils.extractTitles(newMetadata.getDataInfo().getSchemaId(), xml)); List listOfStatusChange = new ArrayList<>(1); listOfStatusChange.add(metadataStatus); - sa.onStatusChange(listOfStatusChange); + sa.onStatusChange(listOfStatusChange, true); } } @@ -607,13 +615,13 @@ public void cloneFiles(AbstractMetadata original, AbstractMetadata dest) { @Override public void replaceFiles(AbstractMetadata original, AbstractMetadata dest) { try { - boolean oldApproved=true; - boolean newApproved=false; + boolean oldApproved = true; + boolean newApproved = false; // If destination is approved then this is a working copy so the original will not be approved. if (metadataUtils.isMetadataApproved(dest.getId())) { - oldApproved=false; - newApproved=true; + oldApproved = false; + newApproved = true; } StoreUtils.replaceDataDir(context, original.getUuid(), dest.getUuid(), oldApproved, newApproved); cloneStoreFileUploadRequests(original, dest); @@ -643,7 +651,7 @@ public void cancelEditingSession(ServiceContext context, String id) throws Excep // --- remove metadata xmlSerializer.delete(id, ServiceContext.get()); - searchManager.delete(id); + searchManager.delete(String.format("+id:%s", id)); // Unset METADATA_EDITING_CREATED_DRAFT flag context.getUserSession().removeProperty(Geonet.Session.METADATA_EDITING_CREATED_DRAFT); @@ -669,9 +677,17 @@ private void cloneStoreFileUploadRequests(AbstractMetadata original, AbstractMet metadataFileUpload.setFileSize(mfu.getFileSize()); metadataFileUpload.setUploadDate(mfu.getUploadDate()); metadataFileUpload.setUserName(mfu.getUserName()); + metadataFileUpload.setDeletedDate(mfu.getDeletedDate()); repo.save(metadataFileUpload); } } + public void setListOfStatusCreatingDraft(Set listOfStatusCreatingDraft) { + this.listOfStatusToTriggerDraftCreation = listOfStatusCreatingDraft; + } + + public Set getListOfStatusCreatingDraft() { + return listOfStatusToTriggerDraftCreation; + } } diff --git a/core/src/main/java/org/fao/geonet/kernel/mef/ExportFormat.java b/core/src/main/java/org/fao/geonet/kernel/mef/ExportFormat.java index 5fd16fdb577..02fe7637483 100644 --- a/core/src/main/java/org/fao/geonet/kernel/mef/ExportFormat.java +++ b/core/src/main/java/org/fao/geonet/kernel/mef/ExportFormat.java @@ -31,6 +31,7 @@ import java.util.Set; import org.fao.geonet.GeonetContext; +import org.fao.geonet.constants.Edit; import org.fao.geonet.constants.Geonet; import org.fao.geonet.domain.AbstractMetadata; import org.fao.geonet.domain.Metadata; @@ -72,7 +73,7 @@ public static Iterable> getFormats(ServiceContext context, String outputFileName = entry.getValue(); Path path = metadataSchema.getSchemaDir().resolve(xslFileName); if (Files.isRegularFile(path)) { - String outputData = formatData(metadata, true, path); + String outputData = formatData(context, metadata, true, path); allExports.add(Pair.read(outputFileName, outputData)); } else { // A conversion that does not exist @@ -96,10 +97,9 @@ public static Iterable> getFormats(ServiceContext context, * * @return ByteArrayInputStream */ - public static String formatData(AbstractMetadata metadata, boolean transform, Path stylePath) throws Exception { - String xmlData = metadata.getData(); - - Element md = Xml.loadString(xmlData, false); + public static String formatData(ServiceContext context, AbstractMetadata metadata, boolean transform, Path stylePath) throws Exception { + Element md = context.getBean(DataManager.class).getMetadata(context, metadata.getId() + "", false, false, true); + md.removeChild("info", Edit.NAMESPACE); // Apply a stylesheet transformation when schema is ISO profil if (transform) { diff --git a/core/src/main/java/org/fao/geonet/kernel/mef/Importer.java b/core/src/main/java/org/fao/geonet/kernel/mef/Importer.java index a5cd2c695fc..1200ff5e913 100644 --- a/core/src/main/java/org/fao/geonet/kernel/mef/Importer.java +++ b/core/src/main/java/org/fao/geonet/kernel/mef/Importer.java @@ -1,5 +1,5 @@ //============================================================================= -//=== Copyright (C) 2001-2020 Food and Agriculture Organization of the +//=== Copyright (C) 2001-2024 Food and Agriculture Organization of the //=== United Nations (FAO-UN), United Nations World Food Programme (WFP) //=== and United Nations Environment Programme (UNEP) //=== @@ -27,6 +27,7 @@ import com.google.common.collect.Maps; import jeeves.server.ServiceConfig; import jeeves.server.context.ServiceContext; +import org.apache.commons.lang.StringUtils; import org.fao.geonet.ApplicationContextHolder; import org.fao.geonet.GeonetContext; import org.fao.geonet.MetadataResourceDatabaseMigration; @@ -45,15 +46,18 @@ import org.fao.geonet.kernel.datamanager.IMetadataValidator; import org.fao.geonet.kernel.search.IndexingMode; import org.fao.geonet.kernel.setting.SettingManager; +import org.fao.geonet.kernel.setting.Settings; import org.fao.geonet.repository.*; import org.fao.geonet.utils.FilePathChecker; import org.fao.geonet.utils.Log; import org.fao.geonet.utils.Xml; import org.fao.oaipmh.exceptions.BadArgumentException; import org.jdom.Element; +import org.jdom.JDOMException; import org.springframework.context.ApplicationContext; import javax.annotation.Nonnull; +import java.io.IOException; import java.io.InputStream; import java.nio.file.DirectoryStream; import java.nio.file.Files; @@ -63,9 +67,15 @@ import static org.fao.geonet.domain.Localized.translationXmlToLangMap; public class Importer { + /** + * Private constructor to avoid instantiate the class. + */ + private Importer() { + } + @Deprecated public static List doImport(final Element params, final ServiceContext context, final Path mefFile, - final Path stylePath) throws Exception { + final Path stylePath) throws Exception { String fileType = Util.getParam(params, "file_type", "mef"); String style = Util.getParam(params, Params.STYLESHEET, "_none_"); String uuidAction = Util.getParam(params, Params.UUID_ACTION, Params.NOTHING); @@ -76,13 +86,13 @@ public static List doImport(final Element params, final ServiceContext c boolean validate = Util.getParam(params, Params.VALIDATE, "off").equals("on"); boolean assign = Util.getParam(params, "assign", "off").equals("on"); - return doImport(fileType, MEFLib.UuidAction.parse(uuidAction), style, source, isTemplate, new String[] { category }, groupId, + return doImport(fileType, MEFLib.UuidAction.parse(uuidAction), style, source, isTemplate, new String[]{category}, groupId, validate, assign, context, mefFile); } public static List doImport(String fileType, final MEFLib.UuidAction uuidAction, final String style, final String source, - final MetadataType isTemplate, final String[] category, final String groupId, final boolean validate, final boolean assign, - final ServiceContext context, final Path mefFile) throws Exception { + final MetadataType isTemplate, final String[] category, final String groupId, final boolean validate, final boolean assign, + final ServiceContext context, final Path mefFile) throws Exception { ApplicationContext applicationContext = ApplicationContextHolder.get(); final DataManager dm = applicationContext.getBean(DataManager.class); final SettingManager sm = applicationContext.getBean(SettingManager.class); @@ -90,9 +100,9 @@ public static List doImport(String fileType, final MEFLib.UuidAction uui // Load preferred schema and set to iso19139 by default String preferredSchema = applicationContext.getBean(ServiceConfig.class).getValue("preferredSchema", "iso19139"); - final List metadataIdMap = new ArrayList(); - final List md = new ArrayList(); - final List fc = new ArrayList(); + final List metadataIdMap = new ArrayList<>(); + final List md = new ArrayList<>(); + final List fc = new ArrayList<>(); // Try to define MEF version from mef file not from parameter if (fileType.equals("mef")) { @@ -144,7 +154,7 @@ public void handleMetadataFiles(DirectoryStream metadataXmlFiles, Element Element metadataValidForImport; - Map> mdFiles = new HashMap>(); + Map> mdFiles = new HashMap<>(); for (Path file : metadataXmlFiles) { if (file != null && java.nio.file.Files.isRegularFile(file)) { Element metadata = Xml.loadFile(file); @@ -267,7 +277,7 @@ public void handleInfo(Element info, int index) throws Exception { throw new Exception("Unknown schema"); // Handle non MEF files insertion - if (info.getChildren().size() == 0) { + if (info.getChildren().isEmpty()) { if (category != null) { categs = new Element("categories"); for (String c : category) { @@ -350,7 +360,7 @@ public void handleInfo(Element info, int index) throws Exception { throw new Exception("Failed to import metadata with uuid '" + uuid + "'. " + e.getLocalizedMessage(), e); } - if (fc.size() != 0 && fc.get(index) != null) { + if (!fc.isEmpty() && fc.get(index) != null) { // UUID is set as @uuid in root element uuid = UUID.randomUUID().toString(); @@ -360,7 +370,10 @@ public void handleInfo(Element info, int index) throws Exception { // insert metadata // int userid = context.getUserSession().getUserIdAsInt(); - String group = null, docType = null, title = null, category = null; + String group = null; + String docType = null; + String title = null; + String category = null; boolean ufo = false; String fcId = dm .insertMetadata(context, "iso19110", fc.get(index), uuid, userid, group, source, isTemplate.codeString, docType, @@ -390,7 +403,8 @@ public void handleInfo(Element info, int index) throws Exception { final Element finalCategs = categs; final String finalGroupId = groupId; context.getBean(IMetadataManager.class).update(iMetadataId, new Updater() { - @Override public void apply(@Nonnull final Metadata metadata) { + @Override + public void apply(@Nonnull final Metadata metadata) { final MetadataDataInfo dataInfo = metadata.getDataInfo(); if (finalPopularity != null) { dataInfo.setPopularity(Integer.valueOf(finalPopularity)); @@ -479,17 +493,21 @@ public static void addCategoriesToMetadata(AbstractMetadata metadata, Element fi } public static void importRecord(String uuid, MEFLib.UuidAction uuidAction, List md, String schema, int index, String source, - String sourceName, Map sourceTranslations, ServiceContext context, List id, String createDate, - String changeDate, String groupId, MetadataType isTemplate) throws Exception { + String sourceName, Map sourceTranslations, ServiceContext context, List id, String createDate, + String changeDate, String groupId, MetadataType isTemplate) throws Exception { GeonetContext gc = (GeonetContext) context.getHandlerContext(Geonet.CONTEXT_NAME); DataManager dm = gc.getBean(DataManager.class); IMetadataManager metadataManager = gc.getBean(IMetadataManager.class); - if (uuid == null || uuid.equals("") || uuidAction == MEFLib.UuidAction.GENERATEUUID) { + if (StringUtils.isBlank(uuid) || uuidAction == MEFLib.UuidAction.GENERATEUUID) { String newuuid = UUID.randomUUID().toString(); source = null; + if (StringUtils.isNotBlank(uuid)) { + md.add(index, updateMetadataUuidReferences(md.get(index), uuid, newuuid)); + } + Log.debug(Geonet.MEF, "Replacing UUID " + uuid + " with " + newuuid); uuid = newuuid; @@ -512,33 +530,71 @@ public static void importRecord(String uuid, MEFLib.UuidAction uuidAction, List< } } - try { - if (dm.existsMetadataUuid(uuid) && uuidAction != MEFLib.UuidAction.NOTHING) { - // user has privileges to replace the existing metadata + boolean metadataExist = dm.existsMetadataUuid(uuid); + + SettingManager settingManager = gc.getBean(SettingManager.class); + boolean isMdWorkflowEnable = settingManager.getValueAsBool(Settings.METADATA_WORKFLOW_ENABLE); + + String metadataId = ""; + if (metadataExist && uuidAction == MEFLib.UuidAction.NOTHING) { + throw new UnAuthorizedException("Record already exists. Change the import mode to overwrite or generating a new UUID.", null); + } else if (metadataExist && uuidAction == MEFLib.UuidAction.OVERWRITE) { + if (isMdWorkflowEnable) { + throw new UnAuthorizedException("Overwrite mode is not allowed when workflow is enabled. Use the metadata editor.", null); + } + + String recordToUpdateId = dm.getMetadataId(uuid); + if (dm.getAccessManager().canEdit(context, recordToUpdateId)) { + MetadataValidationRepository metadataValidationRepository = + context.getBean(MetadataValidationRepository.class); + List validationStatus = metadataValidationRepository + .findAllById_MetadataId(Integer.parseInt(recordToUpdateId)); + + // Refresh validation status if set + boolean validate = !validationStatus.isEmpty(); + metadataManager.updateMetadata( + context, recordToUpdateId, md.get(index), + validate, true, + context.getLanguage(), + null, true, IndexingMode.full); + metadataId = recordToUpdateId; + } else { + throw new UnAuthorizedException("User has no privilege to overwrite existing metadata", null); + } + } else if (metadataExist && uuidAction == MEFLib.UuidAction.REMOVE_AND_REPLACE) { + if (isMdWorkflowEnable) { + throw new UnAuthorizedException("Overwrite mode is not allowed when workflow is enabled. Use the metadata editor.", null); + } + + try { if (dm.getAccessManager().canEdit(context, dm.getMetadataId(uuid))) { if (Log.isDebugEnabled(Geonet.MEF)) { Log.debug(Geonet.MEF, "Deleting existing metadata with UUID : " + uuid); } metadataManager.deleteMetadata(context, dm.getMetadataId(uuid)); metadataManager.flush(); - } - // user does not hav privileges to replace the existing metadata - else { + } else { throw new UnAuthorizedException("User has no privilege to replace existing metadata", null); } + } catch (Exception e) { + throw new Exception(" Existing metadata with UUID " + uuid + " could not be deleted. Error is: " + e.getMessage()); } - } catch (Exception e) { - throw new Exception(" Existing metadata with UUID " + uuid + " could not be deleted. Error is: " + e.getMessage()); + metadataId = insertMetadata(uuid, md, schema, index, source, context, createDate, changeDate, groupId, isTemplate, dm, metadataManager); + } else { + metadataId = insertMetadata(uuid, md, schema, index, source, context, createDate, changeDate, groupId, isTemplate, dm, metadataManager); } + id.add(index, metadataId); + + } + + private static String insertMetadata(String uuid, List md, String schema, int index, String source, ServiceContext context, String createDate, String changeDate, String groupId, MetadataType isTemplate, DataManager dm, IMetadataManager metadataManager) throws Exception { if (Log.isDebugEnabled(Geonet.MEF)) Log.debug(Geonet.MEF, "Adding metadata with uuid:" + uuid); - // - // insert metadata - // int userid = context.getUserSession().getUserIdAsInt(); - String docType = null, category = null; + String docType = null; + String category = null; boolean ufo = false; String metadataId = metadataManager @@ -546,15 +602,11 @@ public static void importRecord(String uuid, MEFLib.UuidAction uuidAction, List< createDate, changeDate, ufo, IndexingMode.none); dm.activateWorkflowIfConfigured(context, metadataId, groupId); - - id.add(index, metadataId); - + return metadataId; } - // -------------------------------------------------------------------------- - private static void saveFile(ServiceContext context, String id, MetadataResourceVisibility access, String file, String changeDate, - InputStream is) throws Exception { + InputStream is) throws Exception { final Store store = context.getBean("resourceStore", Store.class); final IMetadataUtils metadataUtils = context.getBean(IMetadataUtils.class); final String metadataUuid = metadataUtils.getMetadataUuid(id); @@ -573,8 +625,8 @@ private static Group addPrivileges(final ServiceContext context, final DataManag @SuppressWarnings("unchecked") List list = privil.getChildren("group"); Group owner = null; - Set opAllowedToAdd = new HashSet(); - List groupsToAdd = new ArrayList(); + Set opAllowedToAdd = new HashSet<>(); + List groupsToAdd = new ArrayList<>(); for (Element group : list) { String grpName = group.getAttributeValue("name"); @@ -609,10 +661,10 @@ private static Group addPrivileges(final ServiceContext context, final DataManag * Add operations according to information file. */ private static Set addOperations(final ServiceContext context, final DataManager dm, final Element group, - final int metadataId, final int grpId) { + final int metadataId, final int grpId) { @SuppressWarnings("unchecked") List operations = group.getChildren("operation"); - Set toAdd = new HashSet(); + Set toAdd = new HashSet<>(); for (Element operation : operations) { String opName = operation.getAttributeValue("name"); @@ -638,6 +690,17 @@ private static Set addOperations(final ServiceContext context, return toAdd; } + /** + * Replace oldUuid references by newUuid. + * This will update metadata identifier, but also other usages + * which may be in graphicOverview URLs, resources identifier, + * metadata point of truth URL, ... + */ + private static Element updateMetadataUuidReferences(Element xml, String oldUuid, String newUuid) throws IOException, JDOMException { + String data = Xml.getString(xml); + return Xml.loadString(data.replace(oldUuid, newUuid), false); + } + } // ============================================================================= diff --git a/core/src/main/java/org/fao/geonet/kernel/mef/MEF2Exporter.java b/core/src/main/java/org/fao/geonet/kernel/mef/MEF2Exporter.java index 04d8e9cff3c..b202ab051a7 100644 --- a/core/src/main/java/org/fao/geonet/kernel/mef/MEF2Exporter.java +++ b/core/src/main/java/org/fao/geonet/kernel/mef/MEF2Exporter.java @@ -23,10 +23,11 @@ package org.fao.geonet.kernel.mef; +import co.elastic.clients.elasticsearch.core.SearchResponse; +import co.elastic.clients.elasticsearch.core.search.Hit; +import com.fasterxml.jackson.databind.ObjectMapper; import jeeves.server.context.ServiceContext; import org.apache.commons.io.FileUtils; -import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.search.SearchHit; import org.fao.geonet.Constants; import org.fao.geonet.GeonetContext; import org.fao.geonet.ZipUtil; @@ -137,8 +138,9 @@ public static Path doExport(ServiceContext context, Set uuids, String mdSchema = null, mdTitle = null, mdAbstract = null, isHarvested = null; MetadataType mdType = null; - SearchHit[] hits = result.getHits().getHits(); - final Map source = hits[0].getSourceAsMap(); + List hits = result.hits().hits(); + ObjectMapper objectMapper = new ObjectMapper(); + final Map source = objectMapper.convertValue(hits.get(0).source(), Map.class); mdSchema = (String) source.get(Geonet.IndexFieldNames.SCHEMA); mdTitle = (String) source.get(Geonet.IndexFieldNames.RESOURCETITLE); mdAbstract = (String) source.get(Geonet.IndexFieldNames.RESOURCEABSTRACT); diff --git a/core/src/main/java/org/fao/geonet/kernel/mef/MEFLib.java b/core/src/main/java/org/fao/geonet/kernel/mef/MEFLib.java index 2f3ef312843..ab78e4bc312 100644 --- a/core/src/main/java/org/fao/geonet/kernel/mef/MEFLib.java +++ b/core/src/main/java/org/fao/geonet/kernel/mef/MEFLib.java @@ -28,13 +28,9 @@ import static org.fao.geonet.kernel.mef.MEFConstants.FS; import static org.fao.geonet.kernel.mef.MEFConstants.VERSION; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileFilter; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; import java.net.URISyntaxException; +import java.net.URLEncoder; import java.nio.file.DirectoryStream; import java.nio.file.FileSystem; import java.nio.file.Files; @@ -47,6 +43,7 @@ import javax.annotation.Nonnull; import org.apache.commons.io.IOUtils; +import org.fao.geonet.Constants; import org.fao.geonet.GeonetContext; import org.fao.geonet.ZipUtil; import org.fao.geonet.constants.Edit; @@ -68,10 +65,13 @@ import org.fao.geonet.kernel.datamanager.IMetadataUtils; import org.fao.geonet.kernel.SchemaManager; import org.fao.geonet.kernel.setting.SettingManager; +import org.fao.geonet.lib.Lib; import org.fao.geonet.repository.GroupRepository; import org.fao.geonet.repository.OperationAllowedRepository; import org.fao.geonet.repository.OperationRepository; import org.fao.geonet.utils.BinaryFile; +import org.fao.geonet.utils.IO; +import org.fao.geonet.utils.Log; import org.fao.geonet.utils.Xml; import org.jdom.Attribute; import org.jdom.Document; @@ -529,10 +529,51 @@ static String getChangeDate(List files, String fileName) throw new Exception("File not found in info.xml : " + fileName); } + public static void backupRecord(AbstractMetadata metadata, ServiceContext context) { + Log.trace(Geonet.DATA_MANAGER, "Backing up record " + metadata.getId()); + Path outDir = Lib.resource.getRemovedDir(metadata.getId()); + Path outFile; + try { + // When metadata records contains character not supported by filesystem + // it may be an issue. eg. acri-st.fr/96443 + outFile = outDir.resolve(URLEncoder.encode(metadata.getUuid(), Constants.ENCODING) + ".zip"); + } catch (UnsupportedEncodingException e1) { + outFile = outDir.resolve(String.format( + "backup-%s-%s.mef", + new Date(), metadata.getUuid())); + } + + Path file = null; + try { + file = doExport(context, metadata.getUuid(), "full", false, true, false, false, true); + Files.createDirectories(outDir); + try (InputStream is = IO.newInputStream(file); + OutputStream os = Files.newOutputStream(outFile)) { + BinaryFile.copy(is, os); + } + } catch (Exception e) { + throw new RuntimeException("Error performing backup on record '" + metadata.getUuid() + "'. Contact the system administrator if the problem persists: " + e.getMessage(), e); + } finally { + if (file != null) { + IO.deleteFile(file, false, Geonet.MEF); + } + } + } + public enum UuidAction { GENERATEUUID("generateUUID"), NOTHING("nothing"), - OVERWRITE("overwrite"); + + /** + * Update the XML of the metadata record. + */ + OVERWRITE("overwrite"), + + /** + * Remove the metadata (and privileges, status, ...) + * and insert the new one with the same UUID. + */ + REMOVE_AND_REPLACE("removeAndReplace"); String name; UuidAction(String name) { @@ -552,7 +593,7 @@ public static UuidAction parse(String value) { public enum Format { /** - * Only metadata record and infomation + * Only metadata record and information */ SIMPLE, /** diff --git a/core/src/main/java/org/fao/geonet/kernel/metadata/DefaultStatusActions.java b/core/src/main/java/org/fao/geonet/kernel/metadata/DefaultStatusActions.java index 067fd90ee10..8c0c0ca2b33 100644 --- a/core/src/main/java/org/fao/geonet/kernel/metadata/DefaultStatusActions.java +++ b/core/src/main/java/org/fao/geonet/kernel/metadata/DefaultStatusActions.java @@ -1,5 +1,5 @@ //============================================================================= -//=== Copyright (C) 2001-2023 Food and Agriculture Organization of the +//=== Copyright (C) 2001-2024 Food and Agriculture Organization of the //=== United Nations (FAO-UN), United Nations World Food Programme (WFP) //=== and United Nations Environment Programme (UNEP) //=== @@ -23,6 +23,7 @@ package org.fao.geonet.kernel.metadata; +import com.google.common.base.Joiner; import jeeves.server.UserSession; import jeeves.server.context.ServiceContext; import org.apache.commons.lang.StringUtils; @@ -37,17 +38,24 @@ import org.fao.geonet.kernel.setting.Settings; import org.fao.geonet.repository.*; import org.fao.geonet.repository.specification.GroupSpecs; +import org.fao.geonet.util.LocalizedEmail; +import org.fao.geonet.util.LocalizedEmailParameter; +import org.fao.geonet.util.LocalizedEmailComponent; +import org.fao.geonet.languages.FeedbackLanguages; import org.fao.geonet.util.MailUtil; import org.fao.geonet.utils.Log; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; -import java.text.MessageFormat; import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; import static org.fao.geonet.kernel.setting.Settings.SYSTEM_FEEDBACK_EMAIL; - -import com.google.common.base.Joiner; +import static org.fao.geonet.util.LocalizedEmailComponent.ComponentType.*; +import static org.fao.geonet.util.LocalizedEmailComponent.KeyType; +import static org.fao.geonet.util.LocalizedEmailComponent.ReplacementType.*; +import static org.fao.geonet.util.LocalizedEmailParameter.ParameterType; public class DefaultStatusActions implements StatusActions { @@ -65,6 +73,7 @@ public class DefaultStatusActions implements StatusActions { private String replyToDescr; private StatusValueRepository statusValueRepository; protected IMetadataStatus metadataStatusManager; + private IMetadataUtils metadataRepository; /** * Constructor. @@ -105,6 +114,8 @@ public void init(ServiceContext context) throws Exception { dm = applicationContext.getBean(DataManager.class); metadataStatusManager = applicationContext.getBean(IMetadataStatus.class); siteUrl = sm.getSiteURL(context); + + metadataRepository = context.getBean(IMetadataUtils.class); } /** @@ -116,13 +127,11 @@ public void init(ServiceContext context) throws Exception { public void onEdit(int id, boolean minorEdit) throws Exception { if (Log.isTraceEnabled(Geonet.DATA_MANAGER)) { Log.trace(Geonet.DATA_MANAGER, "DefaultStatusActions.onEdit(" + id + ", " + minorEdit + ") with status " - + dm.getCurrentStatus(id)); + + dm.getCurrentStatus(id)); } if (!minorEdit && dm.getCurrentStatus(id).equals(StatusValue.Status.APPROVED)) { - //if (!minorEdit && dm.getCurrentStatus(id).equals(StatusValue.Status.APPROVED) - // && (context.getBean(IMetadataManager.class) instanceof DraftMetadataManager)) { ResourceBundle messages = ResourceBundle.getBundle("org.fao.geonet.api.Messages", - new Locale(this.language)); + new Locale(this.language)); String changeMessage = String.format(messages.getString("status_email_text"), replyToDescr, replyTo, id); Log.trace(Geonet.DATA_MANAGER, "Set DRAFT to current record with id " + id); dm.setStatus(context, id, Integer.valueOf(StatusValue.Status.DRAFT), new ISODate(), changeMessage); @@ -136,15 +145,19 @@ public void onEdit(int id, boolean minorEdit) throws Exception { * @return * @throws Exception */ - public Set onStatusChange(List listOfStatus) throws Exception { + public Map onStatusChange(List listOfStatus, boolean updateIndex) throws Exception { - Set unchanged = new HashSet<>(); + if (listOfStatus.stream().map(MetadataStatus::getMetadataId).distinct().count() != listOfStatus.size()) { + throw new IllegalArgumentException("Multiple status update received on the same metadata"); + } + + Map results = new HashMap<>(); - // -- process the metadata records to set status + // process the metadata records to set status for (MetadataStatus status : listOfStatus) { MetadataStatus currentStatus = dm.getStatus(status.getMetadataId()); - String currentStatusId = (currentStatus != null)? - String.valueOf(currentStatus.getStatusValue().getId()):""; + String currentStatusId = (currentStatus != null) ? + String.valueOf(currentStatus.getStatusValue().getId()) : ""; String statusId = status.getStatusValue().getId() + ""; @@ -152,44 +165,74 @@ public Set onStatusChange(List listOfStatus) throws Exc listOfId.add(status.getMetadataId()); - // --- For the workflow, if the status is already set to value + // For the workflow, if the status is already set to value // of status then do nothing. This does not apply to task and event. if (status.getStatusValue().getType().equals(StatusValueType.workflow) && - (statusId).equals(currentStatusId)) { + (statusId).equals(currentStatusId)) { if (context.isDebugEnabled()) context.debug(String.format("Metadata %s already has status %s ", status.getMetadataId(), status.getStatusValue().getId())); - unchanged.add(status.getMetadataId()); + results.put(status.getMetadataId(), StatusChangeType.UNCHANGED); continue; } - // --- set status, indexing is assumed to take place later - metadataStatusManager.setStatusExt(status); - - // --- inform content reviewers if the status is submitted - try { - notify(getUserToNotify(status), status); - } catch (Exception e) { - context.warning(String.format( - "Failed to send notification on status change for metadata %s with status %s. Error is: %s", - status.getMetadataId(), status.getStatusValue().getId(), e.getMessage())); + // if not possible to go from one status to the other, don't continue + AbstractMetadata metadata = metadataRepository.findOne(status.getMetadataId()); + if (!isStatusChangePossible(session.getProfile(), metadata, currentStatusId, statusId)) { + results.put(status.getMetadataId(), StatusChangeType.UNCHANGED); + continue; } - //Throw events + // debug output if necessary + if (context.isDebugEnabled()) + context.debug("Change status of metadata with id " + status.getMetadataId() + " from " + currentStatusId + " to " + statusId); + + // we know we are allowed to do the change, apply any side effects + boolean deleted = applyStatusChange(status.getMetadataId(), status, statusId, updateIndex); + + if (deleted) { + results.put(status.getMetadataId(), StatusChangeType.DELETED); + } else { + results.put(status.getMetadataId(), StatusChangeType.UPDATED); + } + // throw events Log.trace(Geonet.DATA_MANAGER, "Throw workflow events."); for (Integer mid : listOfId) { - if (!unchanged.contains(mid)) { + if (results.get(mid) != StatusChangeType.DELETED) { Log.debug(Geonet.DATA_MANAGER, " > Status changed for record (" + mid + ") to status " + status); context.getApplicationContext().publishEvent(new MetadataStatusChanged( metadataUtils.findOne(mid), status.getStatusValue(), status.getChangeMessage(), - status.getUserId())); + status.getUserId() + )); } } + // inform content reviewers if the status is submitted + try { + notify(getUserToNotify(status), status); + } catch (Exception e) { + context.warning(String.format( + "Failed to send notification on status change for metadata %s with status %s. Error is: %s", + status.getMetadataId(), status.getStatusValue().getId(), e.getMessage())); + } + } - return unchanged; + return results; + } + + /** + * Placeholder to apply any side effects. + * eg. if APPROVED, publish a record, + * if RETIRED, unpublish or delete the record. + */ + private boolean applyStatusChange(int metadataId, MetadataStatus status, String toStatusId, boolean updateIndex) throws Exception { + boolean deleted = false; + if (!deleted) { + metadataStatusManager.setStatusExt(status, updateIndex); + } + return deleted; } @@ -206,56 +249,108 @@ protected void notify(List userToNotify, MetadataStatus status) throws Exc return; } - ResourceBundle messages = ResourceBundle.getBundle("org.fao.geonet.api.Messages", new Locale(this.language)); + ApplicationContext applicationContext = ApplicationContextHolder.get(); + FeedbackLanguages feedbackLanguages = applicationContext.getBean(FeedbackLanguages.class); - String translatedStatusName = getTranslatedStatusName(status.getStatusValue().getId()); - // TODO: Refactor to allow custom messages based on the type of status - String subjectTemplate = ""; - try { - subjectTemplate = messages - .getString("status_change_" + status.getStatusValue().getName() + "_email_subject"); - } catch (MissingResourceException e) { - subjectTemplate = messages.getString("status_change_default_email_subject"); - } - String subject = MessageFormat.format(subjectTemplate, siteName, translatedStatusName, replyToDescr // Author of the change - ); + Locale[] feedbackLocales = feedbackLanguages.getLocales(new Locale(this.language)); Set listOfId = new HashSet<>(1); listOfId.add(status.getMetadataId()); - String textTemplate = ""; - try { - textTemplate = messages.getString("status_change_" + status.getStatusValue().getName() + "_email_text"); - } catch (MissingResourceException e) { - textTemplate = messages.getString("status_change_default_email_text"); - } - UserRepository userRepository = context.getBean(UserRepository.class); User owner = userRepository.findById(status.getOwner()).orElse(null); IMetadataUtils metadataRepository = ApplicationContextHolder.get().getBean(IMetadataUtils.class); AbstractMetadata metadata = metadataRepository.findOne(status.getMetadataId()); - String metadataUrl = metadataUtils.getDefaultUrl(metadata.getUuid(), this.language); + String subjectTemplateKey = ""; + String textTemplateKey = ""; + boolean failedToFindASpecificSubjectTemplate = false; + boolean failedToFindASpecificTextTemplate = false; + + for (Locale feedbackLocale: feedbackLocales) { + ResourceBundle resourceBundle = ResourceBundle.getBundle("org.fao.geonet.api.Messages", feedbackLocale); + + if (!failedToFindASpecificSubjectTemplate) { + try { + subjectTemplateKey = "status_change_" + status.getStatusValue().getName() + "_email_subject"; + resourceBundle.getString(subjectTemplateKey); + } catch (MissingResourceException e) { + failedToFindASpecificSubjectTemplate = true; + } + } + + if (!failedToFindASpecificTextTemplate) { + try { + textTemplateKey = "status_change_" + status.getStatusValue().getName() + "_email_text"; + resourceBundle.getString(textTemplateKey); + } catch (MissingResourceException e) { + failedToFindASpecificTextTemplate = true; + } + } + + if ((failedToFindASpecificSubjectTemplate) && (failedToFindASpecificTextTemplate)) break; + } - String message = MessageFormat.format(textTemplate, replyToDescr, // Author of the change - status.getChangeMessage(), translatedStatusName, status.getChangeDate(), status.getDueDate(), - status.getCloseDate(), - owner == null ? "" : Joiner.on(" ").skipNulls().join( owner.getName(), owner.getSurname()), - metadataUrl); + if (failedToFindASpecificSubjectTemplate) { + subjectTemplateKey = "status_change_default_email_subject"; + } + + if (failedToFindASpecificTextTemplate) { + textTemplateKey = "status_change_default_email_text"; + } + LocalizedEmailComponent emailSubjectComponent = new LocalizedEmailComponent(SUBJECT, subjectTemplateKey, KeyType.MESSAGE_KEY, NUMERIC_FORMAT); + emailSubjectComponent.enableCompileWithIndexFields(metadata.getUuid()); + + LocalizedEmailComponent emailMessageComponent = new LocalizedEmailComponent(MESSAGE, textTemplateKey, KeyType.MESSAGE_KEY, NUMERIC_FORMAT); + emailMessageComponent.enableCompileWithIndexFields(metadata.getUuid()); + emailMessageComponent.enableReplaceLinks(false); + + LocalizedEmailComponent emailSalutationComponent = new LocalizedEmailComponent(SALUTATION, "{{userName}},\n\n", KeyType.RAW_VALUE, NONE); + + for (Locale feedbackLocale : feedbackLocales) { + // TODO: Refactor to allow custom messages based on the type of status + + emailSubjectComponent.addParameters( + feedbackLocale, + new LocalizedEmailParameter(ParameterType.RAW_VALUE, 1, siteName), + new LocalizedEmailParameter(ParameterType.RAW_VALUE, 2, getTranslatedStatusName(status.getStatusValue().getId(), feedbackLocale)), + new LocalizedEmailParameter(ParameterType.RAW_VALUE, 3, replyToDescr) + ); + + emailMessageComponent.addParameters( + feedbackLocale, + new LocalizedEmailParameter(ParameterType.RAW_VALUE, 1, replyToDescr), + new LocalizedEmailParameter(ParameterType.RAW_VALUE, 2, status.getChangeMessage()), + new LocalizedEmailParameter(ParameterType.RAW_VALUE, 3, getTranslatedStatusName(status.getStatusValue().getId(), feedbackLocale)), + new LocalizedEmailParameter(ParameterType.RAW_VALUE, 4, status.getChangeDate()), + new LocalizedEmailParameter(ParameterType.RAW_VALUE, 5, status.getDueDate()), + new LocalizedEmailParameter(ParameterType.RAW_VALUE, 6, status.getCloseDate()), + new LocalizedEmailParameter(ParameterType.RAW_VALUE, 7, owner == null ? "" : Joiner.on(" ").skipNulls().join(owner.getName(), owner.getSurname())), + new LocalizedEmailParameter(ParameterType.RAW_VALUE, 8, metadataUtils.getDefaultUrl(metadata.getUuid(), feedbackLocale.getISO3Language())) + ); + } - subject = MailUtil.compileMessageWithIndexFields(subject, metadata.getUuid(), this.language); - message = MailUtil.compileMessageWithIndexFields(message, metadata.getUuid(), this.language); for (User user : userToNotify) { - String salutation = Joiner.on(" ").skipNulls().join( user.getName(), user.getSurname()); - //If we have a salutation then end it with a "," - if (StringUtils.isEmpty(salutation)) { - salutation = ""; + LocalizedEmail localizedEmail = new LocalizedEmail(false); + + String userName = Joiner.on(" ").skipNulls().join(user.getName(), user.getSurname()); + //If we have a userName add the salutation + String message; + if (StringUtils.isEmpty(userName)) { + localizedEmail.addComponents(emailSubjectComponent, emailMessageComponent); + + message = localizedEmail.getParsedMessage(feedbackLocales); } else { - salutation += ",\n\n"; + localizedEmail.addComponents(emailSubjectComponent, emailMessageComponent, emailSalutationComponent); + + Map replacements = new HashMap<>(); + replacements.put("{{userName}}", userName); + message = localizedEmail.getParsedMessage(feedbackLocales, replacements); } - sendEmail(user.getEmail(), subject, salutation + message); + String subject = localizedEmail.getParsedSubject(feedbackLocales); + sendEmail(user.getEmail(), subject, message); } } @@ -268,6 +363,35 @@ protected void notify(List userToNotify, MetadataStatus status) throws Exc */ protected List getUserToNotify(MetadataStatus status) { StatusValueNotificationLevel notificationLevel = status.getStatusValue().getNotificationLevel(); + + // If new status is DRAFT and previous status is not SUBMITTED (which means a rejection), + // ignore notifications as the DRAFT status is used also when creating the working copy. + // We don't want to notify when creating a working copy. + if (status.getStatusValue().getId() == Integer.parseInt(StatusValue.Status.DRAFT) && + ((StringUtils.isEmpty(status.getPreviousState())) || + (Integer.parseInt(status.getPreviousState()) != Integer.parseInt(StatusValue.Status.SUBMITTED)))) { + return new ArrayList<>(); + } + + // If status is DRAFT and previous status is SUBMITTED, which means either: + // - a cancel working copy (from editor) --> should be notified the reviewer. + // - rejection (from reviewer) --> should be notified the editor. + // and the notification level is recordUserAuthor or recordProfileReviewer, + // then adjust the notification level, depending on the user role + if ((status.getStatusValue().getId() == Integer.parseInt(StatusValue.Status.DRAFT)) && + (!StringUtils.isEmpty(status.getPreviousState()) && + (status.getPreviousState().equals(StatusValue.Status.SUBMITTED))) && + (notificationLevel.equals(StatusValueNotificationLevel.recordUserAuthor) || (notificationLevel.equals(StatusValueNotificationLevel.recordProfileReviewer)))) { + UserRepository userRepository = ApplicationContextHolder.get().getBean(UserRepository.class); + Optional user = userRepository.findById(status.getUserId()); + if (user.isPresent()) { + if (user.get().getProfile() == Profile.Editor) { + notificationLevel = StatusValueNotificationLevel.recordProfileReviewer; + } else { + notificationLevel = StatusValueNotificationLevel.recordUserAuthor; + } + } + } // TODO: Status does not provide batch update // So taking care of one record at a time. // Currently the code could notify a mix of reviewers @@ -277,7 +401,7 @@ protected List getUserToNotify(MetadataStatus status) { return getUserToNotify(notificationLevel, listOfId, status.getOwner()); } - public static List getUserToNotify(StatusValueNotificationLevel notificationLevel, Set recordIds, Integer ownerId) { + public static List getUserToNotify(StatusValueNotificationLevel notificationLevel, Set recordIds, Integer ownerId) { UserRepository userRepository = ApplicationContextHolder.get().getBean(UserRepository.class); List users = new ArrayList<>(); @@ -329,10 +453,12 @@ public static List getUserToNotify(StatusValueNotificationLevel notificati } } } - return users; + + // Filter out users without email + return users.stream().filter(u -> StringUtils.isNotEmpty(u.getEmail())).collect(Collectors.toList()); } - public static List getGroupToNotify(StatusValueNotificationLevel notificationLevel, List groupNames) { + public static List getGroupToNotify(StatusValueNotificationLevel notificationLevel, List groupNames) { GroupRepository groupRepository = ApplicationContextHolder.get().getBean(GroupRepository.class); List groups = new ArrayList<>(); @@ -359,14 +485,14 @@ protected void unsetAllOperations(int mdId) throws Exception { } } - private String getTranslatedStatusName(int statusValueId) { + private String getTranslatedStatusName(int statusValueId, Locale locale) { String translatedStatusName = ""; StatusValue s = statusValueRepository.findOneById(statusValueId); if (s == null) { translatedStatusName = statusValueId - + " (Status not found in database translation table. Check the content of the StatusValueDes table.)"; + + " (Status not found in database translation table. Check the content of the StatusValueDes table.)"; } else { - translatedStatusName = s.getLabel(this.language); + translatedStatusName = s.getLabel(locale.getISO3Language()); } return translatedStatusName; } @@ -386,11 +512,41 @@ protected void sendEmail(String sendTo, String subject, String message) { ApplicationContext applicationContext = ApplicationContextHolder.get(); SettingManager sm = applicationContext.getBean(SettingManager.class); // Doesn't make sense go further without any mailserver set... - if(StringUtils.isNotBlank(sm.getValue(Settings.SYSTEM_FEEDBACK_MAILSERVER_HOST))) { + if (StringUtils.isNotBlank(sm.getValue(Settings.SYSTEM_FEEDBACK_MAILSERVER_HOST))) { List to = new ArrayList<>(); to.add(sendTo); MailUtil.sendMail(to, subject, message, null, sm, replyTo, replyToDescr); } } } + + /** + * Placeholder to test whether a given status change for a given role is allowed or not. + *

+ * + * @param profile the role that tries to execute the status change + * @param fromStatus the status from which we start + * @param toStatus the status to which we'd like to change + * @return whether the change is allowed + */ + private boolean isStatusChangePossible(Profile profile, AbstractMetadata metadata, String fromStatus, String toStatus) throws Exception { + return true; + // Example: + // if (StringUtils.isEmpty(fromStatus) && toStatus.equals(StatusValue.Status.DRAFT)) + // return true; + // // figure out whether we can switch from status to status, depending on the profile + // Set toProfiles = new HashSet<>(); + // switch (profile) { + // case Editor: + // toProfiles = getEditorFlow().get(fromStatus); + // break; + // case Administrator: + // toProfiles = getAdminFlow().get(fromStatus); + // break; + // case Reviewer: + // toProfiles = getReviewerFlow().get(fromStatus); + // break; + // } + // return toProfiles != null && toProfiles.contains(toStatus); + } } diff --git a/core/src/main/java/org/fao/geonet/kernel/metadata/StatusActions.java b/core/src/main/java/org/fao/geonet/kernel/metadata/StatusActions.java index 21655585738..047c0b1b33a 100644 --- a/core/src/main/java/org/fao/geonet/kernel/metadata/StatusActions.java +++ b/core/src/main/java/org/fao/geonet/kernel/metadata/StatusActions.java @@ -26,6 +26,7 @@ import jeeves.server.context.ServiceContext; import java.util.List; +import java.util.Map; import java.util.Set; import org.fao.geonet.domain.ISODate; @@ -37,6 +38,6 @@ public interface StatusActions { public void onEdit(int id, boolean minorEdit) throws Exception; - public Set onStatusChange(List status) throws Exception; + public Map onStatusChange(List status, boolean updateIndex) throws Exception; } diff --git a/core/src/main/java/org/fao/geonet/kernel/metadata/StatusChangeType.java b/core/src/main/java/org/fao/geonet/kernel/metadata/StatusChangeType.java new file mode 100644 index 00000000000..81d3983ffa8 --- /dev/null +++ b/core/src/main/java/org/fao/geonet/kernel/metadata/StatusChangeType.java @@ -0,0 +1,29 @@ +//============================================================================= +//=== Copyright (C) 2001-2023 Food and Agriculture Organization of the +//=== United Nations (FAO-UN), United Nations World Food Programme (WFP) +//=== and United Nations Environment Programme (UNEP) +//=== +//=== This program is free software; you can redistribute it and/or modify +//=== it under the terms of the GNU General Public License as published by +//=== the Free Software Foundation; either version 2 of the License, or (at +//=== your option) any later version. +//=== +//=== This program is distributed in the hope that it will be useful, but +//=== WITHOUT ANY WARRANTY; without even the implied warranty of +//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//=== General Public License for more details. +//=== +//=== You should have received a copy of the GNU General Public License +//=== along with this program; if not, write to the Free Software +//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA +//=== +//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, +//=== Rome - Italy. email: geonetwork@osgeo.org +//============================================================================== +package org.fao.geonet.kernel.metadata; + +public enum StatusChangeType { + UPDATED, + UNCHANGED, + DELETED +} diff --git a/core/src/main/java/org/fao/geonet/kernel/region/Region.java b/core/src/main/java/org/fao/geonet/kernel/region/Region.java index ff224729d89..58f7e6a7ab3 100644 --- a/core/src/main/java/org/fao/geonet/kernel/region/Region.java +++ b/core/src/main/java/org/fao/geonet/kernel/region/Region.java @@ -29,10 +29,10 @@ import org.geotools.referencing.CRS; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.jdom.Element; -import org.opengis.referencing.FactoryException; -import org.opengis.referencing.NoSuchAuthorityCodeException; -import org.opengis.referencing.crs.CoordinateReferenceSystem; -import org.opengis.referencing.operation.TransformException; +import org.geotools.api.referencing.FactoryException; +import org.geotools.api.referencing.NoSuchAuthorityCodeException; +import org.geotools.api.referencing.crs.CoordinateReferenceSystem; +import org.geotools.api.referencing.operation.TransformException; import java.util.Collections; import java.util.Map; diff --git a/core/src/main/java/org/fao/geonet/kernel/region/RegionsDAO.java b/core/src/main/java/org/fao/geonet/kernel/region/RegionsDAO.java index 4a06e7181a5..5a68a754a60 100644 --- a/core/src/main/java/org/fao/geonet/kernel/region/RegionsDAO.java +++ b/core/src/main/java/org/fao/geonet/kernel/region/RegionsDAO.java @@ -28,7 +28,7 @@ import jeeves.server.context.ServiceContext; import org.jdom.Element; -import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.geotools.api.referencing.crs.CoordinateReferenceSystem; import java.lang.ref.WeakReference; import java.util.Collection; diff --git a/core/src/main/java/org/fao/geonet/kernel/schema/MetadataSchema.java b/core/src/main/java/org/fao/geonet/kernel/schema/MetadataSchema.java index d07dccc595c..3f8e038a88d 100644 --- a/core/src/main/java/org/fao/geonet/kernel/schema/MetadataSchema.java +++ b/core/src/main/java/org/fao/geonet/kernel/schema/MetadataSchema.java @@ -1,29 +1,25 @@ -//============================================================================== -//=== -//=== MetadataSchema -//=== -//============================================================================== -//=== Copyright (C) 2001-2007 Food and Agriculture Organization of the -//=== United Nations (FAO-UN), United Nations World Food Programme (WFP) -//=== and United Nations Environment Programme (UNEP) -//=== -//=== This program is free software; you can redistribute it and/or modify -//=== it under the terms of the GNU General Public License as published by -//=== the Free Software Foundation; either version 2 of the License, or (at -//=== your option) any later version. -//=== -//=== This program is distributed in the hope that it will be useful, but -//=== WITHOUT ANY WARRANTY; without even the implied warranty of -//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -//=== General Public License for more details. -//=== -//=== You should have received a copy of the GNU General Public License -//=== along with this program; if not, write to the Free Software -//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA -//=== -//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, -//=== Rome - Italy. email: geonetwork@osgeo.org -//============================================================================== +/* + * Copyright (C) 2001-2023 Food and Agriculture Organization of the + * United Nations (FAO-UN), United Nations World Food Programme (WFP) + * and United Nations Environment Programme (UNEP) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, + * Rome - Italy. email: geonetwork@osgeo.org + */ package org.fao.geonet.kernel.schema; @@ -34,9 +30,9 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.commons.lang.StringUtils; import org.fao.geonet.api.exception.ResourceNotFoundException; import org.fao.geonet.constants.Geonet; -import org.fao.geonet.domain.Pair; import org.fao.geonet.domain.ReservedOperation; import org.fao.geonet.domain.Schematron; import org.fao.geonet.domain.SchematronCriteria; @@ -82,15 +78,15 @@ public class MetadataSchema { private static final String XSL_FILE_EXTENSION = ".xsl"; private static final String SCH_FILE_EXTENSION = ".sch"; private static final String SCHEMATRON_RULE_FILE_PREFIX = "schematron-rules"; - private Map> hmElements = new HashMap>(); - private Map>> hmRestric = new HashMap>>(); - private Map hmTypes = new HashMap(); - private Map> hmSubs = new HashMap>(); - private Map hmSubsLink = new HashMap(); - private Map hmNameSpaces = new HashMap(); - private Map hmPrefixes = new HashMap(); - private Map> hmOperationFilters = - new HashMap>(); + private Map> hmElements = new HashMap<>(); + private Map>> hmRestric = new HashMap<>(); + private Map hmTypes = new HashMap<>(); + private Map> hmSubs = new HashMap<>(); + private Map hmSubsLink = new HashMap<>(); + private Map hmNameSpaces = new HashMap<>(); + private Map hmPrefixes = new HashMap<>(); + private Map hmOperationFilters = + new HashMap<>(); private String schemaName; private Path schemaDir; private String standardUrl; @@ -294,8 +290,8 @@ void addElement(String name, String type, List alValues, List al // first just add the subs - because these are for global elements we // never have a clash because global elements are all in the same scope // and are thus unique - if (alSubs != null && alSubs.size() > 0) hmSubs.put(name, alSubs); - if (subLink != null && subLink.length() > 0) hmSubsLink.put(name, subLink); + if (alSubs != null && !alSubs.isEmpty()) hmSubs.put(name, alSubs); + if (subLink != null && StringUtils.isNotBlank(subLink)) hmSubsLink.put(name, subLink); List exType = hmElements.get(name); @@ -309,7 +305,8 @@ void addElement(String name, String type, List alValues, List al // it's not there so add a new list } else { - hmElements.put(name, exType = new ArrayList()); + exType = new ArrayList<>(); + hmElements.put(name, exType); } exType.add(type); @@ -323,7 +320,8 @@ void addElement(String name, String type, List alValues, List al // it's not there so add a new list of lists } else { - hmRestric.put(restricName, exValues = new ArrayList>()); + exValues = new ArrayList<>(); + hmRestric.put(restricName, exValues); } exValues.add(alValues); } @@ -361,7 +359,7 @@ public String getNS(String targetNSPrefix) { */ @JsonIgnore public List getNamespaces() { - List list = new ArrayList(hmNameSpaces.size()); + List list = new ArrayList<>(hmNameSpaces.size()); for (Namespace ns : hmNameSpaces.values()) { list.add(ns); } @@ -382,12 +380,12 @@ public String getPrefix(String theNSUri) { //--------------------------------------------------------------------------- @JsonIgnore public List getSchemaNS() { - return new ArrayList(hmPrefixes.values()); + return new ArrayList<>(hmPrefixes.values()); } @JsonProperty(value = "namespaces") public Map getSchemaNSWithPrefix() { - Map mapNs = new HashMap(); + Map mapNs = new HashMap<>(); List schemaNsList = getSchemaNS(); for (Namespace ns : schemaNsList) { @@ -518,7 +516,7 @@ private void setSchematronPriorities() { this.schemaRepo.saveAll(updated); } - public void setOperationFilters(Map> operationFilters) { + public void setOperationFilters(Map operationFilters) { this.hmOperationFilters = operationFilters; } @@ -527,10 +525,14 @@ public void setOperationFilters(Map> operationFilt * * @return The XPath to select element to filter or null */ - public Pair getOperationFilter(ReservedOperation operation) { + public MetadataSchemaOperationFilter getOperationFilter(ReservedOperation operation) { return hmOperationFilters.get(operation.name()); } + public MetadataSchemaOperationFilter getOperationFilter(String operation) { + return hmOperationFilters.get(operation); + } + @JsonIgnore public SchemaPlugin getSchemaPlugin() { return schemaPlugin; diff --git a/core/src/main/java/org/fao/geonet/kernel/schema/MetadataSchemaOperationFilter.java b/core/src/main/java/org/fao/geonet/kernel/schema/MetadataSchemaOperationFilter.java new file mode 100644 index 00000000000..d296b5fa9ee --- /dev/null +++ b/core/src/main/java/org/fao/geonet/kernel/schema/MetadataSchemaOperationFilter.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2001-2023 Food and Agriculture Organization of the + * United Nations (FAO-UN), United Nations World Food Programme (WFP) + * and United Nations Environment Programme (UNEP) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, + * Rome - Italy. email: geonetwork@osgeo.org + */ +package org.fao.geonet.kernel.schema; + +import org.jdom.Element; + +public class MetadataSchemaOperationFilter { + private String xpath; + private String jsonpath; + private String ifNotOperation; + private Element markedElement; + + + public MetadataSchemaOperationFilter(String xpath, String jsonpath, String ifNotOperation) { + this(xpath, jsonpath, ifNotOperation, null); + } + + public MetadataSchemaOperationFilter(String xpath, String jsonpath, String ifNotOperation, Element markedElement) { + this.xpath = xpath; + this.jsonpath = jsonpath; + this.ifNotOperation = ifNotOperation; + this.markedElement = markedElement; + + } + + public String getXpath() { + return xpath; + } + + public String getJsonpath() { + return jsonpath; + } + + public String getIfNotOperation() { + return ifNotOperation; + } + + public Element getMarkedElement() { + return markedElement; + } +} diff --git a/core/src/main/java/org/fao/geonet/kernel/search/EsSearchManager.java b/core/src/main/java/org/fao/geonet/kernel/search/EsSearchManager.java index fd2f4655a6c..978ab63a750 100644 --- a/core/src/main/java/org/fao/geonet/kernel/search/EsSearchManager.java +++ b/core/src/main/java/org/fao/geonet/kernel/search/EsSearchManager.java @@ -23,6 +23,15 @@ package org.fao.geonet.kernel.search; +import co.elastic.clients.elasticsearch._types.ElasticsearchException; +import co.elastic.clients.elasticsearch._types.SortOptions; +import co.elastic.clients.elasticsearch.core.*; +import co.elastic.clients.elasticsearch.core.bulk.BulkOperation; +import co.elastic.clients.elasticsearch.core.bulk.UpdateOperation; +import co.elastic.clients.elasticsearch.core.search.Hit; +import co.elastic.clients.elasticsearch.indices.ExistsRequest; +import co.elastic.clients.elasticsearch.indices.*; +import co.elastic.clients.transport.endpoints.BooleanResponse; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -30,37 +39,18 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import jeeves.server.UserSession; import jeeves.server.context.ServiceContext; -import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; -import org.elasticsearch.action.bulk.BulkRequest; -import org.elasticsearch.action.bulk.BulkResponse; -import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.action.support.master.AcknowledgedResponse; -import org.elasticsearch.action.update.UpdateRequest; -import org.elasticsearch.action.update.UpdateResponse; -import org.elasticsearch.client.RequestOptions; -import org.elasticsearch.client.indices.CreateIndexRequest; -import org.elasticsearch.client.indices.CreateIndexResponse; -import org.elasticsearch.client.indices.GetIndexRequest; -import org.elasticsearch.common.xcontent.XContentType; -import org.elasticsearch.index.query.QueryStringQueryBuilder; -import org.elasticsearch.index.reindex.DeleteByQueryRequest; -import org.elasticsearch.script.Script; -import org.elasticsearch.script.ScriptType; -import org.elasticsearch.search.sort.FieldSortBuilder; -import org.elasticsearch.search.sort.SortBuilder; import org.fao.geonet.ApplicationContextHolder; import org.fao.geonet.constants.Geonet; import org.fao.geonet.domain.*; import org.fao.geonet.index.es.EsRestClient; -import org.fao.geonet.kernel.DataManager; import org.fao.geonet.kernel.GeonetworkDataDirectory; import org.fao.geonet.kernel.SelectionManager; +import org.fao.geonet.kernel.datamanager.IMetadataIndexer; import org.fao.geonet.kernel.datamanager.IMetadataUtils; import org.fao.geonet.kernel.search.index.OverviewIndexFieldUpdater; import org.fao.geonet.kernel.setting.SettingInfo; @@ -82,11 +72,8 @@ import java.nio.file.StandardOpenOption; import java.util.*; -import static org.elasticsearch.rest.RestStatus.CREATED; -import static org.elasticsearch.rest.RestStatus.OK; import static org.fao.geonet.constants.Geonet.IndexFieldNames.IS_TEMPLATE; -import static org.fao.geonet.kernel.search.IndexFields.INDEXING_ERROR_FIELD; -import static org.fao.geonet.kernel.search.IndexFields.INDEXING_ERROR_MSG; +import static org.fao.geonet.kernel.search.IndexFields.*; public class EsSearchManager implements ISearchManager { @@ -153,7 +140,7 @@ public class EsSearchManager implements ISearchManager { .build(); FIELDLIST_RELATED_SCRIPTED = ImmutableMap.builder() - // ElasticSearch scripted field to get the first overview url. Scripted fields must return single values. + // Elasticsearch scripted field to get the first overview url. Scripted fields must return single values. .put("overview", "return params['_source'].overview == null ? [] : params['_source'].overview.stream().map(f -> f.url).findFirst().orElse('');") .build(); } @@ -181,10 +168,10 @@ public void setIndexType(String indexType) { } @Autowired - public EsRestClient client; + private EsRestClient client; @Autowired - OverviewIndexFieldUpdater overviewFieldUpdater; + private OverviewIndexFieldUpdater overviewFieldUpdater; private int commitInterval = 200; @@ -202,7 +189,7 @@ private Path getXSLTForIndexing(Path schemaDir, MetadataType metadataType) { if (!Files.exists(xsltForIndexing)) { throw new RuntimeException(String.format( "XSLT for schema indexing does not exist. Create file '%s'.", - xsltForIndexing.toString())); + xsltForIndexing)); } return xsltForIndexing; } @@ -226,14 +213,21 @@ private void addMDFields(Element doc, Path schemaDir, } catch (Exception e) { LOGGER.error("Indexing stylesheet contains errors: {} \n Marking the metadata as _indexingError=1 in index", e.getMessage()); doc.addContent(new Element(INDEXING_ERROR_FIELD).setText("true")); - doc.addContent(new Element(INDEXING_ERROR_MSG).setText("GNIDX-XSL||" + e.getMessage())); - doc.addContent(new Element(IndexFields.DRAFT).setText("n")); + doc.addContent(createIndexingErrorMsgElement("indexingErrorMsg-indexingStyleSheetError", "error", + Map.of("message", e.getMessage()))); } } private void addMoreFields(Element doc, Multimap fields) { - fields.entries().forEach(e -> doc.addContent(new Element(e.getKey()) - .setText(String.valueOf(e.getValue())))); + ArrayList objectFields = Lists.newArrayList(INDEXING_ERROR_MSG); + fields.entries().forEach(e -> { + Element newElement = new Element(e.getKey()) + .setText(String.valueOf(e.getValue())); + if (objectFields.contains(e.getKey())) { + newElement.setAttribute("type", "object"); + } + doc.addContent(newElement); + }); } public Element makeField(String name, String value) { @@ -249,9 +243,8 @@ public void init(boolean dropIndexFirst, Optional> indices) throws if (indexList != null) { indexList.keySet().forEach(e -> { try { - if (indices.isPresent() ? - indices.get().contains(e) : - true) { + if (!indices.isPresent() || + indices.get().contains(e)) { createIndex(e, indexList.get(e), dropIndexFirst); } } catch (IOException ex) { @@ -268,47 +261,52 @@ public void init(boolean dropIndexFirst, Optional> indices) throws private void createIndex(String indexId, String indexName, boolean dropIndexFirst) throws IOException { if (dropIndexFirst) { try { - DeleteIndexRequest request = new DeleteIndexRequest(indexName); - AcknowledgedResponse deleteIndexResponse = client.getClient().indices().delete(request, RequestOptions.DEFAULT); - if (deleteIndexResponse.isAcknowledged()) { - LOGGER.debug("Index '{}' removed.", new Object[]{indexName}); + DeleteIndexRequest deleteIndexRequest = DeleteIndexRequest.of( + b -> b.index(indexName) + ); + + DeleteIndexResponse deleteIndexResponse = client.getClient().indices().delete(deleteIndexRequest); + if (deleteIndexResponse.acknowledged()) { + LOGGER.debug("Index '{}' removed.", indexName); } } catch (Exception e) { // index does not exist ? - LOGGER.debug("Error during index '{}' removal. Error is: {}", new Object[]{indexName, e.getMessage()}); + LOGGER.debug("Error during index '{}' removal. Error is: {}", indexName, e.getMessage()); } } // Check index exist first - GetIndexRequest request = new GetIndexRequest(indexName); + ExistsRequest existsRequest = ExistsRequest.of( + b -> b.index(indexName) + ); + try { - boolean exists = client.getClient().indices().exists(request, RequestOptions.DEFAULT); - if (exists && !dropIndexFirst) { + BooleanResponse exists = client.getClient().indices().exists(existsRequest); + if (exists.value() && !dropIndexFirst) { return; } - - if (!exists || dropIndexFirst) { + if (!exists.value() || dropIndexFirst) { // Check version of the index - how ? // Create it if not Path indexConfiguration = dataDirectory.getIndexConfigDir().resolve(indexId + ".json"); if (Files.exists(indexConfiguration)) { - String configuration; - try (InputStream is = Files.newInputStream(indexConfiguration, StandardOpenOption.READ)) { - configuration = IOUtils.toString(is); - } - CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName); - createIndexRequest.source(configuration, XContentType.JSON); - CreateIndexResponse createIndexResponse = client.getClient().indices().create(createIndexRequest, RequestOptions.DEFAULT); - - if (createIndexResponse.isAcknowledged()) { - LOGGER.debug("Index '{}' created", new Object[]{indexName}); - } else { - final String message = String.format("Index '%s' was not created. Error is: %s", indexName, createIndexResponse.toString()); - LOGGER.error(message); - throw new IllegalStateException(message); + try (InputStream is = Files.newInputStream(indexConfiguration, StandardOpenOption.READ)) { + CreateIndexRequest createIndexRequest = CreateIndexRequest.of( + b -> b.index(indexName).withJson(is) + ); + + CreateIndexResponse createIndexResponse = client.getClient().indices().create(createIndexRequest); + + if (createIndexResponse.acknowledged()) { + LOGGER.debug("Index '{}' created", indexName); + } else { + final String message = String.format("Index '%s' was not created. Error is: %s", indexName, createIndexResponse); + LOGGER.error(message); + throw new IllegalStateException(message); + } } } else { throw new FileNotFoundException(String.format( @@ -317,10 +315,13 @@ private void createIndex(String indexId, String indexName, boolean dropIndexFirs indexName)); } } + } catch (ElasticsearchException ex) { + LOGGER.error(ex.getMessage(), ex); + throw new IOException(ex.getMessage()); } catch (Exception cnce) { final String message = String.format("Could not connect to index '%s'. Error is %s. Is the index server up and running?", defaultIndex, cnce.getMessage()); - LOGGER.error(message); + LOGGER.error(message, cnce); throw new IOException(message); } } @@ -331,8 +332,14 @@ public void end() { public UpdateResponse updateFields(String id, Map fields) throws IOException { fields.put(Geonet.IndexFieldNames.INDEXING_DATE, new Date()); - UpdateRequest updateRequest = new UpdateRequest(defaultIndex, id).doc(fields); - return client.getClient().update(updateRequest, RequestOptions.DEFAULT); + + UpdateRequest updateRequest = UpdateRequest.of( + b -> b.index(defaultIndex) + .id(id) + .doc(fields) + ); + + return client.getClient().update(updateRequest, Void.class); } public BulkResponse updateFields(String id, Multimap fields, Set fieldsToRemove) throws IOException { @@ -340,38 +347,65 @@ public BulkResponse updateFields(String id, Multimap fields, Set fields.asMap().forEach((e, v) -> fieldMap.put(e, v.toArray())); return updateFields(id, fieldMap, fieldsToRemove); } + public BulkResponse updateFields(String id, Map fieldMap, Set fieldsToRemove) throws IOException { fieldMap.put(Geonet.IndexFieldNames.INDEXING_DATE, new Date()); - BulkRequest bulkrequest = new BulkRequest(); - StringBuilder script = new StringBuilder(); - fieldsToRemove.forEach(f -> - script.append(String.format("ctx._source.remove('%s');", f))); - UpdateRequest deleteFieldRequest = - new UpdateRequest(defaultIndex, id).script(new Script(ScriptType.INLINE, - "painless", - script.toString(), - Collections.emptyMap())); - bulkrequest.add(deleteFieldRequest); - UpdateRequest addFieldRequest = new UpdateRequest(defaultIndex, id) - .doc(fieldMap); - bulkrequest.add(addFieldRequest); - return client.getClient().bulk(bulkrequest, RequestOptions.DEFAULT); + StringBuilder scriptSource = new StringBuilder(); + fieldsToRemove.forEach(f -> + scriptSource.append(String.format("ctx._source.remove('%s');", f))); + + UpdateOperation deleteFieldsOperation = UpdateOperation.of( + b -> b.id(id) + .index(defaultIndex) + .action(action -> action + .scriptedUpsert(true) + .upsert(Map.of()) + .script(script -> script + .inline(inlineScript -> inlineScript + .lang("painless") + .source(scriptSource.toString()) + ) + ) + ) + ); + + UpdateOperation addFieldRequestOperation = UpdateOperation.of( + b -> b.id(id) + .index(defaultIndex) + .action(action -> action.doc(fieldMap)) + ); + + List bulkOperationList = new ArrayList<>(); + bulkOperationList.add(BulkOperation.of(b -> b.update(deleteFieldsOperation))); + bulkOperationList.add(BulkOperation.of(b -> b.update(addFieldRequestOperation))); + + BulkRequest bulkRequest = BulkRequest.of( + b -> b.index(defaultIndex) + .operations(bulkOperationList) + ); + + return client.getClient().bulk(bulkRequest); } public void updateFieldsAsynch(String id, Map fields) { fields.put(Geonet.IndexFieldNames.INDEXING_DATE, new Date()); - UpdateRequest request = new UpdateRequest(defaultIndex, id).doc(fields); - ActionListener listener = new ActionListener() { - @Override - public void onResponse(UpdateResponse updateResponse) { - } - @Override - public void onFailure(Exception e) { - } - }; - client.getClient().updateAsync(request, RequestOptions.DEFAULT, listener); + UpdateRequest updateRequest = UpdateRequest.of( + b -> b.index(defaultIndex) + .id(id) + .doc(fields) + ); + + client.getAsynchClient() + .update(updateRequest, ObjectNode.class) + .whenComplete((response, exception) -> { + if (exception != null) { + LOGGER.error("Failed to index {}", exception); + } else { + LOGGER.info("Updated fields for document {}", id); + } + }); } public UpdateResponse updateField(String id, String field, Object value) throws Exception { @@ -436,7 +470,7 @@ public void index(Path schemaDir, Element metadata, String id, private void sendDocumentsToIndex() { Map documents = new HashMap<>(listOfDocumentsToIndex); listOfDocumentsToIndex.clear(); - if (documents.size() > 0) { + if (!documents.isEmpty()) { try { final BulkResponse bulkItemResponses = client .bulkRequest(defaultIndex, documents); @@ -444,7 +478,7 @@ private void sendDocumentsToIndex() { } catch (Exception e) { LOGGER.error( "An error occurred while indexing {} documents in current indexing list. Error is {}.", - new Object[]{listOfDocumentsToIndex.size(), e.getMessage()}); + listOfDocumentsToIndex.size(), e.getMessage()); } finally { // TODO: Trigger this async ? documents.keySet().forEach(uuid -> overviewFieldUpdater.process(uuid)); @@ -454,58 +488,59 @@ private void sendDocumentsToIndex() { private void checkIndexResponse(BulkResponse bulkItemResponses, Map documents) throws IOException { - if (bulkItemResponses.hasFailures()) { - Map listErrorOfDocumentsToIndex = new HashMap<>(bulkItemResponses.getItems().length); + if (bulkItemResponses.errors()) { + Map listErrorOfDocumentsToIndex = new HashMap<>(bulkItemResponses.items().size()); List errorDocumentIds = new ArrayList<>(); // Add information in index that some items were not properly indexed - Arrays.stream(bulkItemResponses.getItems()).forEach(e -> { - if (e.status() != OK - && e.status() != CREATED) { - errorDocumentIds.add(e.getId()); + bulkItemResponses.items().forEach(e -> { + if (e.error() != null) { + errorDocumentIds.add(e.id()); ObjectMapper mapper = new ObjectMapper(); ObjectNode docWithErrorInfo = mapper.createObjectNode(); - String resourceTitle = String.format("Document #%s", e.getId()); + String resourceTitle = String.format("Document #%s", e.id()); String id = ""; String uuid = ""; String isTemplate = ""; + String isDraft = ""; - String failureDoc = documents.get(e.getId()); + String failureDoc = documents.get(e.id()); try { JsonNode node = mapper.readTree(failureDoc); resourceTitle = node.get("resourceTitleObject").get("default").asText(); id = node.get(IndexFields.DBID).asText(); uuid = node.get("uuid").asText(); isTemplate = node.get(IS_TEMPLATE).asText(); + isDraft = node.get(DRAFT).asText(); } catch (Exception ignoredException) { } docWithErrorInfo.put(IndexFields.DBID, id); docWithErrorInfo.put("uuid", uuid); docWithErrorInfo.put(IndexFields.RESOURCE_TITLE, resourceTitle); docWithErrorInfo.put(IS_TEMPLATE, isTemplate); - docWithErrorInfo.put(IndexFields.DRAFT, "n"); + docWithErrorInfo.put(IndexFields.DRAFT, isDraft); docWithErrorInfo.put(INDEXING_ERROR_FIELD, true); ArrayNode errors = docWithErrorInfo.putArray(INDEXING_ERROR_MSG); - errors.add(e.getFailureMessage()); + errors.add(createIndexingErrorMsgObject(e.error().reason(), "error", Map.of())); // TODO: Report the JSON which was causing the error ? LOGGER.error("Document with error #{}: {}.", - new Object[]{e.getId(), e.getFailureMessage()}); + e.id(), e.error().reason()); LOGGER.error(failureDoc); try { - listErrorOfDocumentsToIndex.put(e.getId(), mapper.writeValueAsString(docWithErrorInfo)); + listErrorOfDocumentsToIndex.put(e.id(), mapper.writeValueAsString(docWithErrorInfo)); } catch (JsonProcessingException e1) { LOGGER.error("Generated document for the index is not properly formatted. Check document #{}: {}.", - new Object[]{e.getId(), e1.getMessage()}); + e.id(), e1.getMessage()); } } }); - if (listErrorOfDocumentsToIndex.size() > 0) { + if (!listErrorOfDocumentsToIndex.isEmpty()) { BulkResponse response = client.bulkRequest(defaultIndex, listErrorOfDocumentsToIndex); - if (response.status().getStatus() != 201) { + if (response.errors()) { LOGGER.error("Failed to save error documents {}.", - new Object[]{Arrays.toString(errorDocumentIds.toArray())}); + Arrays.toString(errorDocumentIds.toArray())); } } } @@ -518,10 +553,12 @@ private void checkIndexResponse(BulkResponse bulkItemResponses, static { arrayFields = ImmutableSet.builder() .add(Geonet.IndexFieldNames.RECORDLINK) + .add("geom") .add("topic") .add("cat") .add("keyword") .add("extentDescriptionObject") + .add("extentIdentifierObject") .add("resourceAltTitleObject") .add("resourceCredit") .add("resourceCreditObject") @@ -537,6 +574,7 @@ private void checkIndexResponse(BulkResponse bulkItemResponses, .add("status_text") .add("coordinateSystem") .add("identifier") + .add("maintenance") .add("responsibleParty") .add("mdLanguage") .add("otherLanguage") @@ -562,9 +600,11 @@ private void checkIndexResponse(BulkResponse bulkItemResponses, .add("orderingInstructionsObject") .add("contact") .add("contactForResource") + .add("contactForProcessing") .add("contactForDistribution") .add("OrgForResource") .add("specificationConformance") + .add("processSteps") .add("measure") .add("resourceProviderOrgForResource") .add("resourceVerticalRange") @@ -581,6 +621,8 @@ private void checkIndexResponse(BulkResponse bulkItemResponses, .add(INDEXING_ERROR_FIELD) .add("isHarvested") .add("isPublishedToAll") + .add("isPublishedToIntranet") + .add("isPublishedToGuest") .add("isSchemaValid") .add("isAboveThreshold") .add("isOpenData") @@ -606,14 +648,14 @@ public ObjectNode documentToJson(Element xml) { for (Element currentField : fields) { String name = currentField.getName(); - // JSON object may be generated in the XSL processing. - // In such case an object type attribute is set. - boolean isObject = "object".equals(currentField.getAttributeValue("type")); - if (elementNames.contains(name)) { continue; } + // JSON object may be generated in the XSL processing. + // In such case an object type attribute is set. + boolean isObject = "object".equals(currentField.getAttributeValue("type")); + // Register list of already processed names elementNames.add(name); @@ -624,16 +666,17 @@ public ObjectNode documentToJson(Element xml) { || arrayFields.contains(propertyName) || propertyName.endsWith("DateForResource") || propertyName.startsWith("cl_"); + if (isArray) { ArrayNode arrayNode = doc.putArray(propertyName); for (Element node : nodeElements) { if (isObject) { try { arrayNode.add( - mapper.readTree(node.getText())); + mapper.readTree(node.getTextNormalize())); } catch (IOException e) { LOGGER.error("Parsing invalid JSON node {} for property {}. Error is: {}", - new Object[]{node.getTextNormalize(), propertyName, e.getMessage()}); + node.getTextNormalize(), propertyName, e.getMessage()); } } else { arrayNode.add( @@ -644,20 +687,7 @@ public ObjectNode documentToJson(Element xml) { } } - continue; - } - - if (name.equals("geom")) { - try { - doc.set("geom", mapper.readTree(nodeElements.get(0).getTextNormalize())); - } catch (IOException e) { - LOGGER.error("Parsing invalid geometry for JSON node {}. Error is: {}", - new Object[]{nodeElements.get(0).getTextNormalize(), e.getMessage()}); - } - continue; - } - - if (isObject) { + } else if (isObject) { try { doc.set(propertyName, mapper.readTree( @@ -665,7 +695,7 @@ public ObjectNode documentToJson(Element xml) { )); } catch (IOException e) { LOGGER.error("Parsing invalid JSON node {} for property {}. Error is: {}", - new Object[]{nodeElements.get(0).getTextNormalize(), propertyName, e.getMessage()}); + nodeElements.get(0).getTextNormalize(), propertyName, e.getMessage()); } } else { doc.put(propertyName, @@ -678,7 +708,8 @@ public ObjectNode documentToJson(Element xml) { } - /** Field starting with _ not supported in Kibana + /** + * Field starting with _ not supported in Kibana * Those are usually GN internal fields */ private String getPropertyName(String name) { @@ -698,9 +729,9 @@ public void forceIndexChanges() { } @Override - public boolean rebuildIndex(ServiceContext context, boolean xlinks, + public boolean rebuildIndex(ServiceContext context, boolean reset, String bucket) throws Exception { - DataManager dataMan = context.getBean(DataManager.class); + IMetadataIndexer metadataIndexer = context.getBean(IMetadataIndexer.class); IMetadataUtils metadataRepository = context.getBean(IMetadataUtils.class); if (reset) { @@ -731,7 +762,7 @@ public boolean rebuildIndex(ServiceContext context, boolean xlinks, } } for (String id : listOfIdsToIndex) { - dataMan.indexMetadata(id + "", false); + metadataIndexer.indexMetadata(id, false, IndexingMode.full); } } else { final Specification metadataSpec = @@ -741,7 +772,7 @@ public boolean rebuildIndex(ServiceContext context, boolean xlinks, Specification.where(metadataSpec) ); for (Integer id : metadataIds) { - dataMan.indexMetadata(id + "", false); + metadataIndexer.indexMetadata(id + "", false, IndexingMode.full); } } sendDocumentsToIndex(); @@ -756,7 +787,7 @@ public SearchResponse query(String luceneQuery, String filterQuery, int startPos return client.query(defaultIndex, luceneQuery, filterQuery, new HashSet<>(), new HashMap<>(), startPosition, maxRecords); } - public SearchResponse query(String luceneQuery, String filterQuery, int startPosition, int maxRecords, List> sort) throws Exception { + public SearchResponse query(String luceneQuery, String filterQuery, int startPosition, int maxRecords, List sort) throws Exception { return client.query(defaultIndex, luceneQuery, filterQuery, new HashSet<>(), new HashMap<>(), startPosition, maxRecords, sort); } @@ -772,7 +803,7 @@ public SearchResponse query(String luceneQuery, String filterQuery, Set } public SearchResponse query(JsonNode jsonRequest, Set includedFields, - int from, int size, List> sort) throws Exception { + int from, int size, List sort) throws Exception { // TODO: Review postFilterBuilder return client.query(defaultIndex, jsonRequest, null, includedFields, new HashMap<>(), from, size, sort); } @@ -783,8 +814,8 @@ public SearchResponse query(JsonNode jsonRequest, Set includedFields, return client.query(defaultIndex, jsonRequest, null, includedFields, from, size); } - public Map getFieldsValues(String id, Set fields) throws IOException { - return client.getFieldsValues(defaultIndex, id, fields); + public Map getFieldsValues(String id, Set fields, String language) throws Exception { + return client.getFieldsValues(defaultIndex, id, fields, language); } @@ -792,26 +823,6 @@ public void clearIndex() throws Exception { client.deleteByQuery(defaultIndex, "*:*"); } -// public void iterateQuery(SolrQuery params, final Consumer callback) throws IOException, SolrServerException { -// final MutableLong pos = new MutableLong(0); -// final MutableLong last = new MutableLong(1); -// while (pos.longValue() < last.longValue()) { -// params.setStart(pos.intValue()); -// client.queryAndStreamResponse(params, new StreamingResponseCallback() { -// @Override -// public void streamSolrDocument(SolrDocument doc) { -// pos.add(1); -// callback.accept(doc); -// } -// -// @Override -// public void streamDocListInfo(long numFound, long start, Float maxScore) { -// last.setValue(numFound); -// } -// }); -// } -// } - static ImmutableSet docsChangeIncludedFields; static { @@ -832,10 +843,15 @@ public Map getDocsChangeDate() throws Exception { final SearchResponse response = client.query(defaultIndex, "*", null, docsChangeIncludedFields, from, size); - response.getHits().forEach(r -> docs.put(r.getId(), (String) r.getSourceAsMap().get(Geonet.IndexFieldNames.DATABASE_CHANGE_DATE))); + ObjectMapper objectMapper = new ObjectMapper(); + + response.hits().hits().forEach(r -> { + Hit h = (Hit) r; + + docs.put(h.id(), (String) objectMapper.convertValue(h.source(), Map.class).get(Geonet.IndexFieldNames.DATABASE_CHANGE_DATE)); + }); } catch (Exception e) { - LOGGER.error("Error while collecting all documents: {}", e.getMessage()); - e.printStackTrace(); + LOGGER.error("Error while collecting all documents: {}", e.getMessage(), e); throw e; } return docs; @@ -849,73 +865,26 @@ public ISODate getDocChangeDate(String mdId) throws Exception { final SearchResponse response = client.query(defaultIndex, "_id:" + mdId, null, docsChangeIncludedFields, from, size); - if (response.getHits().getTotalHits().value == 1) { + if (response.hits().hits().size() == 1) { + Hit hit = (Hit) response.hits().hits().get(0); + ObjectMapper objectMapper = new ObjectMapper(); + String date = - (String) response.getHits().getAt(0).getSourceAsMap().get(Geonet.IndexFieldNames.DATABASE_CHANGE_DATE); + (String) objectMapper.convertValue(hit.source(), Map.class).get(Geonet.IndexFieldNames.DATABASE_CHANGE_DATE); return date != null ? new ISODate(date) : null; } else { return null; } } -// public SolrDocument getDocFieldValue(String query, String... field) throws IOException, SolrServerException { -// final SolrQuery params = new SolrQuery(query); -// params.setFilterQueries(DOC_TYPE + ":metadata"); -// params.setFields(field); -// QueryResponse response = client.query(params); -// final SolrDocumentList results = response.getResults(); -// if (results.size() == 0) { -// return null; -// } else { -// return results.get(0); -// } -// } -// -// public SolrDocumentList getDocsFieldValue(String query, String... field) throws IOException, SolrServerException { -// final SolrQuery params = new SolrQuery(query); -// params.setFilterQueries(DOC_TYPE + ":metadata"); -// params.setFields(field); -// QueryResponse response = client.query(params); -// return response.getResults(); -// } -// -// public List getDocsUuids(String query, Integer rows) throws IOException, SolrServerException { -// final SolrQuery solrQuery = new SolrQuery(query == null ? "*:*" : query); -// solrQuery.setFilterQueries(DOC_TYPE + ":metadata"); -// solrQuery.setFields(IndexFields.UUID); -// if (rows != null) { -// solrQuery.setRows(rows); -// } -// final List result = new ArrayList<>(); -// iterateQuery(solrQuery, doc -> -// result.add(doc.getFieldValue(IndexFields.UUID).toString())); -// return result; -// } - - @Override - public Set getDocsWithXLinks() throws Exception { -// final SolrQuery params = new SolrQuery("*:*"); -// params.setFilterQueries(DOC_TYPE + ":metadata"); -// params.setFilterQueries(Geonet.IndexFieldNames.HASXLINKS + ":1"); -// params.setFields(ID); -// Set result = new HashSet<>(); -// iterateQuery(params, -// doc -> result.add(convertInteger(doc.getFieldValue(ID)))); - return Collections.emptySet(); - } - @Override public void delete(String txt) throws Exception { - DeleteByQueryRequest request = new DeleteByQueryRequest(); - request.indices(defaultIndex); - request.setQuery(new QueryStringQueryBuilder(txt)); - request.setRefresh(true); - client.getClient().deleteByQuery(request, RequestOptions.DEFAULT); + client.deleteByQuery(defaultIndex, txt); } @Override public void delete(List metadataIds) throws Exception { - metadataIds.stream().forEach(metadataId -> { + metadataIds.forEach(metadataId -> { try { this.delete(String.format("+id:%d", metadataId)); } catch (Exception e) { @@ -924,22 +893,12 @@ public void delete(List metadataIds) throws Exception { }); } - @Override - public long getNumDocs() throws Exception { - return getNumDocs(""); - } - public long getNumDocs(String query) throws Exception { if (StringUtils.isBlank(query)) { query = "*:*"; } - - int from = 0; - SettingInfo si = ApplicationContextHolder.get().getBean(SettingInfo.class); - int size = Integer.parseInt(si.getSelectionMaxRecords()); - - final SearchResponse response = client.query(defaultIndex, query, null, docsChangeIncludedFields, from, size); - return response.getHits().getTotalHits().value; + return client.query(defaultIndex, query, null, new HashSet<>(), 0, 0) + .hits().total().value(); } public EsRestClient getClient() { @@ -973,4 +932,54 @@ public static String analyzeField(String analyzer, public boolean isIndexing() { return listOfDocumentsToIndex.size() > 0; } + + public boolean isIndexWritable(String indexName) throws IOException, ElasticsearchException { + String indexBlockRead = "index.blocks.read_only_allow_delete"; + + GetIndicesSettingsRequest request = GetIndicesSettingsRequest.of( + b -> b.index(indexName) + .name(indexBlockRead) + ); + + GetIndicesSettingsResponse settings = this.client.getClient() + .indices().getSettings(request); + + IndexState indexState = settings.get(indexBlockRead); + + return (indexState != null) && "true".equals(indexState.toString()); + } + + + /** + * Make a JSON Object that properly represents an indexingErrorMsg, to be used in the index. + * + * @param type either 'error' or 'warning' + * @param string a string that is translatable (see, e.g., en-search.json) + * @param values values that replace the placeholders in the `string` parameter + * @return a json object that represents an indexingErrorMsg + */ + public ObjectNode createIndexingErrorMsgObject(String string, String type, Map values) { + ObjectMapper objectMapper = new ObjectMapper(); + ObjectNode indexingErrorMsg = objectMapper.createObjectNode(); + indexingErrorMsg.put("string", string); + indexingErrorMsg.put("type", type); + ObjectNode valuesObject = objectMapper.createObjectNode(); + values.forEach((k, v) -> valuesObject.put(k, String.valueOf(v))); + indexingErrorMsg.set("values", valuesObject); + return indexingErrorMsg; + } + + /** + * Create an Element that represents an indexingErrorMsg object, to be used in the index. + * + * @param type either 'error' or 'warning' + * @param string a string that is translatable (see, e.g., en-search.json) + * @param values values that replace the placeholders in the `string` parameter + * @return an Element that represents an indexingErrorMsg + */ + public Element createIndexingErrorMsgElement(String string, String type, Map values) { + return new Element(INDEXING_ERROR_MSG) + .setText(createIndexingErrorMsgObject(string, type, values).toString()) + .setAttribute("type", "object"); + } } diff --git a/core/src/main/java/org/fao/geonet/kernel/search/ISearchManager.java b/core/src/main/java/org/fao/geonet/kernel/search/ISearchManager.java index a8eeafc0aac..f7d4959953b 100644 --- a/core/src/main/java/org/fao/geonet/kernel/search/ISearchManager.java +++ b/core/src/main/java/org/fao/geonet/kernel/search/ISearchManager.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2016 Food and Agriculture Organization of the + * Copyright (C) 2001-2023 Food and Agriculture Organization of the * United Nations (FAO-UN), United Nations World Food Programme (WFP) * and United Nations Environment Programme (UNEP) * @@ -23,6 +23,7 @@ package org.fao.geonet.kernel.search; +import co.elastic.clients.elasticsearch._types.ElasticsearchException; import com.google.common.collect.Multimap; import jeeves.server.context.ServiceContext; import org.fao.geonet.domain.ISODate; @@ -34,7 +35,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; /** * Base interface for the search (Lucene or Solr). @@ -65,12 +65,9 @@ void index(Path schemaDir, Element metadata, String id, Multimap * Rebuilds the Lucene index. If xlink or from selection parameters are defined, reindex a * subset of record. Otherwise reindex all records. * - * @param xlinks Search all docs with XLinks, clear the XLinks cache and index all - * records found. * @param bucket Reindex all records from selection bucket. */ boolean rebuildIndex(ServiceContext context, - boolean xlinks, boolean reset, String bucket) throws Exception; @@ -78,8 +75,6 @@ boolean rebuildIndex(ServiceContext context, ISODate getDocChangeDate(String mdId) throws Exception; - Set getDocsWithXLinks() throws Exception; - /** * deletes a document. */ @@ -90,7 +85,5 @@ boolean rebuildIndex(ServiceContext context, */ void delete(List metadataIds) throws Exception; - long getNumDocs() throws Exception; - - Element makeField(String fieldName, String fieldValue); + boolean isIndexWritable(String indexName) throws IOException, ElasticsearchException; } diff --git a/core/src/main/java/org/fao/geonet/kernel/search/index/OverviewIndexFieldUpdater.java b/core/src/main/java/org/fao/geonet/kernel/search/index/OverviewIndexFieldUpdater.java index 95f9668389f..fdf7583e8db 100644 --- a/core/src/main/java/org/fao/geonet/kernel/search/index/OverviewIndexFieldUpdater.java +++ b/core/src/main/java/org/fao/geonet/kernel/search/index/OverviewIndexFieldUpdater.java @@ -1,7 +1,32 @@ +//============================================================================= +//=== Copyright (C) 2001-2024 Food and Agriculture Organization of the +//=== United Nations (FAO-UN), United Nations World Food Programme (WFP) +//=== and United Nations Environment Programme (UNEP) +//=== +//=== This program is free software; you can redistribute it and/or modify +//=== it under the terms of the GNU General Public License as published by +//=== the Free Software Foundation; either version 2 of the License, or (at +//=== your option) any later version. +//=== +//=== This program is distributed in the hope that it will be useful, but +//=== WITHOUT ANY WARRANTY; without even the implied warranty of +//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//=== General Public License for more details. +//=== +//=== You should have received a copy of the GNU General Public License +//=== along with this program; if not, write to the Free Software +//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA +//=== +//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, +//=== Rome - Italy. email: geonetwork@osgeo.org +//============================================================================== + package org.fao.geonet.kernel.search.index; +import co.elastic.clients.elasticsearch.core.SearchResponse; +import co.elastic.clients.elasticsearch.core.search.Hit; +import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.lang.StringUtils; -import org.elasticsearch.action.search.SearchResponse; import org.fao.geonet.kernel.search.EsSearchManager; import org.fao.geonet.util.XslUtil; import org.springframework.beans.factory.annotation.Autowired; @@ -20,16 +45,31 @@ public class OverviewIndexFieldUpdater { EsSearchManager searchManager; public void process(String uuid) { + processOverview(uuid); + processOverview(uuid + "-draft"); + } + + private ArrayList> getHitOverviews(Map fields) { + Object overviews = fields.get("overview"); + if (overviews != null) { + return ((ArrayList) overviews); + } + return new ArrayList<>(); + } + + private void processOverview(String id) { Set source = new HashSet<>(); source.add("overview"); SearchResponse response = null; try { response = searchManager.query(String.format( - "+uuid:\"%s\" _exists_:overview.url -_exists_:overview.data", - uuid), null, source, 0, 1); - response.getHits().forEach(hit -> { + "+_id:\"%s\" _exists_:overview.url -_exists_:overview.data", + id), null, source, 0, 1); + ObjectMapper objectMapper = new ObjectMapper(); + response.hits().hits().forEach(h -> { + Hit hit = (Hit) h; AtomicBoolean updates = new AtomicBoolean(false); - Map fields = hit.getSourceAsMap(); + Map fields = objectMapper.convertValue(hit.source(), Map.class); getHitOverviews(fields) .stream() .forEach(overview -> { @@ -42,7 +82,7 @@ public void process(String uuid) { }); if (updates.get()) { try { - searchManager.updateFields(uuid, fields, source); + searchManager.updateFields(id, fields, source); } catch (Exception e) { e.printStackTrace(); } @@ -52,12 +92,4 @@ public void process(String uuid) { e.printStackTrace(); } } - - private ArrayList> getHitOverviews(Map fields) { - Object overviews = fields.get("overview"); - if (overviews != null) { - return ((ArrayList) overviews); - } - return new ArrayList<>(); - } } diff --git a/core/src/main/java/org/fao/geonet/kernel/security/keycloak/KeycloakPreAuthActionsLoginFilter.java b/core/src/main/java/org/fao/geonet/kernel/security/keycloak/KeycloakPreAuthActionsLoginFilter.java new file mode 100644 index 00000000000..a8a10cf3fa5 --- /dev/null +++ b/core/src/main/java/org/fao/geonet/kernel/security/keycloak/KeycloakPreAuthActionsLoginFilter.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2001-2023 Food and Agriculture Organization of the + * United Nations (FAO-UN), United Nations World Food Programme (WFP) + * and United Nations Environment Programme (UNEP) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, + * Rome - Italy. email: geonetwork@osgeo.org + */ + +package org.fao.geonet.kernel.security.keycloak; + +import org.fao.geonet.Constants; +import org.fao.geonet.security.web.csrf.GeonetworkCsrfSecurityRequestMatcher; +import org.keycloak.adapters.spi.UserSessionManagement; +import org.keycloak.adapters.springsecurity.filter.KeycloakCsrfRequestMatcher; +import org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter; +import org.keycloak.constants.AdapterConstants; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.AnonymousAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; +import org.springframework.security.web.csrf.CsrfFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.net.URLEncoder; + +public class KeycloakPreAuthActionsLoginFilter extends KeycloakPreAuthActionsFilter { + + @Autowired + LoginUrlAuthenticationEntryPoint loginUrlAuthenticationEntryPoint; + + public KeycloakPreAuthActionsLoginFilter(UserSessionManagement userSessionManagement) { + super(userSessionManagement); + } + + public KeycloakPreAuthActionsLoginFilter(UserSessionManagement userSessionManagement, CsrfFilter csrfFilter, + GeonetworkCsrfSecurityRequestMatcher csrfRequestMatcher) { + super(userSessionManagement); + // Set the csrf filter request matcher for Keycloak so that it allows k_* endpoints to be reached without CSRF. + // Without this fix, the back-channel logout was not working due to CSRF failures. + csrfRequestMatcher.addRequestMatcher(new KeycloakCsrfRequestMatcher()); + csrfFilter.setRequireCsrfProtectionMatcher(csrfRequestMatcher); + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + HttpServletRequest servletRequest = (HttpServletRequest) request; + HttpServletResponse servletResponse = (HttpServletResponse) response; + + // Lets redirect the user to the signin page if + // - The session is not authenticate + // - This is not a request for the signin page (we don't want endless loop to sign in page) + // - It does not match the default request matcher (which is mostly used to validate bearer tokens request for api's) + // No sign in page required for api calls. + // - and it is not an internal k_* request which should be processed by keycloak adapter and also don't required login page. + if (servletRequest.getPathInfo() != null && + !KeycloakAuthenticationProcessingFilter.DEFAULT_REQUEST_MATCHER.matches(servletRequest) && + !isAuthenticated() && + !(servletRequest.getContextPath() + KeycloakUtil.getSigninPath()).equals(servletRequest.getRequestURI()) && + !servletRequest.getRequestURI().endsWith(AdapterConstants.K_LOGOUT) && + !servletRequest.getRequestURI().endsWith(AdapterConstants.K_PUSH_NOT_BEFORE) && + !servletRequest.getRequestURI().endsWith(AdapterConstants.K_QUERY_BEARER_TOKEN) && + !servletRequest.getRequestURI().endsWith(AdapterConstants.K_TEST_AVAILABLE) && + !servletRequest.getRequestURI().endsWith(AdapterConstants.K_JWKS)) { + + // Get request uri which is a relative path. Absolute paths will be ignored if they are received as returning url. + String returningUrl = servletRequest.getRequestURI() + + (servletRequest.getQueryString() == null ? "" : "?" + servletRequest.getQueryString()); + + String encodedRedirectURL = ((HttpServletResponse) response).encodeRedirectURL( + servletRequest.getContextPath() + KeycloakUtil.getSigninPath() + "?redirectUrl=" + URLEncoder.encode(returningUrl, Constants.ENCODING)); + + servletResponse.sendRedirect(encodedRedirectURL); + + // No further action required as we are redirecting to new page + return; + } + + super.doFilter(servletRequest, servletResponse, chain); + } + + private boolean isAuthenticated() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication == null || AnonymousAuthenticationToken.class. + isAssignableFrom(authentication.getClass())) { + return false; + } + return authentication.isAuthenticated(); + } +} diff --git a/core/src/main/java/org/fao/geonet/kernel/security/keycloak/KeycloakUserUtils.java b/core/src/main/java/org/fao/geonet/kernel/security/keycloak/KeycloakUserUtils.java index 899df05fe2f..acb5f796b03 100644 --- a/core/src/main/java/org/fao/geonet/kernel/security/keycloak/KeycloakUserUtils.java +++ b/core/src/main/java/org/fao/geonet/kernel/security/keycloak/KeycloakUserUtils.java @@ -251,8 +251,7 @@ private Map> getProfileGroups(AccessToken accessToken) { * @param user to apply the changes to. */ private void updateGroups(Map> profileGroups, User user) { - // First we remove all previous groups - userGroupRepository.deleteAll(UserGroupSpecs.hasUserId(user.getId())); + Set userGroups = new HashSet<>(); // Now we add the groups for (Profile p : profileGroups.keySet()) { @@ -293,12 +292,14 @@ private void updateGroups(Map> profileGroups, User user) { ug.setGroup(group); ug.setUser(user); ug.setProfile(Profile.Editor); - userGroupRepository.save(ug); + userGroups.add(ug); } - userGroupRepository.save(usergroup); + userGroups.add(usergroup); } } + + userGroupRepository.updateUserGroups(user.getId(), userGroups); } /** diff --git a/core/src/main/java/org/fao/geonet/kernel/security/keycloak/keycloakPreAuthActionsLoginFilter.java b/core/src/main/java/org/fao/geonet/kernel/security/keycloak/keycloakPreAuthActionsLoginFilter.java deleted file mode 100644 index 5d6195f3371..00000000000 --- a/core/src/main/java/org/fao/geonet/kernel/security/keycloak/keycloakPreAuthActionsLoginFilter.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2001-2017 Food and Agriculture Organization of the - * United Nations (FAO-UN), United Nations World Food Programme (WFP) - * and United Nations Environment Programme (UNEP) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * - * Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, - * Rome - Italy. email: geonetwork@osgeo.org - */ - -package org.fao.geonet.kernel.security.keycloak; - -import org.fao.geonet.Constants; -import org.keycloak.adapters.spi.UserSessionManagement; -import org.keycloak.adapters.springsecurity.filter.KeycloakCsrfRequestMatcher; -import org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter; -import org.keycloak.constants.AdapterConstants; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.authentication.AnonymousAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; -import org.springframework.security.web.csrf.CsrfFilter; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.net.URLEncoder; -import java.io.IOException; - -public class keycloakPreAuthActionsLoginFilter extends KeycloakPreAuthActionsFilter { - public static String signinPath = null; - - @Autowired - LoginUrlAuthenticationEntryPoint loginUrlAuthenticationEntryPoint; - - public keycloakPreAuthActionsLoginFilter(UserSessionManagement userSessionManagement) { - super(userSessionManagement); - } - - public keycloakPreAuthActionsLoginFilter(UserSessionManagement userSessionManagement, CsrfFilter csrfFilter) { - super(userSessionManagement); - // Set the csrf filter request matcher for Keycloak so that it allows k_* endpoints to be reached without CSRF. - // Without this fix, the backchannel logout was not working due to CSRF failures. - csrfFilter.setRequireCsrfProtectionMatcher(new KeycloakCsrfRequestMatcher()); - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - throws IOException, ServletException { - HttpServletRequest servletRequest = (HttpServletRequest) request; - HttpServletResponse servletResponse = (HttpServletResponse) response; - - // Lets redirect the user to the signin page if - // - The session is not authenticate - // - This is not a request for the signin page (we don't want endless loop to sign in page) - // - It does not match the default request matcher (which is mostly used to validate bearer tokens request for api's) - // No sign in page required for api calls. - // - and it is not an internal k_* request which should be processed by keycloak adapter and also don't required login page. - if (servletRequest.getPathInfo() != null && - !KeycloakAuthenticationProcessingFilter.DEFAULT_REQUEST_MATCHER.matches(servletRequest) && - !isAuthenticated() && - !(servletRequest.getContextPath() + KeycloakUtil.getSigninPath()).equals(servletRequest.getRequestURI()) && - !servletRequest.getRequestURI().endsWith(AdapterConstants.K_LOGOUT) && - !servletRequest.getRequestURI().endsWith(AdapterConstants.K_PUSH_NOT_BEFORE) && - !servletRequest.getRequestURI().endsWith(AdapterConstants.K_QUERY_BEARER_TOKEN) && - !servletRequest.getRequestURI().endsWith(AdapterConstants.K_TEST_AVAILABLE) && - !servletRequest.getRequestURI().endsWith(AdapterConstants.K_JWKS)) { - - // Get request uri which is a relative path. Absolute paths will be ignored if they are received as returning url. - String returningUrl = servletRequest.getRequestURI() + - (servletRequest.getQueryString() == null ? "" : "?" + servletRequest.getQueryString()); - - String encodedRedirectURL = ((HttpServletResponse) response).encodeRedirectURL( - servletRequest.getContextPath() + KeycloakUtil.getSigninPath() + "?redirectUrl=" + URLEncoder.encode(returningUrl, Constants.ENCODING)); - - servletResponse.sendRedirect(encodedRedirectURL); - - // No further action required as we are redirecting to new page - return; - } - - super.doFilter(servletRequest, servletResponse, chain); - } - - private boolean isAuthenticated() { - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - if (authentication == null || AnonymousAuthenticationToken.class. - isAssignableFrom(authentication.getClass())) { - return false; - } - return authentication.isAuthenticated(); - } -} diff --git a/core/src/main/java/org/fao/geonet/kernel/security/openidconnect/GeonetworkOidcUserService.java b/core/src/main/java/org/fao/geonet/kernel/security/openidconnect/GeonetworkOidcUserService.java index 504c0a8fac8..97a7b917630 100644 --- a/core/src/main/java/org/fao/geonet/kernel/security/openidconnect/GeonetworkOidcUserService.java +++ b/core/src/main/java/org/fao/geonet/kernel/security/openidconnect/GeonetworkOidcUserService.java @@ -22,9 +22,11 @@ */ package org.fao.geonet.kernel.security.openidconnect; +import org.fao.geonet.kernel.security.GeonetworkAuthenticationProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.hierarchicalroles.RoleHierarchy; import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest; import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; @@ -55,12 +57,33 @@ public class GeonetworkOidcUserService extends OidcUserService { @Autowired RoleHierarchy roleHierarchy; + @Autowired + GeonetworkAuthenticationProvider geonetworkAuthenticationProvider; + + @Autowired + protected SimpleOidcUserFactory simpleOidcUserFactory; + @Override public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException { OidcUser user = super.loadUser(userRequest); + Collection authorities; + + if (!oidcConfiguration.isUpdateProfile()) { + // Retrieve the authorities from the local user + try { + SimpleOidcUser simpleUser = simpleOidcUserFactory.create(user.getAttributes()); + UserDetails userDetails = geonetworkAuthenticationProvider.loadUserByUsername(simpleUser.getUsername()); + + authorities = userDetails.getAuthorities(); + } catch (Exception ex) { + authorities = createAuthorities(user); + } + } else { + authorities = createAuthorities(user); + } + OidcUserInfo userInfo = user.getUserInfo(); - Collection authorities = createAuthorities(user); //get the user name from a specific attribute (if specified) or use default. String userNameAttributeName = userRequest.getClientRegistration() diff --git a/core/src/main/java/org/fao/geonet/kernel/security/openidconnect/OidcUser2GeonetworkUser.java b/core/src/main/java/org/fao/geonet/kernel/security/openidconnect/OidcUser2GeonetworkUser.java index 4d9cf1f40a7..34a8c813d52 100644 --- a/core/src/main/java/org/fao/geonet/kernel/security/openidconnect/OidcUser2GeonetworkUser.java +++ b/core/src/main/java/org/fao/geonet/kernel/security/openidconnect/OidcUser2GeonetworkUser.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 Food and Agriculture Organization of the + * Copyright (C) 2023 Food and Agriculture Organization of the * United Nations (FAO-UN), United Nations World Food Programme (WFP) * and United Nations Environment Programme (UNEP) * @@ -41,8 +41,10 @@ import org.springframework.security.oauth2.core.oidc.OidcIdToken; import org.springframework.util.StringUtils; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; /** * Class for handling Oidc User and the Geonetwork User. @@ -74,6 +76,12 @@ public UserDetails getUserDetails(Map attributes, boolean withDbUpdate) throws E if (!StringUtils.hasText(simpleUser.getUsername())) return null; + if (!oidcConfiguration.isUpdateProfile()) { + // SimpleOidcUser.updateUser assigns the user profile to the OpenId user profile, unless + // SimpleOidcUser.profile is empty. Force the empty value, to avoid the assignment. + simpleUser.setProfile(""); + } + User user; boolean newUserFlag = false; try { @@ -88,8 +96,9 @@ public UserDetails getUserDetails(Map attributes, boolean withDbUpdate) throws E simpleUser.updateUser(user); // copy attributes from the IDToken to the GN user Map> profileGroups = oidcRoleProcessor.getProfileGroups(attributes); - user.setProfile(oidcRoleProcessor.getProfile(attributes)); - + if (newUserFlag || oidcConfiguration.isUpdateProfile()) { + user.setProfile(oidcRoleProcessor.getProfile(attributes)); + } //Apply changes to database is required. if (withDbUpdate) { @@ -122,6 +131,12 @@ public UserDetails getUserDetails(OidcIdToken idToken, Map attributes, boolean w if (!StringUtils.hasText(simpleUser.getUsername())) return null; + if (!oidcConfiguration.isUpdateProfile()) { + // SimpleOidcUser.updateUser assigns the user profile to the OpenId user profile, unless + // SimpleOidcUser.profile is empty. Force the empty value, to avoid the assignment. + simpleUser.setProfile(""); + } + User user; boolean newUserFlag = false; try { @@ -136,7 +151,9 @@ public UserDetails getUserDetails(OidcIdToken idToken, Map attributes, boolean w simpleUser.updateUser(user); // copy attributes from the IDToken to the GN user Map> profileGroups = oidcRoleProcessor.getProfileGroups(idToken); - user.setProfile(oidcRoleProcessor.getProfile(idToken)); + if (newUserFlag || oidcConfiguration.isUpdateProfile()) { + user.setProfile(oidcRoleProcessor.getProfile(idToken)); + } //Apply changes to database is required. @@ -159,8 +176,7 @@ public UserDetails getUserDetails(OidcIdToken idToken, Map attributes, boolean w */ //from keycloak protected void updateGroups(Map> profileGroups, User user) { - // First we remove all previous groups - userGroupRepository.deleteAll(UserGroupSpecs.hasUserId(user.getId())); + Set userGroups = new HashSet<>(); // Now we add the groups for (Profile p : profileGroups.keySet()) { @@ -201,13 +217,13 @@ protected void updateGroups(Map> profileGroups, User user) ug.setGroup(group); ug.setUser(user); ug.setProfile(Profile.Editor); - userGroupRepository.save(ug); + userGroups.add(ug); } - userGroupRepository.save(usergroup); + userGroups.add(usergroup); } } - } - + userGroupRepository.updateUserGroups(user.getId(), userGroups); + } } diff --git a/core/src/main/java/org/fao/geonet/kernel/security/openidconnect/bearer/GeonetworkJwtAuthenticationProvider.java b/core/src/main/java/org/fao/geonet/kernel/security/openidconnect/bearer/GeonetworkJwtAuthenticationProvider.java new file mode 100644 index 00000000000..220f024097c --- /dev/null +++ b/core/src/main/java/org/fao/geonet/kernel/security/openidconnect/bearer/GeonetworkJwtAuthenticationProvider.java @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2022 Food and Agriculture Organization of the + * United Nations (FAO-UN), United Nations World Food Programme (WFP) + * and United Nations Environment Programme (UNEP) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, + * Rome - Italy. email: geonetwork@osgeo.org + */ +package org.fao.geonet.kernel.security.openidconnect.bearer; + + +import org.fao.geonet.kernel.security.openidconnect.OIDCConfiguration; +import org.fao.geonet.kernel.security.openidconnect.OIDCRoleProcessor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.core.convert.converter.Converter; +import org.springframework.http.HttpStatus; +import org.springframework.security.access.hierarchicalroles.RoleHierarchy; +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.InternalAuthenticationServiceException; +import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserService; +import org.springframework.security.oauth2.core.OAuth2AccessToken; +import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +import org.springframework.security.oauth2.core.OAuth2Error; +import org.springframework.security.oauth2.core.oidc.OidcUserInfo; +import org.springframework.security.oauth2.core.oidc.user.OidcUser; +import org.springframework.security.oauth2.core.user.DefaultOAuth2User; +import org.springframework.security.oauth2.core.user.OAuth2User; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken; +import org.springframework.security.oauth2.server.resource.BearerTokenError; +import org.springframework.security.oauth2.server.resource.BearerTokenErrorCodes; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter; +import org.springframework.util.Assert; + +import java.time.Instant; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static org.fao.geonet.kernel.security.openidconnect.GeonetworkClientRegistrationProvider.CLIENTREGISTRATION_NAME; +import static org.fao.geonet.kernel.security.openidconnect.bearer.RoleInserter.insertRoles; + +/** + * This is the main class that does all the work. + * + * Note - if this throws, then a 401 will be issued with a header like this; + * + * WWW-Authenticate: Bearer error="invalid_token", error_description="access token has expired!", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1" + * + */ +public class GeonetworkJwtAuthenticationProvider implements AuthenticationProvider { + static UserInfoCache userInfoCache = new UserInfoCache(); + private final OAuth2UserService userService; + AccessTokenParser accessTokenParser; + UserRolesResolver userRolesResolver; + List accessTokenValidators; + @Autowired + ApplicationEventPublisher applicationEventPublisher; + @Autowired + OIDCRoleProcessor oidcRoleProcessor; + @Autowired + RoleHierarchy roleHierarchy; + @Autowired + OIDCConfiguration oidcConfiguration; + @Autowired + ClientRegistrationRepository clientRegistrationRepository; + private OAuth2UserService oauth2UserService = new DefaultOAuth2UserService(); + private Converter jwtAuthenticationConverter = new JwtAuthenticationConverter(); + + public GeonetworkJwtAuthenticationProvider(AccessTokenParser accessTokenParser, + OAuth2UserService userService, + UserRolesResolver userRolesResolver, + List accessTokenValidators + ) { + Assert.notNull(accessTokenParser, "accessTokenParser cannot be null"); + Assert.notNull(userService, "userService cannot be null"); + Assert.notNull(accessTokenValidators, "accessTokenValidators cannot be null"); + + this.userRolesResolver = userRolesResolver; + this.accessTokenParser = accessTokenParser; + this.userService = userService; + this.accessTokenValidators = accessTokenValidators; + } + + private static final OAuth2Error DEFAULT_INVALID_TOKEN = + invalidToken("An error occurred while attempting to decode the Jwt: Invalid token"); + + /** + * from spring - creates an error return + */ + private static OAuth2Error invalidToken(String message) { + try { + return new BearerTokenError( + BearerTokenErrorCodes.INVALID_TOKEN, + HttpStatus.UNAUTHORIZED, + message, + "https://tools.ietf.org/html/rfc6750#section-3.1"); + } catch (IllegalArgumentException malformed) { + // some third-party library error messages are not suitable for RFC 6750's error message charset + return DEFAULT_INVALID_TOKEN; + } + } + + /** + * runs all the AccessTokenValidator on the token. + * + * @param claims + * @param userInfoClaims + * @throws Exception + */ + public void verifyToken(Map claims, Map userInfoClaims) throws Exception { + for (AccessTokenValidator validator : accessTokenValidators) { + validator.verifyToken(claims, userInfoClaims); + } + } + + + /** + * First time using the token, we have to do quite a bit of work. + * i.e. call the userinfo endpoint (and for azure the graph api). + * We cache the results since they shouldn't change over the lifetime of the token. + * + * @param authentication + * @return + */ + public UserInfoCacheItem createCacheItem(Authentication authentication) { + //this is the actual access token + BearerTokenAuthenticationToken bearer = (BearerTokenAuthenticationToken) authentication; + + Map jwt; + try { + //parse it (using either the signature checking or non-signature checking version). + //NOTE: we will use this token with the userinfo endpoint, so the server will signature-validate it + // (meaning its not a big deal if we don't). + jwt = accessTokenParser.parseToken(bearer.getToken()); + } catch (Exception failed) { + OAuth2Error invalidToken = invalidToken(failed.getMessage()); + throw new OAuth2AuthenticationException(invalidToken, invalidToken.getDescription(), failed); + } + + //when is this token valid until + Instant expireTime = Instant.ofEpochMilli((Long) jwt.get("exp") * 1000); + + //if expired, throw + if (expireTime.compareTo(Instant.now()) < 0) { + throw new OAuth2AuthenticationException(invalidToken("access token has expired")); + } + + //execute the userinfo endpoint + ClientRegistration clientRegistration = clientRegistrationRepository.findByRegistrationId(CLIENTREGISTRATION_NAME); + OAuth2AccessToken accessToken = new OAuth2AccessToken( + OAuth2AccessToken.TokenType.BEARER, + bearer.getToken(), + Instant.ofEpochMilli((Long) jwt.get("iat") * 1000)//issuedAt + , Instant.ofEpochMilli((Long) jwt.get("exp") * 1000)//ExpiresAt + ); + OAuth2UserRequest oAuth2UserRequest = new OAuth2UserRequest(clientRegistration, accessToken); + OAuth2User oAuth2User = oauth2UserService.loadUser(oAuth2UserRequest); //executes userinfo endpoint + + + OidcUserInfo userInfo = new OidcUserInfo(oAuth2User.getAttributes()); + + try { + verifyToken(jwt, userInfo.getClaims()); //verify token with all the configured validators + } catch (Exception failed) { + OAuth2Error invalidToken = invalidToken(failed.getMessage()); + throw new OAuth2AuthenticationException(invalidToken, invalidToken.getDescription(), failed); + } + + + List userRoles = null; + try { + //get the list of roles (either from the jwt or the userInfo). Or, you can contact an external API (i.e. MS Graph) + userRoles = userRolesResolver.resolveRoles(bearer.getToken(), jwt, userInfo); + // inject the roles inside the userInfo + userInfo = insertRoles(oidcConfiguration.getIdTokenRoleLocation(), userInfo, userRoles); + } catch (Exception e) { + throw new InternalAuthenticationServiceException("userRolesResolver.resolveRoles exception", e); + } + //user's GrantedAuthorities (i.e. "Administrator" -> ["Administrator","Reviewer","Editor", "RegisteredUser", "Guest"] + Collection authorities = oidcRoleProcessor.createAuthorities(roleHierarchy, userRoles); + + //final user + OAuth2User user = new DefaultOAuth2User(authorities, userInfo.getClaims(), oidcConfiguration.getUserNameAttribute()); + + // create a cachable item for storing all this information + return new UserInfoCacheItem(bearer.getToken(), expireTime, user, authorities); + } + + /** + * Decode and validate the + * Bearer Token. + * + * @param authentication the authentication request object. + * @return A successful authentication + * @throws AuthenticationException if authentication failed for some reason + */ + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + BearerTokenAuthenticationToken bearer = (BearerTokenAuthenticationToken) authentication; + + // has this access token been evaluated before? + UserInfoCacheItem item = userInfoCache.getItem(bearer.getToken()); + if (item == null) { + // never used - re-create + item = createCacheItem(authentication); + userInfoCache.putItem(item); //store in cache + } + + // final result + OAuth2User user = item.getUser(); + Collection authorities = item.getAuthorities(); + OAuth2AuthenticationToken authenticationResult = new OAuth2AuthenticationToken(user, authorities, CLIENTREGISTRATION_NAME); + authenticationResult.setDetails(authentication.getDetails()); + + // user logs in event + if (this.applicationEventPublisher != null) { + applicationEventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authenticationResult, this.getClass())); + } + + return authenticationResult; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean supports(Class authentication) { + return BearerTokenAuthenticationToken.class.isAssignableFrom(authentication); + } + +} diff --git a/core/src/main/java/org/fao/geonet/kernel/security/openidconnect/bearer/UserInfoCache.java b/core/src/main/java/org/fao/geonet/kernel/security/openidconnect/bearer/UserInfoCache.java index 4e75a1282b2..15252009821 100644 --- a/core/src/main/java/org/fao/geonet/kernel/security/openidconnect/bearer/UserInfoCache.java +++ b/core/src/main/java/org/fao/geonet/kernel/security/openidconnect/bearer/UserInfoCache.java @@ -10,19 +10,13 @@ */ public class UserInfoCache { - static Object lockobj = new Object(); + static final Object lockobj = new Object(); Map cache = new HashMap<>(); public UserInfoCacheItem getItem(String accessKey) { synchronized (lockobj) { - if (!cache.containsKey(accessKey)) - return null; - UserInfoCacheItem item = cache.get(accessKey); - if (item.isExpired()) { - cache.remove(accessKey); - return null; - } - return item; + cache.entrySet().removeIf(e -> e.getValue().isExpired()); + return cache.get(accessKey); } } diff --git a/core/src/main/java/org/fao/geonet/kernel/security/shibboleth/ShibbolethUserUtils.java b/core/src/main/java/org/fao/geonet/kernel/security/shibboleth/ShibbolethUserUtils.java index b99c0cb9bf2..c17e9e00788 100644 --- a/core/src/main/java/org/fao/geonet/kernel/security/shibboleth/ShibbolethUserUtils.java +++ b/core/src/main/java/org/fao/geonet/kernel/security/shibboleth/ShibbolethUserUtils.java @@ -48,7 +48,9 @@ import jeeves.component.ProfileManager; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** * @author ETj (etj at geo-solutions.it) @@ -153,9 +155,6 @@ protected UserDetails setupUser(ServletRequest request, ShibbolethUserConfigurat user = (User) authProvider.loadUserByUsername(username); if (config.isUpdateGroup()) { - // First we remove all previous groups - userGroupRepository.deleteAll(UserGroupSpecs.hasUserId(user.getId())); - // Now we add the groups assignGroups(groupRepository, userGroupRepository, roleGroups, roleGroupSeparator, user); @@ -222,6 +221,9 @@ protected UserDetails setupUser(ServletRequest request, ShibbolethUserConfigurat private void assignGroups(GroupRepository groupRepository, UserGroupRepository userGroupRepository, String[] role_groups, String separator, User user) { + + Set userGroups = new HashSet<>(); + // Assign groups int i = 0; @@ -258,14 +260,16 @@ private void assignGroups(GroupRepository groupRepository, UserGroupRepository u ug.setGroup(g); ug.setUser(user); ug.setProfile(Profile.Editor); - userGroupRepository.save(ug); + userGroups.add(ug); } } else { // Failback if no profile usergroup.setProfile(Profile.Guest); } - userGroupRepository.save(usergroup); + userGroups.add(usergroup); } + + userGroupRepository.updateUserGroups(user.getId(), userGroups); } private void assignProfile(String[] role_groups, String roleGroupSeparator, User user) { diff --git a/core/src/main/java/org/fao/geonet/kernel/setting/SettingInfo.java b/core/src/main/java/org/fao/geonet/kernel/setting/SettingInfo.java index cb72fac0a95..7a2f97b0623 100644 --- a/core/src/main/java/org/fao/geonet/kernel/setting/SettingInfo.java +++ b/core/src/main/java/org/fao/geonet/kernel/setting/SettingInfo.java @@ -1,5 +1,5 @@ //============================================================================= -//=== Copyright (C) 2001-2021 Food and Agriculture Organization of the +//=== Copyright (C) 2001-2023 Food and Agriculture Organization of the //=== United Nations (FAO-UN), United Nations World Food Programme (WFP) //=== and United Nations Environment Programme (UNEP) //=== @@ -24,9 +24,6 @@ package org.fao.geonet.kernel.setting; import org.fao.geonet.ApplicationContextHolder; -import org.fao.geonet.constants.Geonet; - -import static org.fao.geonet.kernel.setting.SettingManager.isPortRequired; public class SettingInfo { @@ -39,46 +36,29 @@ public String getSiteName() { //--------------------------------------------------------------------------- /** - * Return a string like 'http://HOST[:PORT]' + * Despite the method name, returns the server URL. That's why it calls settingManager.getServerURL() instead + * of settingManager.getSiteURL(). + * + * @return a string like 'http://HOST[:PORT]' */ public String getSiteUrl() { SettingManager settingManager = ApplicationContextHolder.get().getBean(SettingManager.class); + return settingManager.getServerURL(); + } - String protocol = settingManager.getValue(Settings.SYSTEM_SERVER_PROTOCOL); - Integer port; - String host = settingManager.getValue(Settings.SYSTEM_SERVER_HOST); - Integer configuredPort = toIntOrNull(Settings.SYSTEM_SERVER_PORT); - if (configuredPort != null) { - port = configuredPort; - } else if (protocol.equalsIgnoreCase(Geonet.HttpProtocol.HTTPS)) { - port = Geonet.DefaultHttpPort.HTTPS; - } else { - port = Geonet.DefaultHttpPort.HTTP; - } - - StringBuffer sb = new StringBuffer(protocol + "://"); - - sb.append(host); - - if (isPortRequired(protocol, port + "")) { - sb.append(":"); - sb.append(port); - } - return sb.toString(); + /** + * Retrieves the server port. + * + * @return the server port. + */ + public Integer getSitePort() { + SettingManager settingManager = ApplicationContextHolder.get().getBean(SettingManager.class); + return settingManager.getServerPort(); } //--------------------------------------------------------------------------- - private Integer toIntOrNull(String key) { - try { - SettingManager settingManager = ApplicationContextHolder.get().getBean(SettingManager.class); - return Integer.parseInt(settingManager.getValue(key)); - } catch (NumberFormatException e) { - return null; - } - } - public String getSelectionMaxRecords() { SettingManager settingManager = ApplicationContextHolder.get().getBean(SettingManager.class); String value = settingManager.getValue(Settings.SYSTEM_SELECTIONMANAGER_MAXRECORDS); @@ -102,6 +82,6 @@ public boolean isSearchStatsEnabled() { public String getFeedbackEmail() { SettingManager settingManager = ApplicationContextHolder.get().getBean(SettingManager.class); - return settingManager.getValue("system/feedback/email"); + return settingManager.getValue(Settings.SYSTEM_FEEDBACK_EMAIL); } } diff --git a/core/src/main/java/org/fao/geonet/kernel/setting/SettingManager.java b/core/src/main/java/org/fao/geonet/kernel/setting/SettingManager.java index 7e175b7c4e6..b6f015d6b58 100644 --- a/core/src/main/java/org/fao/geonet/kernel/setting/SettingManager.java +++ b/core/src/main/java/org/fao/geonet/kernel/setting/SettingManager.java @@ -1,5 +1,5 @@ //============================================================================= -//=== Copyright (C) 2001-2021 Food and Agriculture Organization of the +//=== Copyright (C) 2001-2023 Food and Agriculture Organization of the //=== United Nations (FAO-UN), United Nations World Food Programme (WFP) //=== and United Nations Environment Programme (UNEP) //=== @@ -33,11 +33,12 @@ import org.fao.geonet.domain.Setting; import org.fao.geonet.domain.SettingDataType; import org.fao.geonet.domain.Setting_; -import org.fao.geonet.repository.LanguageRepository; +import org.fao.geonet.languages.FeedbackLanguages; import org.fao.geonet.repository.SettingRepository; import org.fao.geonet.repository.SortUtils; import org.fao.geonet.repository.SourceRepository; import org.fao.geonet.utils.Log; +import org.fao.geonet.web.DefaultLanguage; import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; import org.jdom.Element; import org.springframework.beans.factory.annotation.Autowired; @@ -75,7 +76,7 @@ public class SettingManager { public static final ZoneId DEFAULT_SERVER_TIMEZONE = ZoneId.systemDefault(); @PersistenceContext - private EntityManager _entityManager; + private EntityManager entityManager; @Autowired private ServletContext servletContext; @@ -91,6 +92,12 @@ public class SettingManager { @Autowired StandardPBEStringEncryptor encryptor; + @Autowired + DefaultLanguage defaultLanguage; + + @Autowired + FeedbackLanguages feedbackLanguages; + @PostConstruct private void init() { this.pathFinder = new ServletPathFinder(servletContext); @@ -115,7 +122,7 @@ public Element getAllAsXML(boolean asTree) { Element env = new Element("settings"); List settings = repo.findAll(SortUtils.createSort(Setting_.name)); - Map pathElements = new HashMap(); + Map pathElements = new HashMap<>(); for (Setting setting : settings) { if (asTree) { @@ -340,6 +347,12 @@ public boolean setValue(String key, String value) { repo.save(setting); + if (key.equals("system/feedback/languages")) { + feedbackLanguages.updateSupportedLocales(); + } else if (key.equals("system/feedback/translationFollowsText")) { + feedbackLanguages.updateTranslationFollowsText(); + } + return true; } @@ -384,7 +397,7 @@ public final boolean setValues(final Map values) { * without using this class. For example when using an SQL script. */ public final boolean refresh() throws SQLException { - _entityManager.getEntityManagerFactory().getCache().evict(HarvesterSetting.class); + entityManager.getEntityManagerFactory().getCache().evict(HarvesterSetting.class); return true; } @@ -415,9 +428,8 @@ String getSiteURL(@Nonnull ServiceContext context) { public @Nonnull String getSiteURL(String language) { - LanguageRepository languageRepository = ApplicationContextHolder.get().getBean(LanguageRepository.class); if (language == null) { - language = languageRepository.findOneByDefaultLanguage().getId(); + language = defaultLanguage.getLanguage(); } return getNodeURL() + language + "/"; @@ -429,6 +441,15 @@ String getSiteURL(String language) { public @Nonnull String getNodeURL() { + return getBaseURL() + getNodeId() + "/"; + } + + /** + * Return node id - i.e. srv + */ + public + @Nonnull + String getNodeId() { String nodeId = NodeInfo.DEFAULT_NODE; try { NodeInfo node = ApplicationContextHolder.get().getBean(NodeInfo.class); @@ -436,8 +457,7 @@ String getNodeURL() { nodeId = node.getId(); } } catch (Exception e) {} - String locServ = getBaseURL() + nodeId + "/"; - return locServ; + return nodeId; } /** * Return complete node URL eg. http://localhost:8080/geonetwork/ @@ -454,21 +474,55 @@ String getBaseURL() { public @Nonnull String getServerURL() { - String baseURL = pathFinder.getBaseUrl(); String protocol = getValue(Settings.SYSTEM_SERVER_PROTOCOL); String host = getValue(Settings.SYSTEM_SERVER_HOST); - String port = getValue(Settings.SYSTEM_SERVER_PORT); + Integer port = getServerPort(); + + StringBuffer sb = new StringBuffer(protocol + "://"); + + sb.append(host); - return protocol + "://" + host + (isPortRequired(protocol, port) ? ":" + port : ""); + if (isPortRequired(protocol, port + "")) { + sb.append(":"); + sb.append(port); + } + + return sb.toString(); } - static public boolean isPortRequired(String protocol, String port) { - if(Geonet.HttpProtocol.HTTP.equals(protocol) && String.valueOf(Geonet.DefaultHttpPort.HTTP).equals(port)) { + public Integer getServerPort() { + String protocol = getValue(Settings.SYSTEM_SERVER_PROTOCOL); + + // some conditional logic to handle the case where there's no port in the settings + Integer sitePort; + + Integer configuredPort = getValueAsInt(Settings.SYSTEM_SERVER_PORT, -1); + if (configuredPort != -1) { + sitePort = configuredPort; + } else if (protocol != null && protocol.equalsIgnoreCase(Geonet.HttpProtocol.HTTPS)) { + sitePort = Geonet.DefaultHttpPort.HTTPS; + } else { + sitePort = Geonet.DefaultHttpPort.HTTP; + } + + return sitePort; + } + + public static boolean isPortRequired(String protocol, String port) { + if (Geonet.HttpProtocol.HTTP.equals(protocol) && String.valueOf(Geonet.DefaultHttpPort.HTTP).equals(port)) { return false; - } else if(Geonet.HttpProtocol.HTTPS.equals(protocol) && String.valueOf(Geonet.DefaultHttpPort.HTTPS).equals(port)) { + } else if (Geonet.HttpProtocol.HTTPS.equals(protocol) && String.valueOf(Geonet.DefaultHttpPort.HTTPS).equals(port)) { return false; } else { return true; } } + + private Integer toIntOrNull(String key) { + try { + return Integer.parseInt(getValue(key)); + } catch (NumberFormatException e) { + return null; + } + } } diff --git a/core/src/main/java/org/fao/geonet/kernel/setting/Settings.java b/core/src/main/java/org/fao/geonet/kernel/setting/Settings.java index 6d79174a1b2..a96fa132585 100644 --- a/core/src/main/java/org/fao/geonet/kernel/setting/Settings.java +++ b/core/src/main/java/org/fao/geonet/kernel/setting/Settings.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2021 Food and Agriculture Organization of the + * Copyright (C) 2001-2024 Food and Agriculture Organization of the * United Nations (FAO-UN), United Nations World Food Programme (WFP) * and United Nations Environment Programme (UNEP) * @@ -60,6 +60,8 @@ public class Settings { public static final String SYSTEM_USERS_IDENTICON = "system/users/identicon"; public static final String SYSTEM_SEARCHSTATS = "system/searchStats/enable"; public static final String SYSTEM_FEEDBACK_EMAIL = "system/feedback/email"; + public static final String SYSTEM_FEEDBACK_LANGUAGES = "system/feedback/languages"; + public static final String SYSTEM_FEEDBACK_TRANSLATION_FOLLOWS_TEXT = "system/feedback/translationFollowsText"; public static final String SYSTEM_FEEDBACK_MAILSERVER_HOST = "system/feedback/mailServer/host"; public static final String SYSTEM_FEEDBACK_MAILSERVER_PORT = "system/feedback/mailServer/port"; public static final String SYSTEM_FEEDBACK_MAILSERVER_USERNAME = "system/feedback/mailServer/username"; @@ -71,7 +73,6 @@ public class Settings { public static final String SYSTEM_ENABLE_ALL_THESAURUS = "system/metadata/allThesaurus"; public static final String SYSTEM_METADATA_THESAURUS_NAMESPACE = "system/metadata/thesaurusNamespace"; public static final String SYSTEM_METADATA_VALIDATION_REMOVESCHEMALOCATION = "system/metadata/validation/removeSchemaLocation"; - public static final String SYSTEM_METADATA_HISTORY_ENABLED = "system/metadata/history/enabled"; public static final GNSetting SYSTEM_SITE_SVNUUID = new GNSetting("system/site/svnUuid", true); public static final String SYSTEM_INTRANET_NETWORK = "system/intranet/network"; public static final String SYSTEM_INTRANET_NETMASK = "system/intranet/netmask"; @@ -84,6 +85,7 @@ public class Settings { public static final String SYSTEM_CSW_CAPABILITY_RECORD_UUID = "system/csw/capabilityRecordUuid"; public static final String SYSTEM_CSW_METADATA_PUBLIC = "system/csw/metadataPublic"; public static final String SYSTEM_USERSELFREGISTRATION_ENABLE = "system/userSelfRegistration/enable"; + public static final String SYSTEM_USERSELFREGISTRATION_EMAIL_DOMAINS = "system/userSelfRegistration/domainsAllowed"; public static final String SYSTEM_USERSELFREGISTRATION_RECAPTCHA_ENABLE = "system/userSelfRegistration/recaptcha/enable"; public static final String SYSTEM_USERSELFREGISTRATION_RECAPTCHA_PUBLICKEY = "system/userSelfRegistration/recaptcha/publickey"; public static final String SYSTEM_USERSELFREGISTRATION_RECAPTCHA_SECRETKEY = "system/userSelfRegistration/recaptcha/secretkey"; @@ -119,7 +121,6 @@ public class Settings { public static final String SYSTEM_HARVESTING_MAIL_TEMPLATE = "system/harvesting/mail/template"; public static final String SYSTEM_METADATACREATE_GENERATE_UUID = "system/metadatacreate/generateUuid"; public static final String SYSTEM_THREADEDINDEXING_MAXTHREADS = "system/threadedindexing/maxthreads"; - public static final String SYSTEM_INDEX_INDEXINGTIMERECORDLINK = "system/index/indexingTimeRecordLink"; public static final String SYSTEM_RESOURCE_PREFIX = "metadata/resourceIdentifierPrefix"; public static final String SYSTEM_INSPIRE_REMOTE_VALIDATION_URL = "system/inspire/remotevalidation/url"; public static final String SYSTEM_INSPIRE_REMOTE_VALIDATION_URL_QUERY = "system/inspire/remotevalidation/urlquery"; @@ -128,14 +129,20 @@ public class Settings { public static final String REGION_GETMAP_MAPPROJ = "region/getmap/mapproj"; public static final String REGION_GETMAP_WIDTH = "region/getmap/width"; public static final String REGION_GETMAP_SUMMARY_WIDTH = "region/getmap/summaryWidth"; + public static final String REGION_GETMAP_GEODESIC_EXTENTS = "region/getmap/useGeodesicExtents"; public static final String METADATA_WORKFLOW_ENABLE = "metadata/workflow/enable"; public static final String METADATA_WORKFLOW_DRAFT_WHEN_IN_GROUP = "metadata/workflow/draftWhenInGroup"; - public static final String METADATA_WORKFLOW_ALLOW_SUBMIT_APPROVE_INVALID_MD = "metadata/workflow/allowSumitApproveInvalidMd"; + public static final String METADATA_WORKFLOW_ALLOW_SUBMIT_APPROVE_INVALID_MD = "metadata/workflow/allowSubmitApproveInvalidMd"; public static final String METADATA_WORKFLOW_ALLOW_PUBLISH_INVALID_MD = "metadata/workflow/allowPublishInvalidMd"; public static final String METADATA_WORKFLOW_ALLOW_PUBLISH_NON_APPROVED_MD = "metadata/workflow/allowPublishNonApprovedMd"; + public static final String METADATA_WORKFLOW_AUTOMATIC_UNPUBLISH_INVALID_MD = "metadata/workflow/automaticUnpublishInvalidMd"; + public static final String METADATA_WORKFLOW_FORCE_VALIDATION_ON_MD_SAVE = "metadata/workflow/forceValidationOnMdSave"; public static final String METADATA_LINK_EXCLUDEPATTERN = "metadata/link/excludedUrlPattern"; public static final String METADATA_IMPORT_RESTRICT = "metadata/import/restrict"; public static final String METADATA_IMPORT_USERPROFILE = "metadata/import/userprofile"; + public static final String METADATA_BATCH_EDITING_ACCESS_LEVEL = "metadata/batchediting/accesslevel"; + public static final String METADATA_HISTORY_ENABLED = "metadata/history/enabled"; + public static final String METADATA_HISTORY_ACCESS_LEVEL = "metadata/history/accesslevel"; public static final String METADATA_PUBLISHED_DELETE_USERPROFILE = "metadata/delete/profilePublishedMetadata"; public static final String METADATA_PUBLISH_USERPROFILE = "metadata/publication/profilePublishMetadata"; public static final String METADATA_UNPUBLISH_USERPROFILE = "metadata/publication/profileUnpublishMetadata"; @@ -151,7 +158,11 @@ public class Settings { public static final String SYSTEM_SECURITY_PASSWORDENFORCEMENT_USEPATTERN = "system/security/passwordEnforcement/usePattern"; public static final String SYSTEM_SECURITY_PASSWORDENFORCEMENT_PATTERN = "system/security/passwordEnforcement/pattern"; public static final String SYSTEM_SECURITY_PASSWORD_ALLOWADMINRESET = "system/security/password/allowAdminReset"; + public static final String SYSTEM_TRANSLATION_PROVIDER = "system/translation/provider"; + public static final String SYSTEM_TRANSLATION_SERVICEURL = "system/translation/serviceUrl"; + public static final String SYSTEM_TRANSLATION_APIKEY = "system/translation/apiKey"; + public static final String MICROSERVICES_ENABLED = "microservices/enabled"; public static class GNSetting { private String name; diff --git a/core/src/main/java/org/fao/geonet/kernel/url/UrlAnalyzer.java b/core/src/main/java/org/fao/geonet/kernel/url/UrlAnalyzer.java index 5686f54e12a..e904e8114a8 100644 --- a/core/src/main/java/org/fao/geonet/kernel/url/UrlAnalyzer.java +++ b/core/src/main/java/org/fao/geonet/kernel/url/UrlAnalyzer.java @@ -1,5 +1,5 @@ //============================================================================= -//=== Copyright (C) 2001-2019 Food and Agriculture Organization of the +//=== Copyright (C) 2001-2024 Food and Agriculture Organization of the //=== United Nations (FAO-UN), United Nations World Food Programme (WFP) //=== and United Nations Environment Programme (UNEP) //=== @@ -39,10 +39,6 @@ import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; import java.util.Optional; @@ -78,21 +74,19 @@ public void processMetadata(Element element, AbstractMetadata md) throws org.jdo if (schemaPlugin instanceof LinkAwareSchemaPlugin) { metadataLinkRepository - .findAll(metadatalinksTargetting(md)) - .stream() - .forEach(metadatalink -> { - metadatalink.getLink().getRecords().remove(metadatalink); - }); + .findAll(metadatalinksTargetting(md)) + .stream() + .forEach(metadatalink -> metadatalink.getLink().getRecords().remove(metadatalink)); entityManager.flush(); ((LinkAwareSchemaPlugin) schemaPlugin).createLinkStreamer(new ILinkBuilder() { @Override public Link found(String url) { - Link link = linkRepository.findOneByUrl(url); - if (link != null) { - return link; + Optional linkOptional = linkRepository.findOneByUrl(url); + if (linkOptional.isPresent()) { + return linkOptional.get(); } else { - link = new Link(); + Link link = new Link(); link.setUrl(url); linkRepository.save(link); return link; @@ -102,7 +96,7 @@ public Link found(String url) { @Override public void persist(Link link, AbstractMetadata metadata) { MetadataLink metadataLink = new MetadataLink(); - metadataLink.setMetadataId(new Integer(metadata.getId())); + metadataLink.setMetadataId(metadata.getId()); metadataLink.setMetadataUuid(metadata.getUuid()); metadataLink.setLink(link); link.getRecords().add(metadataLink); @@ -115,10 +109,10 @@ public void persist(Link link, AbstractMetadata metadata) { public void purgeMetataLink(Link link) { metadataLinkRepository - .findAll(metadatalinksTargetting(link)) - .stream() - .filter(metadatalink -> isReferencingAnUnknownMetadata((MetadataLink)metadatalink)) - .forEach(metadataLinkRepository::delete); + .findAll(metadatalinksTargetting(link)) + .stream() + .filter(this::isReferencingAnUnknownMetadata) + .forEach(metadataLinkRepository::delete); entityManager.flush(); } @@ -136,28 +130,16 @@ public void testLink(Link link) { } private Specification metadatalinksTargetting(Link link) { - return new Specification() { - @Override - public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) { - return criteriaBuilder.equal(root.get(MetadataLink_.link).get(Link_.id), link.getId()); - } - }; + return (root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.equal(root.get(MetadataLink_.link).get(Link_.id), link.getId()); } private Specification metadatalinksTargetting(AbstractMetadata md) { - return new Specification() { - @Override - public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) { - return criteriaBuilder.equal(root.get(MetadataLink_.metadataId), md.getId()); - } - }; + return (root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.equal(root.get(MetadataLink_.metadataId), md.getId()); } private boolean isReferencingAnUnknownMetadata(MetadataLink metadatalink) { Optional metadata = metadataRepository.findById(metadatalink.getMetadataId()); - return !metadata.isPresent(); + return metadata.isEmpty(); } - - } diff --git a/core/src/main/java/org/fao/geonet/kernel/url/UrlChecker.java b/core/src/main/java/org/fao/geonet/kernel/url/UrlChecker.java index 71b0e12d6ac..a9b65a61802 100644 --- a/core/src/main/java/org/fao/geonet/kernel/url/UrlChecker.java +++ b/core/src/main/java/org/fao/geonet/kernel/url/UrlChecker.java @@ -1,5 +1,5 @@ //============================================================================= -//=== Copyright (C) 2001-2019 Food and Agriculture Organization of the +//=== Copyright (C) 2001-2023 Food and Agriculture Organization of the //=== United Nations (FAO-UN), United Nations World Food Programme (WFP) //=== and United Nations Environment Programme (UNEP) //=== @@ -31,6 +31,7 @@ import org.fao.geonet.constants.Geonet; import org.fao.geonet.domain.LinkStatus; import org.fao.geonet.kernel.setting.SettingManager; +import org.fao.geonet.lib.Lib; import org.fao.geonet.lib.NetLib; import org.fao.geonet.utils.GeonetHttpRequestFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -149,8 +150,7 @@ public Void apply(@Nullable HttpClientBuilder originalConfig) { Log.info(Geonet.GEONETWORK,"UrlChecker: cannot determine hostname from url: "+url); } //now we have hostname, we can configure proxy - NetLib netLib = new NetLib(); - netLib.setupProxy(settingManager, originalConfig, hostname); + Lib.net.setupProxy(settingManager, originalConfig, hostname); return null; } }; diff --git a/core/src/main/java/org/fao/geonet/languages/FeedbackLanguages.java b/core/src/main/java/org/fao/geonet/languages/FeedbackLanguages.java new file mode 100644 index 00000000000..183ac8426f5 --- /dev/null +++ b/core/src/main/java/org/fao/geonet/languages/FeedbackLanguages.java @@ -0,0 +1,129 @@ +//============================================================================= +//=== Copyright (C) 2001-2024 Food and Agriculture Organization of the +//=== United Nations (FAO-UN), United Nations World Food Programme (WFP) +//=== and United Nations Environment Programme (UNEP) +//=== +//=== This library is free software; you can redistribute it and/or +//=== modify it under the terms of the GNU Lesser General Public +//=== License as published by the Free Software Foundation; either +//=== version 2.1 of the License, or (at your option) any later version. +//=== +//=== This library is distributed in the hope that it will be useful, +//=== but WITHOUT ANY WARRANTY; without even the implied warranty of +//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//=== Lesser General Public License for more details. +//=== +//=== You should have received a copy of the GNU Lesser General Public +//=== License along with this library; if not, write to the Free Software +//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +//=== +//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, +//=== Rome - Italy. email: geonetwork@osgeo.org +//============================================================================== + +package org.fao.geonet.languages; + +import org.apache.commons.lang.StringUtils; +import org.fao.geonet.constants.Geonet; +import org.fao.geonet.kernel.setting.SettingManager; +import org.fao.geonet.kernel.setting.Settings; +import org.fao.geonet.utils.Log; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.annotation.PostConstruct; +import java.util.*; + +/** + * Represents a utility class for managing supported locales and translation follows text for feedback. + */ +public class FeedbackLanguages { + private Locale[] supportedLocales; + private String translationFollowsText; + + @Autowired + SettingManager settingManager; + + /** + * Initializes the supported locales and translation follows text after bean creation. + */ + @PostConstruct + public void init() { + updateSupportedLocales(); + updateTranslationFollowsText(); + } + + /** + * Updates the supported locales based on the system feedback languages setting. + */ + public void updateSupportedLocales() { + String systemFeedbackLanguages = getSettingsValue(Settings.SYSTEM_FEEDBACK_LANGUAGES); + + if (StringUtils.isBlank(systemFeedbackLanguages)) { + supportedLocales = null; + return; + } + + supportedLocales = Arrays.stream(systemFeedbackLanguages.split(",")) + .map(String::trim) + .map(Locale::new) + .filter(this::isValidLocale) + .toArray(Locale[]::new); + } + + /** + * Updates the translation follows text based on the system feedback translation text setting. + */ + public void updateTranslationFollowsText() { + translationFollowsText = getSettingsValue(Settings.SYSTEM_FEEDBACK_TRANSLATION_FOLLOWS_TEXT); + } + + /** + * Retrieves the supported locales. If no supported locales are found, returns a fallback locale. + * @param fallbackLocale The fallback locale to be returned if no supported locales are available. + * @return An array of supported locales or a single fallback locale if none are available. + */ + public Locale[] getLocales(Locale fallbackLocale) { + if (supportedLocales == null || supportedLocales.length < 1) { + return new Locale[] { fallbackLocale }; + } + + return supportedLocales; + } + + /** + * Retrieves the translation follows text. + * @return The translation follows text. + */ + public String getTranslationFollowsText() { + return translationFollowsText; + } + + /** + * Checks if the provided locale is valid by attempting to load a ResourceBundle. + * @param locale The locale to validate. + * @return True if the locale is valid, false otherwise. + */ + private boolean isValidLocale(Locale locale) { + Boolean isValid; + try { + isValid = locale.getLanguage().equals(Geonet.DEFAULT_LANGUAGE) + || ResourceBundle.getBundle("org.fao.geonet.api.Messages", locale).getLocale().getLanguage().equals(locale.getLanguage()); + } catch (MissingResourceException e) { + isValid = false; + } + if (!isValid) { + String localeLanguage; + try { + localeLanguage = locale.getISO3Language(); + } catch (MissingResourceException e) { + localeLanguage = locale.getLanguage(); + } + Log.warning(Log.GEONETWORK_MODULE + ".feedbacklanguages", "Locale '" + localeLanguage + "' is invalid or missing message bundles. Ensure feedback locales are correct."); + } + return isValid; + } + + private String getSettingsValue(String settingName) { + return settingManager.getValue(settingName); + } +} diff --git a/core/src/main/java/org/fao/geonet/languages/LocaleMessages.java b/core/src/main/java/org/fao/geonet/languages/LocaleMessages.java index 56260990034..69c31cc4919 100644 --- a/core/src/main/java/org/fao/geonet/languages/LocaleMessages.java +++ b/core/src/main/java/org/fao/geonet/languages/LocaleMessages.java @@ -33,6 +33,7 @@ import org.fao.geonet.utils.Log; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils; +import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.context.support.ResourceBundleMessageSource; import com.google.common.collect.BiMap; @@ -57,16 +58,16 @@ public static String getMessageForLocale(String messageKey, Locale locale, Strin * * @param messageKey message key to use when retrieving the value from the properties file. * @param args Argument that may be supplied to the messagekey string - * @param locale locale to use when getting the message key + * @param locale locale to use when getting the message key. If null then it will default to locale context holder. * @param resourceBundleBeanQualifier resource bundle qualifier to use when getting ResourceBundleMessageSource bean * @return message */ public static String getMessageForLocale(String messageKey, Object[] args, Locale locale, String resourceBundleBeanQualifier) { - if (!StringUtils.isEmpty(messageKey) && locale !=null) { + if (!StringUtils.isEmpty(messageKey)) { ResourceBundleMessageSource resourceBundleMessageSource = getResourceBundleMessageSource(resourceBundleBeanQualifier); if (resourceBundleMessageSource != null) { - return resourceBundleMessageSource.getMessage(messageKey, args, locale); + return resourceBundleMessageSource.getMessage(messageKey, args, locale == null ? LocaleContextHolder.getLocale() : locale); } } // If we could not find the ResourceBundleMessageSource or the messageKey was in an invalid format then lets return the original key as the message. diff --git a/core/src/main/java/org/fao/geonet/lib/DbLib.java b/core/src/main/java/org/fao/geonet/lib/DbLib.java index 1352ee28439..407304043fd 100644 --- a/core/src/main/java/org/fao/geonet/lib/DbLib.java +++ b/core/src/main/java/org/fao/geonet/lib/DbLib.java @@ -1,5 +1,5 @@ //============================================================================= -//=== Copyright (C) 2001-2007 Food and Agriculture Organization of the +//=== Copyright (C) 2001-2024 Food and Agriculture Organization of the //=== United Nations (FAO-UN), United Nations World Food Programme (WFP) //=== and United Nations Environment Programme (UNEP) //=== @@ -67,7 +67,7 @@ public void insertData(ServletContext servletContext, final ServiceContext conte runSQL(context, data); } - static public void runSQL(final ServiceContext context, final List data) { + public static void runSQL(final ServiceContext context, final List data) { TransactionManager.runInTransaction("Apply SQL statements in database", context.getApplicationContext(), TransactionManager.TransactionRequirement.CREATE_ONLY_WHEN_NEEDED, TransactionManager.CommitBehavior.ALWAYS_COMMIT, false, new TransactionTask() { @@ -88,7 +88,7 @@ public void insertData(ServletContext servletContext, Statement statement, Path runSQL(statement, data, true); } - static private void runSQL(EntityManager entityManager, List data, boolean failOnError) throws Exception { + private static void runSQL(EntityManager entityManager, List data, boolean failOnError) throws Exception { StringBuffer sb = new StringBuffer(); boolean inBlock = false; @@ -183,7 +183,7 @@ private void runSQL(Statement statement, List data, boolean failOnError) * * @param type @return */ - private Path checkFilePath(ServletContext servletContext, Path appPath, Path filePath, String prefix, String type) { + private Path checkFilePath(ServletContext servletContext, Path appPath, Path filePath, String prefix, String type) throws IOException { Path finalPath; finalPath = testPath(filePath.resolve(prefix + type + SQL_EXTENSION)); @@ -214,9 +214,10 @@ private Path checkFilePath(ServletContext servletContext, Path appPath, Path fil if (finalPath != null) return finalPath; else { - Log.debug(Geonet.DB, " No default SQL script found: " + (filePath + "/" + prefix + type + SQL_EXTENSION)); + String msg = String.format("SQL script not found: %s", filePath + "/" + prefix + type + SQL_EXTENSION); + Log.debug(Geonet.DB, msg); + throw new IOException(msg); } - return toPath(""); } private Path toPath(String pathString) { @@ -244,7 +245,7 @@ private List loadSqlDataFile(ServletContext servletContext, ApplicationC Path file = checkFilePath(servletContext, appPath, filePath, filePrefix, DatabaseType.lookup(connection).toString()); // --- load the sql data - return Lib.text.load(servletContext, appPath, file, Constants.ENCODING); + return Lib.text.load(file, Constants.ENCODING); } finally { if (connection != null) { connection.close(); @@ -258,7 +259,7 @@ private List loadSqlDataFile(ServletContext servletContext, Statement st Path file = checkFilePath(servletContext, appPath, filePath, filePrefix, DatabaseType.lookup(statement.getConnection()).toString()); // --- load the sql data - return Lib.text.load(servletContext, appPath, file, Constants.ENCODING); + return Lib.text.load(file, Constants.ENCODING); } } diff --git a/core/src/main/java/org/fao/geonet/lib/ElementLib.java b/core/src/main/java/org/fao/geonet/lib/ElementLib.java index 3da8ced307e..b3089cf5f36 100644 --- a/core/src/main/java/org/fao/geonet/lib/ElementLib.java +++ b/core/src/main/java/org/fao/geonet/lib/ElementLib.java @@ -1,5 +1,5 @@ //============================================================================= -//=== Copyright (C) 2001-2007 Food and Agriculture Organization of the +//=== Copyright (C) 2001-2024 Food and Agriculture Organization of the //=== United Nations (FAO-UN), United Nations World Food Programme (WFP) //=== and United Nations Environment Programme (UNEP) //=== @@ -46,7 +46,7 @@ public class ElementLib { //----------------------------------------------------------------------------- public Set getIds(Element elem) { - HashSet hs = new HashSet(); + HashSet hs = new HashSet<>(); for (Object child : elem.getChildren()) hs.add(((Element) child).getChildText("id")); @@ -57,7 +57,7 @@ public Set getIds(Element elem) { //----------------------------------------------------------------------------- public Element pruneChildren(Element elem, Set ids) { - ArrayList alToPrune = new ArrayList(); + ArrayList alToPrune = new ArrayList<>(); //--- collect elements to prune diff --git a/core/src/main/java/org/fao/geonet/lib/Lib.java b/core/src/main/java/org/fao/geonet/lib/Lib.java index 0f199b03fa0..524976fd2e8 100644 --- a/core/src/main/java/org/fao/geonet/lib/Lib.java +++ b/core/src/main/java/org/fao/geonet/lib/Lib.java @@ -1,5 +1,5 @@ //============================================================================= -//=== Copyright (C) 2001-2007 Food and Agriculture Organization of the +//=== Copyright (C) 2001-2024 Food and Agriculture Organization of the //=== United Nations (FAO-UN), United Nations World Food Programme (WFP) //=== and United Nations Environment Programme (UNEP) //=== @@ -24,11 +24,16 @@ package org.fao.geonet.lib; public class Lib { - public final static ElementLib element = new ElementLib(); - public final static DbLib db = new DbLib(); - public final static ResourceLib resource = new ResourceLib(); - public final static TypeLib type = new TypeLib(); - public final static NetLib net = new NetLib(); - public final static SourcesLib sources = new SourcesLib(); - public final static TextLib text = new TextLib(); + public static final ElementLib element = new ElementLib(); + public static final DbLib db = new DbLib(); + public static final ResourceLib resource = new ResourceLib(); + public static final TypeLib type = new TypeLib(); + public static final NetLib net = new NetLib(); + public static final TextLib text = new TextLib(); + + /** + * Private constructor to avoid instantiate the class. + */ + private Lib() { + } } diff --git a/core/src/main/java/org/fao/geonet/lib/NetLib.java b/core/src/main/java/org/fao/geonet/lib/NetLib.java index 353d49d5964..87d53c5fc13 100644 --- a/core/src/main/java/org/fao/geonet/lib/NetLib.java +++ b/core/src/main/java/org/fao/geonet/lib/NetLib.java @@ -1,5 +1,5 @@ //============================================================================= -//=== Copyright (C) 2001-2022 Food and Agriculture Organization of the +//=== Copyright (C) 2001-2024 Food and Agriculture Organization of the //=== United Nations (FAO-UN), United Nations World Food Programme (WFP) //=== and United Nations Environment Programme (UNEP) //=== @@ -34,7 +34,6 @@ import org.fao.geonet.GeonetContext; import org.fao.geonet.constants.Geonet; import org.fao.geonet.kernel.setting.SettingManager; -import org.fao.geonet.kernel.setting.Settings; import org.fao.geonet.utils.Log; import org.fao.geonet.utils.XmlRequest; @@ -44,13 +43,25 @@ import java.net.Proxy; import java.net.URL; import java.net.URLConnection; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.Properties; import java.util.regex.PatternSyntaxException; import jeeves.server.context.ServiceContext; public class NetLib { + private ProxyConfiguration proxyConfiguration; + + public ProxyConfiguration getProxyConfiguration() { + return proxyConfiguration; + } + + public NetLib() { + boolean isProxyConfiguredInSystemProperties = StringUtils.isNotBlank(System.getProperty(ProxyConfiguration.HTTP_PROXY_HOST)) || + StringUtils.isNotBlank(System.getProperty(ProxyConfiguration.HTTPS_PROXY_HOST)); + + proxyConfiguration = new ProxyConfiguration(isProxyConfiguredInSystemProperties); + } public void setupProxy(ServiceContext context, XmlRequest req) { GeonetContext gc = (GeonetContext) context.getHandlerContext(Geonet.CONTEXT_NAME); @@ -66,12 +77,14 @@ public void setupProxy(ServiceContext context, XmlRequest req) { */ public void setupProxy(SettingManager sm, XmlRequest req) { - boolean enabled = sm.getValueAsBool(Settings.SYSTEM_PROXY_USE, false); - String host = sm.getValue(Settings.SYSTEM_PROXY_HOST); - String port = sm.getValue(Settings.SYSTEM_PROXY_PORT); - String username = sm.getValue(Settings.SYSTEM_PROXY_USERNAME); - String password = sm.getValue(Settings.SYSTEM_PROXY_PASSWORD); - String ignoreHostList = sm.getValue(Settings.SYSTEM_PROXY_IGNOREHOSTLIST); + proxyConfiguration.refresh(sm); + + boolean enabled = proxyConfiguration.isEnabled(); + String host = proxyConfiguration.getHost(); + String port = proxyConfiguration.getPort(); + String username = proxyConfiguration.getUsername(); + String password = proxyConfiguration.getPassword(); + String ignoreHostList = proxyConfiguration.getIgnoreHostList(); if (!enabled) { req.setUseProxy(false); @@ -108,12 +121,14 @@ public CredentialsProvider setupProxy(ServiceContext context, HttpClientBuilder * Setup proxy for http client */ public CredentialsProvider setupProxy(SettingManager sm, HttpClientBuilder client, String requestHost) { - boolean enabled = sm.getValueAsBool(Settings.SYSTEM_PROXY_USE, false); - String host = sm.getValue(Settings.SYSTEM_PROXY_HOST); - String port = sm.getValue(Settings.SYSTEM_PROXY_PORT); - String username = sm.getValue(Settings.SYSTEM_PROXY_USERNAME); - String password = sm.getValue(Settings.SYSTEM_PROXY_PASSWORD); - String ignoreHostList = sm.getValue(Settings.SYSTEM_PROXY_IGNOREHOSTLIST); + proxyConfiguration.refresh(sm); + + boolean enabled = proxyConfiguration.isEnabled(); + String host = proxyConfiguration.getHost(); + String port = proxyConfiguration.getPort(); + String username = proxyConfiguration.getUsername(); + String password = proxyConfiguration.getPassword(); + String ignoreHostList = proxyConfiguration.getIgnoreHostList(); CredentialsProvider provider = new BasicCredentialsProvider(); if (enabled) { @@ -153,30 +168,34 @@ public void setupProxy(ServiceContext context) { * Setup proxy for http client */ public void setupProxy(SettingManager sm) { - boolean useProxy = sm.getValueAsBool(Settings.SYSTEM_PROXY_USE, false); + proxyConfiguration.refresh(sm); - if (useProxy) { - String host = sm.getValue(Settings.SYSTEM_PROXY_HOST); - String port = sm.getValue(Settings.SYSTEM_PROXY_PORT); - String username = sm.getValue(Settings.SYSTEM_PROXY_USERNAME); - String ignoreHostList = sm.getValue(Settings.SYSTEM_PROXY_IGNOREHOSTLIST); + // If the proxy is configured in the system properties, + // ignore the proxy configuration in the system settings. + if (proxyConfiguration.isProxyConfiguredInSystemProperties()) return; + + if (proxyConfiguration.isEnabled()) { + String host = proxyConfiguration.getHost(); + String port = proxyConfiguration.getPort(); + String username = proxyConfiguration.getUsername(); + String ignoreHostList = proxyConfiguration.getIgnoreHostList(); Properties props = System.getProperties(); - props.put("http.proxyHost", host); - props.put("http.proxyPort", port); - props.put("https.proxyHost", host); - props.put("https.proxyPort", port); - props.put("http.nonProxyHosts", ignoreHostList); + props.put(ProxyConfiguration.HTTP_PROXY_HOST, host); + props.put(ProxyConfiguration.HTTP_PROXY_PORT, port); + props.put(ProxyConfiguration.HTTPS_PROXY_HOST, host); + props.put(ProxyConfiguration.HTTPS_PROXY_PORT, port); + props.put(ProxyConfiguration.HTTP_NON_PROXY_HOSTS, ignoreHostList); if (username.trim().length() > 0) { Log.error(Geonet.GEONETWORK, "Proxy credentials cannot be used"); } } else { - System.clearProperty("http.proxyHost"); - System.clearProperty("http.proxyPort"); - System.clearProperty("https.proxyHost"); - System.clearProperty("https.proxyPort"); - System.clearProperty("http.nonProxyHosts"); + System.clearProperty(ProxyConfiguration.HTTP_PROXY_HOST); + System.clearProperty(ProxyConfiguration.HTTP_PROXY_PORT); + System.clearProperty(ProxyConfiguration.HTTPS_PROXY_HOST); + System.clearProperty(ProxyConfiguration.HTTPS_PROXY_PORT); + System.clearProperty(ProxyConfiguration.HTTP_NON_PROXY_HOSTS); } } @@ -189,12 +208,14 @@ public URLConnection setupProxy(ServiceContext context, URL url) throws IOExcept GeonetContext gc = (GeonetContext) context.getHandlerContext(Geonet.CONTEXT_NAME); SettingManager sm = gc.getBean(SettingManager.class); - boolean enabled = sm.getValueAsBool(Settings.SYSTEM_PROXY_USE, false); - String host = sm.getValue(Settings.SYSTEM_PROXY_HOST); - String port = sm.getValue(Settings.SYSTEM_PROXY_PORT); - String username = sm.getValue(Settings.SYSTEM_PROXY_USERNAME); - String password = sm.getValue(Settings.SYSTEM_PROXY_PASSWORD); - String ignoreHostList = sm.getValue(Settings.SYSTEM_PROXY_IGNOREHOSTLIST); + proxyConfiguration.refresh(sm); + + boolean enabled = proxyConfiguration.isEnabled(); + String host = proxyConfiguration.getHost(); + String port = proxyConfiguration.getPort(); + String username = proxyConfiguration.getUsername(); + String password = proxyConfiguration.getPassword(); + String ignoreHostList = proxyConfiguration.getIgnoreHostList(); URLConnection conn = null; if (enabled) { @@ -208,7 +229,7 @@ public URLConnection setupProxy(ServiceContext context, URL url) throws IOExcept conn = url.openConnection(proxy); if (username.trim().length() != 0) { - String encodedUserPwd = new Base64().encodeAsString((username + ":" + password).getBytes(Charset.forName("UTF-8"))); + String encodedUserPwd = new Base64().encodeAsString((username + ":" + password).getBytes(StandardCharsets.UTF_8)); conn.setRequestProperty("Accept-Charset", "UTF-8"); conn.setRequestProperty("Proxy-Authorization", "Basic " + encodedUserPwd); } diff --git a/core/src/main/java/org/fao/geonet/lib/ProxyConfiguration.java b/core/src/main/java/org/fao/geonet/lib/ProxyConfiguration.java new file mode 100644 index 00000000000..8454a8caabb --- /dev/null +++ b/core/src/main/java/org/fao/geonet/lib/ProxyConfiguration.java @@ -0,0 +1,138 @@ +//============================================================================= +//=== Copyright (C) 2001-2023 Food and Agriculture Organization of the +//=== United Nations (FAO-UN), United Nations World Food Programme (WFP) +//=== and United Nations Environment Programme (UNEP) +//=== +//=== This program is free software; you can redistribute it and/or modify +//=== it under the terms of the GNU General Public License as published by +//=== the Free Software Foundation; either version 2 of the License, or (at +//=== your option) any later version. +//=== +//=== This program is distributed in the hope that it will be useful, but +//=== WITHOUT ANY WARRANTY; without even the implied warranty of +//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//=== General Public License for more details. +//=== +//=== You should have received a copy of the GNU General Public License +//=== along with this program; if not, write to the Free Software +//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA +//=== +//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, +//=== Rome - Italy. email: geonetwork@osgeo.org +//============================================================================== + +package org.fao.geonet.lib; + +import org.apache.commons.lang.StringUtils; +import org.fao.geonet.kernel.setting.SettingManager; +import org.fao.geonet.kernel.setting.Settings; + +/** + * Class to abstract the http proxy configuration from Java system properties or GeoNetwork configuration. + */ +public class ProxyConfiguration { + // HTTP Proxy host + public static final String HTTP_PROXY_HOST = "http.proxyHost"; + + // HTTP Proxy port + public static final String HTTP_PROXY_PORT = "http.proxyPort"; + + // HTTP Proxy username + public static final String HTTP_PROXY_USERNAME = "http.proxyUser"; + + // HTTP Proxy password + public static final String HTTP_PROXY_PASSWORD = "http.proxyPassword"; + + // HTTPS Proxy host + public static final String HTTPS_PROXY_HOST = "https.proxyHost"; + + // HTTPS Proxy port + public static final String HTTPS_PROXY_PORT = "https.proxyPort"; + + // HTTPS Proxy username + public static final String HTTPS_PROXY_USERNAME = "https.proxyUser"; + + // HTTPS Proxy password + public static final String HTTPS_PROXY_PASSWORD = "https.proxyPassword"; + + // HTTP Non-Proxy Hosts + public static final String HTTP_NON_PROXY_HOSTS = "http.nonProxyHosts"; + + private boolean enabled = false; + + private boolean isProxyConfiguredInSystemProperties = false; + private String host; + private String port; + private String username; + private String password; + private String ignoreHostList; + + public boolean isEnabled() { + return enabled; + } + + public boolean isProxyConfiguredInSystemProperties() { + return isProxyConfiguredInSystemProperties; + } + + public String getHost() { + return host; + } + + public String getPort() { + return port; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public String getIgnoreHostList() { + return ignoreHostList; + } + + public ProxyConfiguration(boolean isProxyConfiguredInSystemProperties) { + this.isProxyConfiguredInSystemProperties = isProxyConfiguredInSystemProperties; + if (this.isProxyConfiguredInSystemProperties) { + this.enabled = true; + } + } + + public void refresh(SettingManager settingManager) { + this.enabled = this.isProxyConfiguredInSystemProperties || + settingManager.getValueAsBool(Settings.SYSTEM_PROXY_USE, false); + + if (this.enabled) { + if (this.isProxyConfiguredInSystemProperties) { + if (StringUtils.isNotBlank(System.getProperty(ProxyConfiguration.HTTPS_PROXY_HOST))) { + this.host = System.getProperty(ProxyConfiguration.HTTPS_PROXY_HOST); + this.port = System.getProperty(ProxyConfiguration.HTTPS_PROXY_PORT); + this.username = System.getProperty(ProxyConfiguration.HTTPS_PROXY_USERNAME, ""); + this.password = System.getProperty(ProxyConfiguration.HTTPS_PROXY_PASSWORD, ""); + } else { + this.host = System.getProperty(ProxyConfiguration.HTTP_PROXY_HOST); + this.port = System.getProperty(ProxyConfiguration.HTTP_PROXY_PORT); + this.username = System.getProperty(ProxyConfiguration.HTTP_PROXY_USERNAME, ""); + this.password = System.getProperty(ProxyConfiguration.HTTP_PROXY_PASSWORD, ""); + } + + // Escape characters for regular expression matching + this.ignoreHostList = System.getProperty(ProxyConfiguration.HTTP_NON_PROXY_HOSTS, "") + .replace("\\.", "\\\\.") + .replace("\\*", "\\.\\*"); + + } else { + this.host = settingManager.getValue(Settings.SYSTEM_PROXY_HOST); + this.port = settingManager.getValue(Settings.SYSTEM_PROXY_PORT); + this.username = settingManager.getValue(Settings.SYSTEM_PROXY_USERNAME); + this.password = settingManager.getValue(Settings.SYSTEM_PROXY_PASSWORD); + this.ignoreHostList = settingManager.getValue(Settings.SYSTEM_PROXY_IGNOREHOSTLIST); + + } + } + } +} diff --git a/core/src/main/java/org/fao/geonet/lib/ResourceLib.java b/core/src/main/java/org/fao/geonet/lib/ResourceLib.java index a198e7a6cbc..ef997006a8a 100644 --- a/core/src/main/java/org/fao/geonet/lib/ResourceLib.java +++ b/core/src/main/java/org/fao/geonet/lib/ResourceLib.java @@ -1,5 +1,5 @@ //============================================================================= -//=== Copyright (C) 2001-2007 Food and Agriculture Organization of the +//=== Copyright (C) 2001-2024 Food and Agriculture Organization of the //=== United Nations (FAO-UN), United Nations World Food Programme (WFP) //=== and United Nations Environment Programme (UNEP) //=== @@ -34,7 +34,6 @@ import org.fao.geonet.exceptions.OperationNotAllowedEx; import org.fao.geonet.kernel.AccessManager; import org.fao.geonet.kernel.GeonetworkDataDirectory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.security.access.AccessDeniedException; import org.springframework.stereotype.Component; @@ -113,7 +112,7 @@ public void checkPrivilege(ServiceContext context, String id, denyAccess(context); } - public void denyAccess(ServiceContext context) throws Exception { + public void denyAccess(ServiceContext context) throws AccessDeniedException, OperationNotAllowedEx { if (context.getUserSession().isAuthenticated()) { throw new AccessDeniedException("User is not permitted to access this resource"); } else { @@ -134,21 +133,6 @@ public void checkEditPrivilege(ServiceContext context, String id) /** * @return the absolute path of the folder choosen to store all deleted metadata */ - @Deprecated - public Path getRemovedDir(ServiceContext context) { - GeonetContext gc = (GeonetContext) context - .getHandlerContext(Geonet.CONTEXT_NAME); - return gc.getBean(GeonetworkDataDirectory.class).getBackupDir(); - } - - /** - * See {@link #getRemovedDir(Path, String)} - */ - @Deprecated - public Path getRemovedDir(ServiceContext context, String id) { - return getRemovedDir(getRemovedDir(context), id); - } - public Path getRemovedDir(int id) { ApplicationContext appContext = ApplicationContextHolder.get(); GeonetworkDataDirectory dataDirectory = appContext.getBean(GeonetworkDataDirectory.class); @@ -172,10 +156,10 @@ public Path getRemovedDir(Path removedDir, String id) { // --- // ----------------------------------------------------------------------------- - private String pad(int group, int lenght) { + private String pad(int group, int length) { String text = Integer.toString(group); - while (text.length() < lenght) + while (text.length() < length) text = "0" + text; return text; diff --git a/core/src/main/java/org/fao/geonet/lib/SourcesLib.java b/core/src/main/java/org/fao/geonet/lib/SourcesLib.java deleted file mode 100644 index e4fa3739f2b..00000000000 --- a/core/src/main/java/org/fao/geonet/lib/SourcesLib.java +++ /dev/null @@ -1,40 +0,0 @@ -//============================================================================= -//=== Copyright (C) 2001-2007 Food and Agriculture Organization of the -//=== United Nations (FAO-UN), United Nations World Food Programme (WFP) -//=== and United Nations Environment Programme (UNEP) -//=== -//=== This program is free software; you can redistribute it and/or modify -//=== it under the terms of the GNU General Public License as published by -//=== the Free Software Foundation; either version 2 of the License, or (at -//=== your option) any later version. -//=== -//=== This program is distributed in the hope that it will be useful, but -//=== WITHOUT ANY WARRANTY; without even the implied warranty of -//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -//=== General Public License for more details. -//=== -//=== You should have received a copy of the GNU General Public License -//=== along with this program; if not, write to the Free Software -//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA -//=== -//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, -//=== Rome - Italy. email: geonetwork@osgeo.org -//============================================================================== - -package org.fao.geonet.lib; - -//============================================================================= - -public class SourcesLib { - //--------------------------------------------------------------------------- - //--- - //--- API methods - //--- - //--------------------------------------------------------------------------- - - //--------------------------------------------------------------------------- - -} - -//============================================================================= - diff --git a/core/src/main/java/org/fao/geonet/lib/TextLib.java b/core/src/main/java/org/fao/geonet/lib/TextLib.java index ca78ee34f0c..a3f7e3b6b33 100644 --- a/core/src/main/java/org/fao/geonet/lib/TextLib.java +++ b/core/src/main/java/org/fao/geonet/lib/TextLib.java @@ -1,5 +1,5 @@ //============================================================================= -//=== Copyright (C) 2001-2007 Food and Agriculture Organization of the +//=== Copyright (C) 2001-2024 Food and Agriculture Organization of the //=== United Nations (FAO-UN), United Nations World Food Programme (WFP) //=== and United Nations Environment Programme (UNEP) //=== @@ -26,11 +26,11 @@ import org.fao.geonet.Util; import org.fao.geonet.utils.IO; -import javax.servlet.ServletContext; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -41,27 +41,25 @@ public class TextLib { private static final Random RANDOM = new Random(); - public List load(ServletContext servletContext, Path appPath, Path file) throws IOException { - return load(servletContext, appPath, file, "ISO-8859-1"); + public List load(Path file) throws IOException { + return load(file, "ISO-8859-1"); } - public List load(ServletContext servletContext, Path appPath, Path file, String encoding) throws IOException { - BufferedReader reader = IO.newBufferedReader(file, Charset.forName(encoding)); - List al = new ArrayList(); - String line = reader.readLine(); - try { + public List load(Path file, String encoding) throws IOException { + try(BufferedReader reader = IO.newBufferedReader(file, Charset.forName(encoding))) { + List al = new ArrayList<>(); + String line = reader.readLine(); + while (line != null) { al.add(line); line = reader.readLine(); } return al; - } finally { - reader.close(); } } public void save(Path file, List lines) throws IOException { - try (BufferedWriter ow = Files.newBufferedWriter(file, Charset.forName("ISO-8859-1"))) { + try (BufferedWriter ow = Files.newBufferedWriter(file, StandardCharsets.ISO_8859_1)) { for (String line : lines) { ow.write(line); ow.newLine(); diff --git a/core/src/main/java/org/fao/geonet/resources/JCloudConfiguration.java b/core/src/main/java/org/fao/geonet/resources/JCloudConfiguration.java deleted file mode 100644 index 2531f78420e..00000000000 --- a/core/src/main/java/org/fao/geonet/resources/JCloudConfiguration.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (C) 2001-2016 Food and Agriculture Organization of the - * United Nations (FAO-UN), United Nations World Food Programme (WFP) - * and United Nations Environment Programme (UNEP) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * - * Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, - * Rome - Italy. email: geonetwork@osgeo.org - */ - -package org.fao.geonet.resources; - -import org.apache.commons.lang.BooleanUtils; -import org.apache.commons.lang.StringUtils; -import org.jclouds.ContextBuilder; -import org.jclouds.blobstore.BlobStoreContext; - -import javax.annotation.Nonnull; -import javax.annotation.PostConstruct; - -public class JCloudConfiguration { - private BlobStoreContext client = null; - private ContextBuilder builder = null; - - private String DEFAULT_CLOUD_FOLDER_SEPARATOR = "/"; // not sure if this is consistent for all clouds defaulting to "/" and make it a config - private final String DEFAULT_EXTERNAL_RESOURCE_MANAGEMENT_WINDOW_PARAMETERS = "toolbar=0,width=600,height=600"; - private final Boolean DEFAULT_EXTERNAL_RESOURCE_MANAGEMENT_MODAL_ENABLED = true; - private final Boolean DEFAULT_EXTERNAL_RESOURCE_MANAGEMENT_FOLDER_ENABLED = true; - private final Boolean DEFAULT_VERSIONING_ENABLED = false; - - private String provider; - private String baseFolder; - private String storageAccountName; - private String storageAccountKey; - private String containerName; - private String endpoint; - private String folderDelimiter = null; - - /** - * Url used for managing enhanced resource properties related to the metadata. - */ - private String externalResourceManagementUrl; - private String externalResourceManagementWindowParameters; - private Boolean externalResourceManagementModalEnabled; - private Boolean externalResourceManagementFolderEnabled; - private String externalResourceManagementFolderRoot; - - /* - * Enable option to add versioning in the link to the resource. - */ - private Boolean versioningEnabled; - - - public void setProvider(String provider) { - this.provider = provider; - } - - public void setEndpoint(String endpoint) { - this.endpoint = endpoint; - } - - public void setStorageAccountName(String storageAccountName) { - this.storageAccountName = storageAccountName; - } - - public void setStorageAccountKey(String storageAccountKey) { - this.storageAccountKey = storageAccountKey; - } - - public void setBaseFolder(String baseFolder) { - if (this.folderDelimiter == null) { - this.folderDelimiter = DEFAULT_CLOUD_FOLDER_SEPARATOR; - } - if (StringUtils.isEmpty(baseFolder)) { - this.baseFolder = this.folderDelimiter; - } else { - if (baseFolder.endsWith(this.folderDelimiter)) { - this.baseFolder = baseFolder; - } else { - this.baseFolder = baseFolder + this.folderDelimiter; - } - } - } - - public void setContainerName(String containerName) { - this.containerName = containerName; - } - - public void setFolderDelimiter(String folderDelimiter) { - if (this.folderDelimiter != null && !this.folderDelimiter.equals(folderDelimiter)) { - throw new RuntimeException("Folder delimiter cannot be changed once set. Ensure that it is set prior to setting base folder"); - } - this.folderDelimiter = folderDelimiter; - } - - @Nonnull - public String getExternalResourceManagementUrl() { - return externalResourceManagementUrl; - } - - public void setExternalResourceManagementUrl(String externalResourceManagementUrl) { - this.externalResourceManagementUrl = externalResourceManagementUrl; - } - - @Nonnull - public String getExternalResourceManagementWindowParameters() { - if (externalResourceManagementWindowParameters == null) { - return DEFAULT_EXTERNAL_RESOURCE_MANAGEMENT_WINDOW_PARAMETERS; - } else { - return externalResourceManagementWindowParameters; - } - } - - public void setExternalResourceManagementWindowParameters(String externalResourceManagementWindowParameters) { - this.externalResourceManagementWindowParameters = externalResourceManagementWindowParameters; - } - - @Nonnull - public Boolean isExternalResourceManagementModalEnabled() { - if (externalResourceManagementModalEnabled == null) { - return DEFAULT_EXTERNAL_RESOURCE_MANAGEMENT_MODAL_ENABLED; - } else { - return externalResourceManagementModalEnabled; - } - } - - public void setExternalResourceManagementModalEnabled(Boolean externalResourceManagementModalEnabled) { - this.externalResourceManagementModalEnabled = externalResourceManagementModalEnabled; - } - - public void setExternalResourceManagementModalEnabled(String externalResourceManagementModalEnabled) { - this.externalResourceManagementModalEnabled = BooleanUtils.toBooleanObject(externalResourceManagementModalEnabled);; - } - - public Boolean isExternalResourceManagementFolderEnabled() { - if (externalResourceManagementFolderEnabled == null) { - return DEFAULT_EXTERNAL_RESOURCE_MANAGEMENT_FOLDER_ENABLED; - } else { - return externalResourceManagementFolderEnabled; - } - } - - public void setExternalResourceManagementFolderEnabled(Boolean externalResourceManagementFolderEnabled) { - this.externalResourceManagementFolderEnabled = externalResourceManagementFolderEnabled; - } - - public String getExternalResourceManagementFolderRoot() { - return this.externalResourceManagementFolderRoot; - } - - public void setExternalResourceManagementFolderRoot(String externalResourceManagementFolderRoot) { - String folderRoot = externalResourceManagementFolderRoot; - if (folderRoot != null) { - if (!folderRoot.startsWith(getFolderDelimiter())) { - folderRoot = getFolderDelimiter() + folderRoot; - } - if (folderRoot.endsWith(getFolderDelimiter())) { - folderRoot = folderRoot.substring(0, folderRoot.length() - 1); - } - } - - this.externalResourceManagementFolderRoot=folderRoot; - } - - @Nonnull - public Boolean isVersioningEnabled() { - if (versioningEnabled == null) { - - return DEFAULT_VERSIONING_ENABLED; - } else { - return versioningEnabled; - } - } - - public void setVersioningEnabled(Boolean versioningEnabled) { - this.versioningEnabled = versioningEnabled; - } - - public void setVersioningEnabled(String versioningEnabled) { - this.versioningEnabled = BooleanUtils.toBooleanObject(versioningEnabled); - ; - } - - @PostConstruct - public void init() { - if (folderDelimiter == null) { - folderDelimiter = DEFAULT_CLOUD_FOLDER_SEPARATOR; - } - - // Run the setBaseFolder following to ensure the baseFolder is formatted correctly. - setBaseFolder(baseFolder); - - if (storageAccountName != null && provider != null) { - builder = ContextBuilder.newBuilder(provider).credentials(storageAccountName, storageAccountKey); - storageAccountName = null; - storageAccountKey = null; - } - - if (endpoint != null) { - builder.endpoint(endpoint); - } - - client = builder.buildView(BlobStoreContext.class); - - builder = null; - if (containerName == null) { - throw new RuntimeException("Missing the container Name configuration"); - } - } - - @Nonnull - public BlobStoreContext getClient() { - return this.client; - } - - @Nonnull - public String getProvider() { - return this.provider; - } - - @Nonnull - public String getContainerName() { - return this.containerName; - } - - public String getBaseFolder() { - return this.baseFolder; - } - - public String getFolderDelimiter() { - return this.folderDelimiter; - } -} diff --git a/core/src/main/java/org/fao/geonet/resources/ResourceFilter.java b/core/src/main/java/org/fao/geonet/resources/ResourceFilter.java index 238fbd2a813..d89883aa0e2 100644 --- a/core/src/main/java/org/fao/geonet/resources/ResourceFilter.java +++ b/core/src/main/java/org/fao/geonet/resources/ResourceFilter.java @@ -24,15 +24,12 @@ package org.fao.geonet.resources; import com.google.common.collect.Maps; - +import com.google.common.collect.Sets; import jeeves.config.springutil.JeevesDelegatingFilterProxy; - import org.fao.geonet.NodeInfo; -import org.fao.geonet.constants.Geonet; import org.fao.geonet.domain.Pair; import org.fao.geonet.kernel.GeonetworkDataDirectory; import org.fao.geonet.kernel.setting.SettingManager; -import org.fao.geonet.utils.Log; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.http.MediaType; import org.springframework.web.context.request.ServletWebRequest; @@ -40,7 +37,6 @@ import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; - import java.io.IOException; import java.nio.file.Path; import java.nio.file.attribute.FileTime; @@ -83,6 +79,7 @@ public class Instance { private final ServletResponse response; private final Path resourcesDir; + private final Path schemaPublicationDir; private final Path appPath; private final String nodeId; private final String siteId; @@ -96,13 +93,14 @@ public Instance(ServletRequest request, ServletResponse response) throws IOExcep this.resources = applicationContext.getBean(Resources.class); this.siteId = applicationContext.getBean(SettingManager.class).getSiteId(); this.resourcesDir = resources.locateResourcesDir(servletContext, applicationContext); + this.schemaPublicationDir = applicationContext.getBean(GeonetworkDataDirectory.class).getSchemaPublicationDir(); if (defaultImage == null) { defaultImage = resources.loadResource(resourcesDir, servletContext, appPath, "images/logos/" + siteId + ".png", new byte[0], -1); } this.nodeId = applicationContext.getBean(NodeInfo.class).getId(); if (!faviconMap.containsKey(nodeId)) { final byte[] defaultImageBytes = defaultImage.one(); - AddFavIcon(nodeId, resources.loadResource(resourcesDir, servletContext, appPath, "images/logos/" + siteId + ".ico", + addFavIcon(nodeId, resources.loadResource(resourcesDir, servletContext, appPath, "images/logos/" + siteId + ".ico", defaultImageBytes, -1)); } @@ -133,21 +131,27 @@ public void execute() throws IOException { return; } - // Resources are images for logos, XML for map config or XSD - String contentType = "xml".equals(ext) || "xsd".equals(ext) - ? MediaType.APPLICATION_XML_VALUE - : "image/" + ext; + // Figure out the content type based on the extensions, defaulting to an image + String contentType = extensionToMediaType(ext); httpServletResponse.setContentType(contentType); httpServletResponse.addHeader("Cache-Control", "max-age=" + SIX_HOURS + ", public"); if (filename.equals("images/logos/" + siteId + ".ico")) { favicon = resources.loadResource(resourcesDir, servletContext, appPath, "images/logos/" + siteId + ".ico", favicon.one(), favicon.two()); - AddFavIcon(nodeId, favicon); + addFavIcon(nodeId, favicon); httpServletResponse.setContentLength(favicon.one().length); httpServletResponse.addHeader("Cache-Control", "max-age=" + FIVE_DAYS + ", public"); response.getOutputStream().write(favicon.one()); + } else if(filename.startsWith("/xml/schemas/")) { + Pair loadedResource = resources.loadResource(schemaPublicationDir, servletContext, appPath, filename, null, -1); + if(loadedResource.two() == -1) { + httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND); + } else { + httpServletResponse.setContentLength(loadedResource.one().length); + response.getOutputStream().write(loadedResource.one()); + } } else { byte[] defaultData = null; @@ -167,7 +171,7 @@ public void execute() throws IOException { } } - private synchronized void AddFavIcon(String nodeId, Pair favicon) { + private synchronized void addFavIcon(String nodeId, Pair favicon) { if (faviconMap.containsKey(nodeId)) { faviconMap.replace(nodeId, favicon); } else { @@ -175,4 +179,16 @@ private synchronized void AddFavIcon(String nodeId, Pair favicon) } } } + + private String extensionToMediaType(String ext) { + final String contentType; + if(Sets.newHashSet("xml", "xsd", "sch", "dtd").contains(ext)) { + contentType = MediaType.APPLICATION_XML_VALUE; + } else if(ext.equals("txt")) { + contentType = MediaType.TEXT_PLAIN_VALUE; + } else { + contentType = "image/" + ext; + } + return contentType; + } } diff --git a/core/src/main/java/org/fao/geonet/security/web/csrf/GeonetworkCsrfSecurityRequestMatcher.java b/core/src/main/java/org/fao/geonet/security/web/csrf/GeonetworkCsrfSecurityRequestMatcher.java index dfb79813733..9d00330882c 100644 --- a/core/src/main/java/org/fao/geonet/security/web/csrf/GeonetworkCsrfSecurityRequestMatcher.java +++ b/core/src/main/java/org/fao/geonet/security/web/csrf/GeonetworkCsrfSecurityRequestMatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2016 Food and Agriculture Organization of the + * Copyright (C) 2001-2023 Food and Agriculture Organization of the * United Nations (FAO-UN), United Nations World Food Programme (WFP) * and United Nations Environment Programme (UNEP) * @@ -25,32 +25,61 @@ import org.springframework.security.web.util.matcher.RegexRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; +import org.springframework.util.Assert; import javax.servlet.http.HttpServletRequest; +import java.util.Arrays; +import java.util.LinkedHashSet; import java.util.Set; import java.util.regex.Pattern; /** * RequestMatcher to exclude the CSRF token from requests. - * + *

* Useful to exclude CSW POST requests for GetRecords. * - * @author Jose García + * @author Jose García. */ public class GeonetworkCsrfSecurityRequestMatcher implements RequestMatcher { private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$"); private RegexRequestMatcher unprotectedMatcher; + private Set otherMatchers = new LinkedHashSet<>(); public GeonetworkCsrfSecurityRequestMatcher(Set unprotectedUrlPatterns) { unprotectedMatcher = new RegexRequestMatcher(String.join("|", unprotectedUrlPatterns), null); } + /** + * Adds additional RequestMatchers used if the list of unprotectedUrlPatters don't match. The check is done in the + * order in what the matchers have been added. + * The matcher must be negative, that's it, it will return false for the patterns that match the patterns. + * + * @param matcher + */ + public void addRequestMatcher(RequestMatcher... matcher) { + Assert.notNull(matcher, "To add additional matchers the parameter matcher cannot be null"); + otherMatchers.addAll(Arrays.asList(matcher)); + } + + /** + * Return {@code}true{@code} if the request doesn't match the methods and patterns defined. + * + * @param request the request to check for a match + * @return + */ @Override public boolean matches(HttpServletRequest request) { - if(allowedMethods.matcher(request.getMethod()).matches()){ - return false; + boolean result = true; + if (allowedMethods.matcher(request.getMethod()).matches()) { + result = false; + } + if (result) { + result = !unprotectedMatcher.matches(request); } - return !unprotectedMatcher.matches(request); + if (result && !otherMatchers.isEmpty()) { + result = otherMatchers.stream().anyMatch(matcher -> matcher.matches(request)); + } + return result; } } diff --git a/core/src/main/java/org/fao/geonet/util/LocalizedEmail.java b/core/src/main/java/org/fao/geonet/util/LocalizedEmail.java new file mode 100644 index 00000000000..0aa1bf978fb --- /dev/null +++ b/core/src/main/java/org/fao/geonet/util/LocalizedEmail.java @@ -0,0 +1,149 @@ +//============================================================================= +//=== Copyright (C) 2001-2024 Food and Agriculture Organization of the +//=== United Nations (FAO-UN), United Nations World Food Programme (WFP) +//=== and United Nations Environment Programme (UNEP) +//=== +//=== This library is free software; you can redistribute it and/or +//=== modify it under the terms of the GNU Lesser General Public +//=== License as published by the Free Software Foundation; either +//=== version 2.1 of the License, or (at your option) any later version. +//=== +//=== This library is distributed in the hope that it will be useful, +//=== but WITHOUT ANY WARRANTY; without even the implied warranty of +//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//=== Lesser General Public License for more details. +//=== +//=== You should have received a copy of the GNU Lesser General Public +//=== License along with this library; if not, write to the Free Software +//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +//=== +//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, +//=== Rome - Italy. email: geonetwork@osgeo.org +//============================================================================== + +package org.fao.geonet.util; + +import org.apache.commons.lang.StringUtils; +import org.fao.geonet.ApplicationContextHolder; +import org.fao.geonet.languages.FeedbackLanguages; +import org.fao.geonet.utils.Log; + +import static org.fao.geonet.util.LocalizedEmailComponent.ComponentType.*; +import static org.fao.geonet.util.LocalizedEmailComponent.ComponentType; + +import java.util.*; + +/** + * Class representing a localized email. + */ +public class LocalizedEmail { + private final Boolean isHtml; + private final Map components; + private final String translationFollowsText; + + private static final String SUBJECT_DELIMITER = " | "; + private static final String HTML_MESSAGE_DELIMITER = "


"; + private static final String HTML_LINE_BREAK = "

"; + private static final String TEXT_MESSAGE_DELIMITER = "\n\n--------------------------------------------------------\n\n"; + private static final String TEXT_LINE_BREAK = "\n\n"; + + public LocalizedEmail(Boolean isHtml) { + this.isHtml = isHtml; + + FeedbackLanguages feedbackLanguages = ApplicationContextHolder.get().getBean(FeedbackLanguages.class); + this.translationFollowsText = feedbackLanguages.getTranslationFollowsText(); + + this.components = new HashMap<>(); + } + + /** + * Add one or more components to the email object. Existing components are replaced. + * + * @param newComponents The components to add to the email. + */ + public void addComponents(LocalizedEmailComponent... newComponents) { + + for (LocalizedEmailComponent newComponent : newComponents) { + + if (newComponent == null) { + throw new IllegalArgumentException("Null parameter not allowed"); + } + + components.put(newComponent.getComponentType(), newComponent); + } + } + + public String getParsedSubject(Locale[] feedbackLocales) { + LinkedHashMap subjects = components.get(SUBJECT).getParsedMessagesMap(feedbackLocales); + return String.join(SUBJECT_DELIMITER, subjects.values()); + } + + public String getParsedMessage(Locale[] feedbackLocales) { + return getParsedMessage(feedbackLocales, null); + } + + public String getParsedMessage(Locale[] feedbackLocales, Map replacements) { + LinkedHashMap messages = components.get(MESSAGE).getParsedMessagesMap(feedbackLocales, true); + + // Prepend the message with a salutation placeholder if the salutation component is present + if (components.containsKey(SALUTATION) && components.get(SALUTATION) != null) { + + LinkedHashMap salutations = components.get(SALUTATION).getParsedMessagesMap(feedbackLocales); + LinkedHashMap messagesWithSalutations = new LinkedHashMap<>(); + + for (Map.Entry entry : messages.entrySet()) { + //Skip messages that have no matching salutation + if (!salutations.containsKey(entry.getKey())) { + continue; + } + + String message = entry.getValue(); + String salutation = salutations.get(entry.getKey()); + + if (replacements != null && !replacements.isEmpty()) { + for (Map.Entry replacement : replacements.entrySet()) { + salutation = salutation.replace(replacement.getKey(), replacement.getValue()); + } + } + + messagesWithSalutations.put(entry.getKey(), salutation + message); + } + + messages = messagesWithSalutations; + + } + + String messageDelimiter; + String lineBreak; + + // Set the delimiter and break string to use based on email type + if (isHtml) { + messageDelimiter = HTML_MESSAGE_DELIMITER; + lineBreak = HTML_LINE_BREAK; + // Wrap each message in a div with a lang attribute for accessibility + messages.replaceAll((locale, message) -> "
" + message + "
"); + } else { + messageDelimiter = TEXT_MESSAGE_DELIMITER; + lineBreak = TEXT_LINE_BREAK; + } + + String emailMessage = String.join(messageDelimiter, messages.values()); + + // Prepend the message with the translation follows text if there is more than one language specified + if (messages.size() > 1 && !StringUtils.isBlank(translationFollowsText)) { + emailMessage = translationFollowsText + lineBreak + emailMessage; + } + + // If the email is html wrap the content in html and body tags + if (isHtml) { + if (emailMessage.contains("") || emailMessage.contains("")) { + Log.warning(Log.GEONETWORK_MODULE + ".localizedemail","Multilingual emails are unsupported for HTML emails with messages containing or tags. Reverting to first specified locale."); + return messages.get(feedbackLocales[0]); + } + emailMessage = "" + emailMessage + ""; + } + + return emailMessage; + } +} + diff --git a/core/src/main/java/org/fao/geonet/util/LocalizedEmailComponent.java b/core/src/main/java/org/fao/geonet/util/LocalizedEmailComponent.java new file mode 100644 index 00000000000..fa61f8e07f8 --- /dev/null +++ b/core/src/main/java/org/fao/geonet/util/LocalizedEmailComponent.java @@ -0,0 +1,372 @@ +//============================================================================= +//=== Copyright (C) 2001-2024 Food and Agriculture Organization of the +//=== United Nations (FAO-UN), United Nations World Food Programme (WFP) +//=== and United Nations Environment Programme (UNEP) +//=== +//=== This library is free software; you can redistribute it and/or +//=== modify it under the terms of the GNU Lesser General Public +//=== License as published by the Free Software Foundation; either +//=== version 2.1 of the License, or (at your option) any later version. +//=== +//=== This library is distributed in the hope that it will be useful, +//=== but WITHOUT ANY WARRANTY; without even the implied warranty of +//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//=== Lesser General Public License for more details. +//=== +//=== You should have received a copy of the GNU Lesser General Public +//=== License along with this library; if not, write to the Free Software +//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +//=== +//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, +//=== Rome - Italy. email: geonetwork@osgeo.org +//============================================================================== + +package org.fao.geonet.util; + +import org.fao.geonet.ApplicationContextHolder; +import org.fao.geonet.kernel.search.JSONLocCacheLoader; +import org.fao.geonet.kernel.setting.SettingManager; + +import java.text.MessageFormat; +import java.util.*; + +import static org.fao.geonet.util.LocalizedEmailComponent.ReplacementType.*; + +/** + * This class is used to handle email parameters used to format localized email messages + */ +public class LocalizedEmailComponent { + + private final ComponentType componentType; + private final String keyOrRawValue; + private final KeyType keyType; + private final ReplacementType replacementType; + private final Map> parameters; + private Boolean compileWithIndexFields; + private String metadataUuid; + private Boolean replaceLinks; + private Boolean replaceLinksWithHtmlFormat = false; + + /** + * Enum representing the types of components in an email. + *

+ * This enum defines four types of components: + *

    + *
  • {@link ComponentType#SUBJECT SUBJECT}: The email subject field.
  • + *
  • {@link ComponentType#MESSAGE MESSAGE}: The email body.
  • + *
  • {@link ComponentType#SALUTATION SALUTATION}: The salutation to prepend each localized message with. (Ex. 'Hello John')
  • + *
  • {@link ComponentType#NESTED NESTED}: A component of insignificant type that is used to generate other components.
  • + *
+ */ + public enum ComponentType { + /** + * The email subject field. + */ + SUBJECT, + + /** + * The email body. + */ + MESSAGE, + + /** + * The salutation to prepend each localized message with. (Ex. 'Hello John'). + */ + SALUTATION, + + /** + * A component of insignificant type that is used to generate other components. + */ + NESTED + } + + /** + * Enum representing the types of keys used to parse a components message. + *

+ * This enum defines four types of keys: + *

    + *
  • {@link KeyType#MESSAGE_OR_JSON_KEY MESSAGE_OR_JSON_KEY}: Represents a component that tries to retrieve its value using {@link ResourceBundle#getString} or JSON localization files if message key was not found.
  • + *
  • {@link KeyType#MESSAGE_KEY MESSAGE_KEY}: Represents a component that retrieves its value using {@link ResourceBundle#getString}.
  • + *
  • {@link KeyType#JSON_KEY JSON_KEY}: Represents a component that retrieves its value by searching the JSON localization files for the specified key.
  • + *
  • {@link KeyType#RAW_VALUE RAW_VALUE}: Represents a component in which keys are not required. The raw value from keyOrRawValue is used.
  • + *
+ *

+ */ + public enum KeyType { + /** + * Represents a component that tries to retrieve its value using {@link ResourceBundle#getString} or JSON localization files if message key was not found. + */ + MESSAGE_OR_JSON_KEY, + + /** + * Represents a component that retrieves its value using {@link ResourceBundle#getString}. + */ + MESSAGE_KEY, + + /** + * Represents a component that retrieves its value by searching the JSON localization files for the specified key. + */ + JSON_KEY, + + /** + * Represents a component in which keys are not required. The raw value from keyOrRawValue is used. + */ + RAW_VALUE + } + + /** + * Enum representing the types of replacements performed on the email component. + *

+ * This enum defines four types of replacement: + *

    + *
  • {@link ReplacementType#POSITIONAL_FORMAT POSITIONAL_FORMAT}: A parameter that retrieves its value using {@link ResourceBundle#getString}. + * The value property is set to the message key to search for.
  • + *
  • {@link ReplacementType#NUMERIC_FORMAT NUMERIC_FORMAT}: A parameter that retrieves its value by searching the JSON localization files for the specified key. + * The value property is set to the json key to search for.
  • + *
  • {@link ReplacementType#NAMED_FORMAT NAMED_FORMAT}: A parameter that retrieves its value using {@link XslUtil#getIndexField}. + * The value property is set to the field name to search for, and the uuid property is set to the record uuid to search for (required).
  • + *
  • {@link ReplacementType#NONE NONE}: For components that require no replacement to compute their values.
  • + *
+ *

+ */ + public enum ReplacementType { + /** + * For {@link String#format}, where parameters are replaced based on their position (Ex. %s). + * The parameter id stores an integer representing the order of the parameters. + */ + POSITIONAL_FORMAT, + + /** + * For {@link MessageFormat#format}, where parameters are replaced based on position (Ex. {0}). + * The parameter id stores an integer representing the order of the parameters. + */ + NUMERIC_FORMAT, + + /** + * For {@link String#replace}, where parameters are replaced based on their names ({{title}}). + * The parameter id stores the string to replace. + */ + NAMED_FORMAT, + + /** + * For components that require no replacement to compute their values. + */ + NONE + } + + /** + * Constructor for LocalizedEmailParameters. + * + * @param replacementType the type of template variable + */ + public LocalizedEmailComponent(ComponentType componentType, String keyOrRawValue, KeyType keyType, ReplacementType replacementType) { + this.componentType = componentType; + this.keyOrRawValue = keyOrRawValue; + this.keyType = keyType; + this.replacementType = replacementType; + this.parameters = new HashMap<>(); + this.compileWithIndexFields = false; + this.metadataUuid = null; + this.replaceLinks = false; + } + + /** + * Adds parameters to the email parameters list. + * + * @param newParameters the parameters to add + * @throws IllegalArgumentException if a null parameter is passed or if a duplicate parameter id is found + */ + public void addParameters(Locale locale, LocalizedEmailParameter... newParameters) { + // If the map does not have the locale as a key add it + if (!parameters.containsKey(locale)) { + parameters.put(locale, new ArrayList<>()); + } + + for (LocalizedEmailParameter newParameter : newParameters) { + + if (newParameter == null) { + throw new IllegalArgumentException("Null parameter not allowed"); + } + + // If the parameter id is already in the list + if (parameters.get(locale).stream().anyMatch(existingParameter -> newParameter.getId().equals(existingParameter.getId()))) { + throw new IllegalArgumentException("Duplicate parameter id: " + newParameter.getId()); + } + + // If the type of parameters are positional and the new parameters id is not an integer + if ((replacementType.equals(POSITIONAL_FORMAT) || replacementType.equals(NUMERIC_FORMAT)) && !(newParameter.getId() instanceof Integer)) { + throw new IllegalArgumentException("Positional parameter id must be an integer"); + } + + parameters.get(locale).add(newParameter); + } + } + + /** + * @return the map of locales to lists of email parameters + */ + public Map> getParameters() { + return parameters; + } + + /** + * Enables the compilation with index fields and sets the metadata UUID. + * + * @param metadataUuid the metadata UUID + */ + public void enableCompileWithIndexFields(String metadataUuid) { + this.compileWithIndexFields = true; + this.metadataUuid = metadataUuid; + } + + /** + * Sets the replace links flag and format. + * + * @param useHtmlFormat replace links using the HTML format instead of the text format. + */ + public void enableReplaceLinks(Boolean useHtmlFormat) { + this.replaceLinks = true; + this.replaceLinksWithHtmlFormat = useHtmlFormat; + } + + /** + * @return The type of the component. + */ + public ComponentType getComponentType() { + return componentType; + } + + /** + * Parses the message based on the provided key or template and locale. + * + * @param locale the locale + * @return the parsed message + * @throws RuntimeException if an unsupported template variable type is encountered + */ + public String parseMessage(Locale locale) { + + ArrayList parametersForLocale = parameters.get(locale); + + String parsedMessage; + switch (keyType) { + case MESSAGE_OR_JSON_KEY: + try { + parsedMessage = getResourceBundleString(locale); + } catch (MissingResourceException missingResourceException) { + parsedMessage = getTranslationMapString(locale); + } + break; + case MESSAGE_KEY: + try { + parsedMessage = getResourceBundleString(locale); + } catch (MissingResourceException e) { + parsedMessage = keyOrRawValue; + } + break; + case JSON_KEY: + parsedMessage = getTranslationMapString(locale); + break; + case RAW_VALUE: + parsedMessage = keyOrRawValue; + break; + default: + throw new IllegalArgumentException("Unsupported key type: " + keyType); + } + + // Handle replacements + if (replacementType == POSITIONAL_FORMAT || replacementType == NUMERIC_FORMAT) { + + Object[] parsedLocaleEmailParameters = parametersForLocale.stream() + .sorted(Comparator.comparing(parameter -> (Integer) parameter.getId())) + .map(parameter -> parameter.parseValue(locale)) + .toArray(); + + if (replacementType == POSITIONAL_FORMAT) { + parsedMessage = String.format(parsedMessage, parsedLocaleEmailParameters); + } else { + // Replace the link placeholders with index field placeholder so that it isn't interpreted as a MessageFormat arg + if (replaceLinks) { + parsedMessage = replaceLinks(parsedMessage); + } + parsedMessage = MessageFormat.format(parsedMessage, parsedLocaleEmailParameters); + } + + } else if (replacementType == NAMED_FORMAT) { + + for (LocalizedEmailParameter parameter : parametersForLocale) { + parsedMessage = parsedMessage.replace(parameter.getId().toString(), parameter.parseValue(locale)); + } + + } + + // Replace link placeholders + if (replaceLinks) { + parsedMessage = replaceLinks(parsedMessage); + } + + // Replace index field placeholders + if (compileWithIndexFields && metadataUuid != null) { + parsedMessage = MailUtil.compileMessageWithIndexFields(parsedMessage, metadataUuid, locale.getLanguage()); + } + + return parsedMessage; + } + + /** + * Returns a map of locales to parsed messages for the provided array of locales. + * + * @param feedbackLocales the array of locales + * @return the map of locales to parsed messages + */ + public LinkedHashMap getParsedMessagesMap(Locale[] feedbackLocales) { + return getParsedMessagesMap(feedbackLocales, false); + } + + /** + * Returns a map of locales to parsed messages for the provided array of locales. + * If flagged only distinct values are returned. + * + * @param feedbackLocales the array of locales + * @param distinct flag to only return messages with distinct values + * @return the map of locales to parsed messages + */ + public LinkedHashMap getParsedMessagesMap(Locale[] feedbackLocales, Boolean distinct) { + + LinkedHashMap parsedMessages = new LinkedHashMap<>(); + + for (Locale locale : feedbackLocales) { + String parsedMessage = parseMessage(locale); + if (!distinct || !parsedMessages.containsValue(parsedMessage)) { + parsedMessages.put(locale, parsedMessage); + } + } + + return parsedMessages; + } + + private String getResourceBundleString(Locale locale) { + return ResourceBundle.getBundle("org.fao.geonet.api.Messages", locale).getString(keyOrRawValue); + } + + private String getTranslationMapString(Locale locale) { + try { + Map translationMap = new JSONLocCacheLoader(ApplicationContextHolder.get(), locale.getISO3Language()).call(); + return translationMap.getOrDefault(keyOrRawValue, keyOrRawValue); + } catch (Exception exception) { + return keyOrRawValue; + } + } + + private String replaceLinks(String message) { + + SettingManager settingManager = ApplicationContextHolder.get().getBean(SettingManager.class); + + String newPlaceholder; + if (replaceLinksWithHtmlFormat) { + newPlaceholder = "{{index:uuid}}"; + } else { + newPlaceholder = "'{{'index:uuid'}}'"; + } + return message.replace("{{link}}", settingManager.getNodeURL() + "api/records/" + newPlaceholder); + } +} diff --git a/core/src/main/java/org/fao/geonet/util/LocalizedEmailParameter.java b/core/src/main/java/org/fao/geonet/util/LocalizedEmailParameter.java new file mode 100644 index 00000000000..f68c36aec38 --- /dev/null +++ b/core/src/main/java/org/fao/geonet/util/LocalizedEmailParameter.java @@ -0,0 +1,179 @@ +//============================================================================= +//=== Copyright (C) 2001-2024 Food and Agriculture Organization of the +//=== United Nations (FAO-UN), United Nations World Food Programme (WFP) +//=== and United Nations Environment Programme (UNEP) +//=== +//=== This library is free software; you can redistribute it and/or +//=== modify it under the terms of the GNU Lesser General Public +//=== License as published by the Free Software Foundation; either +//=== version 2.1 of the License, or (at your option) any later version. +//=== +//=== This library is distributed in the hope that it will be useful, +//=== but WITHOUT ANY WARRANTY; without even the implied warranty of +//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//=== Lesser General Public License for more details. +//=== +//=== You should have received a copy of the GNU Lesser General Public +//=== License along with this library; if not, write to the Free Software +//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +//=== +//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, +//=== Rome - Italy. email: geonetwork@osgeo.org +//============================================================================== + +package org.fao.geonet.util; + +import org.fao.geonet.ApplicationContextHolder; +import org.fao.geonet.kernel.search.JSONLocCacheLoader; + +import java.util.*; + +/** + * Class representing a parameter used in a localized email. + * It provides functionality to set and get parameter properties, and parse parameter values. + */ +public class LocalizedEmailParameter { + private final Object id; + private final ParameterType parameterType; + private final Object value; // (Based on Parameter type) + private final Object metadataUuid; + + /** + * Enum representing different types of parameters used in a localized email context. + *

+ * This enum defines five types of parameters: + *

    + *
  • {@link ParameterType#MESSAGE_OR_JSON_KEY MESSAGE_OR_JSON_KEY}: A parameter that tries to retrieve its value using {@link ResourceBundle#getString} or JSON localization files if message key was not found. + * The value property is set to the (message or json) key to search for.
  • + *
  • {@link ParameterType#MESSAGE_KEY MESSAGE_KEY}: A parameter that retrieves its value using {@link ResourceBundle#getString}. + * The value property is set to the message key to search for.
  • + *
  • {@link ParameterType#JSON_KEY JSON_KEY}: A parameter that retrieves its value by searching the JSON localization files for the specified key. + * The value property is set to the json key to search for.
  • + *
  • {@link ParameterType#INDEX_FIELD INDEX_FIELD}: A parameter that retrieves its value using {@link XslUtil#getIndexField}. + * The value property is set to the field name to search for, and the uuid property is set to the record uuid to search for (required).
  • + *
  • {@link ParameterType#RAW_VALUE RAW_VALUE}: A parameter with a precomputed value that is simply returned. + * The value property contains the precomputed value.
  • + *
+ *

+ * These types can be used to categorize parameters and define their intended use in the context of localized email parameterization. + */ + public enum ParameterType { + /** + * A parameter that tries to retrieve its value using {@link ResourceBundle#getString} or JSON localization files if message key was not found. + * The value property is set to the (message or json) key to search for. + */ + MESSAGE_OR_JSON_KEY, + + /** + * A parameter that retrieves its value using {@link ResourceBundle#getString} + * The value property is set to the message key to search for. + */ + MESSAGE_KEY, + + /** + * A parameter that retrieves its value by searching the JSON localization files for the specified key. + * The value property is set to the json key to search for. + */ + JSON_KEY, + + /** + * A parameter that retrieves its value using {@link XslUtil#getIndexField} + * The value property is set to the field name to search for. + * The uuid property is set to the record uuid to search for and is required. + */ + INDEX_FIELD, + + /** + * A parameter with a precomputed value that is simply returned. + * The value property contains the precomputed value. + */ + RAW_VALUE + } + + /** + * Constructor with parameters. + * + * @param parameterType the type of the parameter + * @param id the id of the parameter + * @param value the value of the parameter + */ + public LocalizedEmailParameter(ParameterType parameterType, Object id, Object value) { + this.parameterType = parameterType; + this.id = id; + this.value = value; + this.metadataUuid = null; + } + + /** + * Constructor with parameters. + * + * @param parameterType the type of the parameter + * @param id the id of the parameter + * @param value the value of the parameter + * @param metadataUuid The metadata uuid to use for parsing index field values + */ + public LocalizedEmailParameter(ParameterType parameterType, Object id, Object value, String metadataUuid) { + this.parameterType = parameterType; + this.id = id; + this.value = value; + this.metadataUuid = metadataUuid; + } + + /** + * @return the id of the parameter + */ + public Object getId() { + return id; + } + + /** + * Parses the value of the parameter based on its type and the provided locale + * + * @param locale the locale to use to parse the value + * @return the parsed string value + */ + public String parseValue(Locale locale) { + + if (value == null) { + return "null"; + } + + switch (parameterType) { + case MESSAGE_OR_JSON_KEY: + try { + return getResourceBundleString(locale); + } catch (MissingResourceException missingResourceException) { + return getJsonTranslationMapString(locale); + } + case MESSAGE_KEY: + try { + return getResourceBundleString(locale); + } catch (MissingResourceException e) { + return value.toString(); + } + case JSON_KEY: + return getJsonTranslationMapString(locale); + case INDEX_FIELD: + if (metadataUuid == null) throw new IllegalArgumentException("Metadata UUID is required for parameters of type INDEX_FIELD"); + return XslUtil.getIndexField(null, metadataUuid, value, locale); + case RAW_VALUE: + return value.toString(); + default: + throw new IllegalArgumentException("Unsupported parameter type: " + parameterType); + } + } + + private String getResourceBundleString(Locale locale) { + return ResourceBundle.getBundle("org.fao.geonet.api.Messages", locale).getString(value.toString()); + } + + private String getJsonTranslationMapString(Locale locale) { + try { + Map translationMap = new JSONLocCacheLoader(ApplicationContextHolder.get(), locale.getISO3Language()).call(); + return translationMap.getOrDefault(value.toString(), value.toString()); + } catch (Exception exception) { + return value.toString(); + } + } +} + diff --git a/core/src/main/java/org/fao/geonet/util/LogUtil.java b/core/src/main/java/org/fao/geonet/util/LogUtil.java index aa1d0d437f4..93f3c023f7d 100644 --- a/core/src/main/java/org/fao/geonet/util/LogUtil.java +++ b/core/src/main/java/org/fao/geonet/util/LogUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2023 Food and Agriculture Organization of the + * Copyright (C) 2001-2024 Food and Agriculture Organization of the * United Nations (FAO-UN), United Nations World Food Programme (WFP) * and United Nations Environment Programme (UNEP) * @@ -57,7 +57,7 @@ public static String initializeHarvesterLog(String type, String name) { // Filename safe representation of harvester name (using '_' as needed). final String harvesterName = name.replaceAll("\\W+", "_"); final String harvesterType = type.replaceAll("\\W+", "_"); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmm"); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); String logfile = "harvester_" + harvesterType @@ -71,7 +71,7 @@ public static String initializeHarvesterLog(String type, String name) { } ThreadContext.put("harvest", harvesterName); - ThreadContext.putIfNull("logfile", logfile); + ThreadContext.put("logfile", logfile); ThreadContext.put("timeZone", timeZoneSetting); return logfile; diff --git a/core/src/main/java/org/fao/geonet/util/MailUtil.java b/core/src/main/java/org/fao/geonet/util/MailUtil.java index f9fbf53aebd..517a292b99f 100644 --- a/core/src/main/java/org/fao/geonet/util/MailUtil.java +++ b/core/src/main/java/org/fao/geonet/util/MailUtil.java @@ -68,6 +68,7 @@ public static Boolean sendHtmlMail(List toAddress, String subject, email.setSubject(subject); try { + email.setCharset(EmailConstants.UTF_8); email.setHtmlMsg(htmlMessage); } catch (EmailException e1) { Log.error("Error setting email HTML content. Subject:" + subject, e1); @@ -363,9 +364,6 @@ private static void configureBasics(String hostName, Integer smtpPort, email.setAuthenticator(new DefaultAuthenticator(username, password)); } - - email.setDebug(true); - if (tls != null && tls) { email.setStartTLSEnabled(tls); email.setStartTLSRequired(tls); diff --git a/core/src/main/java/org/fao/geonet/util/UserUtil.java b/core/src/main/java/org/fao/geonet/util/UserUtil.java index 0a9e2f8e792..a0c790c08b0 100644 --- a/core/src/main/java/org/fao/geonet/util/UserUtil.java +++ b/core/src/main/java/org/fao/geonet/util/UserUtil.java @@ -22,6 +22,11 @@ */ package org.fao.geonet.util; +import jeeves.server.UserSession; +import org.apache.commons.lang.StringUtils; +import org.fao.geonet.api.exception.NotAllowedException; +import org.fao.geonet.domain.Profile; +import org.fao.geonet.kernel.setting.SettingManager; import org.springframework.security.access.hierarchicalroles.RoleHierarchy; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; @@ -55,4 +60,27 @@ public static boolean hasHierarchyRole(String role, RoleHierarchy roleHierarchy) return false; } + /** + * Checks if the user session's profile is allowed to do the transaction + * + * @param userSession current user session + * @param settingManager setting manager bean + * @param roleHierarchy role hierarchy bean + * @param settingConfigPath setting config path check org.fao.geonet.kernel.setting.Settings + * @param defaultProfile default configuration profile is no configuration found + * @param errorText error text to the exception + */ + public static void checkUserProfileLevel(UserSession userSession, SettingManager settingManager, RoleHierarchy roleHierarchy, String settingConfigPath, Profile defaultProfile, String errorText) { + if (userSession.getProfile() != Profile.Administrator) { + String allowedUserProfileFromConfiguration = + StringUtils.defaultIfBlank(settingManager.getValue(settingConfigPath), defaultProfile.toString()); + + // Is the user profile higher than the configuration profile allowed to do the transaction? + if (!UserUtil.hasHierarchyRole(allowedUserProfileFromConfiguration, roleHierarchy)) { + throw new NotAllowedException("The user has no permissions to " + errorText); + } + } + + } + } diff --git a/core/src/main/java/org/fao/geonet/util/WorkflowUtil.java b/core/src/main/java/org/fao/geonet/util/WorkflowUtil.java index 123b455919b..7e3f372c721 100644 --- a/core/src/main/java/org/fao/geonet/util/WorkflowUtil.java +++ b/core/src/main/java/org/fao/geonet/util/WorkflowUtil.java @@ -1,29 +1,25 @@ -//============================================================================= -//=== -//=== ThreadUtils -//=== -//============================================================================= -//=== Copyright (C) 2001-2007 Food and Agriculture Organization of the -//=== United Nations (FAO-UN), United Nations World Food Programme (WFP) -//=== and United Nations Environment Programme (UNEP) -//=== -//=== This program is free software; you can redistribute it and/or modify -//=== it under the terms of the GNU General Public License as published by -//=== the Free Software Foundation; either version 2 of the License, or (at -//=== your option) any later version. -//=== -//=== This program is distributed in the hope that it will be useful, but -//=== WITHOUT ANY WARRANTY; without even the implied warranty of -//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -//=== General Public License for more details. -//=== -//=== You should have received a copy of the GNU General Public License -//=== along with this program; if not, write to the Free Software -//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA -//=== -//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, -//=== Rome - Italy. email: geonetwork@osgeo.org -//============================================================================= +/* + * Copyright (C) 2001-2023 Food and Agriculture Organization of the + * United Nations (FAO-UN), United Nations World Food Programme (WFP) + * and United Nations Environment Programme (UNEP) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, + * Rome - Italy. email: geonetwork@osgeo.org + */ package org.fao.geonet.util; @@ -38,14 +34,27 @@ public class WorkflowUtil { /** - * Checks if a group has the workflow enabled. + * Avoid creation of new instances of this utility class making its constructor private. + */ + private WorkflowUtil() { + + } + + /** + * Checks if the workflow is enabled and a group has the workflow enabled. * * @param groupName Group name - * @return + * @return {@code true} if the workflow is enabled and it has been enabled for all groups or the group name matches + * the regular expression in {@link Settings#METADATA_WORKFLOW_DRAFT_WHEN_IN_GROUP}. False otherwise. */ public static boolean isGroupWithEnabledWorkflow(String groupName) { SettingManager settingManager = ApplicationContextHolder.get().getBean(SettingManager.class); + boolean isWorkflowEnabled = settingManager.getValueAsBool(Settings.METADATA_WORKFLOW_ENABLE); + if (!isWorkflowEnabled) { + return false; + } + String groupMatchingRegex = settingManager.getValue(Settings.METADATA_WORKFLOW_DRAFT_WHEN_IN_GROUP); if (!StringUtils.isEmpty(groupMatchingRegex)) { @@ -56,7 +65,4 @@ public static boolean isGroupWithEnabledWorkflow(String groupName) { return false; } } - - - } diff --git a/core/src/main/java/org/fao/geonet/util/XslUtil.java b/core/src/main/java/org/fao/geonet/util/XslUtil.java index 8c633399cb1..452ab855e75 100644 --- a/core/src/main/java/org/fao/geonet/util/XslUtil.java +++ b/core/src/main/java/org/fao/geonet/util/XslUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2020 Food and Agriculture Organization of the + * Copyright (C) 2001-2023 Food and Agriculture Organization of the * United Nations (FAO-UN), United Nations World Food Programme (WFP) * and United Nations Environment Programme (UNEP) * @@ -23,6 +23,7 @@ package org.fao.geonet.util; +import co.elastic.clients.elasticsearch.core.search.Hit; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -39,28 +40,19 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.lang.NotImplementedException; import org.apache.commons.lang.StringUtils; +import org.apache.commons.text.StringEscapeUtils; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.lucene.search.join.ScoreMode; -import org.elasticsearch.action.search.MultiSearchRequest; -import org.elasticsearch.action.search.MultiSearchResponse; -import org.elasticsearch.action.search.SearchRequest; -import org.elasticsearch.client.RequestOptions; -import org.elasticsearch.index.query.BoolQueryBuilder; -import org.elasticsearch.index.query.QueryBuilder; -import org.elasticsearch.index.query.QueryBuilders; -import org.elasticsearch.search.SearchHits; -import org.elasticsearch.search.builder.SearchSourceBuilder; import org.fao.geonet.ApplicationContextHolder; import org.fao.geonet.SystemInfo; +import org.fao.geonet.analytics.WebAnalyticsConfiguration; import org.fao.geonet.api.records.attachments.FilesystemStore; import org.fao.geonet.api.records.attachments.FilesystemStoreResourceContainer; import org.fao.geonet.api.records.attachments.Store; import org.fao.geonet.constants.Geonet; import org.fao.geonet.domain.*; -import org.fao.geonet.index.es.EsRestClient; import org.fao.geonet.kernel.*; import org.fao.geonet.kernel.datamanager.base.BaseMetadataUtils; import org.fao.geonet.kernel.search.CodeListTranslator; @@ -84,6 +76,7 @@ import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.referencing.CRS; import org.geotools.referencing.crs.DefaultGeographicCRS; +import org.geotools.referencing.crs.DefaultProjectedCRS; import org.geotools.xsd.Parser; import org.jdom.Document; import org.jdom.Element; @@ -95,16 +88,18 @@ import org.locationtech.jts.io.WKTReader; import org.locationtech.jts.operation.valid.IsValidOp; import org.locationtech.jts.precision.GeometryPrecisionReducer; -import org.opengis.referencing.crs.CoordinateReferenceSystem; -import org.opengis.referencing.operation.MathTransform; +import org.geotools.api.referencing.crs.CoordinateReferenceSystem; +import org.geotools.api.referencing.operation.MathTransform; import org.owasp.esapi.errors.EncodingException; import org.owasp.esapi.reference.DefaultEncoder; import org.springframework.beans.factory.BeanCreationException; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.http.HttpStatus; +import org.springframework.security.authentication.AnonymousAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; import org.w3c.dom.Node; import org.xml.sax.SAXException; @@ -186,6 +181,22 @@ public static String gmlToGeoJson(String gml, return "Warning: GML geometry is null."; } + Object userData = geom.getUserData(); + if (userData instanceof DefaultProjectedCRS) { + geom = JTS.transform( + geom, + CRS.findMathTransform((DefaultProjectedCRS) userData, + CRS.decode("EPSG:4326", true), true) + ); + } + else if (userData instanceof DefaultGeographicCRS) { + geom = JTS.transform( + geom, + CRS.findMathTransform((DefaultGeographicCRS) userData, + CRS.decode("EPSG:4326", true), true) + ); + } + if (!geom.isValid()) { IsValidOp isValidOp = new IsValidOp(geom); return String.format( @@ -438,11 +449,35 @@ public static String getNodeName(String key, String lang, boolean withOrganizati + (withOrganization ? " - " + settingsMan.getValue(SYSTEM_SITE_ORGANIZATION) : ""); } + + /** + * Return the ID of the current node (catalog or subportal). + * If the main one, then srv. + * If a sub portal, use the sub portal key. + * + * @return + */ + public static String getNodeId() { + return ApplicationContextHolder.get().getBean(org.fao.geonet.NodeInfo.class).getId(); + } + + public static String getNodeLogo(String key) { Optional source = getSource(key); return source.isPresent() ? source.get().getLogo() : ""; } + public static String getDiscoveryServiceUuid(String key) { + Optional source = getSource(key); + if (source.isPresent() && source.get().getType() == SourceType.subportal) { + return source.get().getServiceRecord(); + } else { + SettingManager settingsMan = ApplicationContextHolder.get().getBean(SettingManager.class); + String uuid = settingsMan.getValue(SYSTEM_CSW_CAPABILITY_RECORD_UUID); + return "-1".equals(uuid) ? "" : uuid; + } + } + private static Optional getSource(String idOrUuid) { SettingManager settingsMan = ApplicationContextHolder.get().getBean(SettingManager.class); if (StringUtils.isEmpty(idOrUuid)) { @@ -509,7 +544,19 @@ public static Node downloadJsonAsXML(String url) { return null; } - /** + /** + * Check if user is authenticated. + */ + public static boolean isAuthenticated() throws Exception { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication == null || AnonymousAuthenticationToken.class.isAssignableFrom(authentication.getClass())) { + return false; + } + return authentication.isAuthenticated(); + } + + + /** * Check if security provider require login form */ public static boolean isDisableLoginForm() { @@ -585,13 +632,19 @@ public static MetadataResourceContainer getResourceContainerDescription(String m Store store = BeanFactoryAnnotationUtils.qualifiedBeanOfType(ApplicationContextHolder.get().getBeanFactory(), Store.class, "filesystemStore"); if (store != null) { - if (store.getResourceManagementExternalProperties() != null && store.getResourceManagementExternalProperties().isFolderEnabled()) { - ServiceContext context = ServiceContext.get(); - return store.getResourceContainerDescription(ServiceContext.get(), metadataUuid, approved); - } else { - // Return an empty object which should not be used because the folder is not enabled. - return new FilesystemStoreResourceContainer(metadataUuid, -1, null, null, null, approved); + try { + if (store.getResourceManagementExternalProperties() != null && store.getResourceManagementExternalProperties().isFolderEnabled()) { + ServiceContext context = ServiceContext.get(); + return store.getResourceContainerDescription(ServiceContext.get(), metadataUuid, approved); + } else { + // Return an empty object which should not be used because the folder is not enabled. + return new FilesystemStoreResourceContainer(metadataUuid, -1, null, null, null, approved); + } + } catch (RuntimeException e) { + Log.error(Geonet.RESOURCES, "Could not locate resource in getResourceContainerDescription due to runtime exception", e); + return null; } + } Log.error(Geonet.RESOURCES, "Could not locate a Store bean in getResourceContainerDescription"); return null; @@ -797,12 +850,10 @@ public static String getIndexField(Object appName, Object uuid, Object field, Ob try { Set fields = new HashSet<>(); fields.add(fieldname); - // TODO: Multilingual fields - final Map values = searchManager.getFieldsValues(id, fields); + final Map values = searchManager.getFieldsValues(id, fields, language); return values.get(fieldname); } catch (Exception e) { - e.printStackTrace(); - Log.error(Geonet.GEONETWORK, "Failed to get index field '" + fieldname + "' value on '" + id + "', caused by " + e.getMessage()); + Log.warning(Geonet.GEONETWORK, "Failed to get index field '" + fieldname + "' value on '" + id + "', caused by " + e.getMessage()); } return ""; } @@ -1189,12 +1240,13 @@ public static String buildDataUrl(String url, Integer size) { String extension = Files.getFileExtension(url).toLowerCase(); if (extension.matches(supportedExtension)) { + InputStream in = null; try { SettingManager settingManager = ApplicationContextHolder.get().getBean(SettingManager.class); Matcher m = Pattern.compile(settingManager.getNodeURL() + "api/records/(.*)/attachments/(.*)$").matcher(url); BufferedImage image; if (m.find()) { - Store store = ApplicationContextHolder.get().getBean(FilesystemStore.class); + Store store = ApplicationContextHolder.get().getBean("filesystemStore", Store.class); try (Store.ResourceHolder file = store.getResourceInternal( m.group(1), MetadataResourceVisibility.PUBLIC, @@ -1202,7 +1254,12 @@ public static String buildDataUrl(String url, Integer size) { image = ImageIO.read(file.getPath().toFile()); } } else { - image = ImageIO.read(new URL(url)); + URL imageUrl = new URL(url); + URLConnection con = imageUrl.openConnection(); + con.setConnectTimeout(1000); + con.setReadTimeout(10000); + in = con.getInputStream(); + image = ImageIO.read(in); } if (image != null) { @@ -1225,6 +1282,8 @@ public static String buildDataUrl(String url, Integer size) { Log.info(Geonet.GEONETWORK, String.format( "Image '%s' is not accessible or can't be converted to Data URL. Error is: %s", url, e.getMessage())); + } finally { + IOUtils.closeQuietly(in); } } else { Log.info(Geonet.GEONETWORK, String.format( @@ -1382,6 +1441,28 @@ public static String getThesaurusIdByTitle(String title) { return thesaurus == null ? "" : "geonetwork.thesaurus." + thesaurus.getKey(); } + /** + * Retrieve the thesaurus title using the thesaurus key. + * + * @param id the thesaurus key + * @return the thesaurus title or empty string if the thesaurus doesn't exist. + */ + public static String getThesaurusTitleByKey(String id) { + ApplicationContext applicationContext = ApplicationContextHolder.get(); + ThesaurusManager thesaurusManager = applicationContext.getBean(ThesaurusManager.class); + Thesaurus thesaurus = thesaurusManager.getThesaurusByName(id); + return thesaurus == null ? "" : thesaurus.getTitle(); + } + + + public static String getThesaurusUriByKey(String id) { + ApplicationContext applicationContext = ApplicationContextHolder.get(); + ThesaurusManager thesaurusManager = applicationContext.getBean(ThesaurusManager.class); + Thesaurus thesaurus = thesaurusManager.getThesaurusByName(id); + return thesaurus == null ? "" : thesaurus.getDefaultNamespace(); + } + + /** * Utility method to retrieve the name (label) for an iso language using it's code for a specific language. @@ -1486,152 +1567,27 @@ public static String getKeywordUri(String keyword, String thesaurusId, String la return ""; } - /** - * Associated resource like - *
    - *
  • parent
  • - *
  • source
  • - *
  • dataset (for service record)
  • - *
  • siblings
  • - *
  • feature catalogue
  • - *
- * are stored in current records - * BUT - * some other relations are stored in the other side of the relation record ie. - *
    - *
  • service operatingOn current = +recordOperateOn:currentUuid
  • - *
  • siblings of current = +recordLink.type:siblings +recordLink.to:currentUuid
  • - *
  • children of current = +parentUuid:currentUuid
  • - *
  • brothersAndSisters = +parentUuid:currentParentUuid
  • - *
- * Instead of relying on related API, it can make sense to index all relations - * (including bidirectional links) at indexing time to speed up rendering of - * associated resources which is slow task on search results. - * - * MetadataUtils#getRelated has the logic to search for all associated resources - * and also takes into account privileges in case of target record is not visible - * to current user. - * - * BTW in some cases, all records are public (or it is not an issue to only display - * a title of a private record) and a more direct approach can be used. - * - * @param uuid - * @return - */ - public static Element getTargetAssociatedResources(String uuid, String parentUuid) { - EsRestClient client = ApplicationContextHolder.get().getBean(EsRestClient.class); - EsSearchManager searchManager = ApplicationContextHolder.get().getBean(EsSearchManager.class); - Element recordLinks = new Element("recordLinks"); - - try { - MultiSearchRequest request = new MultiSearchRequest(); - - - SearchRequest serviceRequest = new SearchRequest(searchManager.getDefaultIndex()); - SearchSourceBuilder serviceSearchSourceBuilder = new SearchSourceBuilder(); - serviceSearchSourceBuilder.fetchSource( - new String[]{"resourceTitleObject.default"}, - null - ); - serviceSearchSourceBuilder.query(QueryBuilders.matchQuery( - "recordOperateOn", uuid)); - serviceRequest.source(serviceSearchSourceBuilder); - request.add(serviceRequest); - - - SearchRequest childrenRequest = new SearchRequest(searchManager.getDefaultIndex()); - SearchSourceBuilder childrenSearchSourceBuilder = new SearchSourceBuilder(); - childrenSearchSourceBuilder.fetchSource( - new String[]{"resourceTitleObject.default"}, - null - ); - childrenSearchSourceBuilder.query(QueryBuilders.matchQuery( - "parentUuid", uuid)); - childrenRequest.source(childrenSearchSourceBuilder); - request.add(childrenRequest); - - - SearchRequest siblingsRequest = new SearchRequest(searchManager.getDefaultIndex()); - SearchSourceBuilder siblingsSearchSourceBuilder = new SearchSourceBuilder(); - siblingsSearchSourceBuilder.fetchSource( - new String[]{"resourceTitleObject.default"}, - null - ); - BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); - List must = boolQuery.must(); - must.add(QueryBuilders.matchQuery("recordLink.type", "siblings")); - must.add(QueryBuilders.matchQuery("recordLink.to", uuid)); - siblingsSearchSourceBuilder.query( - QueryBuilders.nestedQuery( - Geonet.IndexFieldNames.RECORDLINK, - boolQuery, - ScoreMode.Avg)); - siblingsRequest.source(siblingsSearchSourceBuilder); - request.add(siblingsRequest); - - - - boolean hasParent = StringUtils.isNotEmpty(parentUuid); - if (hasParent) { - SearchRequest brothersAndSistersRequest = new SearchRequest(searchManager.getDefaultIndex()); - SearchSourceBuilder brothersAndSistersSearchSourceBuilder = new SearchSourceBuilder(); - brothersAndSistersSearchSourceBuilder.fetchSource( - new String[]{"resourceTitleObject.default"}, - null - ); - brothersAndSistersSearchSourceBuilder.query(QueryBuilders.matchQuery( - "parentUuid", parentUuid)); - brothersAndSistersRequest.source(brothersAndSistersSearchSourceBuilder); - request.add(brothersAndSistersRequest); - } - - - MultiSearchResponse response = client.getClient().msearch(request, RequestOptions.DEFAULT); - recordLinks.addContent(buildRecordLink(response.getResponses()[0].getResponse().getHits(), "services")); - recordLinks.addContent(buildRecordLink(response.getResponses()[1].getResponse().getHits(), "children")); - recordLinks.addContent(buildRecordLink(response.getResponses()[2].getResponse().getHits(), "siblings")); - - if (hasParent) { - recordLinks.addContent(buildRecordLink(response.getResponses()[3].getResponse().getHits(), "brothersAndSisters")); - } - } catch (Exception e) { - Log.error(Geonet.GEONETWORK, - "Get related document '" + uuid + "' error: " + e.getMessage(), e); - } - return recordLinks; - } - - public static Node getTargetAssociatedResourcesAsNode(String uuid, String parentUuid) { - DOMOutputter outputter = new DOMOutputter(); - try { - return outputter.output( - new Document( - getTargetAssociatedResources(uuid, parentUuid))); - } catch (Exception e) { - Log.error(Geonet.GEONETWORK, - "Get related document '" + uuid + "' error: " + e.getMessage(), e); - } - return null; - } - - private static List buildRecordLink(SearchHits hits, String type) { + private static List buildRecordLink(List hits, String type) { ObjectMapper mapper = new ObjectMapper(); SettingManager settingManager = ApplicationContextHolder.get().getBean(SettingManager.class); String recordUrlPrefix = settingManager.getNodeURL() + "api/records/"; ArrayList listOfLinks = new ArrayList<>(); + + ObjectMapper objectMapper = new ObjectMapper(); + hits.forEach(record -> { Element recordLink = new Element("recordLink"); recordLink.setAttribute("type", "object"); ObjectNode recordLinkProperties = mapper.createObjectNode(); - recordLinkProperties.put("to", record.getId()); + recordLinkProperties.put("to", record.id()); recordLinkProperties.put("origin", "catalog"); recordLinkProperties.put("created", "bySearch"); - Map titleObject = (Map) record.getSourceAsMap().get("resourceTitleObject"); + Map titleObject = (Map) objectMapper.convertValue(record.source(), Map.class).get("resourceTitleObject"); if (titleObject != null) { recordLinkProperties.put("title", titleObject.get("default")); } - recordLinkProperties.put("url", recordUrlPrefix + record.getId()); + recordLinkProperties.put("url", recordUrlPrefix + record.id()); recordLinkProperties.put("type", type); try { @@ -1643,4 +1599,22 @@ private static List buildRecordLink(SearchHits hits, String type) { }); return listOfLinks; } + + public static String escapeForJson(String value) { + return StringEscapeUtils.escapeJson(value); + } + + public static String getWebAnalyticsService() { + ApplicationContext applicationContext = ApplicationContextHolder.get(); + WebAnalyticsConfiguration webAnalyticsConfiguration = applicationContext.getBean(WebAnalyticsConfiguration.class); + + return webAnalyticsConfiguration.getService(); + } + + public static String getWebAnalyticsJavascriptCode() { + ApplicationContext applicationContext = ApplicationContextHolder.get(); + WebAnalyticsConfiguration webAnalyticsConfiguration = applicationContext.getBean(WebAnalyticsConfiguration.class); + + return webAnalyticsConfiguration.getJavascriptCode(); + } } diff --git a/core/src/main/java/org/fao/geonet/web/GeoNetworkPortalFilter.java b/core/src/main/java/org/fao/geonet/web/GeoNetworkPortalFilter.java index 240dc876e5b..9330b121959 100644 --- a/core/src/main/java/org/fao/geonet/web/GeoNetworkPortalFilter.java +++ b/core/src/main/java/org/fao/geonet/web/GeoNetworkPortalFilter.java @@ -23,11 +23,12 @@ package org.fao.geonet.web; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.fao.geonet.ApplicationContextHolder; import org.fao.geonet.NodeInfo; import org.fao.geonet.domain.SourceType; import org.fao.geonet.repository.SourceRepository; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; @@ -36,25 +37,34 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; /** * Filter to check that the portal requested is a valid one, otherwise redirects to the default portal: - * - * - Default srv portal. - * - Valid portal defined in the sources table + *

+ * - Default srv portal. + * - Valid portal defined in the sources table */ public class GeoNetworkPortalFilter implements javax.servlet.Filter { - private static final String EXCLUDED_PATHS = "excludedPaths"; + private static final String EXCLUDED_URL_PATHS = "excludedPaths"; private static final String URL_PATH_SEPARATOR = "/"; - private List excludedPaths = new ArrayList<>(); + /** + * Ignored application paths. + **/ + private List excludedPathsMatchers = new ArrayList<>(); + @Override public void init(FilterConfig config) { - String excludedPathsValue = config.getInitParameter(EXCLUDED_PATHS); + String excludedPathsValue = config.getInitParameter(EXCLUDED_URL_PATHS); if (StringUtils.isNotEmpty(excludedPathsValue)) { - excludedPaths = Arrays.asList(excludedPathsValue.split(",")); + excludedPathsMatchers = Arrays.stream(excludedPathsValue.split(",")) + .map(StringUtils::trimToEmpty) + .filter(StringUtils::isNotEmpty) + .map(AntPathRequestMatcher::new) + .collect(Collectors.toList()); } } @@ -62,7 +72,7 @@ public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filte HttpServletResponse httpResp = (HttpServletResponse) resp; HttpServletRequest httpReq = (HttpServletRequest) req; - if (!ignoreUrl(httpReq.getPathInfo())) { + if (!ignoreUrl(httpReq)) { String portal = ""; // Check the url format: /portal/lang/service/..., /portal/api/service/... @@ -75,14 +85,15 @@ public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filte if (!NodeInfo.DEFAULT_NODE.equals(portal)) { SourceRepository sourceRepository = ApplicationContextHolder.get().getBean(SourceRepository.class); // Check the portal exists and it's of type subportal, otherwise redirect to the default portal - boolean redirectToDefaultPortal = !sourceRepository.existsByNameAndType(portal, SourceType.subportal); + boolean redirectToDefaultPortal = !sourceRepository.existsByUuidAndType(portal, SourceType.subportal); if (redirectToDefaultPortal) { String newPath = httpReq.getPathInfo().replace(URL_PATH_SEPARATOR + portal + URL_PATH_SEPARATOR, - URL_PATH_SEPARATOR + NodeInfo.DEFAULT_NODE +URL_PATH_SEPARATOR); - if ( httpReq.getQueryString() != null) { + URL_PATH_SEPARATOR + NodeInfo.DEFAULT_NODE + URL_PATH_SEPARATOR); + if (httpReq.getQueryString() != null) { newPath = newPath + "?" + httpReq.getQueryString(); } + httpResp.sendRedirect(httpReq.getContextPath() + newPath); return; } @@ -97,11 +108,12 @@ public void destroy() { // No cleanup required } - private boolean ignoreUrl(String urlPath) { - if (StringUtils.isEmpty(urlPath)) { + private boolean ignoreUrl(HttpServletRequest request) { + if (StringUtils.isEmpty(request.getPathInfo())) { return true; } else { - return excludedPaths.stream().anyMatch(urlPath::matches); + return excludedPathsMatchers.stream() + .anyMatch(matcher -> matcher.matches(request)); } } } diff --git a/core/src/main/java/org/fao/geonet/web/GeoNetworkStrictHttpFirewall.java b/core/src/main/java/org/fao/geonet/web/GeoNetworkStrictHttpFirewall.java new file mode 100644 index 00000000000..cdf34c45f18 --- /dev/null +++ b/core/src/main/java/org/fao/geonet/web/GeoNetworkStrictHttpFirewall.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2001-2024 Food and Agriculture Organization of the + * United Nations (FAO-UN), United Nations World Food Programme (WFP) + * and United Nations Environment Programme (UNEP) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, + * Rome - Italy. email: geonetwork@osgeo.org + */ + +package org.fao.geonet.web; + +import org.springframework.security.web.firewall.StrictHttpFirewall; + +import java.util.regex.Pattern; + +import static java.nio.charset.StandardCharsets.ISO_8859_1; +import static java.nio.charset.StandardCharsets.UTF_8; + +/** + * Spring Security HttpFirewall that allows parsing UTF8 header values. + */ +public class GeoNetworkStrictHttpFirewall extends StrictHttpFirewall { + private static final Pattern ALLOWED_HEADER_VALUE_PATTERN = Pattern.compile("[\\p{IsAssigned}&&[^\\p{IsControl}]]*"); + + public GeoNetworkStrictHttpFirewall() { + super(); + + this.setAllowedHeaderValues(header -> { + String parsed = new String(header.getBytes(ISO_8859_1), UTF_8); + return ALLOWED_HEADER_VALUE_PATTERN.matcher(parsed).matches(); + }); + } +} diff --git a/core/src/main/java/org/geonetwork/http/SessionTimeoutCookieFilter.java b/core/src/main/java/org/geonetwork/http/SessionTimeoutCookieFilter.java index 21a2227667f..09cba97a0a2 100644 --- a/core/src/main/java/org/geonetwork/http/SessionTimeoutCookieFilter.java +++ b/core/src/main/java/org/geonetwork/http/SessionTimeoutCookieFilter.java @@ -24,8 +24,6 @@ package org.geonetwork.http; import java.io.IOException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; @@ -40,7 +38,6 @@ import org.apache.commons.lang.StringUtils; import jeeves.server.UserSession; -import jeeves.server.dispatchers.ServiceManager; import jeeves.server.sources.http.JeevesServlet; /** @@ -64,18 +61,20 @@ public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filte if (session != null) { long currTime = System.currentTimeMillis(); + String cookiePath = StringUtils.isBlank(httpReq.getContextPath()) ? "/" : httpReq.getContextPath(); + Cookie cookie = new Cookie("serverTime", "" + currTime); - cookie.setPath(httpReq.getContextPath()); + cookie.setPath(cookiePath); cookie.setSecure(req.getServletContext().getSessionCookieConfig().isSecure()); httpResp.addCookie(cookie); UserSession userSession = null; - if (session != null) { - Object tmp = session.getAttribute(JeevesServlet.USER_SESSION_ATTRIBUTE_KEY); - if (tmp instanceof UserSession) { - userSession = (UserSession) tmp; - } + + Object tmp = session.getAttribute(JeevesServlet.USER_SESSION_ATTRIBUTE_KEY); + if (tmp instanceof UserSession) { + userSession = (UserSession) tmp; } + // If user is authenticated, then set expiration time if (userSession != null && StringUtils.isNotEmpty(userSession.getName())) { long expiryTime = currTime + session.getMaxInactiveInterval() * 1000; @@ -83,7 +82,7 @@ public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filte } else { cookie = new Cookie("sessionExpiry", "" + currTime); } - cookie.setPath(httpReq.getContextPath()); + cookie.setPath(cookiePath); cookie.setSecure(req.getServletContext().getSessionCookieConfig().isSecure()); httpResp.addCookie(cookie); } diff --git a/core/src/main/java/org/geonetwork/map/wms/SLDUtil.java b/core/src/main/java/org/geonetwork/map/wms/SLDUtil.java index 35bd9752459..ce162c35b57 100644 --- a/core/src/main/java/org/geonetwork/map/wms/SLDUtil.java +++ b/core/src/main/java/org/geonetwork/map/wms/SLDUtil.java @@ -19,8 +19,8 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import org.opengis.filter.Filter; -import org.opengis.filter.FilterFactory2; +import org.geotools.api.filter.Filter; +import org.geotools.api.filter.FilterFactory; import javax.mail.internet.ContentType; import javax.mail.internet.ParseException; @@ -168,7 +168,7 @@ public static String encodeFilter(Filter filter) throws IOException { */ public static Filter generateCustomFilter(JSONObject userFilters) throws JSONException { - FilterFactory2 ff2 = CommonFactoryFinder.getFilterFactory2(); + FilterFactory ff2 = CommonFactoryFinder.getFilterFactory(); JSONArray filters = userFilters.getJSONArray("filters"); List res = new LinkedList(); @@ -185,7 +185,7 @@ public static Filter generateCustomFilter(JSONObject userFilters) throws JSONExc private static Filter generateFilter(JSONObject jsonObject) throws JSONException { - FilterFactory2 ff2 = CommonFactoryFinder.getFilterFactory2(); + FilterFactory ff2 = CommonFactoryFinder.getFilterFactory(); String fieldName = jsonObject.getString("field_name"); @@ -203,7 +203,7 @@ private static Filter generateFilter(JSONObject jsonObject) throws JSONException private static Filter generateFilter2(String fieldName, JSONObject jsonObject) throws JSONException { - FilterFactory2 ff2 = CommonFactoryFinder.getFilterFactory2(); + FilterFactory ff2 = CommonFactoryFinder.getFilterFactory(); String filterType = jsonObject.getString("filter_type"); @@ -240,6 +240,12 @@ private static Filter generateFilter2(String fieldName, JSONObject jsonObject) t } else if(filterType.equals("PropertyIsBetween")) { if (parameters.size() != 2) throw new JSONException("Invalid parameter count"); return ff2.between(ff2.property(fieldName), ff2.literal(parameters.get(0)), ff2.literal(parameters.get(1))); + } else if(filterType.equals("PropertyIsBetweenExclusive")) { + if (parameters.size() != 2) throw new JSONException("Invalid parameter count"); + return ff2.and( + ff2.greater(ff2.property(fieldName), ff2.literal(parameters.get(0))), + ff2.less(ff2.property(fieldName), ff2.literal(parameters.get(1))) + ); } else { // Currently, no implementation of topological or distance operators throw new JSONException("No implementation for filter type : " + filterType); diff --git a/core/src/main/resources/config-spring-geonetwork.xml b/core/src/main/resources/config-spring-geonetwork.xml index f03fa384aac..052e4d6ae6d 100644 --- a/core/src/main/resources/config-spring-geonetwork.xml +++ b/core/src/main/resources/config-spring-geonetwork.xml @@ -33,9 +33,10 @@ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd "> - + @@ -237,6 +238,7 @@ + - + diff --git a/core/src/main/resources/config-store/config-jcloud-overrides.properties b/core/src/main/resources/config-store/config-jcloud-overrides.properties deleted file mode 100644 index 5b7d183edf9..00000000000 --- a/core/src/main/resources/config-store/config-jcloud-overrides.properties +++ /dev/null @@ -1,16 +0,0 @@ -jcloud.provider=${JCLOUD_PROVIDER} -jcloud.folder.delimiter=${JCLOUD_FOLDER_DELIMITER:#{'/'}} -jcloud.container.name=${JCLOUD_CONTAINER_NAME:geonetwork} -jcloud.base.folder=${JCLOUD_BASE_FOLDER:#{null}} - -jcloud.storage.account.name=${JCLOUD_STORAGE_ACCOUNT_NAME} -jcloud.storage.account.key=${JCLOUD_STORAGE_ACCOUNT_KEY} -jcloud.endpoint=${JCLOUD_ENDPOINT:#{null}} - -jcloud.external.resource.management.url=${JCLOUD_EXTERNAL_RESOURCE_MANAGEMENT_URL:#{null}} -jcloud.external.resource.management.window.parameters=${JCLOUD_EXTERNAL_RESOURCE_MANAGEMENT_WINDOW_PARAMETERS:#{null}} -jcloud.external.resource.management.modal.enabled=${JCLOUD_EXTERNAL_RESOURCE_MANAGEMENT_MODAL_ENABLED:#{null}} -jcloud.external.resource.management.folder.enabled=${JCLOUD_EXTERNAL_RESOURCE_MANAGEMENT_FOLDER_ENABLED:#{null}} -jcloud.external.resource.management.folder.root=${JCLOUD_EXTERNAL_RESOURCE_MANAGEMENT_FOLDER_ROOT:#{null}} - -jcloud.versioning.enabled=${JCLOUD_VERSIONING_ENABLED:#{null}} diff --git a/core/src/test/java/org/fao/geonet/AbstractCoreIntegrationTest.java b/core/src/test/java/org/fao/geonet/AbstractCoreIntegrationTest.java index c32bc8a1825..5bd12fcb26f 100644 --- a/core/src/test/java/org/fao/geonet/AbstractCoreIntegrationTest.java +++ b/core/src/test/java/org/fao/geonet/AbstractCoreIntegrationTest.java @@ -32,7 +32,9 @@ import jeeves.server.dispatchers.ServiceManager; import jeeves.server.sources.ServiceRequest; import org.fao.geonet.constants.Geonet; +import org.fao.geonet.domain.AbstractMetadata; import org.fao.geonet.domain.ISODate; +import org.fao.geonet.domain.Metadata; import org.fao.geonet.domain.MetadataType; import org.fao.geonet.domain.Pair; import org.fao.geonet.domain.Profile; @@ -41,13 +43,19 @@ import org.fao.geonet.domain.User; import org.fao.geonet.kernel.DataManager; import org.fao.geonet.kernel.GeonetworkDataDirectory; +import org.fao.geonet.kernel.SchemaManager; +import org.fao.geonet.kernel.UpdateDatestamp; +import org.fao.geonet.kernel.datamanager.IMetadataManager; import org.fao.geonet.kernel.mef.Importer; import org.fao.geonet.kernel.mef.MEFLib; +import org.fao.geonet.kernel.search.IndexingMode; import org.fao.geonet.repository.AbstractSpringDataTest; import org.fao.geonet.repository.GroupRepository; import org.fao.geonet.repository.SourceRepository; import org.fao.geonet.repository.UserGroupRepository; import org.fao.geonet.repository.UserRepository; +import org.fao.geonet.schema.iso19115_3_2018.ISO19115_3_2018SchemaPlugin; +import org.fao.geonet.schema.iso19139.ISO19139SchemaPlugin; import org.fao.geonet.utils.Log; import org.fao.geonet.utils.Xml; import org.jdom.Element; @@ -79,6 +87,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.UUID; import java.util.concurrent.TimeUnit; import static java.lang.Math.round; @@ -109,6 +118,12 @@ public abstract class AbstractCoreIntegrationTest extends AbstractSpringDataTest protected UserGroupRepository _userGroupRepo; @Autowired protected GroupRepository _groupRepo; + @Autowired + private SchemaManager schemaManager; + @Autowired + private IMetadataManager metadataManager; + @Autowired + private SourceRepository sourceRepository; protected static Element createServiceConfigParam(String name, String value) { return new Element("param") @@ -293,10 +308,21 @@ public MockHttpSession loginAsAnonymous() { return session; } + private Element getSample(String resource) throws IOException, JDOMException { + final URL resourceUrl = AbstractCoreIntegrationTest.class.getResource(resource); + return Xml.loadStream(resourceUrl.openStream()); + } public Element getSampleMetadataXml() throws IOException, JDOMException { - final URL resource = AbstractCoreIntegrationTest.class.getResource("kernel/valid-metadata.iso19139.xml"); - return Xml.loadStream(resource.openStream()); + return getSample("kernel/valid-metadata.iso19139.xml"); + } + + public Element getSampleISO19139MetadataXml() throws IOException, JDOMException { + return getSample("kernel/metadata.iso19139.xml"); + } + + public Element getSampleISO19115MetadataXml() throws IOException, JDOMException { + return getSample("kernel/metadata.iso19115-3.xml"); } /** @@ -359,4 +385,40 @@ protected void addTestSpecificData(GeonetworkDataDirectory geonetworkDataDirecto public boolean resetLuceneIndex() { return true; } + + protected AbstractMetadata injectMetadataInDbDoNotRefreshHeader(Element sampleMetadataXml, ServiceContext context) throws Exception { + return injectMetadataInDb(sampleMetadataXml, context, false); + } + + protected AbstractMetadata injectMetadataInDb(Element sampleMetadataXml, ServiceContext context, boolean resfreshHeader) throws Exception { + String uuid = UUID.randomUUID().toString(); + String schema = schemaManager.autodetectSchema(sampleMetadataXml); + Xml.selectElement(sampleMetadataXml, + "iso19139".equals(schema) + ? "gmd:fileIdentifier/gco:CharacterString" + : "mdb:metadataIdentifier/*/mcc:code/*", + "iso19139".equals(schema) + ? ISO19139SchemaPlugin.allNamespaces.asList() + : ISO19115_3_2018SchemaPlugin.allNamespaces.asList()) + .setText(uuid); + + String source = sourceRepository.findAll().get(0).getUuid(); + final Metadata metadata = new Metadata(); + metadata + .setDataAndFixCR(sampleMetadataXml) + .setUuid(uuid); + metadata.getDataInfo() + .setRoot(sampleMetadataXml.getQualifiedName()) + .setSchemaId(schema) + .setType(MetadataType.METADATA) + .setPopularity(1000); + metadata.getSourceInfo() + .setOwner(1) + .setSourceId(source); + metadata.getHarvestInfo() + .setHarvested(false); + + return metadataManager.insertMetadata(context, metadata, sampleMetadataXml, IndexingMode.none, false, UpdateDatestamp.NO, + false, resfreshHeader); + } } diff --git a/core/src/test/java/org/fao/geonet/GeonetTestFixture.java b/core/src/test/java/org/fao/geonet/GeonetTestFixture.java index d8fc9aa47d0..6669ba48845 100644 --- a/core/src/test/java/org/fao/geonet/GeonetTestFixture.java +++ b/core/src/test/java/org/fao/geonet/GeonetTestFixture.java @@ -40,7 +40,6 @@ import org.fao.geonet.utils.IO; import org.fao.geonet.utils.TransformerFactoryFactory; import org.fao.geonet.utils.Xml; -import org.geotools.data.DataStore; import org.jdom.Element; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.annotation.Autowired; @@ -68,14 +67,21 @@ public class GeonetTestFixture { private volatile static FileSystemPool.CreatedFs templateFs; private volatile static SchemaManager templateSchemaManager; @Autowired - private EsSearchManager templateSearchManager; - @Autowired - protected DataStore dataStore; + private EsSearchManager esSearchManager; @Autowired private ConfigurableApplicationContext _applicationContext; @Autowired private IsoLanguagesMapper isoLanguagesMapper; - + @Autowired + private GeonetworkDataDirectory geonetworkDataDirectory; + @Autowired + private ThesaurusManager thesaurusManager; + @Autowired + private DataManager dataManager; + @Autowired + private DataSource dataSource; + @Autowired + private SettingManager settingManager; private FileSystemPool.CreatedFs currentFs; @@ -111,17 +117,15 @@ public boolean accept(Path entry) throws IOException { } }); - Path schemaPluginsDir = templateDataDirectory.resolve("config/schema_plugins"); deploySchema(webappDir, schemaPluginsDir); - final GeonetworkDataDirectory geonetworkDataDirectory = _applicationContext.getBean(GeonetworkDataDirectory.class); - final ServiceConfig serviceConfig = new ServiceConfig(Lists.newArrayList()); + final ServiceConfig serviceConfig = new ServiceConfig(Lists.newArrayList()); geonetworkDataDirectory.init("geonetwork", webappDir, templateDataDirectory, serviceConfig, null); test.addTestSpecificData(geonetworkDataDirectory); // Create ES index - _applicationContext.getBean(EsSearchManager.class).init(false, Optional.empty()); + esSearchManager.init(true, Optional.empty()); templateSchemaManager = initSchemaManager(webappDir, geonetworkDataDirectory); @@ -130,7 +134,7 @@ public boolean accept(Path entry) throws IOException { isoLanguagesMapper.reinit(); } - final String fsName = test.getClass().getSimpleName().replaceAll("[^a-z0-9A-Z]", "") + UUID.randomUUID().toString(); + final String fsName = test.getClass().getSimpleName().replaceAll("[^a-z0-9A-Z]", "") + UUID.randomUUID(); currentFs = FILE_SYSTEM_POOL.get(fsName); assertTrue(Files.isDirectory(currentFs.dataDir.resolve("config"))); @@ -142,35 +146,21 @@ public boolean accept(Path entry) throws IOException { final GeonetworkDataDirectory dataDir = configureDataDir(test, webappDir, currentFs.dataDir); configureNewSchemaManager(dataDir, webappDir); - // TODO: I don't know why but this corrupts other tests that will fail depending on the run order: - // assertCorrectDataDir(); - // for example, running GeonetworkDataDirectoryMultiNodeServiceConfigOnlySystemDataDirSetTest, then - // GeonetworkDataDirectoryMultiNodeSystemPropertyOnlySystemDataDirSetTest with that line enabled, the second fails. - -// if (test.resetLuceneIndex()) { -// _directoryFactory.resetIndex(); -// } - ServiceContext serviceContext = test.createServiceContext(); ApplicationContextHolder.set(_applicationContext); serviceContext.setAsThreadLocal(); -// TODOES -// _applicationContext.getBean(EsSearchManager.class).initNonStaticData(100); - _applicationContext.getBean(DataManager.class).init(serviceContext, false); - _applicationContext.getBean(ThesaurusManager.class).init(true, serviceContext, "WEB-INF/data/config/codelist"); + dataManager.init(serviceContext, false); + thesaurusManager.init(true, serviceContext, "WEB-INF/data/config/codelist"); addSourceUUID(dataDir); - final DataSource dataSource = _applicationContext.getBean(DataSource.class); try (Connection conn = dataSource.getConnection()) { - ThreadUtils.init(conn.getMetaData().getURL(), _applicationContext.getBean(SettingManager.class)); + ThreadUtils.init(conn.getMetaData().getURL(), settingManager); } - } - protected void configureNewSchemaManager(GeonetworkDataDirectory dataDir, Path webappDir) throws Exception { final SchemaManager schemaManager = _applicationContext.getBean(SchemaManager.class); schemaManager.configureFrom(templateSchemaManager, webappDir, dataDir); @@ -179,7 +169,7 @@ protected void configureNewSchemaManager(GeonetworkDataDirectory dataDir, Path w protected void addSourceUUID(GeonetworkDataDirectory dataDirectory) { String siteUuid = dataDirectory.getSystemDataDir().getFileName().toString(); - _applicationContext.getBean(SettingManager.class).setSiteUuid(siteUuid); + settingManager.setSiteUuid(siteUuid); final SourceRepository sourceRepository = _applicationContext.getBean(SourceRepository.class); List sources = sourceRepository.findAll(); if (sources.isEmpty()) { @@ -191,12 +181,13 @@ protected void addSourceUUID(GeonetworkDataDirectory dataDirectory) { protected SchemaManager initSchemaManager(Path webappDir, GeonetworkDataDirectory geonetworkDataDirectory) throws Exception { final Path schemaPluginsDir = geonetworkDataDirectory.getSchemaPluginsDir(); final Path resourcePath = geonetworkDataDirectory.getResourcesDir(); + final Path schemaPublicationDir = geonetworkDataDirectory.getSchemaPublicationDir(); Path schemaPluginsCatalogFile = schemaPluginsDir.resolve("schemaplugin-uri-catalog.xml"); final SchemaManager schemaManager = _applicationContext.getBean(SchemaManager.class); SchemaManager.registerXmlCatalogFiles(webappDir, schemaPluginsCatalogFile); - schemaManager.configure(_applicationContext, webappDir, resourcePath, + schemaManager.configure(_applicationContext, webappDir, resourcePath, schemaPublicationDir, schemaPluginsCatalogFile, schemaPluginsDir, "eng", "iso19139", true); assertRequiredSchemas(schemaManager); diff --git a/core/src/test/java/org/fao/geonet/kernel/AbstractGeonetworkDataDirectoryTest.java b/core/src/test/java/org/fao/geonet/kernel/AbstractGeonetworkDataDirectoryTest.java index 473f7d77ba6..63624516b09 100644 --- a/core/src/test/java/org/fao/geonet/kernel/AbstractGeonetworkDataDirectoryTest.java +++ b/core/src/test/java/org/fao/geonet/kernel/AbstractGeonetworkDataDirectoryTest.java @@ -26,6 +26,8 @@ import jeeves.server.ServiceConfig; import org.fao.geonet.AbstractCoreIntegrationTest; +import org.fao.geonet.constants.Geonet; +import org.fao.geonet.exceptions.BadParameterEx; import org.jdom.Element; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -34,7 +36,7 @@ import java.nio.file.Path; import java.util.ArrayList; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; /** * Abstract class for GeonetworkDataDirectory tests where the data directory layout is a default @@ -64,6 +66,7 @@ public void testInit() throws Exception { dataDirectory.setHtmlCacheDir(null); dataDirectory.setSchemaPluginsDir(null); dataDirectory.setThesauriDir(null); + dataDirectory.setSchemaPublicationDir(null); final ArrayList serviceConfigParameterElements = getServiceConfigParameterElements(); final ServiceConfig handlerConfig = new ServiceConfig(serviceConfigParameterElements); final Path webappDir = getWebappDir(getClass()); @@ -75,6 +78,29 @@ public void testInit() throws Exception { assertSystemDirSubFolders(expectedDataDir); } + @Test + public void testGetXsltConversion() { + Path xsltConversion = dataDirectory.getXsltConversion("conversion"); + assertEquals(dataDirectory.getWebappDir().resolve(Geonet.Path.IMPORT_STYLESHEETS).resolve("conversion.xsl"), xsltConversion); + try { + dataDirectory.getXsltConversion("../conversion"); + } catch (BadParameterEx e) { + assertEquals("../conversion is not a valid value for: Invalid character found in path.", e.getMessage()); + } + + xsltConversion = dataDirectory.getXsltConversion("schema:iso19115-3.2018:convert/fromISO19115-3.2014"); + assertNotNull(xsltConversion); + try { + dataDirectory.getXsltConversion("schema:notExistingSchema:convert/fromISO19115-3.2014"); + } catch (BadParameterEx e) { + assertEquals("Conversion not found. Schema 'notExistingSchema' is not registered in this catalog.", e.getMessage()); + } + try { + dataDirectory.getXsltConversion("schema:iso19115-3.2018:../../custom/path"); + } catch (BadParameterEx e) { + assertEquals("../../custom/path is not a valid value for: Invalid character found in path.", e.getMessage()); + } + } private void assertSystemDirSubFolders(Path expectedDataDir) { final Path expectedConfigDir = expectedDataDir.resolve("config"); assertEquals(expectedConfigDir, dataDirectory.getConfigDir()); @@ -83,6 +109,7 @@ private void assertSystemDirSubFolders(Path expectedDataDir) { final Path expectedResourcesDir = expectedDataDir.resolve("data").resolve("resources"); assertEquals(expectedResourcesDir, dataDirectory.getResourcesDir()); assertEquals(expectedResourcesDir.resolve("htmlcache"), dataDirectory.getHtmlCacheDir()); + assertEquals(expectedResourcesDir.resolve("schemapublication"), dataDirectory.getSchemaPublicationDir()); assertEquals(expectedConfigDir.resolve("schema_plugins"), dataDirectory.getSchemaPluginsDir()); assertEquals(expectedConfigDir.resolve("codelist"), dataDirectory.getThesauriDir()); } diff --git a/core/src/test/java/org/fao/geonet/kernel/AbstractIntegrationTestWithMockedSingletons.java b/core/src/test/java/org/fao/geonet/kernel/AbstractIntegrationTestWithMockedSingletons.java index 8c07a7fa929..2238444e734 100644 --- a/core/src/test/java/org/fao/geonet/kernel/AbstractIntegrationTestWithMockedSingletons.java +++ b/core/src/test/java/org/fao/geonet/kernel/AbstractIntegrationTestWithMockedSingletons.java @@ -1,20 +1,70 @@ package org.fao.geonet.kernel; +import jeeves.server.context.ServiceContext; import org.fao.geonet.AbstractCoreIntegrationTest; +import org.fao.geonet.domain.AbstractMetadata; +import org.fao.geonet.domain.Metadata; +import org.fao.geonet.domain.MetadataType; +import org.fao.geonet.kernel.datamanager.IMetadataManager; +import org.fao.geonet.kernel.search.IndexingMode; +import org.fao.geonet.repository.SourceRepository; +import org.jdom.Element; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.reset; +import java.util.UUID; +import static org.fao.geonet.domain.MetadataType.METADATA; +import static org.fao.geonet.kernel.UpdateDatestamp.NO; + +@ContextConfiguration( + locations = {"classpath:mocked-core-repository-test-context.xml"} +) public abstract class AbstractIntegrationTestWithMockedSingletons extends AbstractCoreIntegrationTest { - private static SpringLocalServiceInvoker mockInvoker; + private static final int TEST_OWNER_ID = 42; + + @Autowired + private IMetadataManager metadataManager; + + @Autowired + private SchemaManager schemaManager; + + @Autowired + private SourceRepository sourceRepository; + + @Autowired + protected SpringLocalServiceInvoker springLocalServiceInvoker; + + protected AbstractMetadata insertTemplateResourceInDb(ServiceContext serviceContext, Element element) throws Exception { + return insertTemplateResourceInDb(serviceContext, element, METADATA); + } + + protected AbstractMetadata insertTemplateResourceInDb(ServiceContext serviceContext, Element element, MetadataType type) throws Exception { + loginAsAdmin(serviceContext); + + Metadata metadata = new Metadata(); + metadata.setDataAndFixCR(element) + .setUuid(UUID.randomUUID().toString()); + metadata.getDataInfo() + .setRoot(element.getQualifiedName()) + .setSchemaId(schemaManager.autodetectSchema(element)) + .setType(type) + .setPopularity(1000); + metadata.getSourceInfo() + .setOwner(TEST_OWNER_ID) + .setSourceId(sourceRepository.findAll().get(0).getUuid()); + metadata.getHarvestInfo() + .setHarvested(false); - public SpringLocalServiceInvoker resetAndGetMockInvoker() { - if (mockInvoker == null) { - mockInvoker = mock(SpringLocalServiceInvoker.class); - _applicationContext.getBeanFactory().registerSingleton(SpringLocalServiceInvoker.class.getCanonicalName(), mockInvoker); - } - reset(mockInvoker); - return mockInvoker; + return metadataManager.insertMetadata( + serviceContext, + metadata, + element, + IndexingMode.full, + false, + NO, + false, + true); } } diff --git a/core/src/test/java/org/fao/geonet/kernel/DataManagerIntegrationTest.java b/core/src/test/java/org/fao/geonet/kernel/DataManagerIntegrationTest.java index 29748c46e3a..f81456e4f84 100644 --- a/core/src/test/java/org/fao/geonet/kernel/DataManagerIntegrationTest.java +++ b/core/src/test/java/org/fao/geonet/kernel/DataManagerIntegrationTest.java @@ -25,7 +25,6 @@ import com.google.common.base.Optional; import com.google.common.collect.Maps; -import jeeves.server.UserSession; import jeeves.server.context.ServiceContext; import org.fao.geonet.AbstractCoreIntegrationTest; import org.fao.geonet.constants.Geonet; @@ -40,11 +39,9 @@ import org.fao.geonet.domain.Source; import org.fao.geonet.domain.SourceType; import org.fao.geonet.domain.User; -import org.fao.geonet.kernel.datamanager.IMetadataManager; import org.fao.geonet.kernel.search.EsSearchManager; import org.fao.geonet.kernel.search.IndexingMode; import org.fao.geonet.repository.GroupRepository; -import org.fao.geonet.repository.MetadataCategoryRepository; import org.fao.geonet.repository.SourceRepository; import org.fao.geonet.repository.specification.MetadataSpecs; import org.fao.geonet.utils.Xml; @@ -76,24 +73,12 @@ public class DataManagerIntegrationTest extends AbstractDataManagerIntegrationTe public void testDeleteMetadata() throws Exception { ServiceContext serviceContext = createContextAndLogAsAdmin(); long count = metadataRepository.count(); - String mdId = dataManager.insertMetadata( - serviceContext, - "iso19139", - new Element("MD_Metadata"), - "uuid", - serviceContext.getUserSession().getUserIdAsInt(), - "" + ReservedGroup.all.getId(), - "sourceid", - "n", - "doctype", - null, - new ISODate().getDateAndTime(), - new ISODate().getDateAndTime(), - false, - IndexingMode.none); + + int mdId = injectMetadataInDbDoNotRefreshHeader(getSampleMetadataXml(), serviceContext).getId(); + assertEquals(count + 1, metadataRepository.count()); - metadataManager.deleteMetadata(serviceContext, mdId); + metadataManager.deleteMetadata(serviceContext, String.valueOf(mdId)); assertEquals(count, metadataRepository.count()); } @@ -194,12 +179,12 @@ public void testDeleteBatchMetadata() throws Exception { importMetadata(serviceContext, uuid1); importMetadata(serviceContext, uuid2); assertEquals(2, metadataRepository.findAll(spec).size()); - assertEquals(2, searchManager.query(String.format("uuid:(%s OR %s)", uuid1, uuid2), null, 0, 10).getHits().getTotalHits().value); + assertEquals(2, searchManager.query(String.format("uuid:(%s OR %s)", uuid1, uuid2), null, 0, 10).hits().hits().size()); dataManager.batchDeleteMetadataAndUpdateIndex(spec); assertEquals(0, metadataRepository.findAll(spec).size()); - assertEquals(0, searchManager.query(String.format("uuid:(%s OR %s)", uuid1, uuid2), null, 0, 10).getHits().getTotalHits().value); + assertEquals(0, searchManager.query(String.format("uuid:(%s OR %s)", uuid1, uuid2), null, 0, 10).hits().hits().size()); } @Test diff --git a/core/src/test/java/org/fao/geonet/kernel/ElasticsearchIndexingTest.java b/core/src/test/java/org/fao/geonet/kernel/ElasticsearchIndexingTest.java new file mode 100644 index 00000000000..e13577def46 --- /dev/null +++ b/core/src/test/java/org/fao/geonet/kernel/ElasticsearchIndexingTest.java @@ -0,0 +1,66 @@ +package org.fao.geonet.kernel; + +import co.elastic.clients.elasticsearch.core.SearchResponse; +import jeeves.server.context.ServiceContext; +import org.fao.geonet.AbstractCoreIntegrationTest; +import org.fao.geonet.domain.AbstractMetadata; +import org.fao.geonet.kernel.search.EsSearchManager; +import org.fao.geonet.kernel.setting.SettingManager; +import org.fao.geonet.kernel.setting.Settings; +import org.fao.geonet.utils.Xml; +import org.jdom.Element; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import java.net.URL; +import java.util.Objects; +import static org.junit.Assert.*; + +public class ElasticsearchIndexingTest extends AbstractIntegrationTestWithMockedSingletons { + + @Autowired + private EsSearchManager searchManager; + + @Autowired + private SettingManager settingManager; + + private ServiceContext serviceContext; + + @Before + public void setUp() throws Exception { + serviceContext = createServiceContext(); + settingManager.setValue(Settings.SYSTEM_XLINKRESOLVER_ENABLE, true); + } + + @Test + public void complexDatesAreIndexedCheck() throws Exception { + // GIVEN + AbstractMetadata dbInsertedSimpleDataMetadata = loadMetadataWithTemporalExtentUsingSimpleDates(); + validateIndexedExpectedData(dbInsertedSimpleDataMetadata, "forest", 1); + validateIndexedExpectedData(dbInsertedSimpleDataMetadata, "holocene", 0); + URL dateResource = AbstractCoreIntegrationTest.class.getResource("kernel/holocene.xml"); + Element dateElement = Xml.loadStream(Objects.requireNonNull(dateResource).openStream()); + + // WHEN + AbstractMetadata dbInsertedMetadata = insertTemplateResourceInDb(serviceContext, dateElement); + + //THEN + SearchResponse response = this.searchManager.query("_id:" + dbInsertedMetadata.getUuid() + " AND resourceTitleObject.default:holocene", null, 0, 10); + long actualHitNbr = response.hits().hits().size(); + assertEquals(String.format("Incorrect indexation of Holocene data with complex date due to: %s and %s", response, dbInsertedMetadata), 1, actualHitNbr); + } + + private AbstractMetadata loadMetadataWithTemporalExtentUsingSimpleDates() throws Exception { + URL dateResource = AbstractCoreIntegrationTest.class.getResource("kernel/forest.xml"); + Element dateElement = Xml.loadStream(Objects.requireNonNull(dateResource).openStream()); + return insertTemplateResourceInDb(serviceContext, dateElement); + } + + private void validateIndexedExpectedData(AbstractMetadata dbInsertedSimpleDataMetadata, String resourceTitle, long expectedHitNbr) throws Exception { + SearchResponse searchResponse = this.searchManager.query("resourceTitleObject.default:" + resourceTitle, null, 0, 10); + long actualHitNbr = searchResponse.hits().hits().size(); + String assertionErrorMessage = "The %s data was not indexed the expected number of times due to: %s and %s"; + assertEquals(String.format(assertionErrorMessage, resourceTitle, searchResponse, dbInsertedSimpleDataMetadata), expectedHitNbr, actualHitNbr); + } +} diff --git a/core/src/test/java/org/fao/geonet/kernel/LocalXLinksInMetadataIntegrationTest.java b/core/src/test/java/org/fao/geonet/kernel/LocalXLinksInMetadataIntegrationTest.java index cd6923d4d18..5b141a82cb7 100644 --- a/core/src/test/java/org/fao/geonet/kernel/LocalXLinksInMetadataIntegrationTest.java +++ b/core/src/test/java/org/fao/geonet/kernel/LocalXLinksInMetadataIntegrationTest.java @@ -110,40 +110,38 @@ public void testResolveLocalXLink() throws Exception { String id = _dataManager.insertMetadata(context, schema, metadata, uuid, owner, groupOwner, source, metadataType, null, null, createDate, changeDate, false, IndexingMode.none); - SpringLocalServiceInvoker mockInvoker = resetAndGetMockInvoker(); - String keyword1 = "World"; Element element1 = new SAXBuilder().build(new StringReader(String.format(responseTemplate, keyword1))).getRootElement(); - when(mockInvoker.invoke(any(String.class))).thenReturn(element1); + when(springLocalServiceInvoker.invoke(any(String.class))).thenReturn(element1); final String xpath = "*//gmd:descriptiveKeywords//gmd:keyword/gco:CharacterString"; assertNull(Xml.selectElement(metadata, xpath)); - verify(mockInvoker, never()).invoke(any(String.class)); + verify(springLocalServiceInvoker, never()).invoke(any(String.class)); final Element loadedMetadataNoXLinkAttributesNotEdit = _dataManager.getMetadata(context, id, false, false, false); assertEqualsText(keyword1, loadedMetadataNoXLinkAttributesNotEdit, xpath, GCO, GMD); - verify(mockInvoker, times(1)).invoke(any(String.class)); + verify(springLocalServiceInvoker, times(1)).invoke(any(String.class)); final Element loadedMetadataKeepXLinkAttributesNotEdit = _dataManager.getMetadata(context, id, false, false, true); assertEqualsText(keyword1, loadedMetadataKeepXLinkAttributesNotEdit, xpath, GCO, GMD); - verify(mockInvoker, times(2)).invoke(any(String.class)); + verify(springLocalServiceInvoker, times(2)).invoke(any(String.class)); final Element loadedMetadataNoXLinkAttributesEdit = _dataManager.getMetadata(context, id, false, true, false); assertEqualsText(keyword1, loadedMetadataNoXLinkAttributesEdit, xpath, GCO, GMD); - verify(mockInvoker, times(3)).invoke(any(String.class)); + verify(springLocalServiceInvoker, times(3)).invoke(any(String.class)); final Element loadedMetadataKeepXLinkAttributesEdit = _dataManager.getMetadata(context, id, false, true, true); assertEqualsText(keyword1, loadedMetadataKeepXLinkAttributesEdit, xpath, GCO, GMD); - verify(mockInvoker, times(4)).invoke(any(String.class)); + verify(springLocalServiceInvoker, times(4)).invoke(any(String.class)); Processor.clearCache(); String keyword2 = "Other Word"; Element element2 = new SAXBuilder().build(new StringReader(String.format(responseTemplate, keyword2))).getRootElement(); - when(mockInvoker.invoke(any(String.class))).thenReturn(element2); + when(springLocalServiceInvoker.invoke(any(String.class))).thenReturn(element2); final Element newLoad = _dataManager.getMetadata(context, id, false, true, true); assertEqualsText(keyword2, newLoad, xpath, GCO, GMD); - verify(mockInvoker, times(5)).invoke(any(String.class)); + verify(springLocalServiceInvoker, times(5)).invoke(any(String.class)); } } diff --git a/core/src/test/java/org/fao/geonet/kernel/LocalXLinksUpdateDeleteTest.java b/core/src/test/java/org/fao/geonet/kernel/LocalXLinksUpdateDeleteTest.java index cf7e784e20e..e67834f85ef 100644 --- a/core/src/test/java/org/fao/geonet/kernel/LocalXLinksUpdateDeleteTest.java +++ b/core/src/test/java/org/fao/geonet/kernel/LocalXLinksUpdateDeleteTest.java @@ -3,14 +3,10 @@ import jeeves.server.context.ServiceContext; import org.fao.geonet.AbstractCoreIntegrationTest; import org.fao.geonet.domain.AbstractMetadata; -import org.fao.geonet.domain.Metadata; -import org.fao.geonet.domain.MetadataType; import org.fao.geonet.kernel.datamanager.IMetadataManager; -import org.fao.geonet.kernel.search.EsSearchManager; import org.fao.geonet.kernel.search.IndexingMode; import org.fao.geonet.kernel.setting.SettingManager; import org.fao.geonet.kernel.setting.Settings; -import org.fao.geonet.repository.SourceRepository; import org.fao.geonet.utils.Xml; import org.jdom.Attribute; import org.jdom.Element; @@ -20,11 +16,9 @@ import java.net.URL; import java.util.Arrays; -import java.util.UUID; import static org.fao.geonet.domain.MetadataType.SUB_TEMPLATE; import static org.fao.geonet.domain.MetadataType.TEMPLATE; -import static org.fao.geonet.kernel.UpdateDatestamp.NO; import static org.fao.geonet.schema.iso19139.ISO19139Namespaces.GCO; import static org.fao.geonet.schema.iso19139.ISO19139Namespaces.GMD; import static org.junit.Assert.assertNotNull; @@ -34,31 +28,18 @@ public class LocalXLinksUpdateDeleteTest extends AbstractIntegrationTestWithMockedSingletons { - - private static final int TEST_OWNER = 42; - @Autowired private IMetadataManager metadataManager; - @Autowired - private SchemaManager schemaManager; - - @Autowired - private SourceRepository sourceRepository; - - @Autowired - private EsSearchManager searchManager; - @Autowired private SettingManager settingManager; - private ServiceContext context; + private ServiceContext serviceContext; @Before public void setUp() throws Exception { - this.context = createServiceContext(); + serviceContext = createServiceContext(); settingManager.setValue(Settings.SYSTEM_XLINKRESOLVER_ENABLE, true); - resetAndGetMockInvoker(); } @Test @@ -73,7 +54,7 @@ public void updateHasToRegisterReferrersForIndexation() throws Exception { // assertFalse(context.getBean(IndexingList.class).getIdentifiers().contains(vicinityMapMetadata.getId())); Xml.selectElement(contactElement, "gmd:individualName/gco:CharacterString", Arrays.asList(GMD, GCO)).setText("momo"); - metadataManager.updateMetadata(context, + metadataManager.updateMetadata(serviceContext, Integer.toString(contactMetadata.getId()), contactElement, false, @@ -93,8 +74,8 @@ public void deleteAllowedWhenRefNotExists() throws Exception { AbstractMetadata contactMetadata = insertContact(); AbstractMetadata vicinityMapMetadata = insertVicinityMap(contactMetadata); - metadataManager.deleteMetadata(context, Integer.toString(vicinityMapMetadata.getId())); - metadataManager.deleteMetadata(context, Integer.toString(contactMetadata.getId())); + metadataManager.deleteMetadata(serviceContext, Integer.toString(vicinityMapMetadata.getId())); + metadataManager.deleteMetadata(serviceContext, Integer.toString(contactMetadata.getId())); assertNull(metadataManager.getMetadata(Integer.toString(contactMetadata.getId()))); } @@ -105,7 +86,7 @@ public void deleteHasToBeForbiddenWhenRefExistsAndSettingsSaySo() throws Excepti insertVicinityMap(contactMetadata); try { - metadataManager.deleteMetadata(context, + metadataManager.deleteMetadata(serviceContext, Integer.toString(contactMetadata.getId())); } catch (Exception e) { @@ -119,46 +100,16 @@ public void deleteHasToBeAllowedWhenRefExistsAndSettingsSaySo() throws Exception AbstractMetadata contactMetadata = insertContact(); insertVicinityMap(contactMetadata); - metadataManager.deleteMetadata(context, Integer.toString(contactMetadata.getId())); + metadataManager.deleteMetadata(serviceContext, Integer.toString(contactMetadata.getId())); assertNull(metadataManager.getMetadata(Integer.toString(contactMetadata.getId()))); } - private AbstractMetadata insertTemplateResourceInDb(Element element, MetadataType type) throws Exception { - loginAsAdmin(context); - - Metadata metadata = new Metadata(); - metadata.setDataAndFixCR(element) - .setUuid(UUID.randomUUID().toString()); - metadata.getDataInfo() - .setRoot(element.getQualifiedName()) - .setSchemaId(schemaManager.autodetectSchema(element)) - .setType(type) - .setPopularity(1000); - metadata.getSourceInfo() - .setOwner(TEST_OWNER) - .setSourceId(sourceRepository.findAll().get(0).getUuid()); - metadata.getHarvestInfo() - .setHarvested(false); - - AbstractMetadata dbInsertedMetadata = metadataManager.insertMetadata( - context, - metadata, - element, - IndexingMode.full, - false, - NO, - false, - true); - - return dbInsertedMetadata; - } - private AbstractMetadata insertVicinityMap(AbstractMetadata contactMetadata) throws Exception { URL vicinityMapResource = AbstractCoreIntegrationTest.class.getResource("kernel/vicinityMap.xml"); Element vicinityMapElement = Xml.loadStream(vicinityMapResource.openStream()); Attribute href = (Attribute) Xml.selectElement(vicinityMapElement, "gmd:identificationInfo/gmd:MD_DataIdentification/gmd:pointOfContact").getAttributes().get(0); href.setValue(href.getValue().replace("@contact_uuid@", contactMetadata.getUuid())); - return insertTemplateResourceInDb(vicinityMapElement, TEMPLATE); + return insertTemplateResourceInDb(serviceContext, vicinityMapElement, TEMPLATE); } private AbstractMetadata insertContact() throws Exception { @@ -168,10 +119,9 @@ private AbstractMetadata insertContact() throws Exception { } private AbstractMetadata insertContact(Element contactElement) throws Exception { - AbstractMetadata contactMetadata = insertTemplateResourceInDb(contactElement, SUB_TEMPLATE); + AbstractMetadata contactMetadata = insertTemplateResourceInDb(serviceContext, contactElement, SUB_TEMPLATE); - SpringLocalServiceInvoker mockInvoker = resetAndGetMockInvoker(); - when(mockInvoker.invoke(any(String.class))).thenReturn(contactElement); + when(springLocalServiceInvoker.invoke(any(String.class))).thenReturn(contactElement); return contactMetadata; } } diff --git a/core/src/test/java/org/fao/geonet/kernel/XmlSerializerIntegrationTest.java b/core/src/test/java/org/fao/geonet/kernel/XmlSerializerIntegrationTest.java index 453098e09a7..e30b06d96ca 100644 --- a/core/src/test/java/org/fao/geonet/kernel/XmlSerializerIntegrationTest.java +++ b/core/src/test/java/org/fao/geonet/kernel/XmlSerializerIntegrationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2016 Food and Agriculture Organization of the + * Copyright (C) 2001-2023 Food and Agriculture Organization of the * United Nations (FAO-UN), United Nations World Food Programme (WFP) * and United Nations Environment Programme (UNEP) * @@ -45,6 +45,7 @@ import org.fao.geonet.domain.Pair; import org.fao.geonet.kernel.datamanager.IMetadataManager; import org.fao.geonet.kernel.schema.MetadataSchema; +import org.fao.geonet.kernel.schema.MetadataSchemaOperationFilter; import org.fao.geonet.utils.Xml; import org.jdom.Element; import org.jdom.Namespace; @@ -101,23 +102,31 @@ public class XmlSerializerIntegrationTest extends AbstractCoreIntegrationTest { public void setSchemaFilters(boolean withHeld, boolean keepMarkedElement) { MetadataSchema mds = _dataManager.getSchema(metadata.getDataInfo().getSchemaId()); - Map> filters = new HashMap>(); + Map filters = new HashMap<>(); if (withHeld) { if (keepMarkedElement) { Element mark = new Element("keepMarkedElement"); mark.setAttribute("nilReason", "withheld", Geonet.Namespaces.GCO); - filters.put("editing", - Pair.read(XPATH_WITHHELD, mark)); + + MetadataSchemaOperationFilter editFilter = new MetadataSchemaOperationFilter(XPATH_WITHHELD, "", "editing", mark); + + filters.put(editFilter.getIfNotOperation(), + editFilter); } else { - filters.put("editing", - Pair.read(XPATH_WITHHELD, null)); + MetadataSchemaOperationFilter editFilter = new MetadataSchemaOperationFilter(XPATH_WITHHELD, "", "editing", null); + + filters.put(editFilter.getIfNotOperation(), + editFilter); } } - filters.put("download", - Pair.read(XPATH_DOWNLOAD, null)); - filters.put("dynamic", - Pair.read(XPATH_DYNAMIC, null)); + MetadataSchemaOperationFilter downloadFilter = new MetadataSchemaOperationFilter(XPATH_DOWNLOAD, "", "download", null); + filters.put(downloadFilter.getIfNotOperation(), + downloadFilter); + + MetadataSchemaOperationFilter dynamicFilter = new MetadataSchemaOperationFilter(XPATH_DYNAMIC, "", "dynamic", null); + filters.put(dynamicFilter.getIfNotOperation(), + dynamicFilter); mds.setOperationFilters(filters); } @@ -134,17 +143,6 @@ public void testInternalSelectHidingWithheldSettingsDisabled() throws Exception assertHiddenElements(false, false); } - @SuppressWarnings("unchecked") - @Test - public void testInternalSelectHidingWithheldNullServiceContext() throws Exception { - setSchemaFilters(true, true); - Field field = ServiceContext.class.getDeclaredField("THREAD_LOCAL_INSTANCE"); - field.setAccessible(true); - InheritableThreadLocal threadLocalInstance = (InheritableThreadLocal) field.get(null); - threadLocalInstance.set(null); - assertHiddenElements(true); - } - @Test public void testInternalSelectHidingWithheldAdministrator() throws Exception { try (Closeable ignored = configureXmlSerializerAndServiceContext(true, false, false)) { diff --git a/core/src/test/java/org/fao/geonet/kernel/search/EsSearchManagerTest.java b/core/src/test/java/org/fao/geonet/kernel/search/EsSearchManagerTest.java new file mode 100644 index 00000000000..ec0af66d1b3 --- /dev/null +++ b/core/src/test/java/org/fao/geonet/kernel/search/EsSearchManagerTest.java @@ -0,0 +1,66 @@ +package org.fao.geonet.kernel.search; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static org.junit.Assert.assertEquals; + +import org.jdom.Element; +import org.junit.Before; +import org.junit.Test; + +public class EsSearchManagerTest { + + private EsSearchManager instance; + private ObjectMapper objectMapper; + + @Before + public void setup() { + this.instance = new EsSearchManager(); + this.objectMapper = new ObjectMapper(); + } + + @Test + public void documentToJsonSimple() throws JsonProcessingException { + Element input = new Element("doc"); + Element field1 = new Element("field1").setText("content1"); + Element field2 = new Element("field2").setText("content2"); + input.addContent(field1); + input.addContent(field2); + + ObjectNode result = instance.documentToJson(input); + JsonNode expected = objectMapper.readTree(" {\"field1\":\"content1\",\"field2\":\"content2\"}"); + + assertEquals(expected, result); + } + + @Test + public void documentToJsonIndexingErrorMsg() throws JsonProcessingException { + Element input = new Element("doc"); + Element field1 = new Element("field1").setText("content1"); + String escapedJson = "{\n" + + " \"type\": \"error\",\n" + + " \"string\": \"string-reference\",\n" + + " \"values\": {\n" + + " \"value1\": \"content1\",\n" + + " \"value2\": \"content2\"\n" + + " }\n" + + "}"; + Element field2 = new Element(IndexFields.INDEXING_ERROR_MSG).setText(escapedJson); + Element nestedField1 = new Element("nestedField1").setText("nestedContent1"); + Element nestedField2 = new Element("nestedField2").setText("nestedcontent2"); + field2.addContent(nestedField1); + field2.addContent(nestedField2); + field2.setAttribute("type", "object"); + + input.addContent(field1); + input.addContent(field2); + + ObjectNode result = instance.documentToJson(input); + JsonNode expected = objectMapper.readTree("{\"field1\":\"content1\",\"indexingErrorMsg\":[{\"type\":\"error\",\"string\":\"string-reference\",\"values\":{\"value1\":\"content1\",\"value2\":\"content2\"}}]}"); + + assertEquals(expected, result); + } +} diff --git a/core/src/test/java/org/fao/geonet/kernel/security/openidconnect/bearer/UserInfoCacheTest.java b/core/src/test/java/org/fao/geonet/kernel/security/openidconnect/bearer/UserInfoCacheTest.java new file mode 100644 index 00000000000..475171a5ae2 --- /dev/null +++ b/core/src/test/java/org/fao/geonet/kernel/security/openidconnect/bearer/UserInfoCacheTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2022 Food and Agriculture Organization of the + * United Nations (FAO-UN), United Nations World Food Programme (WFP) + * and United Nations Environment Programme (UNEP) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, + * Rome - Italy. email: geonetwork@osgeo.org + */ +package org.fao.geonet.kernel.security.openidconnect.bearer; + +import com.google.common.collect.Lists; +import junit.framework.TestCase; +import org.springframework.security.oauth2.core.user.DefaultOAuth2User; +import org.springframework.security.oauth2.core.user.OAuth2User; + +import java.time.Instant; +import java.util.Collections; + +public class UserInfoCacheTest extends TestCase { + + private OAuth2User user1 = new DefaultOAuth2User(Lists.newArrayList(), Collections.singletonMap("name", "frank"), "name"); + private OAuth2User user2 = new DefaultOAuth2User(Lists.newArrayList(), Collections.singletonMap("name", "jeff"), "name"); + + public void testCache() { + UserInfoCacheItem item1 = new UserInfoCacheItem("a", Instant.now().plusSeconds(1000), user1, Lists.newArrayList()); + UserInfoCacheItem item2 = new UserInfoCacheItem("b", Instant.now().plusSeconds(1000), user2, Lists.newArrayList()); + UserInfoCacheItem item3 = new UserInfoCacheItem("c", Instant.now().minusSeconds(1000), user2, Lists.newArrayList()); + + UserInfoCache cache = new UserInfoCache(); + cache.putItem(item1); + cache.putItem(item2); + cache.putItem(item3); + + assertEquals(3, cache.cache.size()); + assertEquals(item1, cache.getItem("a")); + assertEquals(item2, cache.getItem("b")); + assertNull(cache.getItem("c")); + assertEquals(2, cache.cache.size()); + } +} diff --git a/core/src/test/java/org/fao/geonet/security/web/csrf/GeonetworkCsrfSecurityRequestMatcherTest.java b/core/src/test/java/org/fao/geonet/security/web/csrf/GeonetworkCsrfSecurityRequestMatcherTest.java new file mode 100644 index 00000000000..4c06809aef6 --- /dev/null +++ b/core/src/test/java/org/fao/geonet/security/web/csrf/GeonetworkCsrfSecurityRequestMatcherTest.java @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2001-2023 Food and Agriculture Organization of the + * United Nations (FAO-UN), United Nations World Food Programme (WFP) + * and United Nations Environment Programme (UNEP) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, + * Rome - Italy. email: geonetwork@osgeo.org + */ +package org.fao.geonet.security.web.csrf; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import org.junit.Before; +import org.junit.Test; +import org.keycloak.adapters.springsecurity.filter.KeycloakCsrfRequestMatcher; +import org.keycloak.constants.AdapterConstants; +import org.springframework.http.HttpMethod; +import org.springframework.mock.web.MockHttpServletRequest; + +import java.util.Set; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class GeonetworkCsrfSecurityRequestMatcherTest { + + private static final String ROOT_CONTEXT_PATH = ""; + private static final String SUB_CONTEXT_PATH = "/foo"; + + private GeonetworkCsrfSecurityRequestMatcher matcher; + private MockHttpServletRequest request; + + @Before + public void setUp() { + request = new MockHttpServletRequest(); + Set notCorsPaths = Sets.newLinkedHashSet(Lists.newArrayList( + "/[a-zA-Z0-9_\\-]+/[a-z]{2,3}/csw-publication!?.*", + "/[a-zA-Z0-9_\\-]+/[a-z]{2,3}/csw-.*", + "/[a-zA-Z0-9_\\-]+/[a-z]{2,3}/csw!?.*", + "/[a-zA-Z0-9_\\-]+/api/search/.*", + "/[a-zA-Z0-9_\\-]+/api/site") + ); + matcher = new GeonetworkCsrfSecurityRequestMatcher(notCorsPaths); + } + + @Test + public void testDefaultConfigHttpMethods() { + + request.setMethod(HttpMethod.GET.name()); + assertFalse((matcher.matches(request))); + + request.setMethod(HttpMethod.HEAD.name()); + assertFalse((matcher.matches(request))); + request.setMethod(HttpMethod.TRACE.name()); + assertFalse((matcher.matches(request))); + request.setMethod(HttpMethod.OPTIONS.name()); + assertFalse((matcher.matches(request))); + + request.setMethod(HttpMethod.PATCH.name()); + assertTrue(matcher.matches(request)); + request.setMethod(HttpMethod.POST.name()); + assertTrue(matcher.matches(request)); + request.setMethod(HttpMethod.PUT.name()); + assertTrue(matcher.matches(request)); + request.setMethod(HttpMethod.DELETE.name()); + assertTrue(matcher.matches(request)); + } + + @Test + public void testDefaultMatchesMethodPost() throws Exception { + prepareRequest(HttpMethod.POST, ROOT_CONTEXT_PATH, "some/random/uri"); + assertTrue(matcher.matches(request)); + prepareRequest(HttpMethod.POST, SUB_CONTEXT_PATH, "some/random/uri"); + assertTrue(matcher.matches(request)); + + prepareRequest(HttpMethod.POST, SUB_CONTEXT_PATH, "some/random/uri"); + assertTrue(matcher.matches(request)); + prepareRequest(HttpMethod.POST, SUB_CONTEXT_PATH, "some/random/uri"); + assertTrue(matcher.matches(request)); + + prepareRequest(HttpMethod.POST, ROOT_CONTEXT_PATH, "srv/eng/csw-publication"); + assertFalse(matcher.matches(request)); + prepareRequest(HttpMethod.POST, SUB_CONTEXT_PATH, "srv/eng/csw-publication"); + assertFalse(matcher.matches(request)); + + prepareRequest(HttpMethod.POST, ROOT_CONTEXT_PATH, "srv/eng/csw-foo"); + assertFalse(matcher.matches(request)); + prepareRequest(HttpMethod.POST, SUB_CONTEXT_PATH, "srv/eng/csw-foo"); + assertFalse(matcher.matches(request)); + + prepareRequest(HttpMethod.POST, ROOT_CONTEXT_PATH, "srv/eng/csw"); + assertFalse(matcher.matches(request)); + prepareRequest(HttpMethod.POST, SUB_CONTEXT_PATH, "srv/eng/csw"); + assertFalse(matcher.matches(request)); + + prepareRequest(HttpMethod.POST, ROOT_CONTEXT_PATH, "srv/api/search/foo"); + assertFalse(matcher.matches(request)); + prepareRequest(HttpMethod.POST, SUB_CONTEXT_PATH, "srv/api/search/foo"); + assertFalse(matcher.matches(request)); + + prepareRequest(HttpMethod.POST, ROOT_CONTEXT_PATH, "srv/api/site"); + assertFalse(matcher.matches(request)); + prepareRequest(HttpMethod.POST, SUB_CONTEXT_PATH, "srv/api/site"); + assertFalse(matcher.matches(request)); + + prepareRequest(HttpMethod.POST, ROOT_CONTEXT_PATH, "k_logout"); + assertTrue(matcher.matches(request)); + prepareRequest(HttpMethod.POST, SUB_CONTEXT_PATH, "k_logout"); + assertTrue(matcher.matches(request)); + } + + @Test + public void testKeycloakCorsFilter() { + matcher.addRequestMatcher(new KeycloakCsrfRequestMatcher()); + + prepareRequest(HttpMethod.POST, ROOT_CONTEXT_PATH, "some/random/uri"); + assertTrue(matcher.matches(request)); + prepareRequest(HttpMethod.POST, SUB_CONTEXT_PATH, "some/random/uri"); + assertTrue(matcher.matches(request)); + + prepareRequest(HttpMethod.POST, ROOT_CONTEXT_PATH, "srv/eng/csw-publication"); + assertFalse(matcher.matches(request)); + prepareRequest(HttpMethod.POST, SUB_CONTEXT_PATH, "srv/eng/csw-publication"); + assertFalse(matcher.matches(request)); + + prepareRequest(HttpMethod.POST, ROOT_CONTEXT_PATH, "srv/eng/csw-foo"); + assertFalse(matcher.matches(request)); + prepareRequest(HttpMethod.POST, SUB_CONTEXT_PATH, "srv/eng/csw-foo"); + assertFalse(matcher.matches(request)); + + prepareRequest(HttpMethod.POST, ROOT_CONTEXT_PATH, "srv/eng/csw"); + assertFalse(matcher.matches(request)); + prepareRequest(HttpMethod.POST, SUB_CONTEXT_PATH, "srv/eng/csw"); + assertFalse(matcher.matches(request)); + + prepareRequest(HttpMethod.POST, ROOT_CONTEXT_PATH, "srv/api/search/foo"); + assertFalse(matcher.matches(request)); + prepareRequest(HttpMethod.POST, SUB_CONTEXT_PATH, "srv/api/search/foo"); + assertFalse(matcher.matches(request)); + + prepareRequest(HttpMethod.POST, ROOT_CONTEXT_PATH, "srv/api/site"); + assertFalse(matcher.matches(request)); + prepareRequest(HttpMethod.POST, SUB_CONTEXT_PATH, "srv/api/site"); + assertFalse(matcher.matches(request)); + + prepareRequest(HttpMethod.POST, ROOT_CONTEXT_PATH, AdapterConstants.K_LOGOUT); + assertFalse(matcher.matches(request)); + prepareRequest(HttpMethod.POST, SUB_CONTEXT_PATH, AdapterConstants.K_LOGOUT); + assertFalse(matcher.matches(request)); + + prepareRequest(HttpMethod.POST, ROOT_CONTEXT_PATH, AdapterConstants.K_PUSH_NOT_BEFORE); + assertFalse(matcher.matches(request)); + prepareRequest(HttpMethod.POST, SUB_CONTEXT_PATH, AdapterConstants.K_PUSH_NOT_BEFORE); + assertFalse(matcher.matches(request)); + + prepareRequest(HttpMethod.POST, ROOT_CONTEXT_PATH, AdapterConstants.K_QUERY_BEARER_TOKEN); + assertFalse(matcher.matches(request)); + prepareRequest(HttpMethod.POST, SUB_CONTEXT_PATH, AdapterConstants.K_QUERY_BEARER_TOKEN); + assertFalse(matcher.matches(request)); + + prepareRequest(HttpMethod.POST, ROOT_CONTEXT_PATH, AdapterConstants.K_TEST_AVAILABLE); + assertFalse(matcher.matches(request)); + prepareRequest(HttpMethod.POST, SUB_CONTEXT_PATH, AdapterConstants.K_TEST_AVAILABLE); + assertFalse(matcher.matches(request)); + + } + + private void prepareRequest(HttpMethod method, String contextPath, String uri) { + request.setMethod(method.name()); + request.setContextPath(contextPath); + request.setRequestURI(contextPath + "/" + uri); + request.setServletPath("/" + uri); + } +} diff --git a/core/src/test/java/org/fao/geonet/util/WorkflowUtilTest.java b/core/src/test/java/org/fao/geonet/util/WorkflowUtilTest.java new file mode 100644 index 00000000000..85b907d2795 --- /dev/null +++ b/core/src/test/java/org/fao/geonet/util/WorkflowUtilTest.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2001-2023 Food and Agriculture Organization of the + * United Nations (FAO-UN), United Nations World Food Programme (WFP) + * and United Nations Environment Programme (UNEP) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, + * Rome - Italy. email: geonetwork@osgeo.org + */ + +package org.fao.geonet.util; + +import org.fao.geonet.AbstractCoreIntegrationTest; +import org.fao.geonet.kernel.setting.SettingManager; +import org.fao.geonet.kernel.setting.Settings; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import static org.junit.Assert.*; + +public class WorkflowUtilTest extends AbstractCoreIntegrationTest { + @Autowired + SettingManager settingManager; + + @Test + public void testWorkflowDisabled() { + settingManager.setValue(Settings.METADATA_WORKFLOW_ENABLE, false); + assertFalse(WorkflowUtil.isGroupWithEnabledWorkflow("sample")); + } + + @Test + public void testWorkflowDisabledAndEnabledAllGroups() { + settingManager.setValue(Settings.METADATA_WORKFLOW_ENABLE, false); + settingManager.setValue(Settings.METADATA_WORKFLOW_DRAFT_WHEN_IN_GROUP, ".*"); + assertFalse(WorkflowUtil.isGroupWithEnabledWorkflow("sample")); + } + + @Test + public void testWorkflowDisabledAndEnabledInGroupList() { + settingManager.setValue(Settings.METADATA_WORKFLOW_ENABLE, false); + settingManager.setValue(Settings.METADATA_WORKFLOW_DRAFT_WHEN_IN_GROUP, "sample|test"); + assertFalse(WorkflowUtil.isGroupWithEnabledWorkflow("sample")); + + settingManager.setValue(Settings.METADATA_WORKFLOW_DRAFT_WHEN_IN_GROUP, "sam*|test"); + assertFalse(WorkflowUtil.isGroupWithEnabledWorkflow("sample")); + } + + @Test + public void testWorkflowEnabledAllGroups() { + settingManager.setValue(Settings.METADATA_WORKFLOW_ENABLE, true); + settingManager.setValue(Settings.METADATA_WORKFLOW_DRAFT_WHEN_IN_GROUP, ".*"); + assertTrue(WorkflowUtil.isGroupWithEnabledWorkflow("sample")); + } + + @Test + public void testWorkflowEnabledInGroupList() { + settingManager.setValue(Settings.METADATA_WORKFLOW_ENABLE, true); + settingManager.setValue(Settings.METADATA_WORKFLOW_DRAFT_WHEN_IN_GROUP, "sample|test"); + assertTrue(WorkflowUtil.isGroupWithEnabledWorkflow("sample")); + + settingManager.setValue(Settings.METADATA_WORKFLOW_DRAFT_WHEN_IN_GROUP, "sam*|test"); + assertTrue(WorkflowUtil.isGroupWithEnabledWorkflow("sample")); + } + + @Test + public void testWorkflowEnabledNotInGroupList() { + settingManager.setValue(Settings.METADATA_WORKFLOW_ENABLE, true); + settingManager.setValue(Settings.METADATA_WORKFLOW_DRAFT_WHEN_IN_GROUP, "test"); + assertFalse(WorkflowUtil.isGroupWithEnabledWorkflow("sample")); + } +} diff --git a/core/src/test/java/org/geonetwork/map/wms/SLDUtilTest.java b/core/src/test/java/org/geonetwork/map/wms/SLDUtilTest.java index 4d4c8f157f1..4d10e5cf24a 100644 --- a/core/src/test/java/org/geonetwork/map/wms/SLDUtilTest.java +++ b/core/src/test/java/org/geonetwork/map/wms/SLDUtilTest.java @@ -6,7 +6,7 @@ import org.jdom.output.XMLOutputter; import org.json.JSONObject; import org.junit.Test; -import org.opengis.filter.Filter; +import org.geotools.api.filter.Filter; import org.xmlunit.builder.DiffBuilder; import org.xmlunit.builder.Input; import org.xmlunit.diff.DefaultNodeMatcher; diff --git a/core/src/test/resources/WEB-INF/config.properties b/core/src/test/resources/WEB-INF/config.properties index b5eb3e138bf..4bb53114f98 100644 --- a/core/src/test/resources/WEB-INF/config.properties +++ b/core/src/test/resources/WEB-INF/config.properties @@ -19,3 +19,6 @@ es.index.searchlogs=searchlogs es.index.checker.interval=0/5 * * * * ? thesaurus.cache.maxsize=400000 + +language.default=eng +language.forceDefault=false diff --git a/core/src/test/resources/config-spring-geonetwork.xml b/core/src/test/resources/config-spring-geonetwork.xml index eb609fb15ec..e62debc0730 100644 --- a/core/src/test/resources/config-spring-geonetwork.xml +++ b/core/src/test/resources/config-spring-geonetwork.xml @@ -34,4 +34,9 @@ + + + + + diff --git a/core/src/test/resources/core-repository-test-context.xml b/core/src/test/resources/core-repository-test-context.xml index 7a42eee2535..c0ada088e3f 100644 --- a/core/src/test/resources/core-repository-test-context.xml +++ b/core/src/test/resources/core-repository-test-context.xml @@ -141,4 +141,9 @@ + + + + + diff --git a/core/src/test/resources/mocked-core-repository-test-context.xml b/core/src/test/resources/mocked-core-repository-test-context.xml new file mode 100644 index 00000000000..b3d835c52ad --- /dev/null +++ b/core/src/test/resources/mocked-core-repository-test-context.xml @@ -0,0 +1,33 @@ + + + + + + + + + diff --git a/core/src/test/resources/org/fao/geonet/api/Messages.properties b/core/src/test/resources/org/fao/geonet/api/Messages.properties index cf8222548cc..823338a3a32 100644 --- a/core/src/test/resources/org/fao/geonet/api/Messages.properties +++ b/core/src/test/resources/org/fao/geonet/api/Messages.properties @@ -23,14 +23,14 @@ mail_error=Failed to send email. mail_config_test_subject=%s / Test / Mail configuration -mail_config_test_message=Test message from %s\n\ +mail_config_test_message=Test message from %s\n\

\n\ \n\
\n\ \n\ \n\
\n\ -
+ mail_config_test_success=Mail sent to %s. mail_config_test_only_admin=Only administrator users can test mail configuration. password_change_subject=%s / Password change @@ -54,13 +54,16 @@ user_password_changed='%s' password was updated. user_password_notchanged=A problem occurred trying to change '%s' password. Contact the helpdesk. user_password_invalid_changekey='%s' is an invalid change key for '%s'. Change keys are only valid for one day. user_registered=User '%s' registered. -user_with_that_email_found=A user with this email '%s' already exists. -user_with_that_username_found=A user with this username '%s' already exists. +user_with_that_email_username_found=A user with this email or username already exists. register_email_admin_subject=%s / New account for %s as %s register_email_admin_message=Dear Admin,\n\ Newly registered user %s has requested %s access for %s.\n\ Yours sincerely,\n\ The %s team. +register_email_group_admin_message=Dear Admin,\n\ + Newly registered user %s has requested %s access in group %s for %s.\n\ + Yours sincerely,\n\ + The %s team. register_email_subject=%s / Your account as %s register_email_message=Dear User,\n\ Your registration at %s was successful.\n\ @@ -77,6 +80,21 @@ register_email_message=Dear User,\n\ \n\ Yours sincerely,\n\ The %s team. +register_email_group_message=Dear User,\n\ + Your registration at %s was successful.\n\ + Your account is: \n\ + * username: %s\n\ + * password: %s\n\ + * profile: %s\n\ + \n\ + We have sent your request for %s to the group %s administrator. You will be contacted shortly.\n\ + To log in and access your account, please click on the link below.\n\ + %s\n\ + \n\ + Thanks for your registration.\n\ + \n\ + Yours sincerely,\n\ + The %s team. new_user_rating=%s / New user rating on %s new_user_rating_text=See record %s user_feedback_title=%s / User feedback on %s / %s @@ -92,6 +110,9 @@ user_feedback_text=User %s (%s - %s)\n\ \n\ See record %s status_email_text=GeoNetwork user %s (%s) edited metadata record #%s +metadata_save_submit_text=Save and submit metadata +metadata_save_approve_text=Save and approve metadata +metadata_status_editing_instance_created_text=Editing instance created # SiteName / Workflow / recordTitle statusName by userName status_change_default_email_subject={0} / Workflow / '{{'index:resourceTitleObject'}}' {1} by {2} status_change_default_email_text={0} modified the status of the record '{{'index:resourceTitleObject'}}'.\n\ @@ -101,7 +122,7 @@ Message: \n\ {1} \n\ \n\ View record: \n\ -{7} +{{link}} # SiteName / Task / recordTitle statusName by userName status_change_doiCreationTask_email_subject={0} / Task / {1} for '{{'index:resourceTitleObject'}}' @@ -113,8 +134,14 @@ Message: \n\ {1} \n\ \n\ View record: \n\ -{7} +{{link}} # TODO: Link to DOI creation panel +metadata_published_subject=%s / Metadata publication +metadata_published_text=The following records have been processed:\n\ +
    %s
+metadata_published_record_text=
  • The metadata {{index:resourceTitleObject}} has been published.
  • +metadata_unpublished_record_text=
  • The metadata {{index:resourceTitleObject}} has been unpublished.
  • +metadata_approved_published_record_text=
  • The metadata {{index:resourceTitleObject}} has been published as a new version.
  • api.groups.group_not_found=Group with ID ''{0}'' not found in this catalog. user_watchlist_subject=%s / %d updates in your watch list since %s @@ -131,14 +158,18 @@ user_watchlist_message=The following records have been updated:\n\ \n\ self_registration_disabled=User self-registration is disabled +self_registration_no_valid_mail=The email address is not allowed recaptcha_not_valid=Recaptcha is not valid metadata.title.createdFromTemplate=Copy of template %s created at %s metadata.title.createdFromRecord=Copy of record %s created at %s username.field.required=Username is required password.field.length=Password size should be between {min} and {max} characters password.field.invalid=Password must contain at least 1 uppercase, 1 lowercase, 1 number and 1 symbol. Symbols include: `~!@#$%^&*()-_=+[]{}\\|;:'",.<>/?'); +field.required.name=Name is required +field.required.email=Email address is required +field.notvalid.email=Email address is not valid api.exception.forbidden=Access denied -api.exception.forbidden.description=Access is denied. To access, try again with a user containing more priviledges. +api.exception.forbidden.description=Access is denied. To access, try again with a user containing more privileges. api.exception.resourceNotFound=Resource not found api.exception.resourceNotFound.description=Resource could not be located. api.exception.resourceAlreadyExists=Resource already exists @@ -168,9 +199,23 @@ exception.doi.missingSavedquery.description="Record ''{0}'' is in schema ''{1}'' exception.doi.recordNotConformantMissingInfo=Record is not conform with DataCite format exception.doi.recordNotConformantMissingInfo.description=Record ''{0}'' is not conform with DataCite format. {1} mandatory field(s) missing. {2} exception.doi.recordNotConformantMissingMandatory=Record is not conform with DataCite validation rules for mandatory fields -exception.doi.recordNotConformantMissingMandatory.description=Record ''{0}'' is not conform with DataCite validation rules for mandatory fields. Error is: {1}. Required fields in DataCite are: identifier, creators, titles, publisher, publicationYear, resourceType. Check the DataCite format output and adapt the record content to add missing information. +exception.doi.recordNotConformantMissingMandatory.description=Record ''{0}'' is not conform with DataCite validation rules for mandatory fields. Error is: {1}. Required fields in DataCite are: identifier, creators, titles, publisher, publicationYear, resourceType. Check the DataCite format output and adapt the record content to add missing information. exception.doi.recordInvalid=Record converted to DataCite format is invalid. -exception.doi.recordInvalid.description=Record ''{0}'' converted to DataCite format is invalid. Error is: {1}. Required fields in DataCite are: identifier, creators, titles, publisher, publicationYear, resourceType. Check the DataCite format output and adapt the record content to add missing information. +exception.doi.recordInvalid.description=Record ''{0}'' converted to DataCite format is invalid. Error is: {1}. Required fields in DataCite are: identifier, creators, titles, publisher, publicationYear, resourceType. Check the DataCite format output and adapt the record content to add missing information. +exception.doi.serverErrorCreate=Error creating DOI +exception.doi.serverErrorCreate.description=Error creating DOI: {0} +exception.doi.serverErrorRetrieve=Error retrieving DOI +exception.doi.serverErrorRetrieve.description=Error retrieving DOI: {0} +exception.doi.serverErrorDelete=Error deleting DOI +exception.doi.serverErrorDelete.description=Error deleting DOI: {0} +exception.doi.serverErrorUnregister=Error unregistering DOI +exception.doi.serverErrorUnregister.description=Error unregistering DOI: {0} +exception.doi.serverCanNotHandleRecord=DOI server can not handle the metadata +exception.doi.serverCanNotHandleRecord.description=DOI server ''{0}'' can not handle the metadata with UUID ''{1}'' +exception.doi.configurationMissing=DOI server configuration is not complete +exception.doi.configurationMissing.description=DOI server configuration is not complete. Check the DOI server configuration to complete it +exception.doi.notSupportedOperationError=Operation not supported +exception.doi.notSupportedOperationError.description={0} api.metadata.import.importedWithId=Metadata imported with ID '%s' api.metadata.import.importedWithUuid=Metadata imported with UUID '%s' api.metadata.import.importedFromXMLWithUuid=Metadata imported from XML with UUID '%s' @@ -195,3 +240,7 @@ api.metadata.share.errorMetadataNotApproved=The metadata '%s' it's not approved, api.metadata.share.ErrorUserNotAllowedToPublish=User not allowed to publish the metadata %s. %s api.metadata.share.strategy.groupOwnerOnly=You need to be administrator, or reviewer of the metadata group. api.metadata.share.strategy.reviewerInGroup=You need to be administrator, or reviewer of the metadata group or reviewer with edit privilege on the metadata. +api.metadata.status.errorGetStatusNotAllowed=Only the owner of the metadata can get the status. User is not the owner of the metadata. +api.metadata.status.errorSetStatusNotAllowed=Only the owner of the metadata can set the status of this record. User is not the owner of the metadata. + +feedback_subject_userFeedback=User feedback diff --git a/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties b/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties index 21500366c00..d93b300f600 100644 --- a/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties +++ b/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties @@ -23,6 +23,14 @@ mail_error=Erreur lors de l'envoi du mail. mail_config_test_subject=%s / Test / Configuration serveur de mail +mail_config_test_message=Message de test de %s\n\ +
    \n\ + \n\ +
    \n\ + \n\ + \n\ +
    \n\ +
    mail_config_test_success=Mail envoy\u00E9 \u00E0 %s. mail_config_test_only_admin=Seuls les administrateurs peuvent tester la configuration du serveur de mail. password_change_subject=%s / Mot de passe modifi\u00E9 @@ -45,13 +53,16 @@ user_password_sent=Si l''utilisateur existe, vous recevrez un courriel contenant user_password_changed=Le mot de passe de %s a \u00E9t\u00E9 mis \u00E0 jour. user_password_notchanged=\u00C9chec lors du changement de mot de passe de %s. Contactez le support. user_password_invalid_changekey=%s est une cl\u00E9 invalide pour %s. Les cl\u00E9s ne sont valides que pendant une journ\u00E9e. -user_with_that_email_found=Un utilisateur avec cette adresse email %s existe d\u00E9j\u00E0. -user_with_that_username_found=Un utilisateur avec ce nom d''utilisateur %s existe d\u00E9j\u00E0. +user_with_that_email_username_found=Un utilisateur avec cette adresse email ou ce nom d''utilisateur existe d\u00E9j\u00E0. register_email_admin_subject=%s / Cr\u00E9ation de compte pour %s en tant que %s register_email_admin_message=Cher administrateur,\n\ L'utilisateur %s vient de demander une cr\u00E9ation de compte pour %s.\n\ Salutation,\n\ L'\u00E9quipe %s. +register_email_group_admin_message=Cher administrateur,\n\ + L'utilisateur %s vient de demander une cr\u00E9ation de compte pour %s en groupe %s.\n\ + Salutation,\n\ + L'\u00E9quipe %s. register_email_subject=%s / Votre compte %s register_email_message=Cher utilisateur,\n\ Votre compte a \u00E9t\u00E9 cr\u00E9\u00E9 avec succ\u00E9s pour %s.\n\ @@ -65,6 +76,18 @@ register_email_message=Cher utilisateur,\n\ \n\ Salutations,\n\ L'\u00E9quipe %s. +register_email_group_message=Cher utilisateur,\n\ + Votre compte a \u00E9t\u00E9 cr\u00E9\u00E9 avec succ\u00E9s pour %s.\n\ + * Nom d'utilisateur : %s\n\ + * Mot de passe : %s\n\ + * Profil : %s\n\ + \n\ +Nous avons envoy\u00E9 votre demande de %s à l'administrateur du groupe %s. Vous serez contact\u00E9 rapidement.\n\ + Vous pouvez d\u00E9s \u00E0 pr\u00E9sent vous connecter.\n\ + %s\n\ + \n\ + Salutations,\n\ + L'\u00E9quipe %s. new_user_rating=%s / Nouvelle \u00E9valuation faite pour %s new_user_rating_text=Consulter la fiche %s user_feedback_title=%s / Nouveau commentaire sur %s / %s @@ -80,6 +103,9 @@ user_feedback_text=Utilisateur %s (%s - %s)\n\ \n\ Consulter la fiche %s status_email_text=L''utilisateur %s (%s) a \u00E9dit\u00E9 une fiche #%s +metadata_save_submit_text=Enregistrer et soumettre les m\u00E9tadonn\u00E9es +metadata_save_approve_text=Enregistrer et approuver les m\u00E9tadonn\u00E9es +metadata_status_editing_instance_created_text=L'instance de modification a \u00E9t\u00E9 cr\u00E9\u00E9e # SiteName / Workflow / recordTitle statusName by userName status_change_default_email_subject={0} / Cycle de vie / '{{'index:resourceTitleObject'}}' {1} par {2} status_change_default_email_text={0} a modifi\u00E9 l''\u00E9tat de la fiche '{{'index:resourceTitleObject'}}'.\n\ @@ -89,7 +115,7 @@ Message: \n\ {1} \n\ \n\ Consulter la fiche : \n\ -{7} +{{link}} # SiteName / Task / recordTitle statusName by userName status_change_doiCreationTask_email_subject={0} / Action / {1} pour '{{'index:resourceTitleObject'}}' @@ -102,13 +128,14 @@ Message: \n\ {1} \n\ \n\ Consulter la fiche : \n\ -{7} +{{link}} # TODO: Link to DOI creation panel metadata_published_subject=%s / Publication de m\u00E9tadonn\u00E9es metadata_published_text=Les fiches suivantes ont \u00E9t\u00E9 trait\u00E9es:\n\
      %s
    metadata_published_record_text=
  • La m\u00E9tadonn\u00E9e {{index:resourceTitleObject}} a \u00E9t\u00E9 publi\u00E9e.
  • metadata_unpublished_record_text=
  • La m\u00E9tadonn\u00E9e {{index:resourceTitleObject}} a \u00E9t\u00E9 d\u00E9publi\u00E9e.
  • +metadata_approved_published_record_text=
  • Une nouvelle version de la m\u00E9tadonn\u00E9e {{index:resourceTitleObject}} a \u00E9t\u00E9 publi\u00E9e.
  • api.groups.group_not_found=Le groupe avec l''identifiant ''{0}'' n''a pas \u00E9t\u00E9 trouv\u00E9 dans le catalogue. user_watchlist_subject=%s / %d mises \u00e0 jour dans vos fiches surveill\u00E9es %s @@ -125,10 +152,14 @@ user_watchlist_message=Les fiches suivantes ont \u00E9t\u00E9 mises \u00e0 jour \n\ self_registration_disabled=La cr\u00E9ation de compte par les utilisateurs est d\u00E9sactiv\u00E9e +self_registration_no_valid_mail=L''adresse email n''est pas autoris\u00E9e recaptcha_not_valid=Recaptcha invalide metadata.title.createdFromTemplate=Copie du mod\u00e8le %s cr\u00E9\u00E9e le %s metadata.title.createdFromRecord=Copie de la fiche %s cr\u00E9\u00E9e le %s username.field.required=Le nom d''utilisateur est requis +field.required.name=Nom est obligatoire +field.required.email=L''adresse mail est obligatoire +field.notvalid.email=L''adresse mail n''est pas valide password.field.length=Le mot de passe doit contenir entre {min} et {max} caract\u00E8res password.field.invalid=Le mot de passe doit contenir a minima 1 lettre majuscule, 1 minuscule, 1 chiffre et 1 symbole (ie. `~!@#$%^&*()-_=+[]{}\\|;:'",.<>/?')); api.exception.forbidden=L''acc\u00E8s est refus\u00E9 @@ -163,6 +194,20 @@ exception.doi.recordNotConformantMissingMandatory=La fiche n''est pas conforme a exception.doi.recordNotConformantMissingMandatory.description=La fiche ''{0}'' n''est pas conforme aux r\u00E8gles de validation DataCite pour les champs obligatoires. L''erreur est: {1}. Les champs obligatoires dans DataCite sont : identifiant, cr\u00E9ateurs, titres, \u00E9diteur, publicationYear, resourceType. V\u00E9rifiez la sortie au format DataCite et adaptez le contenu de la fiche pour ajouter les informations manquantes. exception.doi.recordInvalid=Le fiche converti n''est pas conforme au format DataCite exception.doi.recordInvalid.description=Le fiche ''{0}'' converti n''est pas conforme au format DataCite. L''erreur est: {1}. Les champs obligatoires dans DataCite sont : identifiant, cr\u00E9ateurs, titres, \u00E9diteur, ann\u00E9e de publication, type de ressource. V\u00E9rifier la sortie au format DataCite et adapter le contenu de la fiche pour ajouter les informations manquantes. +exception.doi.serverErrorCreate=Erreur lors de la cr\u00E9ation du DOI +exception.doi.serverErrorCreate.description=Erreur lors de la cr\u00E9ation du DOI : {0} +exception.doi.serverErrorRetrieve=Erreur lors de la r\u00E9cup\u00E9ration du DOI +exception.doi.serverErrorRetrieve.description=Erreur lors de la r\u00E9cup\u00E9ration du DOI : {0} +exception.doi.serverErrorDelete=Erreur lors de la suppression du DOI +exception.doi.serverErrorDelete.description=Erreur lors de la suppression du DOI : {0} +exception.doi.serverErrorUnregister=Erreur lors de la d\u00E9sinscription du DOI +exception.doi.serverErrorUnregister.description=Erreur lors de la d\u00E9sinscription du DOI {0} +exception.doi.serverCanNotHandleRecord=DOI server can not handle the metadata +exception.doi.serverCanNotHandleRecord.description=DOI server ''{0}'' can not handle the metadata with UUID ''{1}'' +exception.doi.configurationMissing=DOI server configuration is not complete +exception.doi.configurationMissing.description=DOI server configuration is not complete. Check the DOI server configuration to complete it +exception.doi.notSupportedOperationError=Op\u00E9ration non prise en charge +exception.doi.notSupportedOperationError.description={0} api.metadata.import.importedWithId=Fiche import\u00E9e avec l'ID '%s' api.metadata.import.importedWithUuid=Fiche import\u00E9e avec l'UUID '%s' api.metadata.import.importedFromXMLWithUuid=Fiche import\u00E9e depuis le fichier XML avec l'UUID '%s' @@ -187,3 +232,7 @@ api.metadata.share.errorMetadataNotApproved=La fiche '%s' n'est pas approuv\u00E api.metadata.share.ErrorUserNotAllowedToPublish=L'utilisateur n'est pas autoris\u00E9 \u00E0 publier la fiche %s. %s api.metadata.share.strategy.groupOwnerOnly=Vous devez \u00EAtre administrateur ou relecteur du groupe de la fiche. api.metadata.share.strategy.reviewerInGroup=Vous devez \u00EAtre administrateur ou relecteur du groupe de la fiche ou relecteur avec un privil\u00E8ge de modification sur les fiches. +api.metadata.status.errorGetStatusNotAllowed=Seul le propri\u00E9taire des m\u00E9tadonn\u00E9es peut obtenir le statut de cet enregistrement. L'utilisateur n'est pas le propri\u00E9taire des m\u00E9tadonn\u00E9es +api.metadata.status.errorSetStatusNotAllowed=Seul le propri\u00E9taire des m\u00E9tadonn\u00E9es peut d\u00E9finir le statut de cet enregistrement. L'utilisateur n'est pas le propri\u00E9taire des m\u00E9tadonn\u00E9es + +feedback_subject_userFeedback=Commentaire de l'utilisateur diff --git a/core/src/test/resources/org/fao/geonet/kernel/forest.xml b/core/src/test/resources/org/fao/geonet/kernel/forest.xml new file mode 100644 index 00000000000..cde5dc38252 --- /dev/null +++ b/core/src/test/resources/org/fao/geonet/kernel/forest.xml @@ -0,0 +1,837 @@ + + + 837750fd-5790-4263-ad6d-cd94c43cfe5b + + + + + + + + + + + + + + Atlas of Switzerland + + + Atlas der Schweiz + + + Atlas de la Suisse + + + Atlante della Svizzera + + + Atlas of Switzerland + + + + + + + + + +41 44 633 11 53 + + + + + + + Zurich + + + Zürich + + + Zurich + + + Zurigo + + + Zurich + + + + + 8093 + + + CH + + + atlasinfo@ethz.ch + + + + + + + https://www.atlasderschweiz.ch + + + text/html + + + + + 09h00 - 10h30 / 11h00 - 12h30 / 14h00 - 18h00 GMT+1 + + + + + + + + + + 2023-01-19 + + + ISO 19115/19119 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/4326 + + + INSPIRE RS registry + + + + + + + + + + + Forest + + + Wald + + + Forêt + + + Bosco + + + Forest + + + + + Forest + + + Wald + + + Forêt + + + Bosco + + + Forest + + + + + + + 2014-11-17 + + + + + + + + + + 2016-06-03 + + + + + + + + + + 2020-09-25 + + + + + + + + + + 34 + + + ads:online:maps + + + + + + + + + + Forest. Map type: Choropleths. Spatial extent: Switzerland. Time: 2010 + + + Wald. Kartentyp: Choroplethen. Räumliche Ausdehnung: Schweiz. Zeit: 2010 + + + Forêt. Type de carte: Choroplètes. Étendue spatiale: Suisse. Unité temporelle: 2010 + + + Bosco. Tipo di carta: Coropletiche. Estensione spaziale: Svizzera. Unità temporale: 2010 + + + Forest. Map type: Choropleths. Spatial extent: Switzerland. Time: 2010 + + + + + + + + + + Atlas of Switzerland + + + Atlas der Schweiz + + + Atlas de la Suisse + + + Atlante della Svizzera + + + Atlas of Switzerland + + + + + + + + + +41 44 633 11 53 + + + + + + + Zurich + + + Zürich + + + Zurich + + + Zurigo + + + Zurich + + + + + 8093 + + + CH + + + atlasinfo@ethz.ch + + + + + + + https://www.atlasderschweiz.ch + + + text/html + + + + + 09h00 - 10h30 / 11h00 - 12h30 / 14h00 - 18h00 GMT+1 + + + + + + + + + + + + Swiss Federal Office of Topography + + + Bundesamt für Landestopografie + + + Office fédéral de topographie + + + Ufficio federale di topografia + + + Swiss Federal Office of Topography + + + + + + + + + Wabern + + + Wabern + + + Wabern + + + Wabern + + + Wabern + + + + + CH + + + info@swisstopo.ch + + + + + + + http://www.swisstopo.admin.ch/ + + + text/html + + + + + + + + + + + + + + + + + + + + + Basemaps + + + Basiskarten + + + Fonds de carte + + + Carte di base + + + Basemaps + + + + + Elements + + + Elemente + + + Éléments + + + Elementi + + + Elements + + + + + + + + + + Atlas of Switzerland - Categories + + + Atlas der Schweiz - Kategorien + + + Atlas de la Suisse - Catégories + + + Atlante della Svizzera - Categorie + + + Atlas of Switzerland - Categories + + + + + + + 2016-04-01 + + + + + + + + + + + + + + Land cover + + + Bodenbedeckung + + + Couverture du sol + + + Copertura del suolo + + + Land cover + + + + + + + + + + GEMET - INSPIRE themes, version 1.0 + + + GEMET - INSPIRE themes, version 1.0 + + + GEMET - INSPIRE themes, version 1.0 + + + GEMET - INSPIRE themes, version 1.0 + + + GEMET - INSPIRE themes, version 1.0 + + + + + + + 2008-06-01 + + + + + + + + + + + + + + See end-user license agreement + + + Siehe Endbenutzer-Lizenzvertrag + + + Voir conditions générales d'utilisation + + + Vedi accordo di licenza con l'utente finale + + + See end-user license agreement + + + + + + + + + + + + There are no limitations on public access to spatial data sets and services. + + + + + + + + + + The conditions applying to access and use are unknown. + + + + + + + + + f6243e5a-3816-49ab-9eeb-14f0c16d8847 + + + + + + + + + + + + + + + + + 200000 + + + + + + + + + + + + + + + + + + + + + + imageryBaseMapsEarthCover + + + imageryBaseMapsEarthCover_EarthCover + + + + + Switzerland + + + Schweiz + + + Suisse + + + Svizzera + + + Switzerland + + + + + + + 5.606041613827549 + + + 10.988229452947234 + + + 45.53396348515653 + + + 47.97997376576611 + + + + + + + + 2010-01-01T00:00:00 + 2010-12-31T23:59:59 + + + + + + + + + + + + + + Digital map in a web atlas + + + Digitale Karte in einem Web-Atlas + + + Carte digitale dans un atlas web + + + Mappa digitale in un web atlante + + + Digital map in a web atlas + + + + + - + + + + + + + + + https://www.atlasofswitzerland.ch/forest/ + + + WWW:LINK-1.0-http--link + + + + + + + + + + + + + + + + + + + + + + Conformity_001 + + + INSPIRE + + + + + + + + + COMMISSION REGULATION (EU) No 1089/2010 of 23 November 2010 + implementing Directive 2007/2/EC of the European Parliament and of the + Council as regards interoperability of spatial data sets and services + + + VERORDNUNG (EG) Nr. 1089/2010 + DER KOMMISSION vom 23. November 2010 zur Durchführung der Richtlinie + 2007/2/EG des Europäischen Parlaments und des Rates hinsichtlich der + Interoperabilität von Geodatensätzen und -diensten + + + RÈGLEMENT (UE) No 1089/2010 + DE LA COMMISSION du 23 novembre 2010 portant modalités d'application + de la directive 2007/2/CE du Parlement européen et du Conseil en ce + qui concerne l'interopérabilité des séries et des services de + données géographiques + + + REGOLAMENTO (UE) N. 1089/2010 + DELLA COMMISSIONE del 23 novembre 2010 recante attuazione della + direttiva 2007/2/CE del Parlamento europeo e del Consiglio per + quanto riguarda l'interoperabilità dei set di dati territoriali e + dei servizi di dati territoriali + + + COMMISSION REGULATION (EU) No + 1089/2010 of 23 November 2010 implementing Directive 2007/2/EC of + the European Parliament and of the Council as regards + interoperability of spatial data sets and services + + + + + + + 2010-12-08 + + + + + + + + + + See the referenced specification + + + Siehe referenzierte Spezifikation + + + Voir la spécification référencée + + + Vedi la specifica riferimento + + + See the referenced specification + + + + + true + + + + + + + + + Source data: Swiss Federal Office of Topography. Data processing: Atlas of Switzerland + + + Ursprungsdaten: Bundesamt für Landestopografie. + Datenverarbeitung: Atlas der Schweiz + + + Données originales: Office fédéral de topographie. + Traitement de données: Atlas de la Suisse + + + Dati di origine: Ufficio federale di topografia. + Trattamento dei dati: Atlante della Svizzera + + + Source data: Swiss Federal Office of Topography. Data + processing: Atlas of Switzerland + + + + + + + + \ No newline at end of file diff --git a/core/src/test/resources/org/fao/geonet/kernel/holocene.xml b/core/src/test/resources/org/fao/geonet/kernel/holocene.xml new file mode 100644 index 00000000000..1d80e1256d6 --- /dev/null +++ b/core/src/test/resources/org/fao/geonet/kernel/holocene.xml @@ -0,0 +1,919 @@ + + + 4d2794d4-447e-4bbe-89ba-ab11cfdfc7b8 + + + + + + + + + + + + + + Atlas of Switzerland + + + Atlas der Schweiz + + + Atlas de la Suisse + + + Atlante della Svizzera + + + Atlas of Switzerland + + + + + + + + + +41 44 633 11 53 + + + + + + + Zurich + + + Zürich + + + Zurich + + + Zurigo + + + Zurich + + + + + 8093 + + + CH + + + atlasinfo@ethz.ch + + + + + + + https://www.atlasderschweiz.ch + + + text/html + + + + + 09h00 - 10h30 / 11h00 - 12h30 / 14h00 - 18h00 GMT+1 + + + + + + + + + + 2023-02-28 + + + ISO 19115/19119 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/4326 + + + INSPIRE RS registry + + + + + + + + + + + Volcanic eruptions in the holocene + + + Vulkane und Eruptionen weltweit + + + Eruptions volcaniques durant l'Holocène + + + Eruzioni vulcaniche nell’olocene + + + Volcanic eruptions in the holocene + + + + + Volcanoes: eruptions + + + Vulkane: Eruptionen + + + Volcans: éruptions + + + Vulcani: eruzioni + + + Volcanoes: eruptions + + + + + + + 2014-08-28 + + + + + + + + + + 2019-02-04 + + + + + + + + + + 2023-02-27 + + + + + + + + + + 163 + + + ads:online:maps + + + + + + + + + + Volcanic eruptions in the holocene. Map type: Symbols. Spatial extent: World. Times: 10,000–0 BC, 0–1699, 1700–1799, 1800–1899, 1900–1999, 2000–2021, Total + + + Vulkane und Eruptionen weltweit. Kartentyp: Symbole. Räumliche Ausdehnung: Welt. Zeiten: 10 000–0 v. Chr., 0–1699, 1700–1799, 1800–1899, 1900–1999, 2000–2021, Total + + + Eruptions volcaniques durant l'Holocène. Type de carte: Symboles. Étendue spatiale: Monde. Unités temporelles: 10 000–0 avant J-C, 0–1699, 1700–1799, 1800–1899, 1900–1999, 2000–2021, Total + + + Eruzioni vulcaniche nell’olocene. Tipo di carta: Simboli. Estensione spaziale: Mondo. Unità temporali: 10.000–0 a.C., 0–1699, 1700–1799, 1800–1899, 1900–1999, 2000–2021, Totale + + + Volcanic eruptions in the holocene. Map type: Symbols. Spatial extent: World. Times: 10,000–0 BC, 0–1699, 1700–1799, 1800–1899, 1900–1999, 2000–2021, Total + + + + + + + + + + Atlas of Switzerland + + + Atlas der Schweiz + + + Atlas de la Suisse + + + Atlante della Svizzera + + + Atlas of Switzerland + + + + + + + + + +41 44 633 11 53 + + + + + + + Zurich + + + Zürich + + + Zurich + + + Zurigo + + + Zurich + + + + + 8093 + + + CH + + + atlasinfo@ethz.ch + + + + + + + https://www.atlasderschweiz.ch + + + text/html + + + + + 09h00 - 10h30 / 11h00 - 12h30 / 14h00 - 18h00 GMT+1 + + + + + + + + + + + + Smithsonian Institution's Global Volcanism Program + + + Smithsonian Institution's Global Volcanism Program + + + Smithsonian Institution's Global Volcanism Program + + + Smithsonian Institution's Global Volcanism Program + + + Smithsonian Institution's Global Volcanism Program + + + + + + + + + Washington D.C. + + + Washington D.C. + + + Washington D.C. + + + Washington D.C. + + + Washington D.C. + + + + + US + + + gvp@si.edu + + + + + + + https://volcano.si.edu/ + + + text/html + + + + + + + + + + + + + + National Oceanic and Atmospheric Administration + + + National Oceanic and Atmospheric Administration + + + National Oceanic and Atmospheric Administration + + + National Oceanic and Atmospheric Administration + + + National Oceanic and Atmospheric Administration + + + + + + + + + Washington D.C. + + + Washington D.C. + + + Washington D.C. + + + Washington D.C. + + + Washington D.C. + + + + + US + + + haz.info@noaa.gov + + + + + + + http://www.noaa.gov/ + + + text/html + + + + + + + + + + + + + + + + + + + + + Global Switzerland + + + Globale Schweiz + + + La Suisse à l’international + + + Svizzera internazionale + + + Global Switzerland + + + + + Nature and Environment + + + Natur und Umwelt + + + Nature et Environnement + + + Natura e Ambiente + + + Nature and Environment + + + + + Geology and raw materials + + + Geologie und Rohstoffe + + + Géologie et matières premières + + + Geologia e materie prime + + + Geology and raw materials + + + + + + + + + + Atlas of Switzerland - Categories + + + Atlas der Schweiz - Kategorien + + + Atlas de la Suisse - Catégories + + + Atlante della Svizzera - Categorie + + + Atlas of Switzerland - Categories + + + + + + + 2016-04-01 + + + + + + + + + + + + + + Geology + + + Geologie + + + Géologie + + + Geologia + + + Geology + + + + + + + + + + GEMET - INSPIRE themes, version 1.0 + + + GEMET - INSPIRE themes, version 1.0 + + + GEMET - INSPIRE themes, version 1.0 + + + GEMET - INSPIRE themes, version 1.0 + + + GEMET - INSPIRE themes, version 1.0 + + + + + + + 2008-06-01 + + + + + + + + + + + + + + See end-user license agreement + + + Siehe Endbenutzer-Lizenzvertrag + + + Voir conditions générales d'utilisation + + + Vedi accordo di licenza con l'utente finale + + + See end-user license agreement + + + + + + + + + + + + There are no limitations on public access to spatial data sets and services. + + + + + + + + + + The conditions applying to access and use are unknown. + + + + + + + + + f6243e5a-3816-49ab-9eeb-14f0c16d8847 + + + + + + + + + + + + + + + + + 1000000 + + + + + + + + + + + + + + + + + + + + + + geoscientificInformation + + + geoscientificInformation_Geology + + + + + World + + + Welt + + + Monde + + + Mondo + + + World + + + + + + + -179.97 + + + 179.58 + + + -78.5 + + + 88.27 + + + + + + + + -10000-01-01T00:00:00 + 2021-12-31T23:59:59 + + + + + + + + + + + + + + Digital map in a web atlas + + + Digitale Karte in einem Web-Atlas + + + Carte digitale dans un atlas web + + + Mappa digitale in un web atlante + + + Digital map in a web atlas + + + + + - + + + + + + + + + https://www.atlasofswitzerland.ch/volcanic-eruptions-in-the-holocene/ + + + WWW:LINK-1.0-http--link + + + + + + + + + + + + + + + + + + + + + + Conformity_001 + + + INSPIRE + + + + + + + + + COMMISSION REGULATION (EU) No 1089/2010 of 23 November 2010 + implementing Directive 2007/2/EC of the European Parliament and of the + Council as regards interoperability of spatial data sets and services + + + VERORDNUNG (EG) Nr. 1089/2010 + DER KOMMISSION vom 23. November 2010 zur Durchführung der Richtlinie + 2007/2/EG des Europäischen Parlaments und des Rates hinsichtlich der + Interoperabilität von Geodatensätzen und -diensten + + + RÈGLEMENT (UE) No 1089/2010 + DE LA COMMISSION du 23 novembre 2010 portant modalités d'application + de la directive 2007/2/CE du Parlement européen et du Conseil en ce + qui concerne l'interopérabilité des séries et des services de + données géographiques + + + REGOLAMENTO (UE) N. 1089/2010 + DELLA COMMISSIONE del 23 novembre 2010 recante attuazione della + direttiva 2007/2/CE del Parlamento europeo e del Consiglio per + quanto riguarda l'interoperabilità dei set di dati territoriali e + dei servizi di dati territoriali + + + COMMISSION REGULATION (EU) No + 1089/2010 of 23 November 2010 implementing Directive 2007/2/EC of + the European Parliament and of the Council as regards + interoperability of spatial data sets and services + + + + + + + 2010-12-08 + + + + + + + + + + See the referenced specification + + + Siehe referenzierte Spezifikation + + + Voir la spécification référencée + + + Vedi la specifica riferimento + + + See the referenced specification + + + + + true + + + + + + + + + Source data: Smithsonian Institution's Global Volcanism Program, National Oceanic and Atmospheric Administration. Data processing: Atlas of Switzerland + + + Ursprungsdaten: Smithsonian Institution's Global Volcanism Program, National Oceanic and Atmospheric Administration. + Datenverarbeitung: Atlas der Schweiz + + + Données originales: Smithsonian Institution's Global Volcanism Program, National Oceanic and Atmospheric Administration. + Traitement de données: Atlas de la Suisse + + + Dati di origine: Smithsonian Institution's Global Volcanism Program, National Oceanic and Atmospheric Administration. + Trattamento dei dati: Atlante della Svizzera + + + Source data: Smithsonian Institution's Global Volcanism Program, National Oceanic and Atmospheric Administration. Data + processing: Atlas of Switzerland + + + + + + + + \ No newline at end of file diff --git a/core/src/test/resources/org/fao/geonet/kernel/metadata.iso19115-3.xml b/core/src/test/resources/org/fao/geonet/kernel/metadata.iso19115-3.xml new file mode 100644 index 00000000000..78aa4c939de --- /dev/null +++ b/core/src/test/resources/org/fao/geonet/kernel/metadata.iso19115-3.xml @@ -0,0 +1,1555 @@ + + + + + + {uuid} + + + urn:uuid + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Production géomatique et traitement de données (SPW - Secrétariat général - SPW Digital + - Département Données transversales - Production géomatique et traitement de données) + + + + + + + + geometrologie@spw.wallonie.be + + + + + + + + + + + + + 2023-07-04T07:51:35.236Z + + + + + + + + + + 2019-01-10T12:00:00 + + + + + + + + + + ISO 19115 + + + 2003/Cor 1:2006 + + + + + + + + https://metawal.wallonie.be/geonetwork/srv/api/records/fafb9fc7-4e32-4a40-8163-c64966cb573c + + + + + + + + + + + + + EPSG:3812 + + + ETRS89 / Belgian Lambert 2008 (EPSG:3812) + + + + + + + + + + + + + + Utilisation du Sol en Wallonie - WALOUS 2018 + + + WALOUS_UTS__2018 + + + + + 2020-09-28 + + + + + + + + + + 2020-10-30 + + + + + + + + + + fafb9fc7-4e32-4a40-8163-c64966cb573c + + + http://geodata.wallonie.be/id/ + + + + + + + WALOUS__WAL_UTS__2018 + + + BE.SPW.INFRASIG.CARTON + + + + + + + Cette couche de données reprend la cartographie de l’utilisation du sol de l’ensemble du + territoire wallon pour l’année 2018 (WAL_UTS__2018). + + La cartographie de l’utilisation du sol de l’ensemble du territoire wallon pour l’année 2018 (WAL_UTS__2018) + est complémentaire de la cartographie de l'occupation du sol (WAL_OCS__2018) produite conjointement dans le + cadre de la subvention de recherche WALlonie Occupation et Utilisation du Sol (WALOUS). + + L’utilisation du sol représentée dans la donnée WAL_UTS__2018 se définit comme le « Territoire caractérisé + selon sa dimension fonctionnelle ou son objet socioéconomique actuel (par exemple, résidentiel, industriel, + commercial, agricole, forestier, récréatif) » (directive européenne INSPIRE 2007/2/CE). + La donnée WAL_UTS__2018 fournit donc une information sur l’usage des sols par parcelle cadastrale et pour les + espaces non-cadastrés. + Prochainement, cette information sera consolidée par géométrie métier (voir ressources associées). + + Les spécifications techniques de la donnée WAL_UTS__2018 résultent d’une procédure d’analyse des besoins et de + co-constructions avec un panel d’acteurs wallons. + Une vingtaine de géodonnées sont intégrées pour la construction de la donnée WAL_UTS__2018 . La géométrie de + représentation est définie par le croisement entre : + - Le plan parcellaire cadastral (v. 01/01/2019, © SPF-Finance) ; + - Le squelette vectoriel construit par intégration des données du réseau routier et délinéation du bâti du + PICC 2018 (© SPW) et des cours d’eau navigables et des chemins de fer de l’IGN TOP10vGIS (© IGN) ; + - La Carte d’Occupation des Sols de Wallonie (WAL_OCS__2018) produite dans le cadre de la subvention de + recherche WALOUS ; + - La matrice cadastrale définissant la nature déclarée pour chaque parcelle cadastrale (v. 01/01/2019, © + SPF-Finance) ; + - Le Registre national des Personnes Physiques 2018 géocodé au point adresse (RNPP, Source : Statbel + (Direction générale statistique – Statistics Belgium)) ; + - Le répertoire d’entreprises DBRIS 2018 géolocalisées à la parcelle cadastrale (Source : Statbel (Direction + générale statistique – Statistics Belgium)) ; + - Le parcellaire agricole anonyme 2018 (© SPW) ; + - L’inventaire des sites à réaménager de droit 2018 (© SPW) ; + - Le parcellaire forestier public 2018 (© SPW) ; + - L’inventaire des recyparcs (© SPW) ; + - La base de données « conservation de la nature » (© SPW) ; + - Le Réseau Natura 2000 en vigueur 2018 (© SPW) ; + - Le Plan de Secteur 2018 (© SPW) ; + - La carte des écoles de Wallonie 2019 (© ISSeP/SPW) ; + - L’inventaire géolocalisé des établissements pour ainés 2018 (© SPW) ; + - Les sites SEVESO 2018 (© SPW) ; + - L’inventaire des campings 2018 (© SPW) ; + - L’inventaire consolidé des éoliennes 2020 (© ISSeP/SPW) ; + - L’inventaire ponctuel (centroïde) des carrières actives 2010 (inventaire POTY) (© SPW) ; + - L’IGN Top-10vGIS 2017-2020 (© IGN) ; + - Les plantations de sapins de noël 2015 (© SPW) ; + - Le Projet Informatique de Cartographie Continue (v5.2019, © SPW). + + Au sein d’une approche automatisée par base de données spatiales (PostgreSQL, PostGIS, Python, Jupyter + Notebook), l’ensemble des données d’entrée (bases de données alphanumériques, polygones et raster) sont + traduites dans les différentes légendes. + Par parcelle cadastrale (unité de cartographie), ces données ainsi que l’occupation du sol sont synthétisées + par une série d’indicateurs statistiques (présence/absence, nombre d’éléments, proportions, mode, + recouvrement). Ces indicateurs alimentent les règles de classification qui attribuent plusieurs codes : + • L’ensemble des classes rencontrées (avec critères de superficie et de recouvrement) dans cette parcelle + cadastrale : reprise dans l’attribut « all_hilucs » ; + • Une classe reprenant un code unique identifiant la principale utilisation par nos règles : représentée par « + walousmaj », générée dans une volonté de représentation. Walousmaj est donc une représentation simplifiée et + n'est dès lors pas le reflet de l'ensemble des utilisations pouvant être rencontrées dans cette parcelle + cadastrale. L’attribut « walousmaj » présente l’utilisation du sol principale selon un amendement de la + légende INSPIRE résultant de la procédure de co-construction avec les utilisateurs wallons ; Elle se décline + en 3 niveaux de détails; + • La classification compatible INSPIRE selon les scénarios 1 et 2 (attributs « hilucsLandUse » - légende « + Hierarchical Land Use Classification System (HILUCS) ».) : la parcelle cadastrale est caractérisée par une ou + plusieurs utilisations du sol listées de manière non ordonnée et non-proportionnée. + + Etant issue du croisement automatisé d'une vingtaine de géodonnées, la qualité de la donnée WAL_UTS est + dépendante de la qualité (géométrique, complétude, …) des géodonnées utilisées au sein de cette approche + automatisée. + De plus, ce croisement est régi par un ensemble de règles (voir rapport disponible sur le Géoportail). L'ordre + d'application de ces règles a un impact sur la classe considérée comme "principale utilisation" (représentée + par la symbologie du webservice). Pour une utilisation complète de la donnée WAL_UTS, il est conseillé de se + rapporter au champ "all_HILUCS" + + Néanmoins, la donnée WAL_UTS__2018 a été consolidée via une procédure de contrôle à laquelle un groupe + d’experts wallons a participé. WAL_UTS__2018 a été enfin validée au moyen d’un set de validation de 1200 + parcelles par un expert. Sur base de cette validation, l’exactitude de la carte est de 83% au niveau 1 de la + légende INSPIRE HILUCS. Ces deux procédures ont permis de renforcer l’analyse critique des résultats et + contribuer à l’élaboration de recommandations d’usage et de mise à jour. + + L’information sur l’utilisation du sol est fournie, pour les deux types de représentation spatiale, dans le + système de projection Lambert Belge 2008 (EPSG : 3812 – Pour usage en LB72, voir information sur la grille + NTV2 - http://geoportail.wallonie.be/home/ressources/outils/Lambert-belge-2008-LB08.html). + + La mise en œuvre de la donnée WAL_UTS__2018 s’inscrit dans le cadre du projet WALOUS (2017-2020) subventionné + par la Région wallonne et réalisé par un consortium de deux universités (UCLouvain, ULB) et d’un centre de + recherche public de type UAP (ISSeP). De ce fait, la source à mentionner lors de l'utilisation de cette donnée + est "SPW - UCLouvain/ULB/ISSeP". + + + + + + + + + + + Production géomatique et traitement de données (SPW - Secrétariat général - SPW + Digital - Département Données transversales - Production géomatique et traitement de données) + + + + + + + + geometrologie@spw.wallonie.be + + + + + + + + + + + + + + + + + + Service public de Wallonie (SPW) + + + + + + + helpdesk.carto@spw.wallonie.be + + + + + + + https://geoportail.wallonie.be + + + WWW:LINK + + + Géoportail de la Wallonie + + + Géoportail de la Wallonie + + + + + + + + + + + + + + + + + + + + + Université Libre de Bruxelles (ULB) + + + + + + + ewolff@ulb.ac.be + + + + + + + + + + + + + + + + + + Université catholique de Louvain (UCL) + + + + + + + pierre.Defouny@uclouvain.be + + + + + + + + + + + + + + + + + + Institut Scientifique de Service Public (ISSeP) + + + + + + + ctg@issep.be + + + + + + + + + + + + + + + + + + Université Libre de Bruxelles (ULB) + + + + + + + ewolff@ulb.ac.be + + + + + + + + + Taïs Grippa + + + + + + + Moritz Lennert + + + + + + + Augustin Martinet + + + + + + + Sabine Vanhuysse + + + + + + + Eléonore Wolff + + + + + + + + + + + + + + + + Université catholique de Louvain (UCL) + + + + + + + pierre.Defouny@uclouvain.be + + + + + + + + + Céline Bassine + + + + + + + Céline Champagne + + + + + + + Pierre Defourny + + + + + + + Julien Radoux + + + + + + + + + + + + + + + + Institut Scientifique de Service Public (ISSeP) + + + + + + + ctg@issep.be + + + + + + + + + Benjamin Beaumont + + + + + + + Eric Hallot + + + + + + + Gérard Swinnen + + + + + + + Laura Van de Vyvere + + + + + + + + + + + + + + + + Production géomatique et traitement de données (SPW - Secrétariat général - SPW + Digital - Département Données transversales - Production géomatique et traitement de données) + + + + + + + + geometrologie@spw.wallonie.be + + + + + + + + + + + + + + + + 1 + + + + + imageryBaseMapsEarthCover + + + + + Région wallonne + + + + + 2.75 + + + 6.50 + + + 49.45 + + + 50.85 + + + + + + + + + + + + 2018-01-01 + 2018-12-31 + + + + + + + + + + + https://metawal.wallonie.be/geonetwork/srv/api/records/fafb9fc7-4e32-4a40-8163-c64966cb573c/attachments/WAL_UTS__2018_niv1.png + + + + WAL_UTS__2018_niv1.png + + + + + + + + https://metawal.wallonie.be/geonetwork/srv/api/records/fafb9fc7-4e32-4a40-8163-c64966cb573c/attachments/WAL_UTS__2018.png + + + + WAL_UTS__2018.png + + + + + + + + https://metawal.wallonie.be/geonetwork/srv/api/records/fafb9fc7-4e32-4a40-8163-c64966cb573c/attachments/WAL_UTS__2018_niv3.png + + + + WAL_UTS__2018_niv3.png + + + + + + + + Données de base + + + + + Nature et environnement + + + + + Aménagement du territoire + + + + + Sol et sous-sol + + + + + + + + + Thèmes du + géoportail wallon + + + + + + 2014-01-01 + + + + + + + + + + 2014-06-26 + + + + + + + + + + + geonetwork.thesaurus.external.theme.Themes_geoportail_wallon_hierarchy + + + + + + + + + + + + WalOnMap + + + BDInfraSIG + + + Reporting INSPIRENO + + + Open Data + + + PanierTelechargementGeoportail + + + + + + + + Mots-clés InfraSIG + + + + + 2022-10-03 + + + + + + + + + + 2022-10-03 + + + + + + + + + + + geonetwork.thesaurus.external.theme.infraSIG + + + + + + + + + + + + Régional + + + + + + + + Champ géographique + + + + + + 2019-01-01 + + + + + + + + + + 2019-05-22 + + + + + + + + + + + geonetwork.thesaurus.external.theme.httpinspireeceuropaeumetadatacodelistSpatialScope-SpatialScope + + + + + + + + + + + + Utilisation du sol + + + Usage du sol + + + WALOUS + + + Télédétection + + + Aménagement du territoire + + + UTS + + + COSW + + + + + + + + + + No + limitations to public access + + + + + + + + Conditions d'accès et d'utilisation spécifiques + + + + + + Les + conditions générales d'utilisation s'appliquent. + + + + Les + conditions générales d'accès s’appliquent. + + + + + Les conditions générales d'utilisation s'appliquent et sont étendues par les conditions particulières de + type C + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Modèle de la donnée Utilisation du Sol en Wallonie - WALOUS 2018 + + + + + + https://metawal.wallonie.be/geonetwork/srv/api/records/fafb9fc7-4e32-4a40-8163-c64966cb573c/attachments/MODELE%20WALOUS_WAL_UTS.vsd.pdf + + + + Modèle de la donnée Utilisation du Sol en Wallonie - WALOUS 2018 + + + + Structure de la couche WALOUS 2018 - Utilisation du sol [WAL_UTS__2018] + + + + + + + + + + + + + + + + ESRI File + Geodatabase (.fgdb) + + + + + + + + + + + + OGC + GeoPackage (.gpkg) + + + + + + + + + + + + + + + + + Service public de Wallonie (SPW) + + + + + + + helpdesk.carto@spw.wallonie.be + + + + + + + + + + + + + Les instructions pour obtenir une copie physique d’une donnée sont détaillées sur + https://geoportail.wallonie.be/telecharger. + + Sources à mentionner : SPW - UCLouvain/ULB/ISSeP. + + + + + + + + + + + + + https://geoportail.wallonie.be/walonmap/#ADU=https://geoservices.wallonie.be/arcgis/rest/services/SOL_SOUS_SOL/WALOUS_UTILISATION_SOL/MapServer + + + + WWW:LINK + + + Application WalOnMap - Toute la Wallonie à la carte + + + Application cartographique du Geoportail (WalOnMap) qui permet de découvrir les + données géographiques de la Wallonie. + + + + + + + + + + + + https://geoservices.wallonie.be/arcgis/rest/services/SOL_SOUS_SOL/WALOUS_UTILISATION_SOL/MapServer + + + + ESRI:REST + + + Service de visualisation ESRI-REST + + + Adresse de connexion au service de visualisation ESRI-REST de la couche de données + "Utilisation du Sol en Wallonie - WALOUS 2018" + + + + + + + + + + + + https://geoservices.wallonie.be/arcgis/services/SOL_SOUS_SOL/WALOUS_UTILISATION_SOL/MapServer/WMSServer?request=GetCapabilities&service=WMS + + + + OGC:WMS + + + Service de visualisation WMS + + + Adresse de connexion au service de visualisation WMS de la couche de données + "Utilisation du Sol en Wallonie - WALOUS 2018" + + + + + + + + + + + + https://metawal.wallonie.be/geonetwork/srv/api/records/fafb9fc7-4e32-4a40-8163-c64966cb573c/attachments/Symbologie_WALOUS_UTS_2018.pdf + + + + WWW:LINK + + + application/pdf + + + Document reprenant la symbologie utilisée dans WALOUS_UTS_2018 + + + + + + + + + + + + https://metawal.wallonie.be/geonetwork/srv/api/records/fafb9fc7-4e32-4a40-8163-c64966cb573c/attachments/Table_symbologie_WALOUS_UTS.xlsx + + + + WWW:LINK + + + application/vnd.openxmlformats-officedocument.spreadsheetml.sheet + + + + Table_symbologie_WALOUS_UTS.xlsx + + + + + + + + + + + https://metawal.wallonie.be/geonetwork/srv/api/records/fafb9fc7-4e32-4a40-8163-c64966cb573c/attachments/Description_legende_WALOUS_UTS_2018.pdf + + + + WWW:LINK + + + application/vnd.openxmlformats-officedocument.spreadsheetml.sheet + + + + Description_legende_WALOUS_UTS_2018.pdf + + + + + + + + + + http://geoportail.wallonie.be/walous + + + WWW:LINK + + + Walous sur le Géoportail + + + Page du Géoportail présentant WALOUS + + + + + + + + + + https://storymaps.arcgis.com/stories/11231ee7e2004d5aad12496a85a5fc15 + + + + WWW:LINK + + + Story Map de présentation de WALOUS + + + Story map présentant WALOUS + + + + + + + + + + + https://metawal.wallonie.be/geonetwork/srv/api/records/fafb9fc7-4e32-4a40-8163-c64966cb573c/attachments/Correspondance_COSW2007_Walousmaj2018.xlsx + + + + WWW:DOWNLOAD-1.0-http--download + + + Correspondance COSW2007 Walousmaj2018 + + + Tableau de correspondance entre les classes de WALOUS 2018 et celles de la + COSW2007 + + + + + + + + + + + + + + + + + + + + + + + + + + + + RÈGLEMENT (UE) N o 1089/2010 DE LA + COMMISSION du 23 novembre 2010 portant modalités d'application de la directive 2007/2/CE du + Parlement européen et du Conseil en ce qui concerne l'interopérabilité des séries et des services + de données géographiques + + + + + + 2010-12-08 + + + + + + + + + + Voir la spécification référencée + + + true + + + + + + + + + + + Les étapes principales de production de la donnée WAL_UTS__2018 sont les suivantes : + - Acquisition des données d’entrée et prétraitements ; + - Calculs de statistiques zonales par parcelles cadastrales ; + - Classification sur bases de règles SQL automatisées ; + - Contrôle de qualité ; + - Publication. + + + + + + + + + + + + + + + + + Légende du webservice + + + + + + https://geoservices.wallonie.be/arcgis/rest/services/SOL_SOUS_SOL/WALOUS_UTILISATION_SOL/MapServer/legend + + + + + + + + + + + + + + Légende pour QGIS + + + + + + https://metawal.wallonie.be/geonetwork/srv/api/records/fafb9fc7-4e32-4a40-8163-c64966cb573c/attachments/WALOUS_UTS.qml + + + + + + + + + + + + + + Légende pour AcrGIS - Niveau 1 + + + + + + https://metawal.wallonie.be/geonetwork/srv/api/records/fafb9fc7-4e32-4a40-8163-c64966cb573c/attachments/Utilisation%20majoritaire%20-%20Niveau%201.lyr + + + + + + + + + + + + + + Légende pour AcrGIS - Niveau 2 + + + + + + https://metawal.wallonie.be/geonetwork/srv/api/records/fafb9fc7-4e32-4a40-8163-c64966cb573c/attachments/Utilisation%20majoritaire%20-%20Niveau%202.lyr + + + + + + + + + + + + + + Légende pour AcrGIS - Niveau 3 + + + + + + https://metawal.wallonie.be/geonetwork/srv/api/records/fafb9fc7-4e32-4a40-8163-c64966cb573c/attachments/Utilisation%20majoritaire%20-%20Niveau%203.lyr + + + + + + + + + + + + + + Légende pour AcrGIS - Niveau 3 enrichi + + + + + + https://metawal.wallonie.be/geonetwork/srv/api/records/fafb9fc7-4e32-4a40-8163-c64966cb573c/attachments/Utilisation%20majoritaire%20-%20Niveau%203%20WALOUSMAJ.lyr + + + + + + + + + diff --git a/core/src/test/resources/org/fao/geonet/kernel/metadata.iso19139.xml b/core/src/test/resources/org/fao/geonet/kernel/metadata.iso19139.xml new file mode 100644 index 00000000000..691a6fbf4db --- /dev/null +++ b/core/src/test/resources/org/fao/geonet/kernel/metadata.iso19139.xml @@ -0,0 +1,1054 @@ + + + + {uuid} + + + + + + + + + + + + + + European Environment Agency + + + + + + + Kongens Nytorv 6 + + + Copenhagen + + + K + + + 1050 + + + Denmark + + + sdi@eea.europa.eu + + + + + + + + + + + + 2023-08-15T13:50:02.44Z + + + ISO 19115/19139 + + + 1.0 + + + + + + + EPSG:3035 + + + + + + + + + + + CORINE Land Cover Change 2012-2018 (vector), Europe, 6-yearly - version 2020_20u1, May + 2020 + + + + + + 2019-06-14 + + + + + + + + + + 2019-06-14 + + + + + + + + + + 2020-05-13 + + + + + + + + 20.01 + + + + + copernicus_v_3035_100_m_cha-2012-2018_p_2011-2018_v20_r01 + + + + + + + DAT-49-en + + + + + + + DAT-38-en + + + + + + + + 10.2909/f30f1000-7cf8-43bb-872c-5eb093911b24 + + + + + + + + Corine Land Cover Change 2012-2018 (CHA1218) is one of the Corine Land Cover (CLC) datasets + produced within the frame the Copernicus Land Monitoring Service referring to changes in land cover / land use + status between the years 2012 and 2018. + + CLC service has a long-time heritage (formerly known as "CORINE Land Cover Programme"), coordinated by the + European Environment Agency (EEA). It provides consistent and thematically detailed information on land cover + and land cover changes across Europe. + + CLC datasets are based on the classification of satellite images produced by the national teams of the + participating countries - the EEA members and cooperating countries (EEA39). National CLC inventories are then + further integrated into a seamless land cover map of Europe. The resulting European database relies on + standard methodology and nomenclature with following base parameters: 44 classes in the hierarchical 3-level + CLC nomenclature; minimum mapping unit (MMU) for status layers is 25 hectares; minimum width of linear + elements is 100 metres. Change layers have higher resolution, i.e. minimum mapping unit (MMU) is 5 hectares + for Land Cover Changes (CHA), and the minimum width of linear elements is 100 metres. + + The CLC service delivers important data sets supporting the implementation of key priority areas of the + Environment Action Programmes of the European Union as e.g. protecting ecosystems, halting the loss of + biological diversity, tracking the impacts of climate change, monitoring urban land take, assessing + developments in agriculture or dealing with water resources directives. CLC belongs to the Pan-European + component of the Copernicus Land Monitoring Service (https://land.copernicus.eu/), part of the European + Copernicus Programme coordinated by the European Environment Agency, providing environmental information from + a combination of air- and space-based observation systems and in-situ monitoring. + + Additional information about CLC product description including mapping guides can be found at + https://land.copernicus.eu/user-corner/technical-library/. CLC class descriptions can be found at + https://land.copernicus.eu/user-corner/technical-library/corine-land-cover-nomenclature-guidelines/html/. + + + + + + + + + + + + + + + + + + https://sdi.eea.europa.eu/public/catalogue-graphic-overview/f30f1000-7cf8-43bb-872c-5eb093911b24.png + + + + + + + + Land cover + + + + + + + + GEMET - INSPIRE themes, version 1.0 + + + + + 2008-06-01 + + + + + + + + + + + geonetwork.thesaurus.external.theme.httpinspireeceuropaeutheme-theme + + + + + + + + + + + + + EEA39 + + + + + + + + Continents, countries, sea regions of the world. + + + + + 2015-07-17T12:00:00 + + + + + + + + + + + geonetwork.thesaurus.external.place.regions + + + + + + + + + + + + + landscape + + + landscape alteration + + + land use + + + land cover + + + land + + + + + + + + GEMET + + + + + 2021-11-30 + + + + + + + + + + + geonetwork.thesaurus.external.theme.gemet + + + + + + + + + + + + European + + + + + + + + + Spatial scope + + + + + + 2019-05-22 + + + + + + + + + + + geonetwork.thesaurus.external.theme.httpinspireeceuropaeumetadatacodelistSpatialScope-SpatialScope + + + + + + + + + + + + 2016 2.6.1 + + + + + + + + EEA Management Plan + + + + + 2021-08-25 + + + + + + + + + + + geonetwork.thesaurus.local.theme.eea-mp + + + + + + + + + + + + Land use + + + Water + + + + + + + + EEA topics + + + + + 2020-09-24 + + + + + + + + + + + geonetwork.thesaurus.external.theme.eea-topics + + + + + + + + + + + + + + + no + limitations to public access + + + + + + + + + + + Access to data is based on a principle of full, open and free access as established by + the Copernicus data and information policy Regulation (EU) No 1159/2013 of 12 July 2013. This regulation + establishes registration and licensing conditions for GMES/Copernicus users. + + Free, full and open access to this data set is made on the conditions that: + + 1. When distributing or communicating Copernicus dedicated data and Copernicus service information to the + public, users shall inform the public of the source of that data and information. + + 2. Users shall make sure not to convey the impression to the public that the user's activities are + officially endorsed by the Union. + + 3. Where that data or information has been adapted or modified, the user shall clearly state this. + + 4. The data remain the sole property of the European Union. Any information and data produced in the + framework of the action shall be the sole property of the European Union. Any communication and + publication by the beneficiary shall acknowledge that the data were produced “with funding by the European + Union”. + + + + + + + + + + 68e79f63-d64a-463a-895c-0a15a2adfee0 + + + + + + + + + + + + + + + 100 + + + + + + + + + + + environment + + + imageryBaseMapsEarthCover + + + + + + + -31.561261 + + + 44.820775 + + + 27.405827 + + + 71.409109 + + + + + + + -61.906047 + + + -60.905616 + + + 15.736333 + + + 16.607552 + + + + + + + -54.268239 + + + -51.621253 + + + 3.772692 + + + 5.851958 + + + + + + + -61.326095 + + + -60.711516 + + + 14.29692 + + + 14.970484 + + + + + + + 44.927382 + + + 45.390135 + + + -13.089579 + + + -12.546691 + + + + + + + 55.114983 + + + 55.935919 + + + -21.482245 + + + -20.77811 + + + + + + + + 2017-01-01 + 2018-12-31 + + + + + + + + + + + + + + GDB + + + 1.0 + + + + + + + Spatialite + + + + + + + + + + + + https://land.copernicus.eu/pan-european/corine-land-cover/lcc-2012-2018 + + + WWW:LINK-1.0-http--link + + + + + + + + + + https://image.discomap.eea.europa.eu/arcgis/rest/services/Corine/CHA2012_2018_WM/MapServer + + + + ESRI:REST + + + + + + + + + + + https://image.discomap.eea.europa.eu/arcgis/services/Corine/CHA2012_2018_WM/MapServer/WMSServer?service=WMS&request=GetCapabilities&version=1.3.0 + + + + OGC:WMS + + + CHA2012_2018 + + + + + + + + + + + + + + + + + https://doi.org/10.2909/f30f1000-7cf8-43bb-872c-5eb093911b24 + + + DOI + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Commission Regulation (EU) No 1089/2010 of 23 November 2010 implementing + Directive 2007/2/EC of the European Parliament and of the Council as regards interoperability of + spatial data sets and services + + + + + + 2010-12-08 + + + + + + + + + + See the referenced specification + + + + + + + + + + Version 2020_20u1 + + Release date: 24-02-2020 + File naming conventions simplified and better described. New file naming convention has been introduced + based on user feedback on version 20. Filename is composed of combination of information about update + campaign, data theme and reference year and version specification (including release year and release + number). + + The French DOMs are provided in separate databases (files both for vector and raster version of data). + + All raster layers are back in 8 bit GeoTIFF. Modification is introduced based on the user feedback on + version 20. In order to keep 8 bit resolution for raster change layers, they are divided into two files - + representing consumption (from) and formation (to) part of change. + + Version 20 + Release date: 14-06-2019 + Vector CLC database was provided by National Teams within original CLC1990, I&CLC2000 update, + FTSP/CLC2006 update, CLC2012 update and CLC2018 update projects. All features in original vector database + were classified and digitised based on satellite images with 100 m positional accuracy (according to CLC + specifications) and 25 ha minimum mapping unit into the standardized CLC nomenclature (44 CLC classes). + + European Corine Land Cover seamless DBs represent the final product of European data integration. The + process of data integration started when national deliveries have been accepted and the Database + Acceptance Report (DBTA) delivered . Delivered national data were produced in local national systems of + all participating countries. Each national Coordinate Reference System (CRS) definition had to be known + precisely together with its geometric relationship to a standard system in order to accurately transfer + all national data into a standard European coordinate reference - ETRS89/LAEA1052. + Mostly, the process itself was carried out by global equation-based transformation to ETRS89 (e.g. + seven-parameters Bursa-Wolf methods). The accuracy of a particular transformation ranges from centimetres + to meters depending on the method and the quality and number of control points available to define the + transformation parameters, but, in any case, the accuracy is far above the actual CLC data resolution (for + more details see the DBTA reports for particular country). National data, when transformed into the common + European reference, are introduced into tiled pan-European structure and as final step seamless dataset is + produced. + + In order to achieve production of the real seamless European database, the integration step includes also + harmonization of database along country borders. It consists from edge-matching of land cover polygons + from the national databases across national borders done by a verification / re-interpretation of the + satellite images in the border regions (2 km wide strip along borders). The satellite images from + IMAGE2000. CLC1990, CHA9000 and CLC2000 database were harmonized this way, but the order to priority was + as following: CLC2000, both geometric and thematic adaptations of all polygons in a 2 km strip along + national boundary lines; CHA9000 database to ensure that + changes in CLC2000 are consistent with the change database; corrected CLC90 (if provided by the MS); + corrections were focused to geometric adaptations in semi-automatical way based on CLC00 and CHA00 + databases. Border harmonization step has been skipped for CHA0006, CHA0612, CLC2012 and CLC2018 datasets. + Simplified border harmonization step for CLC2006 dataset has been created for these countries: CH, NO, KO, + TR, IE. + A simplified border matching has been applied: + - <25 ha polygons are NOT systematically removed (see next bullet). + - Sliver-like polygons (area < cca. 5 ha - soft limit) are generalised to largest or thematically most + similar neighbour. + - CLC-code differences in polygons along two sides of the border are NOT changed + Only polygons with area <= 0,1ha were eliminated in CHA0006, CHA0612, CLC2012 and for CLC2018 datasets + and CLC2006 dataset (besides the above-mentioned cases) and in parts newly added in campaigns 2006 and + 2012 too + + Note: Some artificial lines (dividing polygons with the same code) can be still present in database due to + technical constraints of current ArcGIS technology, but has no impact for dataset contents and can be + dissolved for data extracts. + + Version 18 (V18) + Release date: 19-09-2016 (see V18_5_1) + Main purpose of the release: Publication of the final, corrected CLC 2012 data. + The 4th CLC inventory for the reference year of 2012 was produced under the Copernicus Initial Operations + (GIO). It has the shortest production time in history of CLC. Two high-resolution satellite image + coverages (IRS Resourcesat-1/2, SPOT-4/5, RapidEye constellation) taken in 2011-2012 provided + multi-temporal information to support the update. Computer Assisted Photointerpretation (CAPI) was the + prevailing methodology applied in interpreting of satellite images. FI, DE, IC, IE, NO, ES and SE applied + a semi-automatic methodology. UK has turned from semiautomatic processing to CAPI because no national + hi-res dataset was available for 2012. Most of the QC was conducted in remote verifications. IT and ES + were verified by regions. In producing the European products, a simplified border matching was applied + (see Version 15). An independent validation of CLC and CLCC for CLC 2012 was carried out in 2016 and the + results are available at + https://land.copernicus.eu/user-corner/technical-library/clc-2012-validation-report-1. + Changes from previous main release (Version 17): + • Inclusion of CLC 2012 layers for all the EEA39 countries. + • Production of CLC 2006 for Greece (in V18_3) and all CLCs for Channel Islands (V18_1). + • Revised CLC 2000 and CLC 2006 layers were made available (V18_5). + • Change in rasterization algorithm (V18_2). + Known problems: + • Some redundant lines between neighbouring polygons with the same code are still present, but only as + result of persisting ‘adaptive tilling’ procedure (limitation of ESRI ArcGIS technology for large + datasets). + • Polygons <25 ha can be present along national borders and along 'adaptive tilling' tiles boundaries. + + See https://land.copernicus.eu/user-corner/technical-library/clc-country-coverage-v18.5 for full + information about the coverage of this version. + + See https://land.copernicus.eu/user-corner/technical-library/clc-and-clcc-release-lineage for full + information about all sub-versions of this version. + + Version 17 (V17) + Release date: 02-12-2013 + Main purpose of the release: Maintenance / Increased European coverage of CLC time series data. + Changes from previous release (V16): + • Full CLC and CLCC data time series (from CLC 1990 to CLC 2006 including all CLCC datasets) has been + included for the Autonomous Region of the Azores (PT). + + Version 16 (V16) + Release date: 15-04-2012 + Main purpose: Maintenance / Increased and improved European coverage of CLC time series data. + Changes from previous release (V15): + • CLC 1990 coverage: TR has been delivered CLC 1990 and CLCC (1990, 2000) data. Still missing CLC 1990 + data: AL, BA, CH, CY, FI, IS, MK, NO, SE, UK and the XK. + • CLC 2000_revised layer covering 27 countries was included (CLC 2000 data revised during production of + CLC 2006). + • Shift in MT geographic position has been corrected. All CLC layers for MT have been re-projected. + • A few coding inconsistences were corrected. + + Version 15 (V5) + Release date: 20-07-2011 + Main purpose: Publication of final CLC2 006 data. + The 3rd CLC inventory for the reference year of 2006 was produced under GMES Fast Track Service on Land + Monitoring. The CLCC database was considered as the primary product, and a uniform change mapping + methodology was agreed. Dual date satellite imagery (SPOT-4/5 and IRS P6) taken in 2005-2007 provided + enhanced change mapping capabilities. Some of the countries newly entering CLC have produced CLC 2000 + datasets also during the project time frame. Scanned topographic maps and digital aerial ortho-imagery + have become commonly available. CAPI was the prevailing method applied in interpreting of satellite + images. Nevertheless, FI, IS, NO, SE and the UK applied a semiautomatic methodology. Most of the European + QC was conducted by visiting national teams (see Version 2). In some cases, remote verification was + applied (without mission to countries). ES and IT were verified by regions. + Changes from previous release (V14 (V4)): + • CLC 2006 data covering Great Britain (part of UK) and TR were delivered. Thus, CLC 2006 European + coverage includes 38 countries of the EEA39. Still missing CLC 2006 data for Greece. + • A simplified border matching was applied for countries new in CLC: XK, NO, CH and Türkiye: 1) <25 ha + polygons along the borders are not removed systematically; 2) sliver-like polygons (area < cca. 5 ha) + are generalised to largest or thematically most similar neighbour. + • For the rest of CLC 2006 countries a simple border-matching was applied. Code differences along two + sides of borders are not changed. Only polygons with area ≤ 0,1 ha (sliver polygons) are eliminated. + • Data dissemination: CLC data become freely accessible from the EEA to any person or legal entity. + + Version 14 (V4) + Release date: 25-10-2010 + Main purpose: Maintenance / Increased European coverage of CLC 2006 and CLC 2000 data. + Changes from previous release (V13 (V3)): + • CLC 2006 European coverage includes 37 full countries of EEA39. New data for Northern Ireland (part of + the UK), Madeira Islands (part of PT), CH, IS and TR were added to CLC 2006 data. Still missing CLC 2006: + GR and the UK (except Northern Ireland). + • New data for Madeira Islands (PT), CH and IS were added into the European CLC 2000 coverage, which + includes already the EE39. However, CLCC (1990, 2000) is available for 28 countries only. + • New data for Madeira Islands (PT) were added into CLC 1990 and CLCC (1990, 2000). Still missing CLC 1990 + data: AL, BA, CH, CY, FI, IS, MK, NO, SE, TR, UK and XK. + + The seamless European database has been further improved addressing feedback from the EEA on V13 (V3): + • No-data buffer (code 999) outside of valid data area was deleted. + • Small gaps identified in V13 were corrected by tolerance adaptation in ArcGIS v10 geodatabase. + • Remaining neighbour polygons with the same code were resolved by additional dissolve operation. + + Version 13 (V3) + Release date: 02/2010 + Main purpose: Publication of initial European coverage of CLC 2006 data. + Changes from previous release (V2): + • Version numbering was changed to harmonise vector data (V3) and derived raster data (V13) releases. + • First seamless release in ESRI Geodatabase format. + • Initial coverage of CLC 2006 including 35 countries and Northern Ireland (part of the UK). Missing + countries in CLC 2006: GR, CH, TR and the UK (except Northern Ireland). + • Two updates added to CLC 2000: a new version for NO and the first CLC dataset for TR. + • Sea buffer around land has been introduced (15 km as proxy to 12 nautical miles’ sea zone). + + Version 2 (V2) + Release date: 09/2009 + Main purpose: Publication of final CLC 2000 coverages. + The 2nd CLC inventory for the reference year of 2000 (CLC 2000) was carried out in the frames of I&CLC + 2000 project. A single date Landsat-7 ETM satellite imagery taken in 1999-2001 was provided by JRC. The + technology of drawing the interpretation on transparencies was discarded and replaced by CAPI + (computer-assisted photo-interpretation). Prior to mapping changes CLC 1990 data had to be corrected: 1) + bulk geometric mistakes removed and residual geometric errors >100 m and coding mistakes were + corrected; 2) polygons smaller than the 25 ha MMU were generalised. European QC was conducted by visiting + national teams (usually at the start and towards the end of the project). Computer-assisted verification + has provided written, geo-located explanations regarding the mistakes and supported harmonized production + of the database all over Europe. + Changes from previous release (V1): + • It was to deliver a single seamless layer, but was not feasible in ESRI environment. Therefore, seamless + ESRI ArcInfo Librarian map tiles were produced again (but free of tiling artefacts reported in V1). + • New country deliveries integrated into European CLC 2000 ME, RS (incl. XK), IS and NO. Simple + harmonization along national borders of these countries was done (small artefacts cleaned only). + • CLC 2000 data for MT have been updated to reflect changed geometry in CLC 2006 delivery. + • The dissemination and use of products was defined in an agreement between the EEA, the EC and the + participating countries. + + Version 1 (V1) + Release date: 08/2005 + Main purpose: Publication of initial European coverage of CLC 2000 and CLCC (1990, 2000) data. + Changes from previous release (V0): + • The first consolidated version of European CLC data have been produced as integrated and harmonised + seamless layer in ESRI ArcInfo Workstation Librarian map tiles. + • The production of the first CLCC database has started, but no consolidated methodology was available. + • Initial CLC 2000 coverage included 32 countries: AL, AT, BE, BA, BG, CY, CZ, DE, DK, EE, ES, FI, FR, GR, + HR, HU, IE, IT, LV, LI, LT, LU, MK, MT, NL, PL, PT, RO, SI, SK, SE and the UK. Missing countries in CLC + 2000: CH, IS, ME, NO, RS (including XK) and TR. + • CLC 1990 for most of the countries has been replaced by revised CLC 1990. Some additional countries have + produced CLC 1990. Still missing in CLC 1990 European coverage: CY, LI, MT, SE and UK. + • Full harmonization (visual re-interpretation by keeping the 25 ha MMU) inside a 5-km wide strip along + national borders was done including 32 countries for CLC 2000 and 24 countries for CLCC (1990, 2000). + • Semi-automatic harmonisation of 2-km wide strip along national borders was done for CLC 1990. + • Vector to raster conversion: “cell centre” method was applied. + • The 25 ha MMU is considered as hard limit. Polygons <25 ha were generalised. + • Dual ownership of CLC and CLCC data (EEA and the country) was introduced. + + Version 0 (V0) + Release dates: up to 12/2000 + Main purpose: Distribution of country-level CLC 1990 data and creation of European raster products. + The period of the first CLC inventory was rather long (1985-1996) and 1990 is considered as reference + year. CLC 1990 data delivered by countries became part of GISCO database. Releases were provided + bi-annually. Following political changes in Central and Eastern Europe 10 additional countries joined. The + methodology was visual photointerpretation by drawing the CLC map on transparency, placed on top of + satellite image hardcopy at scale 1:100.000. + • CLC 1990 vector and raster data were initially available for 12 countries: AT, BE, DE, DK, ES, FR, GR, + IE, IT, LU, NL and PT. Raster only data were available for FI and UK. + • The EC Phare programme supported the implementation of CLC 1990 in 11 countries of Central and Eastern + Europe between 1992 and 1998: BG, CZ and SK, EE, LV, LT, HU, PL, RO and SI. + • Integrated European vector dataset was available as ESRI ArcInfo Librarian and derived raster products + as ESRI grids in 100m and 250m resolution. + • Data dissemination policy was unclear. + + + + + + + + + + + + + + diff --git a/csw-server/pom.xml b/csw-server/pom.xml index 6a56b216946..f6a27aadb3c 100644 --- a/csw-server/pom.xml +++ b/csw-server/pom.xml @@ -27,7 +27,7 @@ geonetwork org.geonetwork-opensource - 4.2.4-SNAPSHOT + 4.4.7-SNAPSHOT 4.0.0 @@ -72,7 +72,7 @@ org.geotools - gt-opengis + gt-api org.geotools @@ -105,6 +105,11 @@ elasticsearch + + co.elastic.clients + elasticsearch-java + + org.springframework spring-beans @@ -221,6 +226,7 @@ test 9300 9200 + -Xmx2g diff --git a/csw-server/src/main/java/org/fao/geonet/component/csw/GetCapabilities.java b/csw-server/src/main/java/org/fao/geonet/component/csw/GetCapabilities.java index 50f0a420200..72f0dc19c43 100644 --- a/csw-server/src/main/java/org/fao/geonet/component/csw/GetCapabilities.java +++ b/csw-server/src/main/java/org/fao/geonet/component/csw/GetCapabilities.java @@ -65,6 +65,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import static org.fao.geonet.kernel.setting.SettingManager.isPortRequired; @@ -529,6 +530,8 @@ private void setOperationsParameters(Element capabilities) { */ private void populateTypeNameAndOutputSchema(Element op) { Map typenames = _schemaManager.getHmSchemasTypenames(); + List outputSchemas = _schemaManager.getOutputSchemas().values().stream().sorted().collect(Collectors.toList()); + List operations = op.getChildren("Parameter", Csw.NAMESPACE_OWS); for (Element operation : operations) { if ("typeNames".equals(operation.getAttributeValue("name"))) { @@ -541,12 +544,10 @@ private void populateTypeNameAndOutputSchema(Element op) { .setText(typename)); } } else if ("outputSchema".equals(operation.getAttributeValue("name"))) { - for (Map.Entry entry : typenames.entrySet()) { - Namespace ns = entry.getValue(); - operation.addNamespaceDeclaration(ns); + outputSchemas.forEach(uri -> operation.addContent(new Element("Value", Csw.NAMESPACE_OWS) - .setText(ns.getURI())); - } + .setText(uri)) + ); } } } diff --git a/csw-server/src/main/java/org/fao/geonet/component/csw/GetRecordById.java b/csw-server/src/main/java/org/fao/geonet/component/csw/GetRecordById.java index 43d7f725f7b..078fd59cbce 100644 --- a/csw-server/src/main/java/org/fao/geonet/component/csw/GetRecordById.java +++ b/csw-server/src/main/java/org/fao/geonet/component/csw/GetRecordById.java @@ -1,5 +1,5 @@ //============================================================================= -//=== Copyright (C) 2001-2007 Food and Agriculture Organization of the +//=== Copyright (C) 2001-2024 Food and Agriculture Organization of the //=== United Nations (FAO-UN), United Nations World Food Programme (WFP) //=== and United Nations Environment Programme (UNEP) //=== @@ -30,14 +30,9 @@ import jeeves.server.context.ServiceContext; -import org.apache.commons.lang.NotImplementedException; import org.fao.geonet.kernel.SchemaManager; -import org.fao.geonet.kernel.setting.SettingInfo; -import org.fao.geonet.utils.Log; import org.fao.geonet.Util; -import org.fao.geonet.utils.Xml; -import org.apache.commons.lang.StringUtils; import org.fao.geonet.GeonetContext; import org.fao.geonet.constants.Geonet; import org.fao.geonet.csw.common.Csw; @@ -54,7 +49,6 @@ import org.fao.geonet.kernel.csw.CatalogService; import org.fao.geonet.kernel.csw.services.AbstractOperation; import org.fao.geonet.kernel.csw.services.getrecords.SearchController; -import org.fao.geonet.domain.Pair; import org.fao.geonet.lib.Lib; import org.jdom.Element; import org.springframework.beans.factory.annotation.Autowired; @@ -76,12 +70,14 @@ public class GetRecordById extends AbstractOperation implements CatalogService { //--------------------------------------------------------------------------- static final String NAME = "GetRecordById"; - private SearchController _searchController; + + @Autowired + private SearchController searchController; @Autowired - private CatalogConfiguration _catalogConfig; + private CatalogConfiguration catalogConfig; @Autowired - private SchemaManager _schemaManager; + private SchemaManager schemaManager; @Autowired public GetRecordById(ApplicationContext applicationContext) { @@ -106,7 +102,7 @@ public Element execute(Element request, ServiceContext context) throws CatalogEx checkVersion(request); //-- Added for CSW 2.0.2 compliance by warnock@awcubed.com checkOutputFormat(request); - String outSchema = OutputSchema.parse(request.getAttributeValue("outputSchema"), _schemaManager); + String outSchema = OutputSchema.parse(request.getAttributeValue("outputSchema"), schemaManager); //-------------------------------------------------------- ElementSetName setName = getElementSetName(request, ElementSetName.SUMMARY); @@ -135,8 +131,8 @@ public Element execute(Element request, ServiceContext context) throws CatalogEx Lib.resource.checkPrivilege(context, id, ReservedOperation.view); final String displayLanguage = context.getLanguage(); - Element md = SearchController.retrieveMetadata(context, id, setName, outSchema, null, null, ResultType.RESULTS, null, - displayLanguage); + Element md = searchController.retrieveMetadata(context, id, setName, outSchema, null, null, ResultType.RESULTS,null, + displayLanguage, true); if (md != null) { final Map transformers = context.getApplicationContext() @@ -150,7 +146,7 @@ public Element execute(Element request, ServiceContext context) throws CatalogEx response.addContent(md); - if (_catalogConfig.isIncreasePopularity()) { + if (catalogConfig.isIncreasePopularity()) { gc.getBean(DataManager.class).increasePopularity(context, id); } } diff --git a/csw-server/src/main/java/org/fao/geonet/component/csw/GetRecords.java b/csw-server/src/main/java/org/fao/geonet/component/csw/GetRecords.java index feffc0696ab..5b0fb4e224d 100644 --- a/csw-server/src/main/java/org/fao/geonet/component/csw/GetRecords.java +++ b/csw-server/src/main/java/org/fao/geonet/component/csw/GetRecords.java @@ -23,11 +23,9 @@ package org.fao.geonet.component.csw; +import co.elastic.clients.elasticsearch._types.SortOptions; import jeeves.server.context.ServiceContext; import org.apache.commons.lang.StringUtils; -import org.elasticsearch.search.sort.FieldSortBuilder; -import org.elasticsearch.search.sort.SortBuilder; -import org.elasticsearch.search.sort.SortOrder; import org.fao.geonet.GeonetContext; import org.fao.geonet.constants.Geonet; import org.fao.geonet.csw.common.*; @@ -244,7 +242,7 @@ public Element execute(Element request, ServiceContext context) throws CatalogEx response.addContent(echoedRequest); } else { - List> sort = _sortByParser.parseSortBy(request); + List sort = _sortByParser.parseSortBy(request); response = new Element(getName() + "Response", Csw.NAMESPACE_CSW); diff --git a/csw-server/src/main/java/org/fao/geonet/component/csw/Transaction.java b/csw-server/src/main/java/org/fao/geonet/component/csw/Transaction.java index d3d413510af..f571bb968bc 100644 --- a/csw-server/src/main/java/org/fao/geonet/component/csw/Transaction.java +++ b/csw-server/src/main/java/org/fao/geonet/component/csw/Transaction.java @@ -23,10 +23,9 @@ package org.fao.geonet.component.csw; -import org.fao.geonet.kernel.search.IndexingMode; -import org.locationtech.jts.util.Assert; import jeeves.server.UserSession; import jeeves.server.context.ServiceContext; +import org.fao.geonet.ApplicationContextHolder; import org.fao.geonet.GeonetContext; import org.fao.geonet.Util; import org.fao.geonet.constants.Edit; @@ -37,38 +36,31 @@ import org.fao.geonet.csw.common.ResultType; import org.fao.geonet.csw.common.exceptions.CatalogException; import org.fao.geonet.csw.common.exceptions.NoApplicableCodeEx; -import org.fao.geonet.domain.ISODate; -import org.fao.geonet.domain.Pair; -import org.fao.geonet.domain.Profile; -import org.fao.geonet.domain.ReservedGroup; -import org.fao.geonet.domain.ReservedOperation; -import org.fao.geonet.kernel.AccessManager; -import org.fao.geonet.kernel.AddElemValue; -import org.fao.geonet.kernel.DataManager; -import org.fao.geonet.kernel.EditLib; -import org.fao.geonet.kernel.SchemaManager; +import org.fao.geonet.domain.*; +import org.fao.geonet.domain.utils.ObjectJSONUtils; +import org.fao.geonet.events.history.RecordDeletedEvent; +import org.fao.geonet.events.history.RecordImportedEvent; +import org.fao.geonet.events.history.RecordUpdatedEvent; +import org.fao.geonet.kernel.*; import org.fao.geonet.kernel.csw.CatalogService; import org.fao.geonet.kernel.csw.services.AbstractOperation; import org.fao.geonet.kernel.csw.services.getrecords.FieldMapper; import org.fao.geonet.kernel.csw.services.getrecords.SearchController; -import org.fao.geonet.kernel.datamanager.IMetadataUtils; import org.fao.geonet.kernel.datamanager.IMetadataManager; +import org.fao.geonet.kernel.datamanager.IMetadataUtils; import org.fao.geonet.kernel.schema.MetadataSchema; +import org.fao.geonet.kernel.search.IndexingMode; import org.fao.geonet.kernel.setting.SettingManager; import org.fao.geonet.kernel.setting.Settings; import org.fao.geonet.utils.Log; import org.jdom.Element; +import org.jdom.output.XMLOutputter; +import org.locationtech.jts.util.Assert; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; +import java.util.*; //============================================================================= /** @@ -76,6 +68,9 @@ */ @Component(CatalogService.BEAN_PREFIX + Transaction.NAME) public class Transaction extends AbstractOperation implements CatalogService { + private static final boolean applyUpdateFixedInfo = true; + private static final boolean applyValidation = false; + static final String NAME = "Transaction"; @Autowired SchemaManager _schemaManager; @@ -218,7 +213,7 @@ public Element retrieveValues(String parameterName) throws CatalogException { * @throws Exception */ private boolean insertTransaction(Element xml, List documents, ServiceContext context, Set toIndex) - throws Exception { + throws Exception { GeonetContext gc = (GeonetContext) context.getHandlerContext(Geonet.CONTEXT_NAME); DataManager dataMan = gc.getBean(DataManager.class); @@ -263,9 +258,8 @@ private boolean insertTransaction(Element xml, List documents, // insert metadata // String docType = null, isTemplate = null; - boolean ufo = true; String id = dataMan.insertMetadata(context, schema, xml, uuid, userId, group, source, - isTemplate, docType, category, createDate, changeDate, ufo, IndexingMode.none); + isTemplate, docType, category, createDate, changeDate, applyUpdateFixedInfo, IndexingMode.none); // Privileges for the first group of the user that inserts the metadata // (same permissions as when inserting xml file from UI) @@ -287,6 +281,13 @@ private boolean insertTransaction(Element xml, List documents, dataMan.indexMetadata(id, true); + AbstractMetadata metadata = metadataUtils.findOne(id); + ApplicationContext applicationContext = ApplicationContextHolder.get(); + new RecordImportedEvent(metadata.getId(), us.getUserIdAsInt(), + ObjectJSONUtils.convertObjectInJsonObject(us.getPrincipal(), + RecordImportedEvent.FIELD), + metadata.getData()).publish(applicationContext); + documents.add(new InsertedMetadata(schema, id, xml)); toIndex.add(id); @@ -316,6 +317,9 @@ private int updateTransaction(Element request, Element xml, ServiceContext conte int totalUpdated = 0; + Element beforeMetadata; + Element afterMetadata; + // Update full metadata if (xml != null) { @@ -353,10 +357,22 @@ private int updateTransaction(Element request, Element xml, ServiceContext conte changeDate = new ISODate().toString(); } - boolean validate = false; - boolean ufo = false; + beforeMetadata = metadataUtils.findOneByUuid(uuid).getXmlData(false); + String language = context.getLanguage(); - dataMan.updateMetadata(context, id, xml, validate, ufo, language, changeDate, true, IndexingMode.none); + dataMan.updateMetadata(context, id, xml, + applyValidation, applyUpdateFixedInfo, + language, changeDate, true, IndexingMode.none); + + afterMetadata = metadataUtils.findOneByUuid(uuid).getXmlData(false); + + XMLOutputter outp = new XMLOutputter(); + String xmlBefore = outp.outputString(beforeMetadata); + String xmlAfter = outp.outputString(afterMetadata); + new RecordUpdatedEvent(Long.parseLong(id), + context.getUserSession().getUserIdAsInt(), + xmlBefore, xmlAfter) + .publish(ApplicationContextHolder.get()); toIndex.add(id); @@ -397,6 +413,8 @@ private int updateTransaction(Element request, Element xml, ServiceContext conte Element metadata = dataMan.getMetadata(context, id, false, false, true); + beforeMetadata = metadata; + metadata.removeChild("info", Edit.NAMESPACE); // Retrieve the schema and Namespaces of metadata to update @@ -449,22 +467,31 @@ private int updateTransaction(Element request, Element xml, ServiceContext conte // Update the metadata with changes if (metadataChanged) { - boolean validate = false; - boolean ufo = false; try { changeDate = metadataUtils.extractDateModified(schemaId, metadata); } catch (Exception ex) { changeDate = new ISODate().toString(); } String language = context.getLanguage(); - dataMan.updateMetadata(context, id, metadata, validate, ufo, language, changeDate, true, IndexingMode.none); + dataMan.updateMetadata(context, id, metadata, + applyValidation, applyUpdateFixedInfo, + language, changeDate, true, IndexingMode.none); updatedMd.add(id); totalUpdated++; } - + afterMetadata = metadataUtils.findOneByUuid(uuid).getXmlData(false); + + XMLOutputter outp = new XMLOutputter(); + String xmlBefore = outp.outputString(beforeMetadata); + String xmlAfter = outp.outputString(afterMetadata); + new RecordUpdatedEvent(Long.parseLong(id), + context.getUserSession().getUserIdAsInt(), + xmlBefore, xmlAfter) + .publish(ApplicationContextHolder.get()); } + toIndex.addAll(updatedMd); return totalUpdated; @@ -510,8 +537,25 @@ private int deleteTransaction(Element request, ServiceContext context) throws Ex if (!dataMan.getAccessManager().canEdit(context, id)) { throw new NoApplicableCodeEx("User not allowed to delete metadata : " + id); } + AbstractMetadata metadata = metadataUtils.findOneByUuid(uuid); + LinkedHashMap titles = new LinkedHashMap<>(); + try { + titles = metadataUtils.extractTitles(Integer.toString(metadata.getId())); + } catch (Exception e) { + Log.warning(Geonet.DATA_MANAGER, + String.format( + "Error while extracting title for the metadata %d " + + "while creating delete event. Error is %s.", + metadata.getId(), e.getMessage())); + } + RecordDeletedEvent recordDeletedEvent = new RecordDeletedEvent( + metadata.getId(), metadata.getUuid(), titles, + context.getUserSession().getUserIdAsInt(), + metadata.getData()); metadataManager.deleteMetadata(context, id); + recordDeletedEvent.publish(ApplicationContextHolder.get()); + deleted++; } @@ -586,13 +630,13 @@ private void getResponseResult(ServiceContext context, Element request, Element } private static Element applyCswBrief(ServiceContext context, SchemaManager schemaManager, String schema, - Element md, - String id, String displayLanguage) throws Exception + Element md, + String id, String displayLanguage) throws Exception { return org.fao.geonet.csw.common.util.Xml.applyElementSetName( - context, schemaManager, schema, md, - "csw", ElementSetName.BRIEF, ResultType.RESULTS, - id, displayLanguage); + context, schemaManager, schema, md, + "csw", ElementSetName.BRIEF, ResultType.RESULTS, + id, displayLanguage); } /** diff --git a/csw-server/src/main/java/org/fao/geonet/csw/common/OutputSchema.java b/csw-server/src/main/java/org/fao/geonet/csw/common/OutputSchema.java index 9b156b71541..c6d65519c47 100644 --- a/csw-server/src/main/java/org/fao/geonet/csw/common/OutputSchema.java +++ b/csw-server/src/main/java/org/fao/geonet/csw/common/OutputSchema.java @@ -78,16 +78,16 @@ public static String parse(String schema, SchemaManager schemaManager) throws In if (schema.equals("csw:IsoRecord")) return "gmd"; if (schema.equals("own")) return "own"; - Map typenames = schemaManager.getHmSchemasTypenames(); - for (Map.Entry entry : typenames.entrySet()) { - Namespace ns = entry.getValue(); - if (schema.equals(ns.getURI())) { - return ns.getPrefix(); + Map typenames = schemaManager.getOutputSchemas(); + for (Map.Entry entry : typenames.entrySet()) { + String ns = entry.getValue(); + if (schema.equals(ns)) { + return entry.getKey(); } } throw new InvalidParameterValueEx("outputSchema", - String.format("'%s' schema is not valid. Supported values are %s", + String.format("'%s' output schema is not valid. Supported values are %s", schema, schemaManager.getListOfOutputSchemaURI().toString())); } diff --git a/csw-server/src/main/java/org/fao/geonet/csw/common/requests/CatalogRequest.java b/csw-server/src/main/java/org/fao/geonet/csw/common/requests/CatalogRequest.java index a254a26c3f0..8718d565fa8 100644 --- a/csw-server/src/main/java/org/fao/geonet/csw/common/requests/CatalogRequest.java +++ b/csw-server/src/main/java/org/fao/geonet/csw/common/requests/CatalogRequest.java @@ -186,6 +186,7 @@ public Element execute() throws Exception { public void setCredentials(String username, String password) { client.setCredentials(username, password); + client.setPreemptiveBasicAuth(true); } //--------------------------------------------------------------------------- diff --git a/csw-server/src/main/java/org/fao/geonet/csw/common/util/Xml.java b/csw-server/src/main/java/org/fao/geonet/csw/common/util/Xml.java index 51bdeffe793..c5ab2c8053a 100644 --- a/csw-server/src/main/java/org/fao/geonet/csw/common/util/Xml.java +++ b/csw-server/src/main/java/org/fao/geonet/csw/common/util/Xml.java @@ -125,22 +125,24 @@ public static Element applyElementSetName(ServiceContext context, SchemaManager ResultType resultType, String id, String displayLanguage) throws InvalidParameterValueEx { Path schemaDir = schemaManager.getSchemaCSWPresentDir(schema); Path styleSheet = schemaDir.resolve(outputSchema + "-" + elementSetName + ".xsl"); + Path styleSheetWithoutElementSet = schemaDir.resolve(outputSchema + ".xsl"); - if (!Files.exists(styleSheet)) { + if (!Files.exists(styleSheet) && !Files.exists(styleSheetWithoutElementSet)) { throw new InvalidParameterValueEx("OutputSchema", String.format( - "OutputSchema '%s' not supported for metadata with '%s' (%s).\nCorresponding XSL transformation '%s' does not exist for this schema.\nThe record will not be returned in response.", - outputSchema, id, schema, styleSheet.getFileName())); + "OutputSchema '%s' not supported for metadata with '%s' (%s).\nCorresponding XSL transformation '%s' (or '%s') does not exist for this schema.\nThe record will not be returned in response.", + outputSchema, id, schema, styleSheet.getFileName(), styleSheetWithoutElementSet.getFileName())); } else { Map params = new HashMap<>(); params.put("lang", displayLanguage); + Path xslFile = Files.exists(styleSheet) ? styleSheet : styleSheetWithoutElementSet; try { - result = org.fao.geonet.utils.Xml.transform(result, styleSheet, params); + result = org.fao.geonet.utils.Xml.transform(result, xslFile, params); } catch (Exception e) { String msg = String.format( - "Error occured while transforming metadata with id '%s' using '%s'.", - id, styleSheet.getFileName()); + "Error occurred while transforming metadata with id '%s' using '%s'.", + id, xslFile.getFileName()); context.error(msg); context.error(" (C) StackTrace:\n" + Util.getStackTrace(e)); throw new InvalidParameterValueEx("OutputSchema", msg); diff --git a/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/AbstractOperation.java b/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/AbstractOperation.java index 546da5f5cb9..8f9a1334680 100644 --- a/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/AbstractOperation.java +++ b/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/AbstractOperation.java @@ -41,7 +41,7 @@ import org.geotools.xsd.Encoder; import org.jdom.Element; import org.jdom.Namespace; -import org.opengis.filter.Filter; +import org.geotools.api.filter.Filter; import java.io.ByteArrayOutputStream; import java.io.IOException; diff --git a/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/getrecords/FilterParser.java b/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/getrecords/FilterParser.java index 2a5e8866975..b2957b87594 100644 --- a/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/getrecords/FilterParser.java +++ b/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/getrecords/FilterParser.java @@ -34,8 +34,8 @@ import org.geotools.xsd.Configuration; import org.geotools.xsd.Parser; import org.jdom.Element; -import org.opengis.filter.Filter; -import org.opengis.filter.capability.FilterCapabilities; +import org.geotools.api.filter.Filter; +import org.geotools.api.filter.capability.FilterCapabilities; import org.xml.sax.SAXException; public class FilterParser { diff --git a/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/getrecords/SearchController.java b/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/getrecords/SearchController.java index 99ac7c50b37..564280b4ce2 100644 --- a/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/getrecords/SearchController.java +++ b/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/getrecords/SearchController.java @@ -1,5 +1,5 @@ //============================================================================= -//=== Copyright (C) 2001-2007 Food and Agriculture Organization of the +//=== Copyright (C) 2001-2024 Food and Agriculture Organization of the //=== United Nations (FAO-UN), United Nations World Food Programme (WFP) //=== and United Nations Environment Programme (UNEP) //=== @@ -23,14 +23,14 @@ package org.fao.geonet.kernel.csw.services.getrecords; +import co.elastic.clients.elasticsearch._types.SortOptions; +import co.elastic.clients.elasticsearch.core.SearchResponse; +import co.elastic.clients.elasticsearch.core.search.Hit; +import co.elastic.clients.elasticsearch.core.search.TotalHits; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import jeeves.server.context.ServiceContext; import org.apache.commons.lang.StringUtils; -import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.search.SearchHit; -import org.elasticsearch.search.sort.FieldSortBuilder; -import org.elasticsearch.search.sort.SortBuilder; import org.fao.geonet.ApplicationContextHolder; import org.fao.geonet.GeonetContext; import org.fao.geonet.NodeInfo; @@ -53,28 +53,15 @@ import org.fao.geonet.kernel.search.EsSearchManager; import org.fao.geonet.utils.Log; import org.fao.geonet.utils.Xml; -import org.geotools.xsd.Configuration; -import org.geotools.xsd.Parser; import org.jdom.Attribute; import org.jdom.Content; import org.jdom.Element; import org.jdom.Namespace; -import org.opengis.filter.Filter; -import org.opengis.filter.capability.FilterCapabilities; import org.springframework.beans.factory.annotation.Autowired; -import org.xml.sax.SAXException; -import javax.xml.parsers.ParserConfigurationException; -import java.io.IOException; -import java.io.StringReader; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; public class SearchController { @@ -104,21 +91,58 @@ public class SearchController { * Retrieves metadata from the database. Conversion between metadata record and output schema * are defined in xml/csw/schemas/ directory. * - * @param context service context - * @param id id of metadata - * @param setName requested ElementSetName - * @param outSchema requested OutputSchema - * @param elemNames requested ElementNames - * @param typeName requested typeName - * @param resultType requested ResultType - * @param strategy ElementNames strategy - * @throws CatalogException hmm + * @param context service context + * @param id id of metadata + * @param setName requested ElementSetName + * @param outSchema requested OutputSchema + * @param elemNames requested ElementNames + * @param typeName requested typeName + * @param resultType requested ResultType + * @param strategy ElementNames strategy + * @param checkMetadataAvailableInPortal Checks if the metadata can be retrieved in the portal. + * Used in GetRecordById. GetRecords does a query with this check already. * @return The XML metadata record if the record could be converted to the required output * schema. Null if no conversion available for the schema (eg. fgdc record can not be converted * to ISO). + * @throws CatalogException hmm */ - public static Element retrieveMetadata(ServiceContext context, String id, ElementSetName setName, String - outSchema, Set elemNames, String typeName, ResultType resultType, String strategy, String displayLanguage) throws CatalogException { + public Element retrieveMetadata(ServiceContext context, String id, ElementSetName setName, String + outSchema, Set elemNames, String typeName, ResultType resultType, String strategy, String displayLanguage, + boolean checkMetadataAvailableInPortal) throws CatalogException { + + if (checkMetadataAvailableInPortal) { + // Check if the metadata is available in the portal + String elasticSearchQuery = "{ \"bool\": {\n" + + " \"must\": [\n" + + " {" + + " \"term\": {" + + " \"id\": {" + + " \"value\": \"%s\"" + + " }" + + " }" + + " } " + + " ]\n" + + " ,\"filter\":{\"query_string\":{\"query\":\"%s\"}}}}"; + + JsonNode esJsonQuery; + + try { + String filterQueryString = esFilterBuilder.build(context, "metadata", false, node); + String jsonQuery = String.format(elasticSearchQuery, id, filterQueryString); + + ObjectMapper objectMapper = new ObjectMapper(); + esJsonQuery = objectMapper.readTree(jsonQuery); + + TotalHits total = searchManager.query(esJsonQuery, new HashSet<>(), 0, 0).hits().total(); + + if (Optional.ofNullable(total).map(TotalHits::value).orElse(0L) == 0) { + return null; + } + } catch (Exception e) { + throw new RuntimeException(e); + } + + } try { //--- get metadata from DB @@ -157,12 +181,12 @@ public static Element retrieveMetadata(ServiceContext context, String id, Elemen res = applyElementNames(context, elemNames, typeName, scm, schema, res, resultType, info, strategy); - if(Log.isDebugEnabled(Geonet.CSW_SEARCH)) + if (Log.isDebugEnabled(Geonet.CSW_SEARCH)) Log.debug(Geonet.CSW_SEARCH, "SearchController:retrieveMetadata: before applying postprocessing on metadata Element for id " + id); res = applyPostProcessing(context, scm, schema, res, outSchema, setName, resultType, id, displayLanguage); - if(Log.isDebugEnabled(Geonet.CSW_SEARCH)) + if (Log.isDebugEnabled(Geonet.CSW_SEARCH)) Log.debug(Geonet.CSW_SEARCH, "SearchController:retrieveMetadata: All processing is complete on metadata Element for id " + id); if (res != null) { @@ -184,39 +208,39 @@ public static Element retrieveMetadata(ServiceContext context, String id, Elemen /** * Applies requested ElementNames and typeNames. - * + *

    * For ElementNames, several strategies are implemented. Clients can determine the behaviour by * sending attribute "elementname_strategy" with one of the following values: - * + *

    * csw202 relaxed context geonetwork26 - * + *

    * The default is 'relaxed'. The strategies cause the following behaviour: - * + *

    * csw202 -- compliant to the CSW2.0.2 specification. In particular this means that complete * metadata are returned that match the requested ElementNames, only if they are valid for their * XSD. This is because GeoNetwork only supports OutputFormat=application/xml, which mandates * that valid documents are returned. Because possibly not many of the catalog's metadata are * valid, this is not the default. - * + *

    * relaxed -- like csw202, but dropped the requirement to only include valid metadata. So this * returns complete metadata that match the requested ElementNames. This is the default * strategy. - * + *

    * context -- does not return complete metadata but only the elements matching the request, in * their context (i.e. all ancestor elements up to the root of the document are retained). This * strategy is similar to geonetwork26 but the context allows clients to determine which of the * elements returned corresponds to which of the elements requested (in case they have the same * name). - * + *

    * geonetwork26 -- behaviour as in GeoNetwork 2.6. Just return the requested elements, stripped * of any context. This can make it impossible for the client to determine which of the elements * returned corresponds to which of the elements requested; for example if the client asks for * gmd:title, the response may contain various gmd:title elements taken from different locations * in the metadata document. - * + *

    * ------------------------------------------------- Relevant sections of specification about * typeNames: - * + *

    * OGC 07-006 10.8.4.8: The typeNames parameter is a list of one or more names of queryable * entities in the catalogue's information model that may be constrained in the predicate of the * query. In the case of XML realization of the OGC core metadata properties (Subclause 10.2.5), @@ -227,16 +251,16 @@ public static Element retrieveMetadata(ServiceContext context, String id, Elemen * addition, all or some of the these queryable entity names may be specified in the query to * define which metadata record elements the query should present in the response to the * GetRecords operation. - * + *

    * OGC 07-045: - * + *

    * 8.2.2.1.1 Request (GetRecords) TypeNames. Must support *one* of “csw:Record” or * “gmd:MD_Metadata” in a query. Default value is “csw:Record”. - * + *

    * So, in OGC 07-045, exactly one of csw:Record or gmd:MD_Metadata is mandated for typeName. - * + *

    * ---------------------------------- Relevant specs about ElementNames: - * + *

    * OGC 07-006 10.8.4.9: The ElementName parameter is used to specify one or more metadata record * elements, from the output schema specified using the outputSchema parameter, that the query * shall present in the response to the a GetRecords operation. Since clause 10.2.5 realizes the @@ -244,19 +268,19 @@ public static Element retrieveMetadata(ServiceContext context, String id, Elemen * XPath expression perhaps using qualified names. In the general case, a complete XPath * expression may be required to correctly reference an element in the information model of the * catalog. - * + *

    * However, in the case where the typeNames attribute on the Query element contains a single * value, the catalogue can infer the first step in the path expression and it can be omitted. * This is usually the case when querying the core metadata properties since the only queryable * target is csw:Record. - * + *

    * If the metadata record element names are not from the schema specified using the outputSchema * parameter, then the service shall raise an exception as described in Subclause 10.3.7. - * + *

    * OGC 07-045: Usage of the ELEMENTNAME is not further specified here. - * + *

    * ---------------------------------- Relevant specs about outputFormat: - * + *

    * OGC 07-006 10.8.4.4 outputFormat parameter: In the case where the output format is * application/xml, the CSW shall generate an XML document that validates against a schema * document that is specified in the output document via the xsi:schemaLocation attribute @@ -296,7 +320,7 @@ private static Element applyElementNames(ServiceContext context, Set ele } boolean metadataContainsAllRequestedElementNames = true; - List nodes = new ArrayList(); + List nodes = new ArrayList<>(); for (String elementName : elementNames) { if (Log.isDebugEnabled(Geonet.CSW_SEARCH)) Log.debug(Geonet.CSW_SEARCH, "SearchController dealing with elementName: " + elementName); @@ -349,7 +373,7 @@ private static Element applyElementNames(ServiceContext context, Set ele Log.debug(Geonet.CSW_SEARCH, "strategy is context, constructing context to root"); } - List elementsInContextMatching = new ArrayList(); + List elementsInContextMatching = new ArrayList<>(); for (Element match : elementsMatching) { Element parent = match.getParentElement(); while (parent != null) { @@ -377,7 +401,7 @@ private static Element applyElementNames(ServiceContext context, Set ele } } - if (metadataContainsAllRequestedElementNames == true) { + if (metadataContainsAllRequestedElementNames) { if (Log.isDebugEnabled(Geonet.CSW_SEARCH)) Log.debug(Geonet.CSW_SEARCH, "metadata containa all requested elementnames: included in response"); @@ -421,27 +445,27 @@ private static Element applyElementNames(ServiceContext context, Set ele /** * TODO improve description of method. Performs the general search tasks. * - * @param context Service context - * @param startPos start position (if paged) - * @param maxRecords max records to return - * @param resultType requested ResultType - * @param outSchema requested OutputSchema - * @param setName requested ElementSetName - * @param filterExpr requested FilterExpression - * @param filterVersion requested Filter version - * @param sort requested sorting - * @param elemNames requested ElementNames - * @param typeName requested typeName - * @param maxHitsFromSummary ? - * @param strategy ElementNames strategy + * @param context Service context + * @param startPos start position (if paged) + * @param maxRecords max records to return + * @param resultType requested ResultType + * @param outSchema requested OutputSchema + * @param setName requested ElementSetName + * @param filterExpr requested FilterExpression + * @param filterVersion requested Filter version + * @param sort requested sorting + * @param elemNames requested ElementNames + * @param typeName requested typeName + * @param maxHitsFromSummary ? + * @param strategy ElementNames strategy * @return result * @throws CatalogException hmm */ - public Element search(ServiceContext context, int startPos, int maxRecords, - ResultType resultType, String outSchema, ElementSetName setName, - Element filterExpr, String filterVersion, List> sort, - Set elemNames, String typeName, int maxHitsFromSummary, - String strategy) throws CatalogException { + public Element search(ServiceContext context, int startPos, int maxRecords, + ResultType resultType, String outSchema, ElementSetName setName, + Element filterExpr, String filterVersion, List sort, + Set elemNames, String typeName, int maxHitsFromSummary, + String strategy) throws CatalogException { String elasticSearchQuery = convertCswFilterToEsQuery(filterExpr, filterVersion); @@ -462,29 +486,33 @@ public Element search(ServiceContext context, int startPos, int maxRecords, // TODO: Check to get summary or remove custom summary output try { - SearchResponse result = searchManager.query(esJsonQuery, new HashSet(), startPos-1, maxRecords, sort); + SearchResponse result = searchManager.query(esJsonQuery, new HashSet<>(), startPos - 1, maxRecords, sort); - SearchHit[] hits = result.getHits().getHits(); + List hits = result.hits().hits(); - long numMatches = result.getHits().getTotalHits().value; + TotalHits total = result.hits().total(); + long numMatches = total != null ? total.value() : 0; if (numMatches != 0 && startPos > numMatches) { throw new InvalidParameterValueEx("startPosition", String.format( "Start position (%d) can't be greater than number of matching records (%d for current search).", startPos, numMatches - )); + )); } int counter = 0; - for(SearchHit hit : hits) { - int mdId = Integer.parseInt((String) hit.getSourceAsMap().get("id")); + ObjectMapper objectMapper = new ObjectMapper(); + + for (Hit hit : hits) { + int mdId = Integer.parseInt((String) objectMapper.convertValue(hit.source(), Map.class).get("id")); AbstractMetadata metadata = metadataUtils.findOne(mdId); String displayLanguage = context.getLanguage(); + // The query to retrieve GetRecords, filters by portal. No need to re-check again when retrieving each metadata. Element resultMD = retrieveMetadata(context, metadata.getId() + "", - setName, outSchema, elemNames, typeName, resultType, strategy, displayLanguage); + setName, outSchema, elemNames, typeName, resultType, strategy, displayLanguage, false); if (resultMD != null) { if (resultType == ResultType.RESULTS) { @@ -501,7 +529,7 @@ public Element search(ServiceContext context, int startPos, int maxRecords, results.setAttribute("elementSet", setName.toString()); - if (numMatches > counter) { + if (numMatches > counter + (startPos -1)) { results.setAttribute("nextRecord", Long.toString(counter + startPos)); } else { results.setAttribute("nextRecord", "0"); @@ -531,8 +559,8 @@ public Element search(ServiceContext context, int startPos, int maxRecords, * @throws InvalidParameterValueEx hmm */ public Element applyElementSetName(ServiceContext context, SchemaManager schemaManager, String schema, - Element result, String outputSchema, ElementSetName elementSetName, - ResultType resultType, String id, String displayLanguage) throws InvalidParameterValueEx { + Element result, String outputSchema, ElementSetName elementSetName, + ResultType resultType, String id, String displayLanguage) throws InvalidParameterValueEx { Path schemaDir = schemaManager.getSchemaCSWPresentDir(schema); Path styleSheet = schemaDir.resolve(outputSchema + "-" + elementSetName + ".xsl"); @@ -543,7 +571,7 @@ public Element applyElementSetName(ServiceContext context, SchemaManager schemaM outputSchema, id, schema, styleSheet.toString())); return null; } else { - Map params = new HashMap(); + Map params = new HashMap<>(); params.put("lang", displayLanguage); try { @@ -557,33 +585,33 @@ public Element applyElementSetName(ServiceContext context, SchemaManager schemaM } } - private String convertCswFilterToEsQuery(Element xml, String filterVersion) { + private String convertCswFilterToEsQuery(Element xml, String filterVersion) { return CswFilter2Es.translate(FilterParser.parseFilter(xml, filterVersion), fieldMapper); } /** * Applies postprocessing stylesheet if available. - * + *

    * Postprocessing files should be in the present/csw folder of the schema and have this naming: - * + *

    * For default CSW service - * + *

    * 1) gmd-csw-postprocessing.xsl : Postprocessing xsl applied for CSW service when requesting iso (gmd) output * 2) csw-csw-postprocessing.xsl : Postprocessing xsl applied for CSW service when requesting ogc (csw) output + *

    + * For a custom sub-portal named inspire + *

    + * 1) gmd-inspire-postprocessing.xsl : Postprocessing xsl applied for custom inspire sub-portal when requesting iso output + * 2) csw-inspire-postprocessing.xsl : Postprocessing xsl applied for custom inspire sub-portal when requesting ogc (csw) output * - * For a custom CSW service named csw-inspire - * - * 1) gmd-csw-inspire-postprocessing.xsl : Postprocessing xsl applied for custom CSW csw-inspire service when requesting iso output - * 2) csw-csw-inspire-postprocessing.xsl : Postprocessing xsl applied for custom CSW csw-inspire service when requesting ogc (csw) output - * - * @param context Service context - * @param schemaManager schemamanager - * @param schema schema - * @param result result - * @param outputSchema requested OutputSchema - * @param elementSetName requested ElementSetName - * @param resultType requested ResultTYpe - * @param id metadata id + * @param context Service context + * @param schemaManager schemamanager + * @param schema schema + * @param result result + * @param outputSchema requested OutputSchema + * @param elementSetName requested ElementSetName + * @param resultType requested ResultTYpe + * @param id metadata id * @param displayLanguage language to use in response * @return metadata * @throws InvalidParameterValueEx hmm @@ -591,7 +619,7 @@ private String convertCswFilterToEsQuery(Element xml, String filterVersion) { private static Element applyPostProcessing(ServiceContext context, SchemaManager schemaManager, String schema, Element result, String outputSchema, ElementSetName elementSetName, ResultType resultType, String id, String displayLanguage) throws InvalidParameterValueEx { - Path schemaDir = schemaManager.getSchemaCSWPresentDir(schema); + Path schemaDir = schemaManager.getSchemaCSWPresentDir(schema); final NodeInfo nodeInfo = ApplicationContextHolder.get().getBean(NodeInfo.class); @@ -600,7 +628,7 @@ private static Element applyPostProcessing(ServiceContext context, SchemaManager + "-postprocessing.xsl"); if (Files.exists(styleSheet)) { - Map params = new HashMap(); + Map params = new HashMap<>(); params.put("lang", displayLanguage); try { diff --git a/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/getrecords/SortByParser.java b/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/getrecords/SortByParser.java index 87a00f76366..0efcae035ff 100644 --- a/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/getrecords/SortByParser.java +++ b/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/getrecords/SortByParser.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2021 Food and Agriculture Organization of the + * Copyright (C) 2001-2023 Food and Agriculture Organization of the * United Nations (FAO-UN), United Nations World Food Programme (WFP) * and United Nations Environment Programme (UNEP) * @@ -23,19 +23,20 @@ package org.fao.geonet.kernel.csw.services.getrecords; +import co.elastic.clients.elasticsearch._types.FieldSort; +import co.elastic.clients.elasticsearch._types.SortOptions; +import co.elastic.clients.elasticsearch._types.SortOrder; import org.apache.commons.lang.StringUtils; -import org.elasticsearch.search.sort.FieldSortBuilder; -import org.elasticsearch.search.sort.SortBuilder; -import org.elasticsearch.search.sort.SortOrder; import org.fao.geonet.csw.common.Csw; import org.fao.geonet.kernel.csw.CatalogConfiguration; import org.jdom.Element; import org.springframework.beans.factory.annotation.Autowired; import java.util.ArrayList; -import java.util.Collections; import java.util.List; +import static co.elastic.clients.elasticsearch._types.SortOptions.*; + public class SortByParser { @Autowired @@ -44,7 +45,7 @@ public class SortByParser { @Autowired private CatalogConfiguration _catalogConfig; - public List> parseSortBy(Element request) { + public List parseSortBy(Element request) { Element query = request.getChild("Query", Csw.NAMESPACE_CSW); if (query == null) { return getDefaultSort(); @@ -55,14 +56,22 @@ public List> parseSortBy(Element request) { return getDefaultSort(); } - List> sortFields = new ArrayList<>(); + List sortFields = new ArrayList<>(); @SuppressWarnings("unchecked") List list = sortBy.getChildren(); for (Element el : list) { String esSortFieldName = getEsSortFieldName(el); if (!StringUtils.isEmpty(esSortFieldName)) { SortOrder esSortOrder = getEsSortOrder(el); - sortFields.add(new FieldSortBuilder(esSortFieldName).order(esSortOrder)); + + SortOptions sortFieldOptions = + new Builder() + .field(new FieldSort.Builder() + .field(esSortFieldName) + .order(esSortOrder).build()) + .build(); + + sortFields.add(sortFieldOptions); } } @@ -72,11 +81,13 @@ public List> parseSortBy(Element request) { return sortFields; } - private List> getDefaultSort() { - List> sortFields = new ArrayList<>(); - FieldSortBuilder defaultSortField = - new FieldSortBuilder(_catalogConfig.getDefaultSortField()) - .order(SortOrder.fromString(_catalogConfig.getDefaultSortOrder())); + private List getDefaultSort() { + List sortFields = new ArrayList<>(); + + SortOptions defaultSortField = SortOptions.of( + b -> b.field(fb -> fb.field(_catalogConfig.getDefaultSortField()) + .order(_catalogConfig.getDefaultSortOrder().equals("DESC")?SortOrder.Desc:SortOrder.Asc)) + ); sortFields.add(defaultSortField); return sortFields; @@ -97,6 +108,6 @@ private String getEsSortFieldName(Element el) { private SortOrder getEsSortOrder(Element el) { String order = el.getChildText("SortOrder", Csw.NAMESPACE_OGC); boolean isDescOrder = "DESC".equals(order); - return isDescOrder ? SortOrder.DESC : SortOrder.ASC; + return isDescOrder ? SortOrder.Desc : SortOrder.Asc; } } diff --git a/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/getrecords/es/CswFilter2Es.java b/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/getrecords/es/CswFilter2Es.java index 08e2e24d973..d77bfd28818 100644 --- a/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/getrecords/es/CswFilter2Es.java +++ b/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/getrecords/es/CswFilter2Es.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2016 Food and Agriculture Organization of the + * Copyright (C) 2001-2024 Food and Agriculture Organization of the * United Nations (FAO-UN), United Nations World Food Programme (WFP) * and United Nations Environment Programme (UNEP) * @@ -26,131 +26,74 @@ import org.apache.commons.lang.NotImplementedException; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; +import org.apache.commons.text.StringEscapeUtils; import org.fao.geonet.constants.Geonet; import org.fao.geonet.kernel.csw.services.getrecords.IFieldMapper; +import org.fao.geonet.utils.DateUtil; import org.fao.geonet.utils.Log; +import org.geotools.api.filter.*; +import org.geotools.api.filter.expression.Expression; +import org.geotools.api.filter.expression.Literal; +import org.geotools.api.filter.expression.PropertyName; +import org.geotools.api.filter.spatial.*; +import org.geotools.api.filter.temporal.*; +import org.geotools.api.geometry.BoundingBox; import org.geotools.filter.visitor.AbstractFilterVisitor; import org.locationtech.jts.geom.*; import org.locationtech.jts.io.WKTReader; -import org.opengis.filter.And; -import org.opengis.filter.BinaryComparisonOperator; -import org.opengis.filter.BinaryLogicOperator; -import org.opengis.filter.ExcludeFilter; -import org.opengis.filter.Filter; -import org.opengis.filter.Id; -import org.opengis.filter.IncludeFilter; -import org.opengis.filter.Not; -import org.opengis.filter.Or; -import org.opengis.filter.PropertyIsBetween; -import org.opengis.filter.PropertyIsEqualTo; -import org.opengis.filter.PropertyIsGreaterThan; -import org.opengis.filter.PropertyIsGreaterThanOrEqualTo; -import org.opengis.filter.PropertyIsLessThan; -import org.opengis.filter.PropertyIsLessThanOrEqualTo; -import org.opengis.filter.PropertyIsLike; -import org.opengis.filter.PropertyIsNil; -import org.opengis.filter.PropertyIsNotEqualTo; -import org.opengis.filter.PropertyIsNull; -import org.opengis.filter.expression.Expression; -import org.opengis.filter.expression.Literal; -import org.opengis.filter.expression.PropertyName; -import org.opengis.filter.spatial.BBOX; -import org.opengis.filter.spatial.Beyond; -import org.opengis.filter.spatial.BinarySpatialOperator; -import org.opengis.filter.spatial.Contains; -import org.opengis.filter.spatial.Crosses; -import org.opengis.filter.spatial.DWithin; -import org.opengis.filter.spatial.Disjoint; -import org.opengis.filter.spatial.Equals; -import org.opengis.filter.spatial.Intersects; -import org.opengis.filter.spatial.Overlaps; -import org.opengis.filter.spatial.Touches; -import org.opengis.filter.spatial.Within; -import org.opengis.filter.temporal.After; -import org.opengis.filter.temporal.AnyInteracts; -import org.opengis.filter.temporal.Before; -import org.opengis.filter.temporal.Begins; -import org.opengis.filter.temporal.BegunBy; -import org.opengis.filter.temporal.During; -import org.opengis.filter.temporal.EndedBy; -import org.opengis.filter.temporal.Ends; -import org.opengis.filter.temporal.Meets; -import org.opengis.filter.temporal.MetBy; -import org.opengis.filter.temporal.OverlappedBy; -import org.opengis.filter.temporal.TContains; -import org.opengis.filter.temporal.TEquals; -import org.opengis.filter.temporal.TOverlaps; -import org.opengis.geometry.BoundingBox; import java.util.*; import java.util.regex.Pattern; /** - * Manages the translation from CSW <Filter> into a ES query. + * Manages the translation from CSW <Filter> into an ES query. */ public class CswFilter2Es extends AbstractFilterVisitor { - private final String BINARY_OPERATOR_AND = "AND"; - private final String BINARY_OPERATOR_OR = "OR"; + private static final String BINARY_OPERATOR_AND = "AND"; + private static final String BINARY_OPERATOR_OR = "OR"; - static final String SPECIAL_RE = "([" + Pattern.quote("+-&|!(){}[]^\\\"~*?:/") + "])"; - static final String SPECIAL_LIKE_RE = "(? stack = new ArrayDeque(); - - private final String templateNot = " {\"bool\": {\n" + + private static final String SPECIAL_RE = "([" + Pattern.quote("+-&|!(){}[]^\\\"~*?:/") + "])"; + private static final String SPECIAL_LIKE_RE = "(? stack = new ArrayDeque<>(); + private boolean useFilter = true; public CswFilter2Es(IFieldMapper fieldMapper) { expressionVisitor = new Expression2CswVisitor(stack, fieldMapper); @@ -214,22 +160,24 @@ protected static String convertLikePattern(PropertyIsLike filter) { : filter.getSingleChar(); result = result.replaceAll(singleCharRe, "?"); } + + result = StringEscapeUtils.escapeJson(escapeLikeLiteral(result)); return result; } public String getFilter() { - String condition = stack.isEmpty()?"":stack.pop(); + String condition = stack.isEmpty() ? "" : stack.pop(); // Check for single condition (no binary operators to wrap the query if (!condition.startsWith(" \"bool\":")) { - condition = String.format(templateAndWithFilter, condition, "%s"); + condition = String.format(TEMPLATE_AND_WITH_FILTER, condition, "%s"); } if (StringUtils.isEmpty(condition)) { // No filter - condition = "{\"bool\":{\"must\":[{\"query_string\":{\"query\":\"*\"}}],\"filter\":{\"query_string\":{\"query\":\"%s\"}}}"; + condition = "{\"bool\":{\"must\":[{\"query_string\":{\"query\":\"*\"}}],\"filter\":{\"query_string\":{\"query\":\"%s\"}}}"; } else { // Add wrapper - condition = "{" + condition + "}"; + condition = "{" + condition + "}"; } outQueryString.append(condition); @@ -237,21 +185,6 @@ public String getFilter() { return outQueryString.toString(); } - @Override - public Object visitNullFilter(Object extraData) { - return super.visitNullFilter(extraData); - } - - @Override - public Object visit(ExcludeFilter filter, Object extraData) { - return super.visit(filter, extraData); - } - - @Override - public Object visit(IncludeFilter filter, Object extraData) { - return super.visit(filter, extraData); - } - @Override public Object visit(And filter, Object extraData) { return visitBinaryLogic(filter, BINARY_OPERATOR_AND, extraData); @@ -261,9 +194,9 @@ private Object visitBinaryLogic(BinaryLogicOperator filter, String operator, Obj String filterCondition; if (operator.equals(BINARY_OPERATOR_AND)) { - filterCondition = (useFilter?templateAndWithFilter:templateAnd); + filterCondition = (useFilter ? TEMPLATE_AND_WITH_FILTER : TEMPLATE_AND); } else if (operator.equals(BINARY_OPERATOR_OR)) { - filterCondition = (useFilter?templateOrWithFilter:templateOr); + filterCondition = (useFilter ? TEMPLATE_OR_WITH_FILTER : TEMPLATE_OR); } else { throw new NotImplementedException(); } @@ -288,10 +221,10 @@ private Object visitBinaryLogic(BinaryLogicOperator filter, String operator, Obj int count = StringUtils.countMatches(filterCondition, "%s"); if (count == 1) { - filterCondition = String.format(filterCondition, String.join(",", conditionList)); + filterCondition = String.format(filterCondition, String.join(",", conditionList)); } else { - filterCondition = String.format(filterCondition, String.join(",", conditionList), "%s"); + filterCondition = String.format(filterCondition, String.join(",", conditionList), "%s"); } stack.push(filterCondition); @@ -307,7 +240,7 @@ public Object visit(Id filter, Object extraData) { @Override public Object visit(Not filter, Object extraData) { - String filterNot = templateNot; + String filterNot = TEMPLATE_NOT; filter.getFilter().accept(this, extraData); @@ -324,25 +257,32 @@ public Object visit(Or filter, Object extraData) { @Override public Object visit(PropertyIsBetween filter, Object extraData) { - String filterBetween = templateBetween; + String filterBetween = TEMPLATE_BETWEEN; - assert filter.getExpression() instanceof PropertyName; - filter.getExpression().accept(expressionVisitor, extraData); + if (!(filter.getExpression() instanceof PropertyName)) { + throw new IllegalArgumentException("Invalid expression property provided"); + } - assert filter.getLowerBoundary() instanceof Literal; - filter.getLowerBoundary().accept(expressionVisitor, extraData); + if (!(filter.getLowerBoundary() instanceof Literal)) { + throw new IllegalArgumentException("Invalid expression lower boundary literal provided"); + } + + if (!(filter.getUpperBoundary() instanceof Literal)) { + throw new IllegalArgumentException("Invalid expression upper boundary literal provided"); + } - assert filter.getUpperBoundary() instanceof Literal; + filter.getExpression().accept(expressionVisitor, extraData); + filter.getLowerBoundary().accept(expressionVisitor, extraData); filter.getUpperBoundary().accept(expressionVisitor, extraData); String dataPropertyUpperValue = stack.pop(); if (!NumberUtils.isNumber(dataPropertyUpperValue)) { - dataPropertyUpperValue = CswFilter2Es.quoteString(dataPropertyUpperValue); + dataPropertyUpperValue = StringEscapeUtils.escapeJson(CswFilter2Es.quoteString(dataPropertyUpperValue)); } String dataPropertyLowerValue = stack.pop(); if (!NumberUtils.isNumber(dataPropertyLowerValue)) { - dataPropertyLowerValue = CswFilter2Es.quoteString(dataPropertyLowerValue); + dataPropertyLowerValue = StringEscapeUtils.escapeJson(CswFilter2Es.quoteString(dataPropertyLowerValue)); } String dataPropertyName = stack.pop(); @@ -355,17 +295,15 @@ public Object visit(PropertyIsBetween filter, Object extraData) { @Override public Object visit(PropertyIsEqualTo filter, Object extraData) { + checkFilterExpressionsInBinaryComparisonOperator(filter); - assert filter.getExpression1() instanceof PropertyName; filter.getExpression1().accept(expressionVisitor, extraData); - - assert filter.getExpression2() instanceof Literal; filter.getExpression2().accept(expressionVisitor, extraData); String dataPropertyValue = stack.pop(); String dataPropertyName = stack.pop(); - final String filterEqualTo = String.format(templateMatch, dataPropertyName, dataPropertyValue); + final String filterEqualTo = String.format(TEMPLATE_MATCH, dataPropertyName, StringEscapeUtils.escapeJson(escapeLiteral(dataPropertyValue))); stack.push(filterEqualTo); return this; @@ -373,37 +311,40 @@ public Object visit(PropertyIsEqualTo filter, Object extraData) { @Override public Object visit(PropertyIsNotEqualTo filter, Object extraData) { - String filterPropertyIsNot = templatePropertyIsNot; + String filterPropertyIsNot = TEMPLATE_PROPERTY_IS_NOT; - assert filter.getExpression1() instanceof PropertyName; - filter.getExpression1().accept(expressionVisitor, extraData); + checkFilterExpressionsInBinaryComparisonOperator(filter); - assert filter.getExpression2() instanceof Literal; + filter.getExpression1().accept(expressionVisitor, extraData); filter.getExpression2().accept(expressionVisitor, extraData); String dataPropertyValue = stack.pop(); String dataPropertyName = stack.pop(); - filterPropertyIsNot = String.format(filterPropertyIsNot, dataPropertyName, dataPropertyValue); + filterPropertyIsNot = String.format(filterPropertyIsNot, dataPropertyName, + StringEscapeUtils.escapeJson(escapeLiteral(dataPropertyValue))); stack.push(filterPropertyIsNot); return this; } public Object visitRange(BinaryComparisonOperator filter, String operator, Object extraData) { - String filterRange = templateRange; + String filterRange = TEMPLATE_RANGE; - assert filter.getExpression1() instanceof PropertyName; - filter.getExpression1().accept(expressionVisitor, extraData); + checkFilterExpressionsInBinaryComparisonOperator(filter); - assert filter.getExpression2() instanceof Literal; + filter.getExpression1().accept(expressionVisitor, extraData); filter.getExpression2().accept(expressionVisitor, extraData); String dataPropertyValue = stack.pop(); String dataPropertyName = stack.pop(); - if (!NumberUtils.isNumber(dataPropertyValue)) { + boolean isDate = (DateUtil.parseBasicOrFullDateTime(dataPropertyValue) != null); + + if (isDate) { dataPropertyValue = CswFilter2Es.quoteString(dataPropertyValue); + } else if (!NumberUtils.isNumber(dataPropertyValue)) { + dataPropertyValue = StringEscapeUtils.escapeJson(CswFilter2Es.quoteString(dataPropertyValue)); } filterRange = String.format(filterRange, dataPropertyName, operator, dataPropertyValue); @@ -423,7 +364,7 @@ public Object visit(PropertyIsGreaterThanOrEqualTo filter, Object extraData) { } @Override - public Object visit(PropertyIsLessThan filter, Object extraData) { + public Object visit(PropertyIsLessThan filter, Object extraData) { return visitRange(filter, "lt", extraData); } @@ -434,7 +375,7 @@ public Object visit(PropertyIsLessThanOrEqualTo filter, Object extraData) { @Override public Object visit(PropertyIsLike filter, Object extraData) { - String filterIsLike = templateIsLike; + String filterIsLike = TEMPLATE_IS_LIKE; String expression = convertLikePattern(filter); @@ -472,7 +413,7 @@ public Object visit(PropertyIsNil filter, Object extraData) { * @return */ private String fillTemplateSpatial(String shapeType, String coords, String relation) { - return String.format(templateSpatial, shapeType, coords, relation); + return String.format(TEMPLATE_SPATIAL, shapeType, coords, relation); } @Override @@ -495,14 +436,12 @@ public Object visit(BBOX filter, Object extraData) { } private Object addGeomFilter(BinarySpatialOperator filter, String geoOperator, Object extraData) { - if (!(filter.getExpression2() == null || filter.getExpression1() == null)) { filter.getExpression1().accept(expressionVisitor, extraData); } - // out.append(":\"").append(geoOperator).append("("); final Expression geoExpression = filter.getExpression2() == null ? filter.getExpression1() - : filter.getExpression2(); + : filter.getExpression2(); geoExpression.accept(expressionVisitor, extraData); String geom = stack.pop(); @@ -542,7 +481,7 @@ private Object addGeomFilter(BinarySpatialOperator filter, String geoOperator, O stack.push(filterSpatial); } catch (Exception ex) { Log.error(Geonet.CSW, "Error parsing geospatial object", ex); - throw new RuntimeException(ex); + throw new IllegalArgumentException("Invalid expression for spatial filter", ex); } return this; @@ -674,7 +613,7 @@ public Object visit(TOverlaps contains, Object extraData) { private String buildCoordinatesString(Coordinate[] coordinates) { List coordinatesList = new ArrayList<>(); - for(Coordinate c : coordinates) { + for (Coordinate c : coordinates) { // Use Locale.US to make Java use dot "." as decimal separator String coordsValue = String.format(Locale.US, "[%f, %f] ", c.getX(), c.getY()); @@ -684,4 +623,14 @@ private String buildCoordinatesString(Coordinate[] coordinates) { return String.join(" , ", coordinatesList); } + + private void checkFilterExpressionsInBinaryComparisonOperator(BinaryComparisonOperator filter) { + if (!(filter.getExpression1() instanceof PropertyName)) { + throw new IllegalArgumentException("Invalid expression property provided"); + } + + if (!(filter.getExpression2() instanceof Literal)) { + throw new IllegalArgumentException("Invalid expression literal provided"); + } + } } diff --git a/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/getrecords/es/Expression2CswVisitor.java b/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/getrecords/es/Expression2CswVisitor.java index 4f6653f0cf9..a9b08d4f57e 100644 --- a/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/getrecords/es/Expression2CswVisitor.java +++ b/csw-server/src/main/java/org/fao/geonet/kernel/csw/services/getrecords/es/Expression2CswVisitor.java @@ -29,12 +29,12 @@ import org.geotools.referencing.CRS; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.io.WKTWriter; -import org.opengis.filter.expression.Literal; -import org.opengis.filter.expression.PropertyName; -import org.opengis.referencing.FactoryException; -import org.opengis.referencing.crs.CoordinateReferenceSystem; -import org.opengis.referencing.operation.MathTransform; -import org.opengis.referencing.operation.TransformException; +import org.geotools.api.filter.expression.Literal; +import org.geotools.api.filter.expression.PropertyName; +import org.geotools.api.referencing.FactoryException; +import org.geotools.api.referencing.crs.CoordinateReferenceSystem; +import org.geotools.api.referencing.operation.MathTransform; +import org.geotools.api.referencing.operation.TransformException; import java.util.Deque; diff --git a/csw-server/src/test/java/org/fao/geonet/kernel/csw/services/getrecords/es/CswFilter2EsTest.java b/csw-server/src/test/java/org/fao/geonet/kernel/csw/services/getrecords/es/CswFilter2EsTest.java index fc0eee3c643..98770670563 100644 --- a/csw-server/src/test/java/org/fao/geonet/kernel/csw/services/getrecords/es/CswFilter2EsTest.java +++ b/csw-server/src/test/java/org/fao/geonet/kernel/csw/services/getrecords/es/CswFilter2EsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2023 Food and Agriculture Organization of the + * Copyright (C) 2001-2024 Food and Agriculture Organization of the * United Nations (FAO-UN), United Nations World Food Programme (WFP) * and United Nations Environment Programme (UNEP) * @@ -29,10 +29,10 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import org.fao.geonet.kernel.csw.services.getrecords.FilterParser; import org.fao.geonet.kernel.csw.services.getrecords.IFieldMapper; +import org.geotools.api.filter.Filter; +import org.geotools.api.filter.capability.FilterCapabilities; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.opengis.filter.Filter; -import org.opengis.filter.capability.FilterCapabilities; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -45,7 +45,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; /** - * CswFilter2Es converts (XML-based) CSW queries into ElasticSearch queries. + * CswFilter2Es converts (XML-based) CSW queries into Elasticsearch queries. * These ES-queries are in JSON-notation. We do not want to test the resulting * JSON-String char-by-char as this is error-prone.
    *

    @@ -141,12 +141,11 @@ void testPropertyIsEqualTo() throws IOException { // INPUT: final String input = "\n" // - + " \n" // - + " Title\n" // - + " Hydrological\n" // - + " \n" // - + " " // - + ""; + + " \n" // + + " Title\n" // + + " Hydrological\n" // + + " \n" // + + " "; // EXPECTED: final ObjectNode expected = EsJsonHelper.boolbdr(). // @@ -157,34 +156,109 @@ void testPropertyIsEqualTo() throws IOException { assertFilterEquals(expected, input); } + @Test + void testPropertyIsEqualToSpecialChars() throws IOException { + final String input = + "\n" // + + " \n" // + + " OnlineResourceType\n" // + + " OGC:WMS\n" // + + " \n" // + + " "; + + // EXPECTED: + final ObjectNode expected = EsJsonHelper.boolbdr(). // + must(array(queryStringPart("OnlineResourceType", "OGC\\:WMS"))). // + filter(queryStringPart()). // + bld(); + + assertFilterEquals(expected, input); + } + + @Test + void testPropertyIsLike() throws IOException { + + final String input = + "\n" // + + " \n" // + + " AnyText\n" // + + " s\\_rvice\\%\n" // + + " \n" // + + " "; + + // EXPECTED: + final ObjectNode expected = EsJsonHelper.boolbdr(). // + must(array(queryStringPart("AnyText", "s?rvice*"))). // + filter(queryStringPart()). // + bld(); + + assertFilterEquals(expected, input); + } + + @Test + void testPropertyIsLikeSpecialChars() throws IOException { + + final String input = + "\n" // + + " \n" // + + " AnyText\n" // + + " \"service\"\n" // + + " \n" // + + " "; + + // EXPECTED: + final ObjectNode expected = EsJsonHelper.boolbdr(). // + must(array(queryStringPart("AnyText", "\\\"service\\\""))). // + filter(queryStringPart()). // + bld(); + + assertFilterEquals(expected, input); + + + final String input2 = + "\n" // + + " \n" // + + " AnyText\n" // + + " OGC:WMS\\%\n" // + + " \n" // + + " "; + + // EXPECTED: + final ObjectNode expected2 = EsJsonHelper.boolbdr(). // + must(array(queryStringPart("AnyText", "OGC\\:WMS*"))). // + filter(queryStringPart()). // + bld(); + + assertFilterEquals(expected2, input2); + } + @Test void testLogicalAnd() throws IOException { // INPUT: final String input = " \n" // - + " \n" // - + " \n" // - + " Title\n" // - + " Hydrological\n" // - + " \n" // - + " \n" // - + " Title\n" // - + " Africa\n" // - + " \n" // - + " \n" // - + " \n" // - + ""; + + " \n" // + + " \n" // + + " Title\n" // + + " Hydrological\n" // + + " \n" // + + " \n" // + + " Title\n" // + + " Africa\n" // + + " \n" // + + " \n" // + + " \n"; // EXPECTED: final ObjectNode expected = EsJsonHelper.boolbdr(). // must( - array( - queryStringPart("Title", "Africa"), - queryStringPart("Title", "Hydrological"))) // + array( + queryStringPart("Title", "Africa"), + queryStringPart("Title", "Hydrological"))) // . // - filter(queryStringPart()). // - bld(); + filter(queryStringPart()). // + bld(); assertFilterEquals(expected, input); } @@ -195,23 +269,22 @@ void testSpatialBBox() throws IOException { // INPUT: final String input = // " \n" // - + " \n" // - + " \n" // - + " -180 -90\n" // - + " 180 90\n" // - + " \n" // - + " \n" // - + " \n" // - + ""; + + " \n" // + + " \n" // + + " -180 -90\n" // + + " 180 90\n" // + + " \n" // + + " \n" // + + " \n"; // EXPECTED: final ObjectNode expected = boolbdr(). // must(array(geoShape("geom", // - envelope(-180d, 90d, 180d, -90d), // - "intersects"))) // + envelope(-180d, 90d, 180d, -90d), // + "intersects"))) // . // - filter(queryStringPart()). // - bld(); + filter(queryStringPart()). // + bld(); assertFilterEquals(expected, input); } @@ -227,33 +300,33 @@ void testFilterWithAndOrAndSpatialBBox() throws IOException { // INPUT: final String input = // " \n" // - + " \n" // - + " \n" // - + " \n" // - + " Type\n" // - + " data\n" // - + " \n" // - + " \n" // - + " Type\n" // - + " dataset\n" // - + " \n" // - + " \n" // - + " Type\n" // - + " datasetcollection\n" // - + " \n" // - + " \n" // - + " Type\n" // - + " series\n" // - + " \n" // - + " \n" // - + " \n" // - + " \n" // - + " -180 -90\n" // - + " 180 90\n" // - + " \n" // - + " \n" // - + " \n" // - + " "; + + " \n" // + + " \n" // + + " \n" // + + " Type\n" // + + " data\n" // + + " \n" // + + " \n" // + + " Type\n" // + + " dataset\n" // + + " \n" // + + " \n" // + + " Type\n" // + + " datasetcollection\n" // + + " \n" // + + " \n" // + + " Type\n" // + + " series\n" // + + " \n" // + + " \n" // + + " \n" // + + " \n" // + + " -180 -90\n" // + + " 180 90\n" // + + " \n" // + + " \n" // + + " \n" // + + " "; final ObjectNode propertiesPart = boolbdr().should(array( // queryStringPart("Type", "series"), // @@ -270,10 +343,10 @@ void testFilterWithAndOrAndSpatialBBox() throws IOException { // EXPECTED: final ObjectNode expected = boolbdr(). // must(array(geoShapePart, // - propertiesPart)) // + propertiesPart)) // . // - filter(queryStringPart()). // - bld(); + filter(queryStringPart()). // + bld(); assertFilterEquals(expected, input); } @@ -292,10 +365,10 @@ void assertFilterEquals(JsonNode expected, String actual) throws IOException { /** * Converts xml-string into OGC Filter expression using a specific filter - * version. This Filter is then finally converted to an ElasticSearch expression + * version. This Filter is then finally converted to an Elasticsearch expression * and checked against the expected output. * - * @param expected JsonNode representing the expected ElasticSearch + * @param expected JsonNode representing the expected Elasticsearch * query. * @param actual XML text of the OGC Filter. * @param filterSpecVersion see {@link FilterCapabilities} @@ -308,4 +381,27 @@ void assertFilterEquals(JsonNode expected, String actual, String filterSpecVersi assertEquals(expected, MAPPER.readTree(new StringReader(result))); } + + + @Test + void testPropertyIsGreaterThanDateValue() throws IOException { + + // INPUT: + final String input = + " \n" + + " \n" + + " Modified\n" + + " 1910-02-05\n" + + " \n" + + " "; + + // EXPECTED: + final ObjectNode expected = EsJsonHelper.boolbdr(). // + must(array(range("Modified", "gt", "1910-02-05"))). // + filter(queryStringPart()). // + bld(); + + + assertFilterEquals(expected, input); + } } diff --git a/csw-server/src/test/java/org/fao/geonet/kernel/csw/services/getrecords/es/CswSortBy2EsTest.java b/csw-server/src/test/java/org/fao/geonet/kernel/csw/services/getrecords/es/CswSortBy2EsTest.java index 7036125f753..0d177599546 100644 --- a/csw-server/src/test/java/org/fao/geonet/kernel/csw/services/getrecords/es/CswSortBy2EsTest.java +++ b/csw-server/src/test/java/org/fao/geonet/kernel/csw/services/getrecords/es/CswSortBy2EsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2021 Food and Agriculture Organization of the + * Copyright (C) 2001-2023 Food and Agriculture Organization of the * United Nations (FAO-UN), United Nations World Food Programme (WFP) * and United Nations Environment Programme (UNEP) * @@ -25,9 +25,7 @@ import static junit.framework.TestCase.assertEquals; -import org.checkerframework.checker.units.qual.A; -import org.elasticsearch.search.sort.FieldSortBuilder; -import org.elasticsearch.search.sort.SortBuilder; +import co.elastic.clients.elasticsearch._types.SortOptions; import org.fao.geonet.constants.Geonet; import org.fao.geonet.csw.common.Csw; import org.fao.geonet.kernel.csw.CatalogConfiguration; @@ -43,7 +41,7 @@ import java.util.List; /** - * CswFilter2Es converts (XML-based) CSW queries into ElasticSearch queries. + * CswFilter2Es converts (XML-based) CSW queries into Elasticsearch queries. * These ES-queries are in JSON-notation. We do not want to test the resulting * JSON-String char-by-char as this is error-prone.
    *

    @@ -70,12 +68,12 @@ void configureDefaultSort() { Element request = createSortByBaseRequest( new Element("Empty", Geonet.Namespaces.OGC)); - List> sortFields = toTest.parseSortBy(request); + List sortFields = toTest.parseSortBy(request); assertEquals(1, sortFields.size()); - FieldSortBuilder sortField = (FieldSortBuilder)sortFields.get(0); - assertEquals(sortField.getFieldName(), "resourceTitleObject.default.keyword"); - assertEquals(sortField.order().toString(), "desc"); + SortOptions sortField = sortFields.get(0); + assertEquals(sortField.field().field(), "resourceTitleObject.default.keyword"); + assertEquals(sortField.field().order().jsonValue(), "desc"); } @Test @@ -86,12 +84,12 @@ void sortByRelevanceDESC() { .addContent(new Element("PropertyName", Geonet.Namespaces.OGC).setText("Relevance")) .addContent(new Element("SortOrder", Geonet.Namespaces.OGC).setText("DESC")))); - List> sortFields = toTest.parseSortBy(request); + List sortFields = toTest.parseSortBy(request); assertEquals(1, sortFields.size()); - FieldSortBuilder sortField = (FieldSortBuilder)sortFields.get(0); - assertEquals(sortField.getFieldName(), "_score"); - assertEquals(sortField.order().toString(), "desc"); + SortOptions sortField = sortFields.get(0); + assertEquals(sortField.field().field(), "_score"); + assertEquals(sortField.field().order().jsonValue(), "desc"); } @Test @@ -102,12 +100,12 @@ void sortByRelevanceASC() { .addContent(new Element("PropertyName", Geonet.Namespaces.OGC).setText("Relevance")) .addContent(new Element("SortOrder", Geonet.Namespaces.OGC).setText("ASC")))); - List> sortFields = toTest.parseSortBy(request); + List sortFields = toTest.parseSortBy(request); assertEquals(1, sortFields.size()); - FieldSortBuilder sortField = (FieldSortBuilder)sortFields.get(0); - assertEquals(sortField.getFieldName(), "_score"); - assertEquals(sortField.order().toString(), "asc"); + SortOptions sortField = sortFields.get(0); + assertEquals(sortField.field().field(), "_score"); + assertEquals(sortField.field().order().jsonValue(), "asc"); } @Test @@ -118,12 +116,12 @@ void sortByIndexField() { .addContent(new Element("PropertyName", Geonet.Namespaces.OGC).setText("title")) .addContent(new Element("SortOrder", Geonet.Namespaces.OGC).setText("DESC")))); - List> sortFields = toTest.parseSortBy(request); + List sortFields = toTest.parseSortBy(request); assertEquals(1, sortFields.size()); - FieldSortBuilder sortField = (FieldSortBuilder)sortFields.get(0); - assertEquals(sortField.getFieldName(), "title"); - assertEquals(sortField.order().toString(), "desc"); + SortOptions sortField = sortFields.get(0); + assertEquals(sortField.field().field(), "title"); + assertEquals(sortField.field().order().jsonValue(), "desc"); } @Test @@ -137,15 +135,15 @@ void sortByMultipleProperties() { .addContent(new Element("PropertyName", Geonet.Namespaces.OGC).setText("Relevance")) .addContent(new Element("SortOrder", Geonet.Namespaces.OGC).setText("DESC")))); - List> sortFields = toTest.parseSortBy(request); + List sortFields = toTest.parseSortBy(request); assertEquals(2, sortFields.size()); - FieldSortBuilder sortField = (FieldSortBuilder)sortFields.get(0); - assertEquals(sortField.getFieldName(), "title"); - assertEquals(sortField.order().toString(), "desc"); - FieldSortBuilder sortField2 = (FieldSortBuilder)sortFields.get(1); - assertEquals(sortField2.getFieldName(), "_score"); - assertEquals(sortField2.order().toString(), "desc"); + SortOptions sortField = sortFields.get(0); + assertEquals(sortField.field().field(), "title"); + assertEquals(sortField.field().order().jsonValue(), "desc"); + SortOptions sortField2 = sortFields.get(1); + assertEquals(sortField2.field().field(), "_score"); + assertEquals(sortField2.field().order().jsonValue(), "desc"); } private Element createSortByBaseRequest(Element SortBy) { diff --git a/csw-server/src/test/java/org/fao/geonet/kernel/csw/services/getrecords/es/EsJsonHelper.java b/csw-server/src/test/java/org/fao/geonet/kernel/csw/services/getrecords/es/EsJsonHelper.java index 08b345f0ef9..f727509808a 100644 --- a/csw-server/src/test/java/org/fao/geonet/kernel/csw/services/getrecords/es/EsJsonHelper.java +++ b/csw-server/src/test/java/org/fao/geonet/kernel/csw/services/getrecords/es/EsJsonHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2023 Food and Agriculture Organization of the + * Copyright (C) 2001-2024 Food and Agriculture Organization of the * United Nations (FAO-UN), United Nations World Food Programme (WFP) * and United Nations Environment Programme (UNEP) * @@ -31,7 +31,7 @@ import java.util.List; /** - * Tools to build up ElasticSearch JSON structures via Jackson. + * Tools to build up Elasticsearch JSON structures via Jackson. * * @author bhoefling * @@ -62,6 +62,35 @@ public static ObjectNode match(String property, String matchString) { return outer; } + + /** + * Returns a structure like + * + *

    +     *  { "range":
    +     *    {
    +     *      "gt": "value"
    +     *    }
    +     * 
    + * + * @param property + * @param operator + * @param matchString + * @return + */ + public static ObjectNode range(String property, String operator, String matchString) { + final ObjectNode rangeOperatorObject = MAPPER.createObjectNode(); + rangeOperatorObject.put(operator, matchString); + + final ObjectNode rangeObject = MAPPER.createObjectNode(); + rangeObject.put(property, rangeOperatorObject); + + final ObjectNode outer = MAPPER.createObjectNode(); + outer.set("range", rangeObject); + return outer; + } + + private static ArrayNode bound(double x, double y) { final ArrayNode bound = MAPPER.createArrayNode(); bound.add(x); diff --git a/datastorages/README.md b/datastorages/README.md new file mode 100644 index 00000000000..721c1687d55 --- /dev/null +++ b/datastorages/README.md @@ -0,0 +1,12 @@ +# Data storage + +Extensions for data storage (used for storage resources such as record attachments and thumbnails). + +Core provides the default implementation for a data directory: + +* org.fao.geonet.resource.FileResources + +For more information see: + +* org.fao.geonet.resource.Resources + diff --git a/datastorages/cmis/README.md b/datastorages/cmis/README.md new file mode 100644 index 00000000000..5bd20e924f1 --- /dev/null +++ b/datastorages/cmis/README.md @@ -0,0 +1,11 @@ +# CMIS Data storage + +Extension for data storage (used for storage resources such as record attachments and thumbnails). + +* cmis: content management interoperability services + +This data storage is based on the Apache Chemistry project which has been retired. + +Reference: + +* https://chemistry.apache.org/java/opencmis.html diff --git a/datastorages/cmis/pom.xml b/datastorages/cmis/pom.xml new file mode 100644 index 00000000000..dffd357d170 --- /dev/null +++ b/datastorages/cmis/pom.xml @@ -0,0 +1,208 @@ + + + + + + gn-datastorages + org.geonetwork-opensource.datastorage + 4.4.7-SNAPSHOT + + 4.0.0 + + gn-datastorage-cmis + CMIS datastorage + + + + org.geonetwork-opensource + gn-core + ${project.version} + provided + + + + org.springframework + spring-context + provided + + + + org.springframework + spring-context-support + provided + + + + org.apache.chemistry.opencmis + chemistry-opencmis-client-api + + + + org.apache.chemistry.opencmis + chemistry-opencmis-client-impl + + + + + + + maven-jar-plugin + + + test-jar + + test-jar + + + + + + + + src/main/resources + true + + + + + + + run-static-analysis + + + !skipTests + + + + + + org.codehaus.mojo + findbugs-maven-plugin + + + + + + + release + + + + release + + + + + + + maven-dependency-plugin + + + stage-libs + prepare-package + + copy-dependencies + + + + true + runtime + provided + com.google.code.findbugs + false + ${project.build.directory}/lib + false + true + + + + + + + com.ruleoftech + markdown-page-generator-plugin + + + readme + process-resources + + generate + + + ${project.basedir}/src/main/assembly + ${project.build.directory}/html + + + + licenses + process-resources + + generate + + + ${project.basedir}/../../ + ${project.build.directory}/html/license + + + + + false + true + ${project.basedir}/../../release/src/markdown/html/header.html + ${project.basedir}/../../release/src/markdown/html/footer.html + TABLES,FENCED_CODE_BLOCKS + true + + + + + maven-assembly-plugin + + + release-zip + package + + single + + + ${project.artifactId}-${project.version} + false + + src/main/assembly/assembly.xml + + + + + + + + + + + + ${basedir}/.. + + diff --git a/datastorages/cmis/src/main/assembly/README.md b/datastorages/cmis/src/main/assembly/README.md new file mode 100644 index 00000000000..ee08bc7a3e3 --- /dev/null +++ b/datastorages/cmis/src/main/assembly/README.md @@ -0,0 +1,27 @@ +# CMIS data storage provider library + +To install the CMIS data storage provider in GeoNetwork: + +1. Copy the `lib` folder jar files into to `{GEONETWORK_DIR}/WEB-INF/lib` folder. + +2. Define the following environmental variables: + + - Use CMIS data storage provider: + + ```bash + export GEONETWORK_STORE_TYPE=cmis + ``` + + - Setup CMIS connection (check with your setup): + + ```bash + export CMIS_REPOSITORY_ID=-default- + export CMIS_USERNAME=username + export CMIS_PASSWORD=password + export CMIS_SERVICES_BASE_URL=http://localhost:8080/alfresco + export CMIS_BASE_REPOSITORY_PATH=geonetwork + export CMIS_BINDING_TYPE=browser + export CMIS_BROWSER_URL=/api/-default-/public/cmis/versions/1.1/browser + ``` + +3. Start GeoNetwork diff --git a/datastorages/cmis/src/main/assembly/assembly.xml b/datastorages/cmis/src/main/assembly/assembly.xml new file mode 100644 index 00000000000..86569455568 --- /dev/null +++ b/datastorages/cmis/src/main/assembly/assembly.xml @@ -0,0 +1,31 @@ + + bin + + zip + + + + ${project.build.directory}/lib + /lib + + + + + + ${project.build.directory}/${project.artifactId}-${project.version}.jar + /lib + + + + ${project.build.directory}/html/README.html + / + + + + ${project.build.directory}/html/license/LICENSE.html + /license + + + diff --git a/core/src/main/java/org/fao/geonet/api/records/attachments/CMISStore.java b/datastorages/cmis/src/main/java/org/fao/geonet/api/records/attachments/CMISStore.java similarity index 88% rename from core/src/main/java/org/fao/geonet/api/records/attachments/CMISStore.java rename to datastorages/cmis/src/main/java/org/fao/geonet/api/records/attachments/CMISStore.java index 87f74ab9982..989dc719fc4 100644 --- a/core/src/main/java/org/fao/geonet/api/records/attachments/CMISStore.java +++ b/datastorages/cmis/src/main/java/org/fao/geonet/api/records/attachments/CMISStore.java @@ -1,6 +1,6 @@ /* * ============================================================================= - * === Copyright (C) 2001-2016 Food and Agriculture Organization of the + * === Copyright (C) 2001-2024 Food and Agriculture Organization of the * === United Nations (FAO-UN), United Nations World Food Programme (WFP) * === and United Nations Environment Programme (UNEP) * === @@ -190,7 +190,20 @@ public ResourceHolder getResource(final ServiceContext context, final String met @Override public ResourceHolder getResourceInternal(String metadataUuid, MetadataResourceVisibility visibility, String resourceId, Boolean approved) throws Exception { - throw new UnsupportedOperationException("CMISStore does not support getResourceInternal."); + int metadataId = getAndCheckMetadataId(metadataUuid, approved); + checkResourceId(resourceId); + + try { + ServiceContext context = ServiceContext.get(); + final CmisObject object = cmisConfiguration.getClient().getObjectByPath(getKey(context, metadataUuid, metadataId, visibility, resourceId)); + return new ResourceHolderImpl(object, createResourceDescription(context, metadataUuid, visibility, resourceId, + (Document) object, metadataId, approved)); + } catch (CmisObjectNotFoundException e) { + throw new ResourceNotFoundException( + String.format("Metadata resource '%s' not found for metadata '%s'", resourceId, metadataUuid)) + .withMessageKey("exception.resourceNotFound.resource", new String[]{resourceId}) + .withDescriptionKey("exception.resourceNotFound.resource.description", new String[]{resourceId, metadataUuid}); + } } protected String getKey(final ServiceContext context, String metadataUuid, int metadataId, MetadataResourceVisibility visibility, String resourceId) { @@ -385,35 +398,35 @@ public MetadataResource patchResourceStatus(final ServiceContext context, final } @Override - public String delResources(final ServiceContext context, final String metadataUuid, Boolean approved) throws Exception { - int metadataId = canEdit(context, metadataUuid, approved); + public String delResources(final ServiceContext context, final int metadataId) throws Exception { String folderKey = null; try { folderKey = getMetadataDir(context, metadataId); final Folder folder = cmisUtils.getFolderCache(folderKey, true); + Log.info(Geonet.RESOURCES, String.format("Deleting the folder of '%s' and the files within the folder", folderKey)); folder.deleteTree(true, UnfileObject.DELETE, true); cmisUtils.invalidateFolderCache(folderKey); Log.info(Geonet.RESOURCES, - String.format("Metadata '%s(%s)' directory '%s' removed.", metadataUuid, metadataId, folderKey)); - return String.format("Metadata '%s(%s)' directory '%s' removed.", metadataUuid, metadataId, folderKey); + String.format("Metadata '%d' directory '%s' removed.", metadataId, folderKey)); + return String.format("Metadata '%d' directory '%s' removed.", metadataId, folderKey); } catch (CmisObjectNotFoundException e) { Log.warning(Geonet.RESOURCES, - String.format("Unable to located metadata '%s(%s)' directory '%s' to be removed.", metadataUuid, metadataId, folderKey)); - return String.format("Unable to located metadata '%s(%s)' directory '%s' to be removed.", metadataUuid, metadataId, folderKey); + String.format("Unable to located metadata '%d' directory '%s' to be removed.", metadataId, folderKey)); + return String.format("Unable to located metadata '%d' directory '%s' to be removed.", metadataId, folderKey); } catch (ResourceNotFoundException e) { Log.warning(Geonet.RESOURCES, - String.format("Unable to located metadata '%s(%s)' directory '%s' to be removed.", metadataUuid, metadataId, folderKey)); - return String.format("Unable to located metadata '%s(%s)' directory '%s' to be removed.", metadataUuid, metadataId, folderKey); + String.format("Unable to located metadata '%d' directory '%s' to be removed.", metadataId, folderKey)); + return String.format("Unable to located metadata '%d' directory '%s' to be removed.", metadataId, folderKey); } catch (CmisPermissionDeniedException e) { Log.warning(Geonet.RESOURCES, - String.format("Insufficient privileges, unable to remove metadata '%s(%s)' directory '%s'.", metadataUuid, metadataId, folderKey)); - return String.format("Insufficient privileges, unable to remove metadata '%s(%s)' directory '%s'.", metadataUuid, metadataId, folderKey); + String.format("Insufficient privileges, unable to remove metadata '%d' directory '%s'.", metadataId, folderKey)); + return String.format("Insufficient privileges, unable to remove metadata '%d' directory '%s'.", metadataId, folderKey); } catch (CmisConstraintException e) { Log.warning(Geonet.RESOURCES, - String.format("Unable to remove metadata '%s(%s)' directory '%s' due so constraint violation or locks.", metadataUuid, metadataId, folderKey)); - return String.format("Unable to remove metadata '%s(%s)' directory '%s' due so constraint violation or locks.", metadataUuid, metadataId, folderKey); + String.format("Unable to remove metadata '%d' directory '%s' due so constraint violation or locks.", metadataId, folderKey)); + return String.format("Unable to remove metadata '%d' directory '%s' due so constraint violation or locks.", metadataId, folderKey); } } @@ -424,13 +437,9 @@ public String delResource(final ServiceContext context, final String metadataUui for (MetadataResourceVisibility visibility : MetadataResourceVisibility.values()) { if (tryDelResource(context, metadataUuid, metadataId, visibility, resourceId)) { - Log.info(Geonet.RESOURCES, - String.format("MetadataResource '%s' removed.", resourceId)); - return String.format("MetadataResource '%s' removed.", resourceId); + return String.format("Metadata resource '%s' removed.", resourceId); } } - Log.info(Geonet.RESOURCES, - String.format("Unable to remove resource '%s'.", resourceId)); return String.format("Unable to remove resource '%s'.", resourceId); } @@ -439,12 +448,8 @@ public String delResource(final ServiceContext context, final String metadataUui final String resourceId, Boolean approved) throws Exception { int metadataId = canEdit(context, metadataUuid, approved); if (tryDelResource(context, metadataUuid, metadataId, visibility, resourceId)) { - Log.info(Geonet.RESOURCES, - String.format("MetadataResource '%s' removed.", resourceId)); - return String.format("MetadataResource '%s' removed.", resourceId); + return String.format("Metadata resource '%s' removed.", resourceId); } - Log.info(Geonet.RESOURCES, - String.format("Unable to remove resource '%s'.", resourceId)); return String.format("Unable to remove resource '%s'.", resourceId); } @@ -459,6 +464,8 @@ protected boolean tryDelResource(final ServiceContext context, final String meta try { final CmisObject object = cmisConfiguration.getClient().getObjectByPath(key, oc); object.delete(); + Log.info(Geonet.RESOURCES, + String.format("Resource '%s' removed for metadata %d (%s).", resourceId, metadataId, metadataUuid)); if (object instanceof Folder) { cmisUtils.invalidateFolderCacheItem(key); } @@ -467,6 +474,8 @@ protected boolean tryDelResource(final ServiceContext context, final String meta //CmisPermissionDeniedException when user does not have permissions. //CmisConstraintException when there is a lock on the file from a checkout. } catch (CmisObjectNotFoundException | CmisPermissionDeniedException | CmisConstraintException e) { + Log.info(Geonet.RESOURCES, + String.format("Unable to remove resource '%s' for metadata %d (%s). %s", resourceId, metadataId, metadataUuid, e.getMessage())); return false; } } @@ -509,7 +518,9 @@ public MetadataResourceContainer getResourceContainerDescription(final ServiceCo @Override public void copyResources(ServiceContext context, String sourceUuid, String targetUuid, MetadataResourceVisibility metadataResourceVisibility, boolean sourceApproved, boolean targetApproved) throws Exception { final int sourceMetadataId = canEdit(context, sourceUuid, metadataResourceVisibility, sourceApproved); + final int targetMetadataId = canEdit(context, sourceUuid, metadataResourceVisibility, targetApproved); final String sourceResourceTypeDir = getMetadataDir(context, sourceMetadataId) + cmisConfiguration.getFolderDelimiter() + metadataResourceVisibility.toString(); + final String targetResourceTypeDir = getMetadataDir(context, targetMetadataId) + cmisConfiguration.getFolderDelimiter() + metadataResourceVisibility.toString(); try { Folder sourceParentFolder = cmisUtils.getFolderCache(sourceResourceTypeDir, true); @@ -523,6 +534,8 @@ public void copyResources(ServiceContext context, String sourceUuid, String targ for (Map.Entry sourceEntry : sourceDocumentMap.entrySet()) { Document sourceDocument = sourceEntry.getValue(); + + Log.info(Geonet.RESOURCES, String.format("Copying %s to %s" , sourceResourceTypeDir+cmisConfiguration.getFolderDelimiter()+sourceDocument.getName(), targetResourceTypeDir)); // Get cmis properties from the source document Map sourceProperties = getProperties(sourceDocument); putResource(context, targetUuid, sourceDocument.getName(), sourceDocument.getContentStream().getStream(), null, metadataResourceVisibility, targetApproved, sourceProperties); @@ -617,14 +630,16 @@ protected Path getBaseMetadataDir(ServiceContext context, Path metadataFullDir) } private GeonetworkDataDirectory getDataDirectory(ServiceContext context) { - return context.getBean(GeonetworkDataDirectory.class); + return ApplicationContextHolder.get().getBean(GeonetworkDataDirectory.class); } /** * get external resource management for the supplied resource. * Replace the following + * {objectId} type:visibility:metadataId:version:resourceId in base64 encoding * {id} resource id - * {type:folder:document} // If the type is folder then type "folder" will be displayed else if document then "document" will be displayed + * {type:folder:document} // Custom return type based on type. If the type is folder then type "folder" will be displayed else if document then "document" will be displayed + * {type} // If the type is folder then type "folder" will be displayed else if document then "document" will be displayed * {uuid} metadatauuid * {metadataid} metadataid * {visibility} visibility @@ -653,16 +668,27 @@ protected MetadataResourceExternalManagementProperties getMetadataResourceExtern ) { String metadataResourceExternalManagementPropertiesUrl = cmisConfiguration.getExternalResourceManagementUrl(); if (!StringUtils.isEmpty(metadataResourceExternalManagementPropertiesUrl)) { + // {objectid} objectId // It will be the type:visibility:metadataId:version:resourceId in base64 + // i.e. folder::100::100 # Folder in resource 100 + // i.e. document:public:100:v1:sample.jpg # public document 100 version v1 name sample.jpg + if (metadataResourceExternalManagementPropertiesUrl.contains("{objectid}")) { + metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("(\\{objectid\\})", + getResourceManagementExternalPropertiesObjectId((type == null ? "document" : (type instanceof Folder ? "folder" : "document")), visibility, metadataId, version, resourceId)); + } // {id} id if (metadataResourceExternalManagementPropertiesUrl.contains("{id}")) { metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("(\\{id\\})", (resourceId==null?"":resourceId)); } - // {type:folder:document} // If the type is folder then type "folder" will be displayed else if document then "document" will be displayed + // {type:folder:document} // Custom return type based on type. If the type is folder then type "folder" will be displayed else if document then "document" will be displayed if (metadataResourceExternalManagementPropertiesUrl.contains("{type:")) { metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("\\{type:([a-zA-Z0-9]*?):([a-zA-Z0-9]*?)\\}", (type==null?"":(type instanceof Folder?"$1":"$2"))); } - + // {type} // If the type is folder then type "folder" will be displayed else if document then "document" will be displayed + if (metadataResourceExternalManagementPropertiesUrl.contains("{type}")) { + metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("(\\{type\\})", + (type == null ? "document" : (type instanceof Folder ? "folder" : "document"))); + } // {uuid} metadatauuid if (metadataResourceExternalManagementPropertiesUrl.contains("{uuid}")) { metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("(\\{uuid\\})", (metadataUuid==null?"":metadataUuid)); @@ -690,7 +716,7 @@ protected MetadataResourceExternalManagementProperties getMetadataResourceExtern if (metadataResourceExternalManagementPropertiesUrl.contains("{lang}") || metadataResourceExternalManagementPropertiesUrl.contains("{ISO3lang}")) { final IsoLanguagesMapper mapper = ApplicationContextHolder.get().getBean(IsoLanguagesMapper.class); - String contextLang = context.getLanguage() == null ? Geonet.DEFAULT_LANGUAGE : context.getLanguage(); + String contextLang = context==null || context.getLanguage() == null ? Geonet.DEFAULT_LANGUAGE : context.getLanguage(); String lang; String iso3Lang; diff --git a/core/src/main/java/org/fao/geonet/resources/CMISConfiguration.java b/datastorages/cmis/src/main/java/org/fao/geonet/resources/CMISConfiguration.java similarity index 93% rename from core/src/main/java/org/fao/geonet/resources/CMISConfiguration.java rename to datastorages/cmis/src/main/java/org/fao/geonet/resources/CMISConfiguration.java index 257ef3246d6..87b76ec0821 100644 --- a/core/src/main/java/org/fao/geonet/resources/CMISConfiguration.java +++ b/datastorages/cmis/src/main/java/org/fao/geonet/resources/CMISConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2016 Food and Agriculture Organization of the + * Copyright (C) 2001-2024 Food and Agriculture Organization of the * United Nations (FAO-UN), United Nations World Food Programme (WFP) * and United Nations Environment Programme (UNEP) * @@ -59,26 +59,28 @@ public class CMISConfiguration { private Session client = null; - public final static Integer CMIS_MAX_ITEMS_PER_PAGE = 1000; - public final static String CMIS_FOLDER_DELIMITER = "/"; // Specs indicate that "/" is the folder delimiter/separator - not sure if other delimiter can be used?. - public final static String CMIS_SECONDARY_PROPERTY_SEPARATOR = "->"; - private final String CMIS_DEFAULT_WEBSERVICES_ACL_SERVICE = "/services/ACLService?wsdl"; - private final String CMIS_DEFAULT_WEBSERVICES_DISCOVERY_SERVICE = "/services/DiscoveryService?wsdl"; - private final String CMIS_DEFAULT_WEBSERVICES_MULTIFILING_SERVICE = "/services/MultiFilingService?wsdl"; - private final String CMIS_DEFAULT_WEBSERVICES_NAVIGATION_SERVICE = "/services/NavigationService?wsdl"; - private final String CMIS_DEFAULT_WEBSERVICES_OBJECT_SERVICE = "/services/ObjectService?wsdl"; - private final String CMIS_DEFAULT_WEBSERVICES_POLICY_SERVICE = "/services/PolicyService?wsdl"; - private final String CMIS_DEFAULT_WEBSERVICES_RELATIONSHIP_SERVICE = "/services/RelationshipService?wsdl"; - private final String CMIS_DEFAULT_WEBSERVICES_REPOSITORY_SERVICE = "/services/RepositoryService?wsdl"; - private final String CMIS_DEFAULT_WEBSERVICES_VERSIONING_SERVICE = "/services/VersioningService?wsdl"; - private final String CMIS_DEFAULT_WEBSERVICES_BASE_URL_SERVICE = "/cmis"; - private final String CMIS_DEFAULT_BROWSER_URL_SERVICE = "/browser"; - private final String CMIS_DEFAULT_ATOMPUB_URL_SERVICE = "/atom"; - - private final String CMIS_DEFAULT_EXTERNAL_RESOURCE_MANAGEMENT_WINDOW_PARAMETERS = "toolbar=0,width=600,height=600"; - private final Boolean CMIS_DEFAULT_EXTERNAL_RESOURCE_MANAGEMENT_MODAL_ENABLED = true; - private final Boolean CMIS_DEFAULT_EXTERNAL_RESOURCE_MANAGEMENT_FOLDER_ENABLED = true; - private final Boolean CMIS_DEFAULT_VERSIONING_ENABLED = false; + // DFO change to 100. Due to bug with open text cmis where if max is set to 1000, it will return 100 but if it is set to 100 it will return all records. + // https://dev.azure.com/foc-poc/EDH-CDE/_workitems/edit/95878 + public static final Integer CMIS_MAX_ITEMS_PER_PAGE = 100; + public static final String CMIS_FOLDER_DELIMITER = "/"; // Specs indicate that "/" is the folder delimiter/separator - not sure if other delimiter can be used?. + public static final String CMIS_SECONDARY_PROPERTY_SEPARATOR = "->"; + private static final String CMIS_DEFAULT_WEBSERVICES_ACL_SERVICE = "/services/ACLService?wsdl"; + private static final String CMIS_DEFAULT_WEBSERVICES_DISCOVERY_SERVICE = "/services/DiscoveryService?wsdl"; + private static final String CMIS_DEFAULT_WEBSERVICES_MULTIFILING_SERVICE = "/services/MultiFilingService?wsdl"; + private static final String CMIS_DEFAULT_WEBSERVICES_NAVIGATION_SERVICE = "/services/NavigationService?wsdl"; + private static final String CMIS_DEFAULT_WEBSERVICES_OBJECT_SERVICE = "/services/ObjectService?wsdl"; + private static final String CMIS_DEFAULT_WEBSERVICES_POLICY_SERVICE = "/services/PolicyService?wsdl"; + private static final String CMIS_DEFAULT_WEBSERVICES_RELATIONSHIP_SERVICE = "/services/RelationshipService?wsdl"; + private static final String CMIS_DEFAULT_WEBSERVICES_REPOSITORY_SERVICE = "/services/RepositoryService?wsdl"; + private static final String CMIS_DEFAULT_WEBSERVICES_VERSIONING_SERVICE = "/services/VersioningService?wsdl"; + private static final String CMIS_DEFAULT_WEBSERVICES_BASE_URL_SERVICE = "/cmis"; + private static final String CMIS_DEFAULT_BROWSER_URL_SERVICE = "/browser"; + private static final String CMIS_DEFAULT_ATOMPUB_URL_SERVICE = "/atom"; + + private static final String CMIS_DEFAULT_EXTERNAL_RESOURCE_MANAGEMENT_WINDOW_PARAMETERS = "toolbar=0,width=600,height=600"; + private static final Boolean CMIS_DEFAULT_EXTERNAL_RESOURCE_MANAGEMENT_MODAL_ENABLED = true; + private static final Boolean CMIS_DEFAULT_EXTERNAL_RESOURCE_MANAGEMENT_FOLDER_ENABLED = true; + private static final Boolean CMIS_DEFAULT_VERSIONING_ENABLED = false; private String servicesBaseUrl; private String bindingType; @@ -111,7 +113,6 @@ public class CMISConfiguration { * Property name for validation status that is expected to be an integer with values of null, 0, 1, 2 * (See MetadataResourceExternalManagementProperties.ValidationStatus for code meaning) * Property name follows the same format as cmisMetadataUUIDPropertyName - * * If null then validation status will default to UNKNOWN. */ private String externalResourceManagementValidationStatusPropertyName; @@ -505,7 +506,6 @@ public void setExternalResourceManagementValidationStatusPropertyName(String ext String.format("Invalid format for property name %s property will not be used", externalResourceManagementValidationStatusPropertyName)); this.externalResourceManagementValidationStatusPropertyName = null; this.externalResourceManagementValidationStatusSecondaryProperty = false; - return; } else { this.externalResourceManagementValidationStatusSecondaryProperty = true; } @@ -514,7 +514,7 @@ public void setExternalResourceManagementValidationStatusPropertyName(String ext public MetadataResourceExternalManagementProperties.ValidationStatus getValidationStatusDefaultValue() { // We only need to set the default if there is a status property supplied, and it is not already set - if (this.defaultStatus == null && !org.springframework.util.StringUtils.isEmpty(getExternalResourceManagementValidationStatusPropertyName())) { + if (this.defaultStatus == null && org.springframework.util.StringUtils.hasLength(getExternalResourceManagementValidationStatusPropertyName())) { if (getExternalResourceManagementValidationStatusDefaultValue() != null) { // If a default property name does exist then use it this.defaultStatus = MetadataResourceExternalManagementProperties.ValidationStatus.valueOf(getExternalResourceManagementValidationStatusDefaultValue()); @@ -536,9 +536,8 @@ public void init() { } // default factory implementation - Map parameters = new HashMap(); + Map parameters = new HashMap<>(); - this.baseRepositoryPath = baseRepositoryPath; if (this.baseRepositoryPath == null) { this.baseRepositoryPath = ""; } @@ -609,7 +608,7 @@ public void init() { } } } else { - // Try to find the repository name for the id that we have specified.. + // Try to find the repository name for the id that we have specified. try { for (Repository repository : factory.getRepositories(parameters)) { if (repository.getId().equalsIgnoreCase(this.repositoryId)) { @@ -633,7 +632,7 @@ public void init() { repositoryUrl + "' using product '" + client.getRepositoryInfo().getProductName() + "' version '" + client.getRepositoryInfo().getProductVersion() + "'."); - // Check if we can parse the secondary parameters from human readable to secondary ids. + // Check if we can parse the secondary parameters from human-readable to secondary ids. parsedCmisMetadataUUIDPropertyName = parseSecondaryProperty(client, cmisMetadataUUIDPropertyName); parsedExternalResourceManagementValidationStatusPropertyName = parseSecondaryProperty(client, externalResourceManagementValidationStatusPropertyName); @@ -743,7 +742,7 @@ public boolean existExternalResourceManagementValidationStatusSecondaryProperty( } /** - * Generte a full url based on the supplied entered serviceurl and the default. + * Generate a full url based on the supplied entered serviceUrl and the default. * * @param baseUrl Base url * @param serviceUrl Supplied service url (This could start with / or http. If it starts with http then ignore baseUrl) diff --git a/core/src/main/java/org/fao/geonet/resources/CMISResources.java b/datastorages/cmis/src/main/java/org/fao/geonet/resources/CMISResources.java similarity index 100% rename from core/src/main/java/org/fao/geonet/resources/CMISResources.java rename to datastorages/cmis/src/main/java/org/fao/geonet/resources/CMISResources.java diff --git a/core/src/main/java/org/fao/geonet/resources/CMISUtils.java b/datastorages/cmis/src/main/java/org/fao/geonet/resources/CMISUtils.java similarity index 100% rename from core/src/main/java/org/fao/geonet/resources/CMISUtils.java rename to datastorages/cmis/src/main/java/org/fao/geonet/resources/CMISUtils.java diff --git a/core/src/main/resources/config-store/config-cmis-overrides.properties b/datastorages/cmis/src/main/resources/config-store/config-cmis-overrides.properties similarity index 88% rename from core/src/main/resources/config-store/config-cmis-overrides.properties rename to datastorages/cmis/src/main/resources/config-store/config-cmis-overrides.properties index f0a62c1920a..4c154639ca5 100644 --- a/core/src/main/resources/config-store/config-cmis-overrides.properties +++ b/datastorages/cmis/src/main/resources/config-store/config-cmis-overrides.properties @@ -11,8 +11,8 @@ cmis.external.resource.management.window.parameters=${CMIS_EXTERNAL_RESOURCE_MAN cmis.external.resource.management.modal.enabled=${CMIS_EXTERNAL_RESOURCE_MANAGEMENT_MODAL_ENABLED:#{null}} cmis.external.resource.management.folder.enabled=${CMIS_EXTERNAL_RESOURCE_MANAGEMENT_FOLDER_ENABLED:#{null}} cmis.external.resource.management.folder.root=${CMIS_EXTERNAL_RESOURCE_MANAGEMENT_FOLDER_ROOT:#{null}} -cmis.external.resource.status.property.name=${CMIS_EXTERNAL_RESOURCE_STATUS_PROPERTY_NAME:#{null}} -cmis.external.resource.management.status.default.value=${CMIS_EXTERNAL_RESOURCE_MANAGEMENT_STATUS_DEFAULT_VALUE:#{null}} +cmis.external.resource.management.validation.status.property.name=${CMIS_EXTERNAL_RESOURCE_MANAGEMENT_VALIDATION_STATUS_PROPERTY_NAME:#{null}} +cmis.external.resource.management.validation.status.default.value=${CMIS_EXTERNAL_RESOURCE_MANAGEMENT_VALIDATION_STATUS_DEFAULT_VALUE:#{null}} cmis.versioning.enabled=${CMIS_VERSIONING_ENABLED:#{null}} cmis.versioning.state=#{'${CMIS_VERSIONING_STATE:MAJOR}'.toUpperCase()} diff --git a/core/src/main/resources/config-store/config-cmis.xml b/datastorages/cmis/src/main/resources/config-store/config-cmis.xml similarity index 96% rename from core/src/main/resources/config-store/config-cmis.xml rename to datastorages/cmis/src/main/resources/config-store/config-cmis.xml index 76abe73572c..1c302788b5c 100644 --- a/core/src/main/resources/config-store/config-cmis.xml +++ b/datastorages/cmis/src/main/resources/config-store/config-cmis.xml @@ -1,6 +1,6 @@ + + + + gn-datastorages + org.geonetwork-opensource.datastorage + 4.4.7-SNAPSHOT + + 4.0.0 + + gn-datastorage-jcloud + JCloud datastorage + + + + org.geonetwork-opensource + gn-core + ${project.version} + provided + + + + org.geonetwork-opensource + gn-domain + ${project.version} + provided + + + + org.geonetwork-opensource + gn-core + ${project.version} + tests + test + + + + org.geonetwork-opensource + gn-domain + ${project.version} + tests + test + + + + org.geonetwork-opensource + gn-services + ${project.version} + tests + test + + + + org.springframework + spring-context + provided + + + + org.springframework + spring-context-support + provided + + + + org.apache.jclouds + jclouds-all + + + + + + + + maven-jar-plugin + + + test-jar + + test-jar + + + + + + + + src/main/resources + true + + + + + + + run-static-analysis + + + !skipTests + + + + + + org.codehaus.mojo + findbugs-maven-plugin + + + + + + + release + + + + release + + + + + + + maven-dependency-plugin + + + stage-libs + prepare-package + + copy-dependencies + + + + true + runtime + provided + com.google.code.findbugs + false + ${project.build.directory}/lib + false + true + + + + + + + com.ruleoftech + markdown-page-generator-plugin + + + readme + process-resources + + generate + + + ${project.basedir}/src/main/assembly + ${project.build.directory}/html + + + + licenses + process-resources + + generate + + + ${project.basedir}/../../ + ${project.build.directory}/html/license + + + + + false + true + ${project.basedir}/../../release/src/markdown/html/header.html + ${project.basedir}/../../release/src/markdown/html/footer.html + TABLES,FENCED_CODE_BLOCKS + true + + + + + maven-assembly-plugin + + + release-zip + package + + single + + + ${project.artifactId}-${project.version} + false + + src/main/assembly/assembly.xml + + + + + + + + + + + + ${basedir}/.. + + diff --git a/datastorages/jcloud/src/main/assembly/README.md b/datastorages/jcloud/src/main/assembly/README.md new file mode 100644 index 00000000000..2d6ff271b9f --- /dev/null +++ b/datastorages/jcloud/src/main/assembly/README.md @@ -0,0 +1,17 @@ +# JCloud data storage provider library + +To install the JCloud data storage provider in GeoNetwork: + +1. Copy the `lib` folder jar files into to `{GEONETWORK_DIR}/WEB-INF/lib` folder. + +2. Define the following environmental variables: + + - Use JCloud data storage provider: + + ```bash + export GEONETWORK_STORE_TYPE=jcloud + ``` + + - Setup JCloud connection `TODO` + +3. Start GeoNetwork diff --git a/datastorages/jcloud/src/main/assembly/assembly.xml b/datastorages/jcloud/src/main/assembly/assembly.xml new file mode 100644 index 00000000000..86569455568 --- /dev/null +++ b/datastorages/jcloud/src/main/assembly/assembly.xml @@ -0,0 +1,31 @@ + + bin + + zip + + + + ${project.build.directory}/lib + /lib + + + + + + ${project.build.directory}/${project.artifactId}-${project.version}.jar + /lib + + + + ${project.build.directory}/html/README.html + / + + + + ${project.build.directory}/html/license/LICENSE.html + /license + + + diff --git a/datastorages/jcloud/src/main/java/org/fao/geonet/api/records/attachments/JCloudStore.java b/datastorages/jcloud/src/main/java/org/fao/geonet/api/records/attachments/JCloudStore.java new file mode 100644 index 00000000000..e4016a72e37 --- /dev/null +++ b/datastorages/jcloud/src/main/java/org/fao/geonet/api/records/attachments/JCloudStore.java @@ -0,0 +1,694 @@ +/* + * ============================================================================= + * === Copyright (C) 2001-2024 Food and Agriculture Organization of the + * === United Nations (FAO-UN), United Nations World Food Programme (WFP) + * === and United Nations Environment Programme (UNEP) + * === + * === This program is free software; you can redistribute it and/or modify + * === it under the terms of the GNU General Public License as published by + * === the Free Software Foundation; either version 2 of the License, or (at + * === your option) any later version. + * === + * === This program is distributed in the hope that it will be useful, but + * === WITHOUT ANY WARRANTY; without even the implied warranty of + * === MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * === General Public License for more details. + * === + * === You should have received a copy of the GNU General Public License + * === along with this program; if not, write to the Free Software + * === Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * === + * === Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, + * === Rome - Italy. email: geonetwork@osgeo.org + * ============================================================================== + */ +package org.fao.geonet.api.records.attachments; + + +import static org.jclouds.blobstore.options.PutOptions.Builder.multipart; + +import jeeves.server.context.ServiceContext; + +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang.StringUtils; +import org.fao.geonet.ApplicationContextHolder; +import org.fao.geonet.api.exception.ResourceNotFoundException; +import org.fao.geonet.constants.Geonet; +import org.fao.geonet.domain.MetadataResource; +import org.fao.geonet.domain.MetadataResourceContainer; +import org.fao.geonet.domain.MetadataResourceExternalManagementProperties; +import org.fao.geonet.domain.MetadataResourceVisibility; +import org.fao.geonet.kernel.GeonetworkDataDirectory; +import org.fao.geonet.kernel.setting.SettingManager; +import org.fao.geonet.languages.IsoLanguagesMapper; +import org.fao.geonet.lib.Lib; +import org.fao.geonet.resources.JCloudConfiguration; +import org.fao.geonet.utils.IO; +import org.fao.geonet.utils.Log; +import org.jclouds.blobstore.ContainerNotFoundException; +import org.jclouds.blobstore.domain.*; +import org.jclouds.blobstore.options.CopyOptions; +import org.jclouds.blobstore.options.ListContainerOptions; +import org.springframework.beans.factory.annotation.Autowired; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.text.SimpleDateFormat; +import java.util.ArrayList; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nullable; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class JCloudStore extends AbstractStore { + + // For azure Blob ADSL hdi_isfolder property name used to identify folders + private final static String AZURE_BLOB_IS_FOLDER_PROPERTY_NAME="hdi_isfolder"; + + private Path baseMetadataDir = null; + + @Autowired + JCloudConfiguration jCloudConfiguration; + + @Autowired + SettingManager settingManager; + + @Override + public List getResources(final ServiceContext context, final String metadataUuid, + final MetadataResourceVisibility visibility, String filter, Boolean approved) throws Exception { + final int metadataId = canDownload(context, metadataUuid, visibility, approved); + + final String resourceTypeDir = getMetadataDir(context, metadataId) + jCloudConfiguration.getFolderDelimiter() + visibility.toString() + jCloudConfiguration.getFolderDelimiter(); + + List resourceList = new ArrayList<>(); + if (filter == null) { + filter = FilesystemStore.DEFAULT_FILTER; + } + + PathMatcher matcher = + FileSystems.getDefault().getPathMatcher("glob:" + filter); + + ListContainerOptions opts = new ListContainerOptions(); + opts.delimiter(jCloudConfiguration.getFolderDelimiter()).prefix(resourceTypeDir);; + + // Page through the data + String marker = null; + do { + if (marker != null) { + opts.afterMarker(marker); + } + + PageSet page = jCloudConfiguration.getClient().getBlobStore().list(jCloudConfiguration.getContainerName(), opts); + + for (StorageMetadata storageMetadata : page) { + // Only add to the list if it is a blob and it matches the filter. + Path keyPath = new File(storageMetadata.getName()).toPath().getFileName(); + if (storageMetadata.getType() == StorageType.BLOB && matcher.matches(keyPath)){ + final String filename = getFilename(storageMetadata.getName()); + MetadataResource resource = createResourceDescription(context, metadataUuid, visibility, filename, storageMetadata, metadataId, approved); + resourceList.add(resource); + } + } + marker = page.getNextMarker(); + } while (marker != null); + + + resourceList.sort(MetadataResourceVisibility.sortByFileName); + + return resourceList; + } + + private MetadataResource createResourceDescription(final ServiceContext context, final String metadataUuid, + final MetadataResourceVisibility visibility, final String resourceId, + StorageMetadata storageMetadata, int metadataId, boolean approved) { + String filename = getFilename(metadataUuid, resourceId); + + String versionValue = null; + if (jCloudConfiguration.isVersioningEnabled()) { + versionValue = storageMetadata.getETag(); // ETAG is cryptic may need some other value? + } + + MetadataResourceExternalManagementProperties.ValidationStatus validationStatus = MetadataResourceExternalManagementProperties.ValidationStatus.UNKNOWN; + if (!StringUtils.isEmpty(jCloudConfiguration.getExternalResourceManagementValidationStatusPropertyName())) { + String validationStatusPropertyName = jCloudConfiguration.getExternalResourceManagementValidationStatusPropertyName(); + String propertyValue = null; + if (storageMetadata.getUserMetadata().containsKey(validationStatusPropertyName)) { + propertyValue = storageMetadata.getUserMetadata().get(validationStatusPropertyName); + } + if (StringUtils.isNotEmpty(propertyValue)) { + validationStatus = MetadataResourceExternalManagementProperties.ValidationStatus.fromValue(Integer.parseInt(propertyValue)); + } + } + + MetadataResourceExternalManagementProperties metadataResourceExternalManagementProperties = + getMetadataResourceExternalManagementProperties(context, metadataId, metadataUuid, visibility, resourceId, filename, storageMetadata.getETag(), storageMetadata.getType(), validationStatus); + + return new FilesystemStoreResource(metadataUuid, metadataId, filename, + settingManager.getNodeURL() + "api/records/", visibility, storageMetadata.getSize(), storageMetadata.getLastModified(), versionValue, metadataResourceExternalManagementProperties, approved); + } + + protected static String getFilename(final String key) { + final String[] splittedKey = key.split("/"); + return splittedKey[splittedKey.length - 1]; + } + + @Override + public ResourceHolder getResource(final ServiceContext context, final String metadataUuid, final MetadataResourceVisibility visibility, + final String resourceId, Boolean approved) throws Exception { + // Those characters should not be allowed by URL structure + int metadataId = canDownload(context, metadataUuid, visibility, approved); + try { + final Blob object = jCloudConfiguration.getClient().getBlobStore().getBlob( + jCloudConfiguration.getContainerName(), getKey(context, metadataUuid, metadataId, visibility, resourceId)); + if (object == null) { + throw new ResourceNotFoundException( + String.format("Metadata resource '%s' not found for metadata '%s'", resourceId, metadataUuid)) + .withMessageKey("exception.resourceNotFound.resource", new String[]{resourceId}) + .withDescriptionKey("exception.resourceNotFound.resource.description", new String[]{resourceId, metadataUuid}); + } + return new ResourceHolderImpl(object, createResourceDescription(context, metadataUuid, visibility, resourceId, + object.getMetadata(), metadataId, approved)); + } catch (ContainerNotFoundException e) { + throw new ResourceNotFoundException( + String.format("Metadata container for resource '%s' not found for metadata '%s'", resourceId, metadataUuid)) + .withMessageKey("exception.resourceNotFound.resource", new String[]{resourceId}) + .withDescriptionKey("exception.resourceNotFound.resource.description", new String[]{resourceId, metadataUuid}); + } + } + + @Override + public ResourceHolder getResourceInternal(String metadataUuid, MetadataResourceVisibility visibility, String resourceId, Boolean approved) throws Exception { + int metadataId = getAndCheckMetadataId(metadataUuid, approved); + checkResourceId(resourceId); + + try { + ServiceContext context = ServiceContext.get(); + final Blob object = jCloudConfiguration.getClient().getBlobStore().getBlob( + jCloudConfiguration.getContainerName(), getKey(context, metadataUuid, metadataId, visibility, resourceId)); + return new ResourceHolderImpl(object, createResourceDescription(context, metadataUuid, visibility, resourceId, + object.getMetadata(), metadataId, approved)); + } catch (ContainerNotFoundException e) { + throw new ResourceNotFoundException( + String.format("Metadata resource '%s' not found for metadata '%s'", resourceId, metadataUuid)) + .withMessageKey("exception.resourceNotFound.resource", new String[]{resourceId}) + .withDescriptionKey("exception.resourceNotFound.resource.description", new String[]{resourceId, metadataUuid}); + } + + } + + protected String getKey(final ServiceContext context, String metadataUuid, int metadataId, MetadataResourceVisibility visibility, String resourceId) { + checkResourceId(resourceId); + final String metadataDir = getMetadataDir(context, metadataId); + return metadataDir + jCloudConfiguration.getFolderDelimiter() + visibility.toString() + jCloudConfiguration.getFolderDelimiter() + getFilename(metadataUuid, resourceId); + } + + @Override + public MetadataResource putResource(final ServiceContext context, final String metadataUuid, final String filename, + final InputStream is, @Nullable final Date changeDate, final MetadataResourceVisibility visibility, Boolean approved) + throws Exception { + return putResource(context, metadataUuid, filename, is, changeDate, visibility, approved, null); + } + + protected MetadataResource putResource(final ServiceContext context, final String metadataUuid, final String filename, + final InputStream is, @Nullable final Date changeDate, final MetadataResourceVisibility visibility, Boolean approved, Map additionalProperties) + throws Exception { + final int metadataId = canEdit(context, metadataUuid, approved); + String key = getKey(context, metadataUuid, metadataId, visibility, filename); + + Map properties = null; + + try { + StorageMetadata storageMetadata = jCloudConfiguration.getClient().getBlobStore().blobMetadata(jCloudConfiguration.getContainerName(), key); + if (storageMetadata != null) { + properties = storageMetadata.getUserMetadata(); + } + } catch (ContainerNotFoundException ignored) { + // ignored + } + + + if (properties == null) { + properties = new HashMap<>(); + } + + addProperties(metadataUuid, properties, changeDate, additionalProperties); + + Blob blob = jCloudConfiguration.getClient().getBlobStore().blobBuilder(key) + .payload(is) + .contentLength(is.available()) + .userMetadata(properties) + .build(); + // Upload the Blob in multiple chunks to supports large files. + jCloudConfiguration.getClient().getBlobStore().putBlob(jCloudConfiguration.getContainerName(), blob, multipart()); + Blob blobResults = jCloudConfiguration.getClient().getBlobStore().getBlob(jCloudConfiguration.getContainerName(), key); + + + return createResourceDescription(context, metadataUuid, visibility, filename, blobResults.getMetadata(), metadataId, approved); + + } + + protected void addProperties(String metadataUuid, Map properties, Date changeDate, Map additionalProperties) { + + // Add additional properties if exists. + if (MapUtils.isNotEmpty(additionalProperties)) { + properties.putAll(additionalProperties); + } + + // now update metadata uuid and status and change date . + + setMetadataUUID(properties, metadataUuid); + + // JCloud does not allow changing the last modified date. So the change date will be put in defined changed date field if supplied. + setExternalResourceManagementChangedDate(properties, changeDate); + + // If it is a new record so set the default status value property if it does not already exist as an additional property. + if (!StringUtils.isEmpty(jCloudConfiguration.getExternalResourceManagementValidationStatusPropertyName()) && + !properties.containsKey(jCloudConfiguration.getExternalResourceManagementValidationStatusPropertyName())) { + setExternalManagementResourceValidationStatus(properties, jCloudConfiguration.getValidationStatusDefaultValue()); + } + + } + protected void setMetadataUUID(Map properties, String metadataUuid) { + // Don't allow users metadata uuid to be supplied as a property so let's overwrite any value that may exist. + if (!StringUtils.isEmpty(jCloudConfiguration.getMetadataUUIDPropertyName())) { + setProperty(properties, jCloudConfiguration.getMetadataUUIDPropertyName(), metadataUuid); + } + } + + protected void setExternalResourceManagementChangedDate(Map properties, Date changeDate) { + // Don't allow change date to be supplied as a property so let's overwrite any value that may exist. + if (changeDate != null && !StringUtils.isEmpty(jCloudConfiguration.getExternalResourceManagementChangedDatePropertyName())) { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + properties.put(jCloudConfiguration.getExternalResourceManagementChangedDatePropertyName(), dateFormat.format(changeDate)); + } + } + + protected void setExternalManagementResourceValidationStatus(Map properties, MetadataResourceExternalManagementProperties.ValidationStatus status) { + if (!StringUtils.isEmpty(jCloudConfiguration.getExternalResourceManagementValidationStatusPropertyName())) { + setProperty(properties, jCloudConfiguration.getExternalResourceManagementValidationStatusPropertyName(), String.valueOf(status.getValue())); + } + } + + protected void setProperty(Map properties, String propertyName, String value) { + if (!StringUtils.isEmpty(propertyName)) { + properties.put(propertyName, value); + } + } + @Override + public MetadataResource patchResourceStatus(final ServiceContext context, final String metadataUuid, final String resourceId, + final MetadataResourceVisibility visibility, Boolean approved) throws Exception { + int metadataId = canEdit(context, metadataUuid, approved); + + String sourceKey = null; + StorageMetadata storageMetadata = null; + for (MetadataResourceVisibility sourceVisibility : MetadataResourceVisibility.values()) { + final String key = getKey(context, metadataUuid, metadataId, sourceVisibility, resourceId); + try { + storageMetadata = jCloudConfiguration.getClient().getBlobStore().blobMetadata(jCloudConfiguration.getContainerName(), key); + if (storageMetadata != null) { + if (sourceVisibility != visibility) { + sourceKey = key; + break; + } else { + // already the good visibility + return createResourceDescription(context, metadataUuid, visibility, resourceId, storageMetadata, metadataId, approved); + } + } + } catch (ContainerNotFoundException ignored) { + // ignored + } + } + if (sourceKey != null) { + final String destKey = getKey(context, metadataUuid, metadataId, visibility, resourceId); + + jCloudConfiguration.getClient().getBlobStore().copyBlob(jCloudConfiguration.getContainerName(), sourceKey, jCloudConfiguration.getContainerName(), destKey, CopyOptions.NONE); + jCloudConfiguration.getClient().getBlobStore().removeBlob(jCloudConfiguration.getContainerName(), sourceKey); + + Blob blobResults = jCloudConfiguration.getClient().getBlobStore().getBlob(jCloudConfiguration.getContainerName(), destKey); + + return createResourceDescription(context, metadataUuid, visibility, resourceId, blobResults.getMetadata(), metadataId, approved); + } else { + Log.warning(Geonet.RESOURCES, + String.format("Could not update permissions. Metadata resource '%s' not found for metadata '%s'", resourceId, metadataUuid)); + throw new ResourceNotFoundException( + String.format("Could not update permissions. Metadata resource '%s' not found for metadata '%s'", resourceId, metadataUuid)); + } + } + + @Override + public String delResources(final ServiceContext context, final int metadataId) throws Exception { + try { + ListContainerOptions opts = new ListContainerOptions(); + opts.prefix(getMetadataDir(context, metadataId) + jCloudConfiguration.getFolderDelimiter()).recursive(); + + Log.info(Geonet.RESOURCES, String.format("Deleting all files from metadataId '%s'", metadataId)); + // Page through the data + String marker = null; + do { + if (marker != null) { + opts.afterMarker(marker); + } + + PageSet page = jCloudConfiguration.getClient().getBlobStore().list(jCloudConfiguration.getContainerName(), opts); + + for (StorageMetadata storageMetadata : page) { + if (!isFolder(storageMetadata)) { + jCloudConfiguration.getClient().getBlobStore().removeBlob(jCloudConfiguration.getContainerName(), storageMetadata.getName()); + } + } + marker = page.getNextMarker(); + } while (marker != null); + Log.info(Geonet.RESOURCES, + String.format("Metadata '%d' directory removed.", metadataId)); + return String.format("Metadata '%d' directory removed.", metadataId); + } catch (ContainerNotFoundException e) { + Log.warning(Geonet.RESOURCES, + String.format("Unable to located metadata '%d' directory to be removed.", metadataId)); + return String.format("Unable to located metadata '%d' directory to be removed.", metadataId); + } + } + + @Override + public String delResource(final ServiceContext context, final String metadataUuid, final String resourceId, Boolean approved) + throws Exception { + int metadataId = canEdit(context, metadataUuid, approved); + + for (MetadataResourceVisibility visibility : MetadataResourceVisibility.values()) { + if (tryDelResource(context, metadataUuid, metadataId, visibility, resourceId)) { + return String.format("Metadata resource '%s' removed.", resourceId); + } + } + return String.format("Unable to remove resource '%s'.", resourceId); + } + + @Override + public String delResource(final ServiceContext context, final String metadataUuid, final MetadataResourceVisibility visibility, + final String resourceId, Boolean approved) throws Exception { + int metadataId = canEdit(context, metadataUuid, approved); + if (tryDelResource(context, metadataUuid, metadataId, visibility, resourceId)) { + return String.format("Metadata resource '%s' removed.", resourceId); + } + return String.format("Unable to remove resource '%s'.", resourceId); + } + + protected boolean tryDelResource(final ServiceContext context, final String metadataUuid, final int metadataId, final MetadataResourceVisibility visibility, + final String resourceId) throws Exception { + final String key = getKey(context, metadataUuid, metadataId, visibility, resourceId); + + if (jCloudConfiguration.getClient().getBlobStore().blobExists(jCloudConfiguration.getContainerName(), key)) { + jCloudConfiguration.getClient().getBlobStore().removeBlob(jCloudConfiguration.getContainerName(), key); + Log.info(Geonet.RESOURCES, + String.format("Resource '%s' removed for metadata %d (%s).", resourceId, metadataId, metadataUuid)); + return true; + } + Log.info(Geonet.RESOURCES, + String.format("Unable to remove resource '%s' for metadata %d (%s).", resourceId, metadataId, metadataUuid)); + return false; + } + + @Override + public MetadataResource getResourceDescription(final ServiceContext context, final String metadataUuid, + final MetadataResourceVisibility visibility, final String filename, Boolean approved) throws Exception { + int metadataId = getAndCheckMetadataId(metadataUuid, approved); + final String key = getKey(context, metadataUuid, metadataId, visibility, filename); + try { + final Blob object = jCloudConfiguration.getClient().getBlobStore().getBlob(jCloudConfiguration.getContainerName(), key); + if (object == null) { + return null; + } else { + final StorageMetadata metadata = object.getMetadata(); + return createResourceDescription(context, metadataUuid, visibility, filename, metadata, metadataId, approved); + } + } catch (ContainerNotFoundException e) { + return null; + } + } + + @Override + public MetadataResourceContainer getResourceContainerDescription(final ServiceContext context, final String metadataUuid, Boolean approved) throws Exception { + int metadataId = getAndCheckMetadataId(metadataUuid, approved); + + final String key = getMetadataDir(context, metadataId); + + + String folderRoot = jCloudConfiguration.getExternalResourceManagementFolderRoot(); + if (folderRoot == null) { + folderRoot = ""; + } + MetadataResourceExternalManagementProperties metadataResourceExternalManagementProperties = + getMetadataResourceExternalManagementProperties(context, metadataId, metadataUuid, null, String.valueOf(metadataId), null, null, StorageType.FOLDER, + MetadataResourceExternalManagementProperties.ValidationStatus.UNKNOWN); + + return new FilesystemStoreResourceContainer(metadataUuid, metadataId, metadataUuid, + settingManager.getNodeURL() + "api/records/", metadataResourceExternalManagementProperties, approved); + } + + private String getMetadataDir(ServiceContext context, final int metadataId) { + + Path metadataFullDir = Lib.resource.getMetadataDir(getDataDirectory(context), metadataId); + Path baseMetadataDir = getBaseMetadataDir(context, metadataFullDir); + Path metadataDir; + if (baseMetadataDir.toString().equals(".")) { + metadataDir = Paths.get(jCloudConfiguration.getBaseFolder()).resolve(metadataFullDir); + } else { + metadataDir = Paths.get(jCloudConfiguration.getBaseFolder()).resolve(baseMetadataDir.relativize(metadataFullDir)); + } + + String key; + // For windows it may be "\" in which case we need to change it to folderDelimiter which is normally "/" + if (metadataDir.getFileSystem().getSeparator().equals(jCloudConfiguration.getFolderDelimiter())) { + key = metadataDir.toString(); + } else { + key = metadataDir.toString().replace(metadataDir.getFileSystem().getSeparator(), jCloudConfiguration.getFolderDelimiter()); + } + + // For Windows, the pathString may start with // so remove one if this is the case. + if (key.startsWith("//")) { + key = key.substring(1); + } + + // Make sure the key that is returns does not starts with "/" as it is already assumed to be relative to the container. + if (key.startsWith(jCloudConfiguration.getFolderDelimiter())) { + return key.substring(1); + } else { + return key; + } + } + + protected Path getBaseMetadataDir(ServiceContext context, Path metadataFullDir) { + //If we not already figured out the base metadata dir then lets figure it out. + if (baseMetadataDir == null) { + Path systemFullDir = getDataDirectory(context).getSystemDataDir(); + + // If the metadata full dir is relative from the system dir then use system dir as the base dir. + if (metadataFullDir.toString().startsWith(systemFullDir.toString())) { + baseMetadataDir = systemFullDir; + } else { + // If the metadata full dir is an absolute folder then use that as the base dir. + if (getDataDirectory(context).getMetadataDataDir().isAbsolute()) { + baseMetadataDir = metadataFullDir.getRoot(); + } else { + // use it as a relative url. + baseMetadataDir = Paths.get("."); + } + } + } + return baseMetadataDir; + } + + private GeonetworkDataDirectory getDataDirectory(ServiceContext context) { + return ApplicationContextHolder.get().getBean(GeonetworkDataDirectory.class); + } + + private boolean isFolder(StorageMetadata storageMetadata) { + // For azure Blob ADSL if the type is folder then the storage type will be BLOB and hdi_isfolder=true so we cannot only rely on StorageType.FOLDER + return storageMetadata.getType().equals(StorageType.FOLDER) || "true".equals(storageMetadata.getUserMetadata().get(AZURE_BLOB_IS_FOLDER_PROPERTY_NAME)); + } + + /** + * get external resource management for the supplied resource. + * Replace the following + * {objectId} type:visibility:metadataId:version:resourceId in base64 encoding + * {id} resource id + * {type} // If the type is folder then type "folder" will be displayed else if document then "document" will be displayed + * {uuid} metadatauuid + * {metadataid} metadataid + * {visibility} visibility + * {filename} filename + * {version} version + * {lang} ISO639-1 2 char language + * {iso3lang} ISO 639-2/T language + *

    + * Sample url for custom app + * http://localhost:8080/artifact?filename={filename}&version={version}&lang={lang} + */ + + private MetadataResourceExternalManagementProperties getMetadataResourceExternalManagementProperties(ServiceContext context, + int metadataId, + final String metadataUuid, + final MetadataResourceVisibility visibility, + final String resourceId, + String filename, + String version, + StorageType type, + MetadataResourceExternalManagementProperties.ValidationStatus validationStatus + ) { + String metadataResourceExternalManagementPropertiesUrl = jCloudConfiguration.getExternalResourceManagementUrl(); + String objectId = getResourceManagementExternalPropertiesObjectId((type == null ? "document" : (StorageType.FOLDER.equals(type) ? "folder" : "document")), visibility, metadataId, version, + resourceId); + if (!StringUtils.isEmpty(metadataResourceExternalManagementPropertiesUrl)) { + // {objectid} objectId // It will be the type:visibility:metadataId:version:resourceId in base64 + // i.e. folder::100::100 # Folder in resource 100 + // i.e. document:public:100:v1:sample.jpg # public document 100 version v1 name sample.jpg + if (metadataResourceExternalManagementPropertiesUrl.contains("{objectid}")) { + metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("(\\{objectid\\})", objectId); + } + // {id} id + if (metadataResourceExternalManagementPropertiesUrl.contains("{id}")) { + metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("(\\{id\\})", resourceId); + } + // {type} // If the type is folder then type "folder" will be displayed else if document then "document" will be displayed + if (metadataResourceExternalManagementPropertiesUrl.contains("{type}")) { + metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("(\\{type\\})", + (type == null ? "document" : (StorageType.FOLDER.equals(type) ? "folder" : "document"))); + } + // {uuid} metadata uuid + if (metadataResourceExternalManagementPropertiesUrl.contains("{uuid}")) { + metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("(\\{uuid\\})", (metadataUuid == null ? "" : metadataUuid)); + } + // {metadataid} metadataId + if (metadataResourceExternalManagementPropertiesUrl.contains("{metadataid}")) { + metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("(\\{metadataid\\})", String.valueOf(metadataId)); + } + // {visibility} visibility + if (metadataResourceExternalManagementPropertiesUrl.contains("{visibility}")) { + metadataResourceExternalManagementPropertiesUrl = + metadataResourceExternalManagementPropertiesUrl.replaceAll("(\\{visibility\\})", (visibility == null ? "" : visibility.toString().toLowerCase())); + } + // {filename} filename + if (metadataResourceExternalManagementPropertiesUrl.contains("{filename}")) { + metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("(\\{filename\\})", (filename == null ? "" : filename)); + } + // {version} version + if (metadataResourceExternalManagementPropertiesUrl.contains("{version}")) { + metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("(\\{version\\})", (version == null ? "" : version)); + } + + if (metadataResourceExternalManagementPropertiesUrl.contains("{lang}") || metadataResourceExternalManagementPropertiesUrl.contains("{ISO3lang}")) { + final IsoLanguagesMapper mapper = context.getBean(IsoLanguagesMapper.class); + String contextLang = context.getLanguage() == null ? Geonet.DEFAULT_LANGUAGE : context.getLanguage(); + String lang; + String iso3Lang; + + if (contextLang.length() == 2) { + lang = contextLang; + iso3Lang = mapper.iso639_1_to_iso639_2(contextLang); + } else { + lang = mapper.iso639_2_to_iso639_1(contextLang); + iso3Lang = contextLang; + } + // {lang} ISO639-1 2 char language + if (metadataResourceExternalManagementPropertiesUrl.contains("{lang}")) { + metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("(\\{lang\\})", lang); + } + // {iso3lang} ISO 639-2/T language + if (metadataResourceExternalManagementPropertiesUrl.contains("{iso3lang}")) { + metadataResourceExternalManagementPropertiesUrl = metadataResourceExternalManagementPropertiesUrl.replaceAll("(\\{iso3lang\\})", iso3Lang); + } + } + } + + MetadataResourceExternalManagementProperties metadataResourceExternalManagementProperties + = new MetadataResourceExternalManagementProperties(objectId, metadataResourceExternalManagementPropertiesUrl, validationStatus); + + return metadataResourceExternalManagementProperties; + } + + public ResourceManagementExternalProperties getResourceManagementExternalProperties() { + return new ResourceManagementExternalProperties() { + @Override + public boolean isEnabled() { + // Return true if we have an external management url + return !StringUtils.isEmpty(jCloudConfiguration.getExternalResourceManagementUrl()); + } + + @Override + public String getWindowParameters() { + return jCloudConfiguration.getExternalResourceManagementWindowParameters(); + } + + @Override + public boolean isModal() { + return jCloudConfiguration.isExternalResourceManagementModalEnabled(); + } + + @Override + public boolean isFolderEnabled() { + return isEnabled() && jCloudConfiguration.isExternalResourceManagementFolderEnabled(); + } + + @Override + public String toString() { + try { + return new ObjectMapper().writeValueAsString(this); + } catch (JsonProcessingException e) { + throw new RuntimeException("Error converting ResourceManagementExternalProperties to json", e); + } + } + }; + } + + protected static class ResourceHolderImpl implements ResourceHolder { + private Path tempFolderPath; + private Path path; + private final MetadataResource metadataResource; + + public ResourceHolderImpl(final Blob object, MetadataResource metadataResource) throws IOException { + // Preserve filename by putting the files into a temporary folder and using the same filename. + tempFolderPath = Files.createTempDirectory("gn-meta-res-" + String.valueOf(metadataResource.getMetadataId() + "-")); + tempFolderPath.toFile().deleteOnExit(); + path = tempFolderPath.resolve(getFilename(object.getMetadata().getName())); + this.metadataResource = metadataResource; + try (InputStream in = object.getPayload().openStream()) { + Files.copy(in, path, StandardCopyOption.REPLACE_EXISTING); + } + } + + @Override + public Path getPath() { + return path; + } + + @Override + public MetadataResource getMetadata() { + return metadataResource; + } + + @Override + public void close() throws IOException { + // Delete temporary file and folder. + IO.deleteFileOrDirectory(tempFolderPath, true); + path=null; + tempFolderPath = null; + } + + @Override + protected void finalize() throws Throwable { + close(); + super.finalize(); + } + } +} diff --git a/datastorages/jcloud/src/main/java/org/fao/geonet/resources/JCloudConfiguration.java b/datastorages/jcloud/src/main/java/org/fao/geonet/resources/JCloudConfiguration.java new file mode 100644 index 00000000000..5971855c8a2 --- /dev/null +++ b/datastorages/jcloud/src/main/java/org/fao/geonet/resources/JCloudConfiguration.java @@ -0,0 +1,342 @@ +/* + * Copyright (C) 2001-2024 Food and Agriculture Organization of the + * United Nations (FAO-UN), United Nations World Food Programme (WFP) + * and United Nations Environment Programme (UNEP) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, + * Rome - Italy. email: geonetwork@osgeo.org + */ + +package org.fao.geonet.resources; + +import org.apache.commons.lang.BooleanUtils; +import org.fao.geonet.domain.MetadataResourceExternalManagementProperties; +import org.jclouds.ContextBuilder; +import org.jclouds.blobstore.BlobStoreContext; +import org.springframework.util.StringUtils; + +import javax.annotation.Nonnull; +import javax.annotation.PostConstruct; + +public class JCloudConfiguration { + + private BlobStoreContext client = null; + + private static final String DEFAULT_CLOUD_FOLDER_SEPARATOR = "/"; // not sure if this is consistent for all clouds defaulting to "/" and make it a config + private static final String DEFAULT_EXTERNAL_RESOURCE_MANAGEMENT_WINDOW_PARAMETERS = "toolbar=0,width=600,height=600"; + private static final Boolean DEFAULT_EXTERNAL_RESOURCE_MANAGEMENT_MODAL_ENABLED = true; + private static final Boolean DEFAULT_EXTERNAL_RESOURCE_MANAGEMENT_FOLDER_ENABLED = true; + private static final Boolean DEFAULT_VERSIONING_ENABLED = false; + + private String provider; + private String baseFolder; + private String storageAccountName; + private String storageAccountKey; + private String containerName; + private String endpoint; + private String folderDelimiter = null; + + /** + * Property name for storing the metadata uuid that is expected to be a String + */ + private String metadataUUIDPropertyName; + /** + * Url used for managing enhanced resource properties related to the metadata. + */ + private String externalResourceManagementUrl; + private String externalResourceManagementWindowParameters; + private Boolean externalResourceManagementModalEnabled; + private Boolean externalResourceManagementFolderEnabled; + private String externalResourceManagementFolderRoot; + + /** + * Property name for storing the changed date as JCloud does not allow changing the last modified date. + */ + private String externalResourceManagementChangedDatePropertyName; + + /** + * Property name for validation status that is expected to be an integer with values of null, 0, 1, 2 + * (See MetadataResourceExternalManagementProperties.ValidationStatus for code meaning) + * If null then validation status will default to UNKNOWN. + */ + private String externalResourceManagementValidationStatusPropertyName; + /** + * Default value to be used for the validation status. + * If null then it will use INCOMPLETE as the default. + * Note that if property name is not supplied then it will always default to UNKNOWN + */ + private String externalResourceManagementValidationStatusDefaultValue; + private MetadataResourceExternalManagementProperties.ValidationStatus defaultStatus = null; + + /* + * Enable option to add versioning in the link to the resource. + */ + private Boolean versioningEnabled; + + + public void setProvider(String provider) { + this.provider = provider; + } + + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } + + public void setStorageAccountName(String storageAccountName) { + this.storageAccountName = storageAccountName; + } + + public void setStorageAccountKey(String storageAccountKey) { + this.storageAccountKey = storageAccountKey; + } + + public void setBaseFolder(String baseFolder) { + if (this.folderDelimiter == null) { + this.folderDelimiter = DEFAULT_CLOUD_FOLDER_SEPARATOR; + } + if (!StringUtils.hasLength(baseFolder)) { + this.baseFolder = this.folderDelimiter; + } else { + if (baseFolder.endsWith(this.folderDelimiter)) { + this.baseFolder = baseFolder; + } else { + this.baseFolder = baseFolder + this.folderDelimiter; + } + } + } + + public void setContainerName(String containerName) { + this.containerName = containerName; + } + + public void setFolderDelimiter(String folderDelimiter) { + if (this.folderDelimiter != null && !this.folderDelimiter.equals(folderDelimiter)) { + throw new RuntimeException("Folder delimiter cannot be changed once set. Ensure that it is set prior to setting base folder"); + } + this.folderDelimiter = folderDelimiter; + } + + @Nonnull + public String getExternalResourceManagementUrl() { + return externalResourceManagementUrl; + } + + public void setExternalResourceManagementUrl(String externalResourceManagementUrl) { + this.externalResourceManagementUrl = externalResourceManagementUrl; + } + + @Nonnull + public String getExternalResourceManagementWindowParameters() { + if (externalResourceManagementWindowParameters == null) { + return DEFAULT_EXTERNAL_RESOURCE_MANAGEMENT_WINDOW_PARAMETERS; + } else { + return externalResourceManagementWindowParameters; + } + } + + public void setExternalResourceManagementWindowParameters(String externalResourceManagementWindowParameters) { + this.externalResourceManagementWindowParameters = externalResourceManagementWindowParameters; + } + + @Nonnull + public Boolean isExternalResourceManagementModalEnabled() { + if (externalResourceManagementModalEnabled == null) { + return DEFAULT_EXTERNAL_RESOURCE_MANAGEMENT_MODAL_ENABLED; + } else { + return externalResourceManagementModalEnabled; + } + } + + public void setExternalResourceManagementModalEnabled(Boolean externalResourceManagementModalEnabled) { + this.externalResourceManagementModalEnabled = externalResourceManagementModalEnabled; + } + + public void setExternalResourceManagementModalEnabled(String externalResourceManagementModalEnabled) { + this.externalResourceManagementModalEnabled = BooleanUtils.toBooleanObject(externalResourceManagementModalEnabled); + } + + public Boolean isExternalResourceManagementFolderEnabled() { + if (externalResourceManagementFolderEnabled == null) { + return DEFAULT_EXTERNAL_RESOURCE_MANAGEMENT_FOLDER_ENABLED; + } else { + return externalResourceManagementFolderEnabled; + } + } + + public void setExternalResourceManagementFolderEnabled(Boolean externalResourceManagementFolderEnabled) { + this.externalResourceManagementFolderEnabled = externalResourceManagementFolderEnabled; + } + + public String getExternalResourceManagementFolderRoot() { + return this.externalResourceManagementFolderRoot; + } + + public void setExternalResourceManagementFolderRoot(String externalResourceManagementFolderRoot) { + String folderRoot = externalResourceManagementFolderRoot; + if (folderRoot != null) { + if (!folderRoot.startsWith(getFolderDelimiter())) { + folderRoot = getFolderDelimiter() + folderRoot; + } + if (folderRoot.endsWith(getFolderDelimiter())) { + folderRoot = folderRoot.substring(0, folderRoot.length() - 1); + } + } + + this.externalResourceManagementFolderRoot = folderRoot; + } + + public String getExternalResourceManagementValidationStatusDefaultValue() { + return externalResourceManagementValidationStatusDefaultValue; + } + + public void setExternalResourceManagementValidationStatusDefaultValue(String externalResourceManagementValidationStatusDefaultValue) { + this.externalResourceManagementValidationStatusDefaultValue = externalResourceManagementValidationStatusDefaultValue; + } + + @Nonnull + public Boolean isVersioningEnabled() { + if (versioningEnabled == null) { + + return DEFAULT_VERSIONING_ENABLED; + } else { + return versioningEnabled; + } + } + + public void setVersioningEnabled(Boolean versioningEnabled) { + this.versioningEnabled = versioningEnabled; + } + + public void setVersioningEnabled(String versioningEnabled) { + this.versioningEnabled = BooleanUtils.toBooleanObject(versioningEnabled); + } + + public String getMetadataUUIDPropertyName() { + return metadataUUIDPropertyName; + } + + public void setMetadataUUIDPropertyName(String metadataUUIDPropertyName) { + this.metadataUUIDPropertyName = metadataUUIDPropertyName; + } + + public String getExternalResourceManagementChangedDatePropertyName() { + return externalResourceManagementChangedDatePropertyName; + } + + public void setExternalResourceManagementChangedDatePropertyName(String externalResourceManagementChangedDatePropertyName) { + this.externalResourceManagementChangedDatePropertyName = externalResourceManagementChangedDatePropertyName; + } + public String getExternalResourceManagementValidationStatusPropertyName() { + return externalResourceManagementValidationStatusPropertyName; + } + + public void setExternalResourceManagementValidationStatusPropertyName(String externalResourceManagementValidationStatusPropertyName) { + this.externalResourceManagementValidationStatusPropertyName = externalResourceManagementValidationStatusPropertyName; + } + + public MetadataResourceExternalManagementProperties.ValidationStatus getValidationStatusDefaultValue() { + // We only need to set the default if there is a status property supplied, and it is not already set + if (this.defaultStatus == null && StringUtils.hasLength(getExternalResourceManagementValidationStatusPropertyName())) { + if (getExternalResourceManagementValidationStatusDefaultValue() != null) { + // If a default property name does exist then use it + this.defaultStatus = MetadataResourceExternalManagementProperties.ValidationStatus.valueOf(getExternalResourceManagementValidationStatusDefaultValue()); + } else { + // Otherwise let's default to incomplete. + // Reason - as the administrator decided to use the status, it most likely means that there are extra properties that need to be set after a file is uploaded so defaulting it to + // incomplete seems reasonable. + this.defaultStatus = MetadataResourceExternalManagementProperties.ValidationStatus.INCOMPLETE; + } + } + return this.defaultStatus; + } + + @PostConstruct + public void init() { + if (folderDelimiter == null) { + folderDelimiter = DEFAULT_CLOUD_FOLDER_SEPARATOR; + } + + // Run the setBaseFolder following to ensure the baseFolder is formatted correctly. + setBaseFolder(baseFolder); + + validateMetadataPropertyNames(); + + ContextBuilder builder; + if (storageAccountName != null && provider != null) { + builder = ContextBuilder.newBuilder(provider).credentials(storageAccountName, storageAccountKey); + storageAccountName = null; + storageAccountKey = null; + } else { + throw new RuntimeException("Need to supply storage account name and provider for JCloud configuration"); + } + + + if (endpoint != null) { + builder.endpoint(endpoint); + } + + client = builder.buildView(BlobStoreContext.class); + + if (containerName == null) { + throw new RuntimeException("Missing the container Name configuration"); + } + } + + /** + * Checks if the metadata names that were supplied are correct. + * + * @throws IllegalArgumentException is any of the metadata property names are invalid. + */ + private void validateMetadataPropertyNames() throws IllegalArgumentException { + + // If provider not supplied then nothing to check. + if (this.provider == null) { + return; + } + + String[] names = { + getMetadataUUIDPropertyName(), + getExternalResourceManagementChangedDatePropertyName(), + getExternalResourceManagementValidationStatusPropertyName() + }; + + JCloudMetadataNameValidator.validateMetadataNamesForProvider(provider, names); + } + + @Nonnull + public BlobStoreContext getClient() { + return this.client; + } + + @Nonnull + public String getProvider() { + return this.provider; + } + + @Nonnull + public String getContainerName() { + return this.containerName; + } + + public String getBaseFolder() { + return this.baseFolder; + } + + public String getFolderDelimiter() { + return this.folderDelimiter; + } +} diff --git a/datastorages/jcloud/src/main/java/org/fao/geonet/resources/JCloudMetadataNameValidator.java b/datastorages/jcloud/src/main/java/org/fao/geonet/resources/JCloudMetadataNameValidator.java new file mode 100644 index 00000000000..c9a22eceae6 --- /dev/null +++ b/datastorages/jcloud/src/main/java/org/fao/geonet/resources/JCloudMetadataNameValidator.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2001-2024 Food and Agriculture Organization of the + * United Nations (FAO-UN), United Nations World Food Programme (WFP) + * and United Nations Environment Programme (UNEP) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, + * Rome - Italy. email: geonetwork@osgeo.org + */ + +package org.fao.geonet.resources; + +import java.util.Map; +import java.util.HashMap; +import java.util.regex.Pattern; + +import org.springframework.util.StringUtils; + +/** + * Each JCloud provider has different restrictions on the naming standard used for the metadata property names. + * This class is used to check the requirement of these headers so that we don't get obscure errors when attempting to set the metadata property names. + */ +public class JCloudMetadataNameValidator { + + public static class ProviderMetadataNamingRules { + private final String maxLength; + private final Pattern regex; + + public ProviderMetadataNamingRules(String maxLength, Pattern regex) { + this.maxLength = maxLength; + this.regex = regex; + } + + public String getMaxLength() { + return maxLength; + } + + public Pattern getRegex() { + return regex; + } + } + + // Define metadata naming rules for each provider + private static final Map providerMetadataNamingRules = new HashMap<>(); + private static final ProviderMetadataNamingRules defaultRules = new ProviderMetadataNamingRules( + "255", + Pattern.compile("^[a-zA-Z0-9._-]{1,255}$") + ); + + // Note: All these patterns have not been tested with all providers and may need adjustments. + static { + providerMetadataNamingRules.put("aws-s3", new ProviderMetadataNamingRules( + "255", + Pattern.compile("^[a-zA-Z0-9._-]{1,255}$") + )); + + providerMetadataNamingRules.put("b2", new ProviderMetadataNamingRules( + "255", + Pattern.compile("^[a-zA-Z0-9._-]{1,255}$") + )); + + providerMetadataNamingRules.put("google-cloud-storage", new ProviderMetadataNamingRules( + "1024", + Pattern.compile("^[a-zA-Z0-9._-]{1,1024}$") + )); + + /** + * Azure blob + * https://learn.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata#metadata-names + * Follows C# naming in lowercase only + */ + providerMetadataNamingRules.put("azureblob", new ProviderMetadataNamingRules( + "255", + Pattern.compile("^[a-z_][a-z0-9_]{0,254}$") + )); + + providerMetadataNamingRules.put("rackspace-cloudfiles-us", new ProviderMetadataNamingRules( + "255", + Pattern.compile("^[a-zA-Z0-9._-]{1,255}$") + )); + + providerMetadataNamingRules.put("rackspace-cloudfiles-uk", new ProviderMetadataNamingRules( + "255", + Pattern.compile("^[a-zA-Z0-9._-]{1,255}$") + )); + } + + /** + * Validates metadata names for each provider. + * + * @param provider The name of the provider. + * @param metadataNames Array of metadata names to validate. + * @throws IllegalArgumentException if any metadata name is invalid according to the provider's rules. + */ + public static void validateMetadataNamesForProvider(String provider, String[] metadataNames) throws IllegalArgumentException { + ProviderMetadataNamingRules rules = providerMetadataNamingRules.getOrDefault(provider.toLowerCase(), defaultRules); + + for (String name : metadataNames) { + if (StringUtils.hasLength(name) && !isValidMetadataName(name, rules)) { + throw new IllegalArgumentException(String.format("Invalid metadata name for provider %s: %s", provider, name)); + } + } + } + + /** + * Checks if a single metadata name is valid based on the provider's rules. + * + * @param name The metadata name to check. + * @param rules The metadata naming rules for the provider. + * @return True if the name is valid, false otherwise. + */ + private static boolean isValidMetadataName(String name, ProviderMetadataNamingRules rules) { + // Null/Empty property names are allow as it means they will not be used. + if (!StringUtils.hasLength(name)) { + return false; + } + + if (name.length() > Integer.parseInt(rules.getMaxLength())) { + return false; + } + + return rules.getRegex().matcher(name).matches(); + } +} diff --git a/core/src/main/java/org/fao/geonet/resources/JCloudResources.java b/datastorages/jcloud/src/main/java/org/fao/geonet/resources/JCloudResources.java similarity index 100% rename from core/src/main/java/org/fao/geonet/resources/JCloudResources.java rename to datastorages/jcloud/src/main/java/org/fao/geonet/resources/JCloudResources.java diff --git a/datastorages/jcloud/src/main/resources/config-store/config-jcloud-overrides.properties b/datastorages/jcloud/src/main/resources/config-store/config-jcloud-overrides.properties new file mode 100644 index 00000000000..4a2bafe5b34 --- /dev/null +++ b/datastorages/jcloud/src/main/resources/config-store/config-jcloud-overrides.properties @@ -0,0 +1,22 @@ +jcloud.provider=${JCLOUD_PROVIDER} +jcloud.folder.delimiter=${JCLOUD_FOLDER_DELIMITER:#{'/'}} +jcloud.container.name=${JCLOUD_CONTAINER_NAME:geonetwork} +jcloud.base.folder=${JCLOUD_BASE_FOLDER:#{null}} + +jcloud.storage.account.name=${JCLOUD_STORAGE_ACCOUNT_NAME} +jcloud.storage.account.key=${JCLOUD_STORAGE_ACCOUNT_KEY} +jcloud.endpoint=${JCLOUD_ENDPOINT:#{null}} + +jcloud.external.resource.management.url=${JCLOUD_EXTERNAL_RESOURCE_MANAGEMENT_URL:#{null}} +jcloud.external.resource.management.window.parameters=${JCLOUD_EXTERNAL_RESOURCE_MANAGEMENT_WINDOW_PARAMETERS:#{null}} +jcloud.external.resource.management.modal.enabled=${JCLOUD_EXTERNAL_RESOURCE_MANAGEMENT_MODAL_ENABLED:#{null}} +jcloud.external.resource.management.folder.enabled=${JCLOUD_EXTERNAL_RESOURCE_MANAGEMENT_FOLDER_ENABLED:#{null}} +jcloud.external.resource.management.folder.root=${JCLOUD_EXTERNAL_RESOURCE_MANAGEMENT_FOLDER_ROOT:#{null}} +jcloud.external.resource.management.validation.status.property.name=${JCLOUD_EXTERNAL_RESOURCE_MANAGEMENT_VALIDATION_STATUS_PROPERTY_NAME:#{null}} +jcloud.external.resource.management.validation.status.default.value=${JCLOUD_EXTERNAL_RESOURCE_MANAGEMENT_VALIDATION_STATUS_DEFAULT_VALUE:#{null}} + +jcloud.external.resource.management.changed.date.property.name=${JCLOUD_EXTERNAL_RESOURCE_MANAGEMENT_CHANGE_DATE_PROPERTY_NAME:#{null}} + +jcloud.versioning.enabled=${JCLOUD_VERSIONING_ENABLED:#{null}} + +jcloud.metadata.uuid.property.name=${JCLOUD_METADATA_UUID_PROPERTY_NAME:#{null}} diff --git a/core/src/main/resources/config-store/config-jcloud.xml b/datastorages/jcloud/src/main/resources/config-store/config-jcloud.xml similarity index 84% rename from core/src/main/resources/config-store/config-jcloud.xml rename to datastorages/jcloud/src/main/resources/config-store/config-jcloud.xml index 1824fb452ec..e6a43b63a16 100644 --- a/core/src/main/resources/config-store/config-jcloud.xml +++ b/datastorages/jcloud/src/main/resources/config-store/config-jcloud.xml @@ -1,6 +1,6 @@ + + + + geonetwork + org.geonetwork-opensource + 4.4.7-SNAPSHOT + + 4.0.0 + + + org.geonetwork-opensource.datastorage + gn-datastorages + GeoNetwork datastorage providers + pom + + + + + datastorage-cmis + + + + release + + + + cmis + + + + + datastorage-s3 + + + + release + + + + s3 + + + + + datastorage-jcloud + + + + release + + + + jcloud + + + + + + ../.. + + diff --git a/datastorages/s3/README.md b/datastorages/s3/README.md new file mode 100644 index 00000000000..10cbc40199e --- /dev/null +++ b/datastorages/s3/README.md @@ -0,0 +1,9 @@ +# S3 Data storage + +Extension for data storage (used for storage resources such as record attachments and thumbnails). + +This extension uses Amazon Web Services Simple Storage Service (S3) data storage directly. + +Reference: + +* https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html diff --git a/datastorages/s3/pom.xml b/datastorages/s3/pom.xml new file mode 100644 index 00000000000..7c348f271e2 --- /dev/null +++ b/datastorages/s3/pom.xml @@ -0,0 +1,235 @@ + + + + + + gn-datastorages + org.geonetwork-opensource.datastorage + 4.4.7-SNAPSHOT + + 4.0.0 + + gn-datastorage-s3 + S3 datastorage + + + + org.geonetwork-opensource + gn-core + ${project.version} + provided + + + + org.geonetwork-opensource + gn-domain + ${project.version} + provided + + + + org.geonetwork-opensource + gn-core + ${project.version} + tests + test + + + + org.geonetwork-opensource + gn-domain + ${project.version} + tests + test + + + + + org.geonetwork-opensource + gn-services + ${project.version} + tests + test + + + + org.springframework + spring-context + provided + + + + org.springframework + spring-context-support + provided + + + + com.amazonaws + aws-java-sdk-s3 + + + + + + + maven-jar-plugin + + + test-jar + + test-jar + + + + + + + + src/main/resources + true + + + + + + + run-static-analysis + + + !skipTests + + + + + + org.codehaus.mojo + findbugs-maven-plugin + + + + + + + release + + + + release + + + + + + + maven-dependency-plugin + + + stage-libs + prepare-package + + copy-dependencies + + + + true + runtime + provided + com.google.code.findbugs + false + ${project.build.directory}/lib + false + true + + + + + + + com.ruleoftech + markdown-page-generator-plugin + + + readme + process-resources + + generate + + + ${project.basedir}/src/main/assembly + ${project.build.directory}/html + + + + licenses + process-resources + + generate + + + ${project.basedir}/../../ + ${project.build.directory}/html/license + + + + + false + true + ${project.basedir}/../../release/src/markdown/html/header.html + ${project.basedir}/../../release/src/markdown/html/footer.html + TABLES,FENCED_CODE_BLOCKS + true + + + + + maven-assembly-plugin + + + release-zip + package + + single + + + ${project.artifactId}-${project.version} + false + + src/main/assembly/assembly.xml + + + + + + + + + + + + ${basedir}/.. + + diff --git a/datastorages/s3/src/main/assembly/README.md b/datastorages/s3/src/main/assembly/README.md new file mode 100644 index 00000000000..7d10887aa70 --- /dev/null +++ b/datastorages/s3/src/main/assembly/README.md @@ -0,0 +1,17 @@ +# Amazon S3 data storage provider library + +To install the Amazon S3 data storage provider in GeoNetwork: + +1. Copy the `lib` folder jar files into to `{GEONETWORK_DIR}/WEB-INF/lib` folder. + +2. Define the following environmental variables: + + - Use S3 data storage provider: + + ```shell + export GEONETWORK_STORE_TYPE=s3 + ``` + + - Setup S3 connection as described in https://geonetwork-opensource.org/manuals/4.0.x/en/install-guide/customizing-data-directory.html#using-a-s3-object-storage + +3. Start GeoNetwork diff --git a/datastorages/s3/src/main/assembly/assembly.xml b/datastorages/s3/src/main/assembly/assembly.xml new file mode 100644 index 00000000000..86569455568 --- /dev/null +++ b/datastorages/s3/src/main/assembly/assembly.xml @@ -0,0 +1,31 @@ + + bin + + zip + + + + ${project.build.directory}/lib + /lib + + + + + + ${project.build.directory}/${project.artifactId}-${project.version}.jar + /lib + + + + ${project.build.directory}/html/README.html + / + + + + ${project.build.directory}/html/license/LICENSE.html + /license + + + diff --git a/core/src/main/java/org/fao/geonet/api/records/attachments/S3Store.java b/datastorages/s3/src/main/java/org/fao/geonet/api/records/attachments/S3Store.java similarity index 92% rename from core/src/main/java/org/fao/geonet/api/records/attachments/S3Store.java rename to datastorages/s3/src/main/java/org/fao/geonet/api/records/attachments/S3Store.java index cdd5d1e95f1..061f566aab3 100644 --- a/core/src/main/java/org/fao/geonet/api/records/attachments/S3Store.java +++ b/datastorages/s3/src/main/java/org/fao/geonet/api/records/attachments/S3Store.java @@ -34,11 +34,13 @@ import com.amazonaws.services.s3.model.S3ObjectSummary; import jeeves.server.context.ServiceContext; import org.fao.geonet.api.exception.ResourceNotFoundException; +import org.fao.geonet.constants.Geonet; import org.fao.geonet.domain.MetadataResource; import org.fao.geonet.domain.MetadataResourceContainer; import org.fao.geonet.domain.MetadataResourceVisibility; import org.fao.geonet.kernel.setting.SettingManager; import org.fao.geonet.resources.S3Credentials; +import org.fao.geonet.utils.Log; import org.springframework.beans.factory.annotation.Autowired; import java.io.File; @@ -182,17 +184,22 @@ public MetadataResource patchResourceStatus(final ServiceContext context, final } @Override - public String delResources(final ServiceContext context, final String metadataUuid, Boolean approved) throws Exception { - int metadataId = canEdit(context, metadataUuid, approved); + public String delResources(final ServiceContext context, final int metadataId) throws Exception { try { final ListObjectsV2Result objects = s3.getClient().listObjectsV2( s3.getBucket(), getMetadataDir(metadataId)); + + Log.info(Geonet.RESOURCES, String.format("Deleting all files from metadataId '%s'", metadataId)); for (S3ObjectSummary object: objects.getObjectSummaries()) { s3.getClient().deleteObject(s3.getBucket(), object.getKey()); } - return String.format("Metadata '%s' directory removed.", metadataId); + Log.info(Geonet.RESOURCES, + String.format("Metadata '%d' directory removed.", metadataId)); + return String.format("Metadata '%d' directory removed.", metadataId); } catch (AmazonServiceException e) { - return String.format("Unable to remove metadata '%s' directory.", metadataId); + Log.warning(Geonet.RESOURCES, + String.format("Unable to remove metadata '%d' directory. %s", metadataId, e.getMessage())); + return String.format("Unable to remove metadata '%d' directory.", metadataId); } } @@ -203,7 +210,7 @@ public String delResource(final ServiceContext context, final String metadataUui for (MetadataResourceVisibility visibility: MetadataResourceVisibility.values()) { if (tryDelResource(metadataUuid, metadataId, visibility, resourceId)) { - return String.format("MetadataResource '%s' removed.", resourceId); + return String.format("Metadata resource '%s' removed.", resourceId); } } return String.format("Unable to remove resource '%s'.", resourceId); @@ -214,7 +221,7 @@ public String delResource(final ServiceContext context, final String metadataUui final String resourceId, Boolean approved) throws Exception { int metadataId = canEdit(context, metadataUuid, approved); if (tryDelResource(metadataUuid, metadataId, visibility, resourceId)) { - return String.format("MetadataResource '%s' removed.", resourceId); + return String.format("Metadata resource '%s' removed.", resourceId); } return String.format("Unable to remove resource '%s'.", resourceId); } @@ -224,8 +231,12 @@ private boolean tryDelResource(final String metadataUuid, final int metadataId, final String key = getKey(metadataUuid, metadataId, visibility, resourceId); if (s3.getClient().doesObjectExist(s3.getBucket(), key)) { s3.getClient().deleteObject(s3.getBucket(), key); + Log.info(Geonet.RESOURCES, + String.format("Resource '%s' removed for metadata %d (%s).", resourceId, metadataId, metadataUuid)); return true; } + Log.info(Geonet.RESOURCES, + String.format("Unable to remove resource '%s' for metadata %d (%s).", resourceId, metadataId, metadataUuid)); return false; } diff --git a/core/src/main/java/org/fao/geonet/resources/S3Credentials.java b/datastorages/s3/src/main/java/org/fao/geonet/resources/S3Credentials.java similarity index 100% rename from core/src/main/java/org/fao/geonet/resources/S3Credentials.java rename to datastorages/s3/src/main/java/org/fao/geonet/resources/S3Credentials.java diff --git a/core/src/main/java/org/fao/geonet/resources/S3Resources.java b/datastorages/s3/src/main/java/org/fao/geonet/resources/S3Resources.java similarity index 100% rename from core/src/main/java/org/fao/geonet/resources/S3Resources.java rename to datastorages/s3/src/main/java/org/fao/geonet/resources/S3Resources.java diff --git a/core/src/main/resources/config-store/config-s3.xml b/datastorages/s3/src/main/resources/config-store/config-s3.xml similarity index 100% rename from core/src/main/resources/config-store/config-s3.xml rename to datastorages/s3/src/main/resources/config-store/config-s3.xml diff --git a/services/src/test/java/org/fao/geonet/api/records/attachments/S3StoreTest.java b/datastorages/s3/src/test/java/org/fao/geonet/api/records/attachments/S3StoreTest.java similarity index 100% rename from services/src/test/java/org/fao/geonet/api/records/attachments/S3StoreTest.java rename to datastorages/s3/src/test/java/org/fao/geonet/api/records/attachments/S3StoreTest.java diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 00000000000..20f2716957f --- /dev/null +++ b/docker/README.md @@ -0,0 +1,3 @@ +# Docker Test Environments + +These docker images are intended for development and debugging. For production we recommend the official GeoNetwork docker images at https://github.com/geonetwork/docker-geonetwork.git repository. diff --git a/docker/docker-geonetwork.txt b/docker/docker-geonetwork.txt deleted file mode 100644 index 1e1ae93bf58..00000000000 --- a/docker/docker-geonetwork.txt +++ /dev/null @@ -1 +0,0 @@ -Please see https://github.com/geonetwork/docker-geonetwork.git. diff --git a/docker/gn-cas-ldap/README.md b/docker/gn-cas-ldap/README.md index 326641c3a64..ae16f5181ed 100644 --- a/docker/gn-cas-ldap/README.md +++ b/docker/gn-cas-ldap/README.md @@ -1,4 +1,4 @@ -# Introduction +# GeoNetwork CAS Test Environment This composition is meant to make runtime testing the CAS integration of GeoNetwork easier. @@ -6,6 +6,8 @@ GeoNetwork easier. This composition also integrates a LDAP, so that testing the config-spring-cas-ldap configuration is also possible. +These docker images are intended for development and debugging. For production we recommend the official GeoNetwork docker images at https://github.com/geonetwork/docker-geonetwork.git repository. + # Prerequisites It requires the GeoNetwork webapp to be built first: @@ -18,7 +20,6 @@ Then it can be launched: ``` $ docker-compose up - ``` # Accessing the CAS login page from GeoNetwork diff --git a/docker/gn-postgres/README.md b/docker/gn-postgres/README.md new file mode 100644 index 00000000000..fb5aa0e58d2 --- /dev/null +++ b/docker/gn-postgres/README.md @@ -0,0 +1,8 @@ +# GeoNetwork PostgreSQL Test Environment + +This composition is meant to make runtime testing the PostgreSQL integration of +GeoNetwork easier. + +This folder provides a ``docker-compose.yml`` file for local testing. + +These docker images are intended for development and debugging. For production we recommend the official GeoNetwork docker images at https://github.com/geonetwork/docker-geonetwork.git repository. diff --git a/docker/docker-compose.yml b/docker/gn-postgres/docker-compose.yml similarity index 97% rename from docker/docker-compose.yml rename to docker/gn-postgres/docker-compose.yml index c6d942427d9..3c40e613034 100644 --- a/docker/docker-compose.yml +++ b/docker/gn-postgres/docker-compose.yml @@ -4,7 +4,7 @@ volumes: services: geonetwork: - image: geonetwork:3.99.0 + image: geonetwork:latest restart: always ports: - 8080:8080 diff --git a/docker/gn-postgres/kibana/kibana.txt b/docker/gn-postgres/kibana/kibana.txt new file mode 100644 index 00000000000..942837bbb76 --- /dev/null +++ b/docker/gn-postgres/kibana/kibana.txt @@ -0,0 +1,5 @@ +server.basePath: "/geonetwork/dashboards" +server.rewriteBasePath: false +kibana.index: ".dashboards" +elasticsearch.hosts: ["http://elasticsearch:9200"] + diff --git a/docs/README.md b/docs/README.md index 5eb45d9295f..79b0e5b4afd 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,9 +1,9 @@ -Documentation -============= +# Documentation This module contains: -* Documentation in RST format -* Change logs -* Copyright template -* Licenses for library -* Utility folder with scripts to generate extra docs \ No newline at end of file + +* `changes/` change logs txt files +* `manual/` in Markdown format for MkDocs +* `licenses/` for library +* `schema-doc/` folder with scripts to generate extra docs +* [copyright.txt](copyright.txt) Copyright template diff --git a/docs/changes2.1.x.txt b/docs/changes/changes2.1.x.txt similarity index 99% rename from docs/changes2.1.x.txt rename to docs/changes/changes2.1.x.txt index 84a0c41255c..803c1ec16de 100644 --- a/docs/changes2.1.x.txt +++ b/docs/changes/changes2.1.x.txt @@ -769,7 +769,7 @@ === Changes ================================================================================ -- Search for templates is hidden to simple registerd users (only allow from editors up) +- Search for templates is hidden to simple registered users (only allow from editors up) - Moved login info to the righ diff --git a/docs/changes2.10.x.txt b/docs/changes/changes2.10.x.txt similarity index 100% rename from docs/changes2.10.x.txt rename to docs/changes/changes2.10.x.txt diff --git a/docs/changes2.2.x.txt b/docs/changes/changes2.2.x.txt similarity index 99% rename from docs/changes2.2.x.txt rename to docs/changes/changes2.2.x.txt index c37ec5f926b..a8b2cd9c720 100644 --- a/docs/changes2.2.x.txt +++ b/docs/changes/changes2.2.x.txt @@ -1098,7 +1098,7 @@ InterMap: === Changes ================================================================================ -- Search for templates is hidden to simple registerd users (only allow from +- Search for templates is hidden to simple registered users (only allow from editors up) - Moved login info to the righ diff --git a/docs/changes2.4.x.txt b/docs/changes/changes2.4.x.txt similarity index 100% rename from docs/changes2.4.x.txt rename to docs/changes/changes2.4.x.txt diff --git a/docs/changes2.6.x.txt b/docs/changes/changes2.6.x.txt similarity index 100% rename from docs/changes2.6.x.txt rename to docs/changes/changes2.6.x.txt diff --git a/docs/changes2.8.x.txt b/docs/changes/changes2.8.x.txt similarity index 100% rename from docs/changes2.8.x.txt rename to docs/changes/changes2.8.x.txt diff --git a/docs/changes3.0.0-0.txt b/docs/changes/changes3.0.0-0.txt similarity index 100% rename from docs/changes3.0.0-0.txt rename to docs/changes/changes3.0.0-0.txt diff --git a/docs/changes3.0.1-0.txt b/docs/changes/changes3.0.1-0.txt similarity index 100% rename from docs/changes3.0.1-0.txt rename to docs/changes/changes3.0.1-0.txt diff --git a/docs/changes3.0.2-0.txt b/docs/changes/changes3.0.2-0.txt similarity index 100% rename from docs/changes3.0.2-0.txt rename to docs/changes/changes3.0.2-0.txt diff --git a/docs/changes3.0.3-0.txt b/docs/changes/changes3.0.3-0.txt similarity index 100% rename from docs/changes3.0.3-0.txt rename to docs/changes/changes3.0.3-0.txt diff --git a/docs/changes3.0.4-0.txt b/docs/changes/changes3.0.4-0.txt similarity index 100% rename from docs/changes3.0.4-0.txt rename to docs/changes/changes3.0.4-0.txt diff --git a/docs/changes3.0.5-0.txt b/docs/changes/changes3.0.5-0.txt similarity index 100% rename from docs/changes3.0.5-0.txt rename to docs/changes/changes3.0.5-0.txt diff --git a/docs/changes3.10.0-0.txt b/docs/changes/changes3.10.0-0.txt similarity index 100% rename from docs/changes3.10.0-0.txt rename to docs/changes/changes3.10.0-0.txt diff --git a/docs/changes3.10.1-0.txt b/docs/changes/changes3.10.1-0.txt similarity index 100% rename from docs/changes3.10.1-0.txt rename to docs/changes/changes3.10.1-0.txt diff --git a/docs/changes3.10.2-0.txt b/docs/changes/changes3.10.2-0.txt similarity index 100% rename from docs/changes3.10.2-0.txt rename to docs/changes/changes3.10.2-0.txt diff --git a/docs/changes3.10.3-0.txt b/docs/changes/changes3.10.3-0.txt similarity index 100% rename from docs/changes3.10.3-0.txt rename to docs/changes/changes3.10.3-0.txt diff --git a/docs/changes3.10.4-0.txt b/docs/changes/changes3.10.4-0.txt similarity index 100% rename from docs/changes3.10.4-0.txt rename to docs/changes/changes3.10.4-0.txt diff --git a/docs/changes3.10.5-0.txt b/docs/changes/changes3.10.5-0.txt similarity index 100% rename from docs/changes3.10.5-0.txt rename to docs/changes/changes3.10.5-0.txt diff --git a/docs/changes3.10.6-0.txt b/docs/changes/changes3.10.6-0.txt similarity index 100% rename from docs/changes3.10.6-0.txt rename to docs/changes/changes3.10.6-0.txt diff --git a/docs/changes3.12.0-0.txt b/docs/changes/changes3.12.0-0.txt similarity index 100% rename from docs/changes3.12.0-0.txt rename to docs/changes/changes3.12.0-0.txt diff --git a/docs/changes/changes3.12.12-0.txt b/docs/changes/changes3.12.12-0.txt new file mode 100644 index 00000000000..43a4fce6aa0 --- /dev/null +++ b/docs/changes/changes3.12.12-0.txt @@ -0,0 +1,64 @@ +================================================================================ +=== +=== GeoNetwork 3.12.12: List of changes +=== +================================================================================ +- Documentation / GeoNetwork 3.12 doing a release fixes (#7852) +- [Backport 3.12.x] GeoNetwork harvester / Check if a resource exists to save it, instead of trying to retrieve the file details, to avoid confusing NoSuchFileException exception (#7846) +- Harvesters / Reset harvester history pagination when selecting a harvester (#7836) +- Follow up of #7279 to unify the button links in the metadata detail page as done for the analog change in main branch (#7391) +- Remove invalid empty migration added accidentally in https://github.com/geonetwork/core-geonetwork/commit/93377dd1866a5ee3f5b0098bcd1dd6188c009771 (#7821) +- Doc / Editor configuration improvements (#7826) +- [Backport 3.12.x] Bump actions/setup-java from 4.0.0 to 4.1.0 (#7816) +- [Backport 3.12.x] Fix alignment of user enabled checkbox (#7772) +- Remove handlebars.js v2.0.0 (#7762) +- update 3.12.x branch to recent sphinx-build and crank up warnings +- Addressing docs glitch #7666 creating-group and authentication-mode +- Addressing docs glitch #7666 tutorials/deployment/index +- addressing docs-glitch in install-guide/configuring-database +- addressing docs-glitch in search-ui/enrichview and search-ui/loadview +- addressing docs-glitch in install-guide/map-print-setup +- addressing docs-glitch in publishing/managing-privileges +- corrected minor typo in install-guide/map-print-setup +- Fix conversion errors after switching to MkDocs +- manual review of mkdocs glitches +- [Backport 3.12.x] Create a metadata / Add dynamic and download privileges to the users in the same group (#7748) +- Metadata detail page - don't display the resources description duplicated (#6798) +- Use the generated metadata UUID for resource links when importing metadata with the option 'Generate UUID' (#7734) +- Remove unused jslint-maven-plugin +- [Backport 3.12.x] Bump org.json:json from 20140107 to 20240205 (#7723) +- [Backport 3.12.x] Github Actions / Bump stCarolas/setup-maven from 4 to 5 (#7719) +- [Backport 3.12.x] Bump commons-fileupload from 1.3.3 to 1.5 (#7698) +- Fix pdf link issue +- Fix mimetypes on attachments as some were incorrect. (#7676) +- Docs / Update copyright year +- Fix the grid on the homepage of the documentation (#7559) +- troubleshoot release module order of execution and profile acivation and handling of jetty folder +- Remember to include -Drelease flag so that all modules (even optional modules) are compiled and tested during QA +- [BP] Bump actions/setup-java from 3.12.0 to 4.0.0 (#7522) +- [BP] Service context null pointer (#7593) +- [BP] Overview not shown in PDF export when the overview image is stored in GeoNetwork and requires authentication to access it. Fixes #7540 (#7556) +- [BP] Update iso19139 csw-full.xsl (#7558) +- [BP] Add ownerId to geonet:info (#7547) +- [BP] Don't display header menu and footer in single metadata PDF export (#7532) +- [BP] Bump actions/setup-python from 4 to 5 (#7543) +- [BP] Remote INSPIRE Atom Feeds harvester - Remove duplicates by dataset identifier (#7491) +- [BP] When getting locale message, default locale to LocaleContextHolder when locale is null (#7516) +- [BP] Fix some cases that were not considering both message and description when displaying errors. (#7517) +- [BP] Docs / Fix the mike version to 2.0.0 and change the parameter --no-redirect to --alias-type=copy (changed in mike 2.0.0) (#7507) +- [BP] Check http links in documentation (#7496) +- [BP] Update manual links to use https://docs.geonetwork-opensource.org/ (#7487) +- [BP] Change the structure of the MkDocs assets. Stylesheets and logos are moved to the `overrides` directory (#7429) +- Fix publish link (#7479) +- Fix url link in full view. bracket ") " could be included in link (#7483) +- [BP] Batch edit access level for editor role (#7464) +- [BP] Add node identifier parameter for xlst processing. Required in skin.xsl (#7454) +- Fix other exceptions in tests related to (#6977) +- [BP] Remove exception class name from the error message (#6977) +- [BP] Fix cookies path when deployed on root "/" context (#7446) +- [BP] Fix exception handling from schematron validation so that it flags the metadata as invalid if there is an exception (#6978) +- [BP] Remove old password field for admins (#7417) +- [backport 3.12.x] Add documentation to GitHub workflows (#7414) +- [BP] Change the url the icon in the homepage is linking to (#7422) +- Remove changelog for latest and stable +- Correct canonical_version to stable diff --git a/docs/changes3.2.0-0.txt b/docs/changes/changes3.2.0-0.txt similarity index 100% rename from docs/changes3.2.0-0.txt rename to docs/changes/changes3.2.0-0.txt diff --git a/docs/changes3.2.1-0.txt b/docs/changes/changes3.2.1-0.txt similarity index 100% rename from docs/changes3.2.1-0.txt rename to docs/changes/changes3.2.1-0.txt diff --git a/docs/changes3.2.2-0.txt b/docs/changes/changes3.2.2-0.txt similarity index 100% rename from docs/changes3.2.2-0.txt rename to docs/changes/changes3.2.2-0.txt diff --git a/docs/changes3.4.0-0.txt b/docs/changes/changes3.4.0-0.txt similarity index 100% rename from docs/changes3.4.0-0.txt rename to docs/changes/changes3.4.0-0.txt diff --git a/docs/changes3.4.1-0.txt b/docs/changes/changes3.4.1-0.txt similarity index 100% rename from docs/changes3.4.1-0.txt rename to docs/changes/changes3.4.1-0.txt diff --git a/docs/changes3.4.2-0.txt b/docs/changes/changes3.4.2-0.txt similarity index 100% rename from docs/changes3.4.2-0.txt rename to docs/changes/changes3.4.2-0.txt diff --git a/docs/changes3.6.0-0.txt b/docs/changes/changes3.6.0-0.txt similarity index 100% rename from docs/changes3.6.0-0.txt rename to docs/changes/changes3.6.0-0.txt diff --git a/docs/changes3.8.0-0.txt b/docs/changes/changes3.8.0-0.txt similarity index 99% rename from docs/changes3.8.0-0.txt rename to docs/changes/changes3.8.0-0.txt index 832c2d67898..f367694b79f 100644 --- a/docs/changes3.8.0-0.txt +++ b/docs/changes/changes3.8.0-0.txt @@ -292,7 +292,7 @@ - Support gmx:Anchor in extract relations xslt process - refactor - Support gmx:Anchor in extract relations xslt process - fix pdf generation from full view, flying saucer trouble with float: left -- in manage record priviledges help groups sorter to sort +- in manage record privileges help groups sorter to sort - Metadata editor - associated panel doesn't remove error red highlight when filling the url in thumbnail mode #3756 - Fix JS build. - Fixes empty owner select in admin's batch process @@ -439,4 +439,4 @@ - fixes #3207, add warning when layer not in capabilities (for wmts and wfs), with option to open service panel to select alternative layer (adding type to warning translation, so it can be used for multiple types). Also fixes bug with url having &. - Updated slf4j dependencies - Updated avalon-framework dependencies -- Updated json-path dependencies \ No newline at end of file +- Updated json-path dependencies diff --git a/docs/changes3.8.1-0.txt b/docs/changes/changes3.8.1-0.txt similarity index 100% rename from docs/changes3.8.1-0.txt rename to docs/changes/changes3.8.1-0.txt diff --git a/docs/changes3.8.2-0.txt b/docs/changes/changes3.8.2-0.txt similarity index 100% rename from docs/changes3.8.2-0.txt rename to docs/changes/changes3.8.2-0.txt diff --git a/docs/changes3.8.3-0.txt b/docs/changes/changes3.8.3-0.txt similarity index 100% rename from docs/changes3.8.3-0.txt rename to docs/changes/changes3.8.3-0.txt diff --git a/docs/changes4.0.0-0.txt b/docs/changes/changes4.0.0-0.txt similarity index 100% rename from docs/changes4.0.0-0.txt rename to docs/changes/changes4.0.0-0.txt diff --git a/docs/changes4.0.0-alpha.1.txt b/docs/changes/changes4.0.0-alpha.1.txt similarity index 100% rename from docs/changes4.0.0-alpha.1.txt rename to docs/changes/changes4.0.0-alpha.1.txt diff --git a/docs/changes4.0.0-alpha.2.txt b/docs/changes/changes4.0.0-alpha.2.txt similarity index 100% rename from docs/changes4.0.0-alpha.2.txt rename to docs/changes/changes4.0.0-alpha.2.txt diff --git a/docs/changes4.0.1-0.txt b/docs/changes/changes4.0.1-0.txt similarity index 100% rename from docs/changes4.0.1-0.txt rename to docs/changes/changes4.0.1-0.txt diff --git a/docs/changes4.0.2-0.txt b/docs/changes/changes4.0.2-0.txt similarity index 100% rename from docs/changes4.0.2-0.txt rename to docs/changes/changes4.0.2-0.txt diff --git a/docs/changes4.0.3-0.txt b/docs/changes/changes4.0.3-0.txt similarity index 100% rename from docs/changes4.0.3-0.txt rename to docs/changes/changes4.0.3-0.txt diff --git a/docs/changes4.0.4-0.txt b/docs/changes/changes4.0.4-0.txt similarity index 100% rename from docs/changes4.0.4-0.txt rename to docs/changes/changes4.0.4-0.txt diff --git a/docs/changes4.0.5-0.txt b/docs/changes/changes4.0.5-0.txt similarity index 100% rename from docs/changes4.0.5-0.txt rename to docs/changes/changes4.0.5-0.txt diff --git a/docs/changes4.0.6-0.txt b/docs/changes/changes4.0.6-0.txt similarity index 100% rename from docs/changes4.0.6-0.txt rename to docs/changes/changes4.0.6-0.txt diff --git a/docs/changes4.2.0-0.txt b/docs/changes/changes4.2.0-0.txt similarity index 100% rename from docs/changes4.2.0-0.txt rename to docs/changes/changes4.2.0-0.txt diff --git a/docs/changes4.2.1-0.txt b/docs/changes/changes4.2.1-0.txt similarity index 100% rename from docs/changes4.2.1-0.txt rename to docs/changes/changes4.2.1-0.txt diff --git a/docs/changes/changes4.2.10-0.txt b/docs/changes/changes4.2.10-0.txt new file mode 100644 index 00000000000..a10a08cbd71 --- /dev/null +++ b/docs/changes/changes4.2.10-0.txt @@ -0,0 +1,91 @@ +================================================================================ +=== +=== GeoNetwork 4.2.10: List of changes +=== +================================================================================ +- Map viewer / Add layer with styles from a metadata doesn't show the styles selector (#8181) +- Synchronize transifex translations (#8166) +- Map viewer / fix TMS layer persistence in map context (#8179) +- Fix issue with Map Attribution not being toggled correctly in data preview. (#8165) +- Map / Feature table / Missing translation (#8148) +- Transfer ownership / fix translation key for 'Save' button (#8135) +- Metadata tooltips - improve the check method to try to find a match a standard default with no context defined, if there is no entry with the element context (#8139) +- Delete draft resource at the end of draft util transaction. (#8100) (#8147) +- Fix issues with category icons in search results list view (#8144) +- update last changed date when restore metadata (#8131) +- Update DOI exceptions to be multilingual exceptions (#8128) +- Indexing / ISO19115-3 / Avoir error on multiple contact website (#8129) +- Harvesters / remove unused groupsCopyPolicy property (#8130) +- Remove link from admin-guide to schematron details as inappropriate +- XSL / Utility / Add multilingual support to getIndexField (#8065) +- Editor / Groupowner change error (#8123) +- Editor / Group owner change / Fix label on error (#8124) +- Indexing / ISO / Properly index all keywords even if in different (#8115) +- Be able to edit metadata when backend store is not available (#8110) +- Documentation / Add information about the type of users that can request a DOI (#8109) +- Used new mike alias: true setting to simplify publication +- Flatten changelog into current release and release history for ease of maintenance (#8093) +- Record view / ISO19139 / ISO19115-3.2008 display the unit part in @uom attribute - avoid duplicated value (#8085) +- HTTP proxy servlet / update error messages. (#8084) +- Map / Add scale. (#7967) (#8073) +- WMS GetMap HEAD request error response - check response status defined (#8076) +- Users / reset form status when creating a user (#8075) +- Cleanup onbeforeunload event when loading the editorboard controller (#8074) +- search menu size (#8068) +- Record view / Fix JS error related to publication options display. (#8067) +- Editor / Map / Use main context to have a better default on new extent (#8064) +- Standard / ISO19115-3 / Avoid indexing error on multilingual feature catalogue (#8062) +- Standard / ISO19115-3 / Remove geographicElement when removing bounding box (#8061) +- Workflow / Edit action / Fix link in search results (#8054) +- Synchronize Messages.properties from web and test (#8053) +- Mail / Log / Remove debug level (#8045) +- Map viewer / ESRIREST layers / Scale the layer extent to show the symbology of the features in the corners of the extent. (#8038) +- Search tab map is blank on first page load. Fixes #7961 (#8037) +- Fix migration script configuration for 4.2.10 version (#8022) +- ISO19139 metadata full view / display citation titles (#8017) +- Merge pull request from GHSA-52rf-25hq-5m33 +- Status dashboard / Don't include indexing warnings as errors (#8010) +- Record view / Add service type info and metadata standard name (#8005) +- Indexing / Improve geometry indexing and display (#7988) +- Standard / ISO19115-3 / Feature catalogue improvements (#8001) +- Standard / ISO19115-3 / Ensure dqm namespace is on top of the document. Remove gts namespace which is ISO19139. (#8000) +- Standards / ISO19115-3 / Cleanup project specific template (#7999) +- Fix for nextrecord in csw getrecord response when using pagination (#7996) +- French translation update for metadata_approved_published_record_text (#7994) +- Report users - Display profile for Administrator / Guest profiles that are not related to groups (#7991) +- Remove unused JeevesDelegatingFilterProxy servlet parameter 'loginService' configuration, related to multinode feature, removed from GeoNework 4.x (#7992) +- Update the default sort field name in editor board and batch editor. (#7990) +- Editor / GeoNames search failing with space (#7987) +- CSW server / Use portal filter in GetRecordById requests (#7986) +- Editor board / Use metadata database change date instead of the metadata dateStamp (xml) (#7985) +- System setting for documentation url (#7984) +- Support additional metadata processing when publishing / un-publishing metadata. (#7973) +- INSPIRE Atom feeds / Fix link to atom search endpoint (#7972) +- Update Jetty to version 9.4.54.v20240208 (#7965) +- Update sort by fields configuration with language placeholder, to support sort by multilingual fields (#7964) +- Doc / Editor configuration / Subtemplate insert mode (#7963) +- Remove q service, used to query in previous versions that used Lucene as the search engine (#7953) +- Fix sql syntax for migrate to 4.4.4 script (#7958) +- Update revise use of empty or mostly empty pages (#7957) +- Modify csv search export to escape double-quotes with double-quotes instead of backslash +- Fix harvester URIMapper to handle local metadata (#7949) +- metadata history viewing with user profile level (#7450) (#7934) +- Fix Javascript issues, mostly related to missing variable declarations (#7914) +- Hide the typeahead search suggestions when hitting the ENTER key in the search field without selecting a suggested value (#7921) +- Standard / ISO19115-3 / Editor / Uom encoding support (#7920) +- API / Import does not overwrite metadata if any validation status (#7907) +- Search / May fail with random_score depending on ES config (#7913) +- Standard / ISO19115-3 / Use anchor encoding for IACS keywords (#7906) +- Standard / ISO19115-3 / Schema / Move from srv 2.1 to 2.0 (#7904) +- Upgrade springdoc to 1.7.0 (#7596) (#7903) +- Fix issue with saving metadata status causes indexing of metadata which causes issues for db rollbacks (#7901) +- move email notification at the end of status change transaction (#7900) +- Configure harvesters log to avoid application log duplicated in harvester_default.log file. Fixes #7895 (#7897) +- Fix typo in Messages.properties (#7894) +- Feedback / Fix email to multiple recipients (#7888) +- Passing key into update/remove process xslt for iso 19139 to fix issue with updating/deleting resources with same url (#7740) +- Map / Extent API / Background image failure if matrixset is not SRS code (#7883) +- Optimise query used to retrieve metadata links results (#7877) +- Fill in 4.2.x releases for maintenance page (#7884) +- OpenID / Cleaning up cached tokens (#7874) +- ISO19139 / Index online resources application profile element encoded as anchor (#7856) diff --git a/docs/changes4.2.2-0.txt b/docs/changes/changes4.2.2-0.txt similarity index 100% rename from docs/changes4.2.2-0.txt rename to docs/changes/changes4.2.2-0.txt diff --git a/docs/changes4.2.3-0.txt b/docs/changes/changes4.2.3-0.txt similarity index 100% rename from docs/changes4.2.3-0.txt rename to docs/changes/changes4.2.3-0.txt diff --git a/docs/changes/changes4.2.4-0.txt b/docs/changes/changes4.2.4-0.txt new file mode 100644 index 00000000000..cc249223490 --- /dev/null +++ b/docs/changes/changes4.2.4-0.txt @@ -0,0 +1,151 @@ +================================================================================ +=== +=== GeoNetwork 4.2.4: List of changes +=== +================================================================================ +- Merge pull request #7059 from tkohr/xsl-fixes +- Add migration for static pages (#7005) +- Map / WPS / Fixes and improvements +- Translations / Updates from transifex. +- Admin / Link analysis / Use POST / Fix test +- Standard / Associated resources / Add check for duplicated references. +- Standard / ISO19115-3 / Add link fails if record has no language. +- Editor / Display attributes when an element only have attributes eg. metadataReference. +- Standard / ISO19115-3 / Remove parentIdentifier linking which is not used. Users use associated resources for this type of links. +- Maps library / Fix home page link to display the map. +- Record view / Break keywords with long values +- Fix display of user selections panel for logged users (#7001) +- disable link to parent button to use ng-disabled (#7045) +- gn - fix(ods): copy ods themes to topicCategory instead of keywords +- gn - fix(dkan): accept optional - separator and seconds +- gn - fix(dkan): make regExLoc for date conversion more permissive +- Admin / Link analysis / Use POST. (#7022) +- gn - fix(ods): fix mapping of ods metadata and ressource dates +- i18n / Fix loading of languages for ICE, KOR and CZE (#7055) +- Indexing / More robust on invalid thesaurus type (#7052) +- Indexing / More robust on vertical range. (#7054) +- Indexing / Add timeout when retrieving overview. (#6905) +- Editing / dateStamp = changeDate on update (#7012) +- Standard / ISO19115-3 / Add same mechanism as ISO19139 for parentIdentifier (#6976) +- Editor / Suggestions / Suggest to add a date depending on the status. (#6967) +- i18n / Add Danish language (#6933) +- Import metadata / If workflow is enable hide publish option (#7008) +- Sharing / Batch mode / Fix +/- icon on Firefox. +- Download xml in new tab (#6975) +- PDF / Report image URL in case of error (#7032) +- Library update / WRO4J / Remove unused extensions with CVE reported. +- Library update. +- Quick fix for missing comma in #7034 +- Automatic formatting +- Prevent breaking of topic titles in middle of title (#7036) +- Add pagination to the footer of the search page (#7035) +- Verify the portal requested exists - configure servlet names to exclude (#7034) +- CSW / Transactions are not in history. (#7016) +- Portal redirection / Search portal by uuid not by name. (#7030) +- Test / API / Page label null trigger error (#6989) +- Dependency / Rever camel update triggerring issue on Tomcat +- ISO19139 / Editor / Fieldset on processor +- CSW / Transaction / Consistently apply update-fixed-info (#7004) +- fix: upgrade com.google.code.findbugs:jsr305 from 2.0.1 to 2.0.3 +- Bump camel.version from 2.25.1 to 2.25.4 +- Update publish link so that it is disabled if the metadata has not been approved. (#7009) +- Pass created, modified, issued date from thesaurus to the schemas (#6972) +- Revert empty properties format +- fix: pom.xml to reduce vulnerabilities +- Harvester / Simple URL / Total harvested records when using pagination is incorrect +- Fix admin setting error with duplicate id="metadata/workflow/draftWhenInGroup" (#6980) +- Metadata publication mail - support additional fields: (#6906) +- Map viewer / make configurable to display the metadata bboxes using geodesic extents for local projections (#6982) +- Fix related to #6946, scope.config is not ready when the metadata editor is being loaded +- Metadata editor / normalize the values provided to AngularJs directives +- Editor / Thesaurus / Add option to display or not the SKOS browser. +- Editor / Tooltip / Add onhover mode. +- Editor / Improve default tab configuration. +- Test / Fixes (#6932) +- Admin / Page / Styling. +- UI configuration for static pages, to allow customise the order of the pages in the sections +- Add page label property to use for the links text instead of using the page identifier +- Respond with JSON +- Return 201 when creating pages +- Remove unreacheable if statement +- Remove code smells +- Add help text for page sections +- Additional formatting updates +- Use translations page statuses +- Updates: - Use format translations. - Don't show page link when creating a new page. - Fix layout of the HTML editor +- Admin / Page / Avoid :baddata] Data must be a valid JSON. +- Admin / Page manager / Add translations. +- API / Pages / Clear queue after upload. +- API / Pages / Fix warning on POST. +- API / Pages / Fix update content. +- API / Pages / Fix test. +- Page API improvement +- API / Pages / Set HTML content type if page is an upload HTML. +- API / Pages - Initial support to upload page files +- API / Pages - Update check file type check and when uploading a file, store the file name in the link field +- API / Pages - add message translations and fix delete request +- API / Pages - unify sections parameter name, support multiple sections per page and show in the list the page id and the language +- API / Pages - update gnStaticPagesListViewer directive to use the new API +- API / Pages - add a service to return the static pages and update UI to use the new API services +- API / Pages / Keep it simple and test. +- Prettier and AngularJS update. +- Static pages UI configuration +- ISO19139 / Editor / Fieldset on resource usage and userContactInfo +- Metadata file downloads report - fix check to retrieve user related information (#6971) +- Configure the users profile allowed to publish / un-publish metadata (#6956) +- ISO19139 / ISO19115-3.2008 / use also xlink:href element to identify related datasets (#6973) +- Map / Feature table improvement. (#6969) +- Filter to verify the portal requested exists, otherwise redirects to the default portal +- Map / Context / Style may or may not declare namespace. +- Standard / ISO19115-3 / Do not alter creation date and allow editing of metadata identifier descriptors (#6968) +- Standard / ISO19115-3 / Editor / Reference system from EPSG database +- Editor / Configuration / Add for each support. (#6907) +- Map / Layer / Styling tab for better legend readability. +- Map / Layer / Use caret icon instead of radio. +- Map / Layer / Improve layout and add server URL and layer name to easily copy value (eg. to add layer in GIS). +- Map / Layer / Better alignment. +- Map / WMS Time / Add slider control. +- Map / Group layer tools and avoid to have too many buttons in layer row. +- Map / WMS Time and elevation / Animation interval. +- Map / WMS Time and elevation. +- Prettier formatting +- Users management - disable save button if password check doesn't match the password (#6890) +- Search results / List / Associated resource group by title / Styling. +- Search results / List / Associated resource group by title. +- Release / Cleanup folder. +- Doc / Fix warning. +- Add online resources from WMS layers with the 'resourcename' mode: +- Implement a more extendable openid connect security +- Network / Intranet configuration / Add support for multiple ip ranges (#6894) +- Merge branch 'Informatievlaanderen-dv/pr/root-context' +- Make local jetty run plugin context path configurable / doc. +- Make local jetty run plugin context path configurable thought JVM options +- Remove duplicate and run Prettier +- Add a setting to make the map accessible. The setting is off by default. +- Fix issue with initial db creation not having language list when @PostConstruct was called. (#6870) +- Search / Use scripted field for more like this and isSuperseded directive. +- Use scripted field to retrieve associated resources first overview url. Sonarlint code improvements. +- Update EsFacet.js +- Search / Review _source to contains only necessary fields. Fixed some field names for category and topic. +- Search / Use scripted field to only load the first overview. +- Changed the messages about existing users or emails to be identical, to make it harder to enumerate through users +- Remove requirement for gmd:fileDescription so that thumbnail urls are transformed when migrating records. +- change the method for the password's minLength to be max, so if a bigger value than 6 is retrieved from "system.security.passwordEnforcement.minLength" this is taken into account (#6953) +- UI / Add a read more directive +- Avoid retrieve metadata associated records aggregations when the metadata have no associated records +- Doc / Editor configuration / Spelling improvements (#6944) +- Extend date range filter directive to configure the date field to use. +- Feature catalogue / Index producer +- Record view / don't call records history when not authorised +- Update validation report to include more information in the report. (#6900) +- Update CSW GetRecords samples. Fixes #6935 +- Bump httpclient from 4.5.9 to 4.5.14 (#6928) +- OutOfMemory exception on tomcat / Change logging bridge dependency. (#6904) +- Update Geotools to v28.2 (#6925) +- Create mvn-dep-tree.yml (#6923) +- Update CSW queryable mappings for contacts +- Build / git.properties file not created (#6915) +- Avoid index empty values of online resources protocols. If the ES field is used for facet filter, it displays the empty value +- Search / allow to configure additional fields to exclude from searches (#6911) +- Cmis performance enhancements (#6893) +- Update version to 4.2.4-SNAPSHOT \ No newline at end of file diff --git a/docs/changes/changes4.2.5-0.txt b/docs/changes/changes4.2.5-0.txt new file mode 100644 index 00000000000..5c0e1a2dd77 --- /dev/null +++ b/docs/changes/changes4.2.5-0.txt @@ -0,0 +1,112 @@ +================================================================================ +=== +=== GeoNetwork 4.2.5: List of changes +=== +================================================================================ +- Thesaurus / Region / Use ISO format for date (#7208) +- Transifex updates. +- Static pages / Fix links to load html pages content (#7203) +- Sort custom translations by translation key to display them in the UI grouped by translation +- API / Import record / Overwrite mode improvement. (#7178) +- Additional code refactor related to pull request 7124 to avoid code duplication (#7200) +- Editor / Thesaurus widget initialization improvement. +- Thesaurus / Multilingual title / Set title according to record language. +- Merge pull request #7124 from AstunTechnology/jeevesnodeawarelogout-port-fix +- Bulk publish / Publish privileges should be assigned to the approved version, not to the working copy version. +- [FP] Metadata workflow - publish an approved record with a draft copy, publishes the draft copy. Fixes #5556 (#5557) +- Fix load of static pages html content +- Remote INSPIRE ATOM Feed / code cleanup and optimisations for ATOM describe service (#7189) +- Exclude ATOM opensearch URLs from the portal filter checker. Related to #6970 (#7196) +- Add a Dutch translation for the datepicker (#7193) +- Merge pull request #7181 from pi-geosolutions/external-viewer-add-wfs-to-map +- Pages / Top toolbar / Add support for submenu (#7138) +- XslUtil / Add a function to get current node id (srv or subportal id) +- [WFS / external viewer] Remove trailing semi-colon +- [WFS / External viewer] Support localized title but fallback on link name +- Change line-height for username so that it is not truncated. (#7185) +- Update core/src/main/java/jeeves/config/springutil/JeevesNodeAwareLogoutSuccessHandler.java +- Update core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataManager.java +- Update core/src/main/java/org/fao/geonet/kernel/setting/SettingInfo.java +- Created new instances of SettingInfo.getSitePort in JeevesNodeAwareLogoutSuccessHandler and BaseMetadataManager to get around compilation error about not referring to a non-static method from a static context +- External map viewer / Fix add WFS to map empty variable +- Site information - return ES index information +- Updated Java 8 download link (#7177) +- Standard / Translations / Load contact role codelist from the schema (#7153) +- Configuration / Externalize Kibana configuration (#7098) +- Test / Fix for default language. (#7175) +- Record view / Keyword popup / Improve label. (#7152) +- Fixed broken link for Maven Reference +- CSW / DCAT output / Fix for multilingual records (#7161) +- Record view / Citation / Improve layout +- Remove Language table isdefault column and use DefaultLanguage bean instead +- Fixing SONAR warnings about SQL Injections. (#7146) +- Search / Full text / Add individual name and email. (#7167) +- Standard / ISO19115-3 / Preserve revision date type. (#7168) +- Standard / ISO19115-3 / Editor / Do not add default lang id (#7174) +- Standard / ISO19115-3 / Better label for metadata language. (#7173) +- Standard / ISO19115-3 / From 19139 conversion / Fix MD_VectorSpatialRepresentation namespace (#7172) +- Editor / Template field label fix (#7171) +- Standard / ISO19115-3 / Editor / Expand abstract for multilingual records (#7170) +- Move tooltip from reccusive input field to a single label (#7039) +- Minor formatting changes. (#7164) +- Do not make Danish language a default language. +- Support code elements with anchors in ATOM predefined feeds +- Support customising the metadata publication options (#7148) +- Update TESTING.md to include a hint to the it maven profile (#7149) +- missed file in pull/6494 (#7150) +- Map / Background layer / Fix active layer on load. (#7126) +- Map / Layer manager / Add support for multilingual layer title. (#7121) +- UI / Language picker / Display all entries on focus. Search by code and labels (#7076) +- Standard / ISO19115-3 / Formatter / JSONLD / Avoid error on multilingual URL +- Fixed typos in es README (#7151) +- FeatureInfo - lower case columns names - related to #6801 +- Fixed another broken link for Installing from source code (#7141) +- Send metadata mail notifications for public metadata when is re-approved (#7074) +- Update transifex translations +- Update metadata status values translations +- Workflow / Facets / Generic translations (#7135) +- Remove sort by translations, duplicated in en-core.json file +- Related resources - fix the check to display association information +- Indexing / Update objects definition to index a sort field that is case insensitive and ignore accents +- ISO19139 / Metadata editor / Fix display of contact individual name label in German (#7122) +- Workflow / Remove magic numbers in label and avoid issue when using custom status (#7104) +- Fixed broken link for Installing from source code +- Add Spring Security mappings for local INSPIRE ATOM feed services +- Allow multiple request matchers to decide if require CSRF (#7123) +- Changed logic to check actual value of port setting +- Using correct setting for default port, and better handling of null values +- Include the parent exception in the MetadataProcessingReport error so that we can see the real error in the logs. (#7119) +- Fix check of harvester log file path +- ISO19139 / Fix indexing of CRS codespace when contains a multilingual value +- Added some logic into JeevesNodeAwareLogoutSuccessHandler to deal with the case where no port is set in the settings manager +- Fix selection / filter Only my records (#7111) +- Return contact information in the search results, used in the results templates +- Index configuration / define dynamic template for conformTo_* fields pattern +- Update sortby-combo directive to use the field name and the sort order information. +- Metadata editor / include the metadata file store in the default configuration of the online resources. Fixes #7103 +- Copying the resources/config folder to the data dir +- Workflow / On Cancel / Properly remove draft from index (#7101) +- Remove code smells +- Fix javascript error when creating / editing online resources +- Fix microservices proxy detection +- Metadata workflow / send mail notifications for metadata status change to DRAFT when doing a rejection, not when creating a working copy +- Workflow improvements (#7011) +- DB / Only update schema on startup (#7100) +- Display footer rss endpoint(s) when OGC API Records service is enabled (#7094) +- SEO / Set HTML head title and description +- Build / Fix missing font awesome files in WAR +- Map / Define location of search map. (#7071) +- fixed links to debugging tomcat in eclipse and remote debugging (#7075) +- Add criteria-type.xml for iso19115-3.2018 +- Fix for broken icons in the editor, admin pages, file uploader and multiselect (#7093) +- Config / Add property file overlay. (#6954) +- Test / Fixes (#7091) +- Workflow / Fix typo in setting key. (#7070) +- UI / Dependency / CatController depends on facets also on signin. (#7084) +- i18n / NL / INSPIRE Themes / Fix language code +- Home page / Aggregations / Fix label for facet based on multilingual thesaurus. +- Standard / ISO19139 / Schematron / NL translation (#7063) +- DOI / Add European Union Publication Office format for DOI. (#6979) +- Update to Font Awesome 6.x (6.4) (#7007) +- Fix multiple default tab in a single view +- Update version to 4.2.5-SNAPSHOT \ No newline at end of file diff --git a/docs/changes/changes4.2.6-0.txt b/docs/changes/changes4.2.6-0.txt new file mode 100644 index 00000000000..cd18593910e --- /dev/null +++ b/docs/changes/changes4.2.6-0.txt @@ -0,0 +1,107 @@ +================================================================================ +=== +=== GeoNetwork 4.2.6: List of changes +=== +================================================================================ +- Doc / Changelog / 4.2.6. (#7393) +- [BP] Changed GENERATEUUID to NOTHING based on discussion on issue #7274 +- Documentation 4.2: Update link to the 4.2 manual and release scripts (#7380) +- [BP] Fixed typos for SOURCE.md (#7384) +- [BP] Update MkDocs configuration to publish to gh-pages branch (#7375) +- [BP] Workflow / Related records of the draft (#7377) +- [BP] User Manual refresh using Markdown and MkDocs (#7329) +- [BP] batch edit user profile check in APIs (#7243) +- [BP] Record view / Support multiple status. +- [BP] Groups maintenance / fix the display of the metadata owned by a group (#7371) +- [BP] Map viewer / Option to configure WMS tiling (#7312) +- [BP] Fix working copy display so that links go to working copy (#7248) +- [BP] Send metadata mail notifications for public metadata when is re-approved - fill missing information for submitter, reviewer and publisher user (#7292) +- [BP] Map viewer / context map / only WMS layers have dimensions information +- [BP] Standard / ISO19110 improvements +- [BP] fix for untranslated userRecord and userRecords labels in user admin page (#7354) +- [BP] Add support for emails with subdomains (#7314) +- [BP] Improved handling of empty titles (#7362) +- [BP] Indexing / Bounding Polygon / Coordinate order (#7364) +- [BP] Indexing / Bounding Polygon / Reproject if needed #7340 +- [BP] Editor / Online source / Fix button icon +- [BP] Fix CORSInterceptor, usage of a variable before is defined. Related to #5941 (#7361) +- [BP] Display the login menu for authenticated users when the setting 'gnCfg.mods.authentication.enabled' is disabled +- [BP] Map / WMS dimension saved in map (#7339) +- [BP] Add icons for related types (association and initiative) (#7264) +- [BP] WFS layer improvements (#7317) +- [BP] Create metadata category - check doesn't exist a category with the same name (#7296) +- Fix HTML/Javascript prettier formatting / 4.2.x branch (#7356) +- [BP] Portal / RSS feeds point to current portal (#7343) +- [BP] Prevent invalid date written into xml (#7321) +- [BP] Fix write after response commit on proxy response (#7353) +- [BP] Map / Localisation / Empty results if no query (#7338) +- [BP] Indexing / Do not create empty object if no text (#7349) +- [BP] Indexing / Do not create empty object if no text (#7294) +- [BP] Batch Editing access level in general system settings (#7238) +- [BP] User feedback API fixes: - Update mail message, related to #6792. - Don't fail the user feedback creation if the mail server is not configured +- [BP] Remove configuration for the UI setting 'isMenubarAccessible', removed in #7138 +- [BP] Batch editing / Update xpath spec link +- [BP] Fix robots.txt and sitemap 500 errors if no right content type is provided (#7327) +- [BP] INSPIRE ATOM - retrieve the metadata ATOM feed using only the resource identifier (#7305) +- fix(ods): add CI_OnlineResource linkages for ods v1 +- [BP] Hide thumbnail image in metadata page when the image can't be loaded due to an error. (#7319) +- feat(ods): use ods explore api for CI_OnlineResource linkages +- [BP] Bump actions/checkout from 3 to 4 (#7318) +- [BP] Updated embedded documentation on naming convention for postprocessing files for sub-portals (#7310) +- [BP] Fix permalink option in the application footer +- [BP] Fix the check to display the Transfer ownership option in the metadata detail page +- [BP] Minor cleanup (#7301) +- [BP] Fix metadata editor tooltips close button when using the icon mode +- [BP] Notifications / Errors / Fix message on group creation (#7295) +- [BP] Metadata editor / recommended values for fields show an empty value. (#7232) +- [BP] Standard / ISO / Mimefiletype encoding. +- [BP] WMS tile images - if HEAD request fails, default to OL image src set +- [BP] Search / Aggregation on organisation in Dutch (#7290) +- [BP] Do not break link in the middle of a word. +- [BP] Set html emails as utf-8 +- [BP] ISO19139 / ISO19115-3.2018 / Don't index resource identifiers with empty code +- [BP] Update GeonetHttpRequestFactory to use system proxy defined in JAVA_OPTS +- [BP] Update AbstractHttpRequest to use system proxy defined in JAVA_OPTS +- [BP] fix ui issue (#7256) +- [BP] Use resource files for messages (#7281) +- [BP] API / Attachements / Stream files to servlet response (#7287) +- [BP] Metadata index set of records - index the approved and working copies when the workflow is enabled (#7269) +- [BP] Bump actions/setup-java from 3.10.0 to 3.12.0 (#7239) +- [BP] Metadata editor / display metadata uuid for remote resources if the metadata title is not available +- [BP] Handle empty allGroupOpsAfter instead of throwing error. If we cannot find publishedAfter then default to publishedBefore so that no emails are sent. +- [BP] Full view on working copy fails. Fixes #7270 +- [BP] WMS time dimension - basic support for time intervals (#7280) +- [BP] Fix error that would occur when there were duplicate languages. (#7275) +- [BP] Fix deletion sequence in editor: wait for DOM update before saving +- [BP] Standard / ISO19115-3 / Processing / Metadata contact lost. (#7278) +- [BP] Add XmlTransient annotation to ISODate.getDateAndTimeUtc +- [BP] Fix directive to display the most popular records, to display the most popular first +- [BP] Fix DOI logging +- [BP] Use http proxy in DOI client +- [BP] Fix record history parameter name. Related to #7074 (#7249) +- [BP] Fix German typo of the label for 'otherRestrictions' (#7245) +- [BP] Fix wmsQueue clear method logic +- Update Github actions for 4.2.x branch (#7225) +- [BP] Escape {{ to avoid error parsing argument. (#7237) +- [BP] Update skin.xsl so that it works better in nojs mode. (#7015) +- [BP]When authenticating user, only update the usergroups in the database if they have changed (#7165) +- [BP] Map viewer / 'Default map' javascript error. Fixes #7228 +- [BP] Add support for OL Attributions (#7062) +- Update status emails to contain link to metadata which does not contain anchor. (#7130) +- [BP] Use Apache Commons StringUtils to join keywords in atom service description +- Record view / Contact / Move website to popup (#7220) +- ISO19139 - Improve metadata full view for contacts when fields information is missing (#7214) +- Prettier formatting updates (#7222) +- Record view / Decorate map with geographic identifier or description. (#7221) +- Standard / ISO19139 / Indexing / Temporal range in GML 3.2.0 (#7218) +- ArcSDE harvester / If the metadata stored in ArcSDE is matched against a known metadata schema, harvest the record as it is. +- Increase the limit to retrieve the related metadata in the search results +- Standard / ISO19115-3 / Do not declare main language in other languages (#7188) +- changed english display text for batch editor xpath gn_add and gn_update modes +- Standard / ISO19115-3 / Formatter / Layout improvements (#7187) +- avoid race condition, resize map once target size ok (#6931) +- camel tests, avoid side effects (#6836) +- [gn] Support negative dates for temporal extents (#6843) +- Metadata workflow / Don't increase popularity when viewing a metadata working copy +- Map / WFS Features / Improvements (#7000) +- Standard / ISO19110 / Add cardinality. (#7182) diff --git a/docs/changes/changes4.2.7-0.txt b/docs/changes/changes4.2.7-0.txt new file mode 100644 index 00000000000..2dc3e58b372 --- /dev/null +++ b/docs/changes/changes4.2.7-0.txt @@ -0,0 +1,44 @@ +================================================================================ +=== +=== GeoNetwork 4.2.7: List of changes +=== +================================================================================ +- [BP] i18n / Transifex update. (#7505) +- [BP] Security / Jolokia update. (#7501) +- [BP] Don't override proxy configuration when saving the settings, if the http proxy is configured in Java system properties (#7325) +- [BP] Check http links in documentation (#7496) +- [BP] Add more db information to the site information page. (#7403) +- [BP] Update manual links to use https://docs.geonetwork-opensource.org/ (#7487) +- [BP] Change the structure of the MkDocs assets. Stylesheets and logos are moved to the `overrides` directory (#7429) +- [BP] Fix url link in full view. bracket ") " could be included in link (#7483) +- [BP] Batch edit access level for editor role (#7464) +- [BP] Fixed broken links and formatting in BUILDING.md (#7471) +- [BP] Editor / Remove extra space on mandatory add action (#7438) +- [BP] change label to "Access to the catalogue" (#7467) +- [BP] Remove exception class name from the error message (#6977) +- [BP] List styling for related records (#7442) +- [BP] Fix cookies path when deployed on root "/" context (#7446) +- [BP] Standard / Feature catalogues / Do not index empty codelist value (#7440) +- Update the links to documentation in the sofware development pages (4.2.x) (#7409) +- [BP] Fixed typos, formatting and numbering (#7430) +- [BP]Fix issue with canViewRecord when calling related api (#7373) +- [BP] Transifex updates (#7432) +- [BP] Fix exception handling from schematron validation so that it flags the metadata as invalid if there is an exception (#6978) +- [BP] Rename ElasticSearch to Elasticsearch (#7404) +- [BP] Sort the portals by label, not by name (identifier) (#7424) +- [BP] Metadata editor / ISO19115-3.2008 / Filter out metadata templates in the online resources dialog +- [BP] Fix system info when ES throw errors (#7413) +- [BP] Remove old password field for admins (#7417) +- [backport 4.2.x] Add documentation to GitHub workflows (#7415) +- [BP] Change the url the icon in the homepage is linking to (#7422) +- [BP] Fixed typos and updated SearchManager to EsSearchManager in core readme (#7418) +- [BP] Update the CONTRIBUTING guide to detail the steps, before merging the pull requests (#7419) +- [BP] Transifex updates +- [BP] Record view / fix double approved parameter in the metadata working copy page, for the buttons in the online resources panel. Related to #7248 (#7402) +- [BP] Doc / Fix list (#7401) +- [BP] Fixed typos in code_quality readme (#7407) +- Remove changelog for latest +- Use default mike settings to fix interaction between language chooser and versions +- Correct canical_version to stable +- Add 3.12.11 changelog and fix the display of the changelogs in the navigation bar (#7397) +- Doc / 4.4.0 / Add note about datastore changes (#7398) diff --git a/docs/changes/changes4.2.8-0.txt b/docs/changes/changes4.2.8-0.txt new file mode 100644 index 00000000000..4775ab02b1e --- /dev/null +++ b/docs/changes/changes4.2.8-0.txt @@ -0,0 +1,84 @@ +================================================================================ +=== +=== GeoNetwork 4.2.8: List of changes +=== +================================================================================ +- [BP] Transifex updates. (#7651) +- [BP] Upgrade guidance for geonetwork 3 users (#7644) +- Remove unused Jeeves classes (#7643) +- Miscellaneous code cleanup with MetadataStatus and RelatedResponse Fix some incorrect comments Remove class prefix as it was not required. Added missing license. +- Move Direction as an reference object in the open api specification. +- Bump actions/cache from 3 to 4 +- [BP] build release procedure updates to include docs in release tag (#7412) +- [BP] unpack schema sample data into folders, produce mef files at build time (#7457) +- document `backport 4.2.x` label change required for bot +- Fix the grid on the homepage of the documentation (#7559) +- [BP] Fix error on edit page elements with non-unique id #gnRemoteRecordUrl (#7621) +- [BP] Record view / Display WFS downloads for WFS online resources without a name defined (#7626) +- Do not clean api docs out of src/main/webapp +- build fix: do not remove api docs during clean:clean@reset +- build: fix jetty-download activiation required for release +- [BP] Bump actions/setup-java from 3.12.0 to 4.0.0 (#7522) +- [BP] Build / Use Java 21 for Sonarcloud plugin (#7622) +- [BP] Build / release module build workflow improvements / fixes (#7619) +- [BP] Remove default response from open api specification. (#7609) +- [BP] Cleanup consumes from metadata insert api. (#7616) +- [BP] Add missing @ApiResponse status for successful api search response. (#7594) +- [BP] Fix SpringDoc duplicate OperationId (#7580) +- [BP] CSW GetRecords doesn't escape query values when creating the Elasticsearch query (#7529) +- [BP] Add missing import from commit 63cd59fb38df389694566d69459bcfbedb7ca89e (Service context null pointer (#7593)) +- [BP] Changed http to https for urls that appear in open api specification. (#7601) +- [BP] Fix duplicate API endpoint /feeds (#7581) +- [BP] Service context null pointer (#7593) +- [BP] Fix linux specific file separator used for harvester transform option list +- [BP] Fix issue with @ResponseStatus and @ApiResponse being out of sync. (#7588) +- [BP] Spring doc - Set API enum as ref (#7595) +- [BP] Add missing swagger icons that were referenced in the index.html file. Icons taken from https://github.com/swagger-api/swagger-ui/tree/master/dist +- Fix duplicate operation id caused by use of 2 methods GET/POST method from getKeywordById api (#7586) +- [BP] Fix add element attribute in the metadata editor, causing the element section is removed from the user interface until the metadata is saved +- [BP] Record view / Invalid timezone shift for years outside moment's 10 years range. +- [BP] Home page / sort topic categories and INSPIRE themes facets alphabetically (#7569) +- [BP] Metadata extents API / Make configurable to display the metadata bboxes using geodesic extents for local projections. (#7560) +- [BP] Spring doc API for link api should accept a structured object instead of JSONObject (#7585) +- [BP] Update SpringDoc json/yaml generator to make the results more deterministic. (#7574) +- [BP] Add missing apiResponse for group and map api (#7590) +- GeoNetwork 4.2.x minor versions library updates (#7405) +- [BP] API should return a structured object instead of JSONObject (#7584) +- [BP] Fix initialization of SpringDoc so that it does not use null servername and null version (#7575) +- [BP] Fix duplicate spring doc tags. Ensure that all tags have the same description. +- [BP] Fix case of wrong use for HttpStatus.CREATED and HttpStatus.OK In some cases HttpStatus.CREATED was used when it should have been HttpStatus.OK and other cases it is the opposite. +- [BP] Overview not shown in PDF export when the overview image is stored in GeoNetwork and requires authentication to access it. Fixes #7540 (#7556) +- [BP] fix for empty language leading to spurious comma +- [BP] Display metadata user and group owner in the transfer ownership dialog +- [BP] Add German codelist translations for scope code (#7566) +- [BP] Remove ?debug from link to admin dashboard. (#7564) +- [BP] Visual fix for icon text circles (firefox) +- [BP] cryptic parse exception +- [BP] Update iso19139 csw-full.xsl (#7558) +- [BP] Documentation / Update Elasticsearch installation page typos and remove the old elastic search documentation. Fixes #7551 (#7555) +- [BP] Metadata indexing - create an organisation name field that tracks the organisations of the different types of contacts +- [BP] Elasticsearch index creation - log the exception when a parsing error of the index configuration file occurs +- [BP] Add ownerId to geonet:info (#7547) +- [BP] Don't display header menu and footer in single metadata PDF export (#7532) +- [BP] Use Apache Commons Text library to escape JSON content in xslt processing (#7525) +- Edited small typos and text. Some link fixes. +- [BP] OpenId / Use the user profile configured locally if the configuration option OPENIDCONNECT_USERPROFILEUPDATEENABLED is disabled (#7445) +- [BP] Bump actions/setup-python from 4 to 5 (#7543) +- [BP] INSPIRE Validator - exception handling improvements (#7519) +- [BP] Fix check to verify if a group has enabled the workflow, checking if the workflow is also enabled (#7535) +- [BP] Reset user password dialog - don't display the field to request the old password for administrators - unify UI check with backend check (#7510) +- [BP] consistent styling of recordgroup label +- [BP] Metadata workflow / Record view / reload the page with the approved version when cancelling a working copy (#7503) +- [BP] Search / Add option to show less facet values (#7497) +- [BP] Metadata indexing / Escape website and logo information for contacts +- [BP] Validation of INSPIRE ATOM services to return API exceptions instead of error 400 (#7490) +- [BP] INSPIRE Atom Search - add missing filter by feed dataset identifiers (#7492) +- [BP] Remote INSPIRE Atom Feeds harvester - Remove duplicates by dataset identifier (#7491) +- [BP] Fix language for region picker directives (#7495) +- [BP] When getting locale message, default locale to LocaleContextHolder when locale is null (#7516) +- [BP] Fix some cases that were not considering both message and description when displaying errors. (#7517) +- [BP] Elasticsearch / Update to 7.17.15 (#7368) +- [BP] Fix indexing of iso19110 metadata with cardinalities composed of multiple ranges (#7486) +- [BP] Harvesting / WFS / Cleaning comment (#7504) +- [BP] CSW Harvester / Don't set a default search filter field (#7494) +- [BP] Docs / Fix the mike version to 2.0.0 and change the parameter --no-redirect to --alias-type=copy (changed in mike 2.0.0) (#7507) diff --git a/docs/changes/changes4.2.9-0.txt b/docs/changes/changes4.2.9-0.txt new file mode 100644 index 00000000000..28b376d7ba9 --- /dev/null +++ b/docs/changes/changes4.2.9-0.txt @@ -0,0 +1,70 @@ +================================================================================ +=== +=== GeoNetwork 4.2.9: List of changes +=== +================================================================================ +- Fix startup error. Follow up #7456 (#7859) +- Documentation / GeoNetwork 4.2 doing a release fixes (#7647) +- [Backport 4.2.x] Extend proxy to manage duplicated parameters (#7854) +- [Backport 4.2.x] Configuration to restrict the hosts and ports accessible by the http proxy servlet (#7326) +- [Backport 4.2.x] GeoNetwork harvester / Check if a resource exists to save it, instead of trying to retrieve the file details, to avoid confusing NoSuchFileException exception (#7845) +- Standards / Formatter / Citation / Pick latest date (#7835) +- [Backport 4.2.x] INSPIRE / Add testsuite for IACS (#7834) +- [Backport 4.2.x] Harvester / Localfilesystem / Log properly to harvester log file. (#7833) +- [Backport 4.2.x] Record view / ISO19139 / ISO19115-3.2008 display the unit part in @uom attribute, not the full url (#7832) +- Harvesters / Reset harvester history pagination when selecting a harvester (#7831) +- Trigger metadata unpublish event when removing the privileges to the ALL group in the privileges dialog (#7828) +- Doc / Editor configuration improvements (#7827) +- Update lodash to version 4.17.21 (#7825) +- [Backport 4.2.x] Bump actions/setup-java from 4.0.0 to 4.1.0 (#7814) +- Record view / Don't add the associated resources in the metadata static page, this page doesn't include JS libs (#7797) +- [Backport 4.2.x] Decouple metadata user feedback from metadata rating feature (#7796) +- [Backport 4.2.x] Fix wrong manual links (#7793) +- [Backport 4.2.x] Additional ISO19139 German translations (#7788) +- [Backport 4.2.x] Replace the 'unlock' icon with the 'lock open' icon (#7787) +- [Backport 4.2.x] Removed @RequestHeader for "Accept" headers as it is not supported by openAPI specification (#7785) +- Fix missing MetadataStatusResponse and MetadataWorkflowStatusResponse in open api spec (#7783) +- Fix SpringDoc duplicate Schema name (#7781) +- [Backport 4.2.x] Fix duplicate GET operation on /{portal}/api/sources and missing /subportal endpoint (#7780) +- Spit getRecordAs @RequestMapping into getRecordAsJson and getRecordAsXML in order to fix duplicate operation Id - By having multiple @RequestMapping was causing to create operation id as getRecordAs and getRecordAs_1 +- [Backport 4.2.x] Fix alignment of user enabled checkbox (#7773) +- [Backport 4.2.x] Fix ISO19139 German labels (#7763) +- Remove handlebars.js v2.0.0 +- Reports / Fix extract user groups for non-admin users (#7746) +- Addressing docs glitch #7666 creating-group and authentication-mode +- Addressing docs glitch #7666 in installing-from-war-file, version-4.0.2 and tutorials/deployment/index +- addressing docs-glitch in install-guide/configuring-database +- addressing docs-glitch in search-ui/enrichview and search-ui/loadview +- addressing docs-glitch in install-guide/map-print-setup +- addressing docs-glitch in publishing/managing-privileges +- corrected minor typo in install-guide/map-print-setup +- Fix conversion errors after switching to MkDocs +- manual review of mkdocs glitches +- [Backport 4.2.x] Create a metadata / Add dynamic and download privileges to the users in the same group (#7744) +- Index / Add danish language. (#7736) +- [Backport 4.2.x] Documentation / Elasticsearch query endpoint - query samples (#7732) +- [Backport 4.2.x] Separate docs for _search and _msearch (#7731) +- Map viewer / Remove Stamen background layers - no longer available (#7730) +- Use the generated metadata UUID for resource links when importing metadata with the option 'Generate UUID' (#7729) +- Remove unused jslint-maven-plugin (#7727) +- [Backport 4.2.x] Bump org.json:json from 20140107 to 20240205 (#7724) +- [Backport 4.2.x] Github Actions / Bump stCarolas/setup-maven from 4 to 5 (#7720) +- Enable preemptive for csw requests with credentials (#5497) (#7716) +- [Backport 4.2.x] Add a role and feature matrix to the GeoNetwork documentation (#7709) +- Addressing docs translation glitch #7687- fixes creating-custom-editor +- Addressing docs translation glitch #7687- fixes adding-static-pages and configuring-search-fields +- [Backport 4.2.x] Bump commons-fileupload from 1.3.3 to 1.5 (#7699) +- [Backport 4.2.x] Remove empty class SourcesLib and deprecated/unused methods in ResourceLib / Sonarlint improvements (#7694) +- Update Springdoc so that it supports Map objects in the request parameters. By default injectable parameters are excluded from request parameters. Map is one of those object however it does occur where map objects are supplied as parameters and they should be added to open api spec. There are currently no cases where a map is injected on purpose into the request parameters. This will fix issues with missing request parameters documentation which are based on Map objects. +- Fix spring doc for attachment and keyword to better identify files resources being returned. Update attachment api "Get a metadata resource" should indicate that gets a file resource Also "Create a new resource" should identify that it consumes any resources Update keywords api "Download a thesaurus by name" should indicate that gets a file resource +- Fix springdoc so that enums names are used instead of toString This fixes bug where some apis will not execute correctly from the swagger pager due to the wrong enum value being supplied. i.e. visibility should be using enum values PUBLIC/PRIVATE instead of public/private in formatters/zip api, the format should be SIMPLE/PARTIAL/FULL instead of simple/partial/full +- Editor / Fix add element attribute (#7685) +- [Backport 4.2.x] Metadata editor / Fix javascript error in the add thumbnail option when the metadata has 1 WMS layer (#7684) +- [BP] Search results / Configure related records type depending on template. (#7376) +- Metadata editor / Fix javascript error when editing a metadata, due to undefined property in gnLinkToMetadata directive (#7682) +- Fix pdf link issue (#7681) +- Fix mimetypes on attachments as some were incorrect. (#7675) +- accidental localhost link in docs +- Docs / Update copyright year +- Bump github/codeql-action from 2 to 3 (#7662) +- Bump advanced-security/maven-dependency-submission-action from 3 to 4 (#7661) diff --git a/docs/changes/changes4.4.0-0.txt b/docs/changes/changes4.4.0-0.txt new file mode 100644 index 00000000000..cf38bb0f885 --- /dev/null +++ b/docs/changes/changes4.4.0-0.txt @@ -0,0 +1,182 @@ +================================================================================ +=== +=== GeoNetwork 4.4.0: List of changes +=== +================================================================================ +- Doc / Changelog / 4.2.6 and 4.4.0 (#7392) +- Changed GENERATEUUID to NOTHING based on discussion on issue #7274 +- Make samples generate new uuid so that they don't overwrite any existing data. Fix for #7274 +- Jetty bundle / Add JAVA_OPTS configuration for the /monitor/metrics endpoint to work correctly (#7385) +- Documentation 4.4: Update Java references to Java 11, update link to the manual and release scripts (#7378) +- Fixed typos for SOURCE.md (#7384) +- Update Java version and include the information in the readme.html in the release bundle (#7383) +- Update MkDocs configuration to publish to gh-pages branch (#7375) +- Workflow / Related records of the draft (#7377) +- Create CNAME +- User Manual refresh using Markdown and MkDocs (#7329) +- batch edit user profile check in APIs (#7243) +- Record view / Support multiple status. +- Groups maintenance / fix the display of the metadata owned by a group (#7371) +- Map viewer / Option to configure WMS tiling (#7312) +- Fix working copy display so that links go to working copy (#7248) +- Move datastorage providers to maven modules and include them in the build on demand (#7302) +- Send metadata mail notifications for public metadata when is re-approved - fill missing information for submitter, reviewer and publisher user (#7292) +- Map viewer / context map / only WMS layers have dimensions information +- Formatter / Remove unused Groovy mode. (#7346) +- fix for untranslated userRecord and userRecords labels in user admin page (#7354) +- Standard / ISO19110 improvements +- Add support for emails with subdomains (#7314) +- Improved handling of empty titles (#7362) +- Merge pull request #7337 from geonetwork/ha +- Indexing / Bounding Polygon / Coordinate order (#7364) +- Indexing / Bounding Polygon / Reproject if needed #7340 +- Editor / Online source / Fix button icon +- Fix CORSInterceptor, usage of a variable before is defined. Related to #5941 (#7361) +- Add a new DOI icon (#7357) +- Display the login menu for authenticated users when the setting 'gnCfg.mods.authentication.enabled' is disabled +- Map / WMS dimension saved in map (#7339) +- Add icons for related types (association and initiative) (#7264) +- Update harvesters/src/main/java/org/fao/geonet/kernel/harvest/RefreshHarvesterJob.java +- Java doc. Check also GeoNetworkDataDirectory for description of folders. +- WFS layer improvements (#7317) +- Map / WPS / Add support for custom parameter CRS +- Don't override proxy configuration when saving the settings, if the http proxy is configured in Java system properties (#7325) +- Create metadata category - check doesn't exist a category with the same name (#7296) +- Editor / Preserve scroll position on Firefox +- Portal / RSS feeds point to current portal (#7343) +- Fix HTML/Javascript prettier formatting / main branch +- Prevent invalid date written into xml (#7321) +- Record view / Add configuration to support statistics on more than 100 (#7348) +- Update xalan dependency (remove potential vuln) (#7140) +- Fix write after response commit on proxy response (#7353) +- Standard / ISO / Labels improvements (#7341) +- RSS / Fix number of records parameter +- Display metadata user and group owner in the transfer ownership dialog +- Adding schemapublication_dir to admin info panel +- DOI / ISO19115-3 / Support DOI set in resource identifier or distribution (#7288) +- Map / Localisation / Empty results if no query (#7338) +- Record view / Social network link points to permalink. (#7347) +- Metadata editor / link to remote dataset improvements (#7324) +- Indexing / Do not create empty object if no text (#7349) +- Batch Editing access level in general system settings (#7238) +- Indexing / Do not create empty object if no text (#7294) +- User feedback API fixes: - Update mail message, related to #6792. - Don't fail the user feedback creation if the mail server is not configured +- Jetty / Update version and fix sending mail +- Jetty / Form config consistent with default docker one +- Test / Remove duplicated prop. +- Test / Add new properties. +- HA / Introducing scheduled refresh of harvesterjobs. +- HA / Added hostname to the system information panel. +- Remove configuration for the UI setting 'isMenubarAccessible', removed in #7138 +- Batch editing / Update xpath spec link +- Library / Update to wro4j 1.10.1 (#7315) +- Fix robots.txt and sitemap 500 errors if no right content type is provided (#7327) +- API / Sitemap / Improve speed +- Merge remote-tracking branch 'origin/main' into ha +- INSPIRE ATOM - retrieve the metadata ATOM feed using only the resource identifier (#7305) +- Hide thumbnail image in metadata page when the image can't be loaded due to an error. (#7319) +- Merge pull request #7253 from tkohr/core-main-ods-api +- Bump actions/checkout from 3 to 4 (#7318) +- Updated embedded documentation on naming convention for postprocessing files for sub-portals (#7310) +- Fix permalink option in the application footer +- Fix the check to display the Transfer ownership option in the metadata detail page +- Merge branch '440-harvesterscheduleconfig' into ha +- Merge branch '424-multipleinstances' into ha +- Minor cleanup (#7301) +- Record view / Lineage & Quality section improvements (#7180) +- Editor / Top bar / Avoid hiding editor tabs with tool bar actions. (#7073) +- Fix metadata editor tooltips close button when using the icon mode +- Extend ElasticSearch proxy to filter out elements defined in the schema filters configurations (#6869) +- Notifications / Errors / Fix message on group creation (#7295) +- Metadata editor / recommended values for fields show an empty value. (#7232) +- Standard / ISO / Mimefiletype encoding. +- WMS tile images - if HEAD request fails, default to OL image src set +- Search / Aggregation on organisation in Dutch (#7290) +- Do not break link in the middle of a word. +- API / CSV export / Add support for custom export. (#7132) +- Extend keyword picker directive to support displaying all the suggested values when there is a selected value. +- Set html emails as utf-8 +- ISO19139 / ISO19115-3.2018 / Don't index resource identifiers with empty code +- Metadata tooltips - improve the check method to try to find a match a standard default with no context defined, if there is no entry with the element context +- Update GeonetHttpRequestFactory to use system proxy defined in JAVA_OPTS +- Update AbstractHttpRequest to use system proxy defined in JAVA_OPTS +- INSPIRE / Validation / Add API usage. +- fix ui issue (#7256) +- Use resource files for messages (#7281) +- API / Attachements / Stream files to servlet response (#7287) +- Metadata index set of records - index the approved and working copies when the workflow is enabled (#7269) +- Bump actions/setup-java from 3.10.0 to 3.12.0 (#7239) +- Metadata editor / display metadata uuid for remote resources if the metadata title is not available +- Handle empty allGroupOpsAfter instead of throwing error. If we cannot find publishedAfter then default to publishedBefore so that no emails are sent. +- Full view on working copy fails. Fixes #7270 +- WMS time dimension - basic support for time intervals (#7280) +- Fix error that would occur when there were duplicate languages. (#7275) +- Standard / ISO19115-3 / Processing / Metadata contact lost. (#7278) +- Merge pull request #7186 from geonetwork/lib-spring5java11 +- Add XmlTransient annotation to ISODate.getDateAndTimeUtc +- Make editor snippets referenceable and reusable +- Fix directive to display the most popular records, to display the most popular first +- Allow mulitple conditional default tabs in a single editor view +- Fix deletion sequence in editor: wait for DOM update before saving +- Fix DOI logging +- Use http proxy in DOI client +- feat(ods): use ods explore api for CI_OnlineResource linkages +- Fix record history parameter name. Related to #7074 (#7249) +- Fix German typo of the label for 'otherRestrictions' (#7245) +- fix(ods): add CI_OnlineResource linkages for ods v1 +- Escape {{ to avoid error parsing argument. (#7237) +- Update skin.xsl so that it works better in nojs mode. (#7015) +- Fix wmsQueue clear method logic +- When authenticating user, only update the usergroups in the database if they have changed (#7165) +- Map viewer / 'Default map' javascript error. Fixes #7228 +- Add support for OL Attributions (#7062) +- Update MetadataExtentApiTest hashes, probably images differ due to JVM change to version 11 +- Update status emails to contain link to metadata which does not contain anchor. (#7130) +- Update GitHub actions configuration +- Update GitHub actions configuration +- Remove Java 8 maven configuration +- Update services/src/main/java/org/fao/geonet/api/OpenApiController.java +- Update harvesters/src/main/java/org/fao/geonet/kernel/harvest/harvester/geoPREST/Harvester.java +- Update harvesters/src/main/java/org/fao/geonet/kernel/harvest/harvester/geoPREST/Harvester.java +- Update harvesters/src/main/java/org/fao/geonet/kernel/harvest/harvester/geoPREST/Harvester.java +- Update harvesters/src/main/java/org/fao/geonet/kernel/harvest/harvester/geoPREST/Harvester.java +- Update GitHub actions configuration +- Merge branch 'main' into lib-spring5java11 +- Use Apache Commons StringUtils to join keywords in atom service description +- Update to version 4.4.x (#7223) +- Record view / Contact / Move website to popup (#7220) +- ISO19139 - Improve metadata full view for contacts when fields information is missing (#7214) +- Prettier formatting updates (#7222) +- Record view / Decorate map with geographic identifier or description. (#7221) +- Prettier. +- Standard / ISO19139 / Indexing / Temporal range in GML 3.2.0 (#7218) +- ArcSDE harvester / If the metadata stored in ArcSDE is matched against a known metadata schema, harvest the record as it is. +- Increase the limit to retrieve the related metadata in the search results +- System info / Add env variables related to database migration and harvester scheduler. Add some more precise doc links. +- Java header. +- Proposal to disable harvesters. +- Bad configuration of a harvester could prevent geonetwork startup +- Missing translations. +- Translations / Add better message in case of harvester save issue. +- Standard / ISO19115-3 / Do not declare main language in other languages (#7188) +- changed english display text for batch editor xpath gn_add and gn_update modes +- Standard / ISO19115-3 / Formatter / Layout improvements (#7187) +- avoid race condition, resize map once target size ok (#6931) +- camel tests, avoid side effects (#6836) +- [gn] Support negative dates for temporal extents (#6843) +- Metadata workflow / Don't increase popularity when viewing a metadata working copy +- Map / WFS Features / Improvements (#7000) +- Standard / ISO19110 / Add cardinality. (#7182) +- Update version to 4.2.6-SNAPSHOT +- Test / Fix related to XSD publication dir. +- Lib / update snakeyaml to version 2.0 +- Remove toolchain for Java 8 and update maven compiler configuration for integration tests to use Java 11 +- Lib / Update / Spring 5, Hibernate 5, Jetty 9. +- harvesters - disabling tests +- harvester - attempt to fix date parsing tests with Jdk11 +- commons - jdk11 - better fix for test +- jdk11 - fixing tests +- being able to use a more recent jdk (11) +- API / Site info / Add all data directory info +- Data directory / Add parameter for XML schemas. +- WRO4J / Move cache to HTML cache folder. \ No newline at end of file diff --git a/docs/changes/changes4.4.1-0.txt b/docs/changes/changes4.4.1-0.txt new file mode 100644 index 00000000000..c82d73a4136 --- /dev/null +++ b/docs/changes/changes4.4.1-0.txt @@ -0,0 +1,65 @@ +================================================================================ +=== +=== GeoNetwork 4.4.1: List of changes +=== +================================================================================ +- Changelog / 441 and 427. (#7508) +- i18n / Transifex update. (#7505) +- Security / Jolokia update. (#7501) +- Add web/src/main/webapp/WEB-INF/data/data/resources/schemapublication folder to .gitignore +- Check http links in documentation (#7496) +- Add more db information to the site information page. (#7403) +- Update manual links to use https://docs.geonetwork-opensource.org/ (#7487) +- Change the structure of the MkDocs assets. Stylesheets and logos are moved to the `overrides` directory (#7429) +- Fix url link in full view. bracket ") " could be included in link (#7483) +- Batch edit access level for editor role (#7464) +- Fixed broken links and formatting in BUILDING.md (#7471) +- Editor / Remove extra space on mandatory add action (#7438) +- WRO4J / Fix unresolvable source map file on Windows (#7476) +- Add node identifier parameter for xlst processing. Required in skin.xsl (#7454) +- change label to "Access to the catalogue" (#7467) +- API / Batch editing / XPath / Add support for attribute with namespace. +- Remove exception class name from the error message (#6977) +- Release / Create SQL migration script for new version (#7395) +- Standard / Formatter / Citation improvements (#7434) +- Update to GeoTools 30.0 Release (#7416) +- Record view / Series / Technical information +- List styling for related records (#7442) +- Standard / Processes / Collection merge (#7436) +- Indexing / Add related record title to the full text search (#7437) +- Update docker.md +- Fix cookies path when deployed on root "/" context (#7446) +- Search results / Fix button size +- Standard / Feature catalogues / Do not index empty codelist value (#7440) +- Remove the `Download metadata` button in the metadata block on the Metadata page. +- Fixed typos, formatting and numbering (#7430) +- Fix issue with canViewRecord when calling related api (#7373) +- Transifex updates (#7432) +- Fix exception handling from schematron validation so that it flags the metadata as invalid if there is an exception (#6978) +- Rename ElasticSearch to Elasticsearch (#7404) +- Sort the portals by label, not by name (identifier) (#7424) +- Metadata editor / ISO19115-3.2008 / Filter out metadata templates in the online resources dialog +- Fix system info when ES throw errors (#7413) +- Remove old password field for admins (#7417) +- Add documentation to GitHub workflows (#7411) +- GeoNetwork 4.4.x minor versions library updates +- Change the url the icon in the homepage is linking to (#7422) +- Fixed typos and updated SearchManager to EsSearchManager in core readme (#7418) +- Update the links to documentation in the sofware development pages (#7408) +- Update the CONTRIBUTING guide to detail the steps, before merging the pull requests (#7419) +- Transifex updates +- [feat] allow to open COG links in external viewer (#7387) +- please prettier-java +- Add 3DTILES support to gn_relatedresources_service module +- add badge support for 3dtiles +- add OGC:3DTILES to gnSearchSettings.mapProtocols.layers +- support OGC:3DTILES protocol, set type to 3dtiles in buildAddToMapConfig +- add OGC:3DTILES to possible values for gmd:protocol +- Record view / fix double approved parameter in the metadata working copy page, for the buttons in the online resources panel. Related to #7248 (#7402) +- Doc / Fix list (#7401) +- Fixed typos in code_quality readme (#7407) +- Use default mike settings to fix interaction between language chooser and versions +- Correct canical_version to stable +- Add 3.12.11 changelog and fix the display of the changelogs in the navigation bar (#7397) +- Doc / 4.4.0 / Add note about datastore changes (#7398) +- Update version to 4.4.1-SNAPSHOT \ No newline at end of file diff --git a/docs/changes/changes4.4.2-0.txt b/docs/changes/changes4.4.2-0.txt new file mode 100644 index 00000000000..737215d8ac0 --- /dev/null +++ b/docs/changes/changes4.4.2-0.txt @@ -0,0 +1,120 @@ +================================================================================ +=== +=== GeoNetwork 4.4.2: List of changes +=== +================================================================================ +- Transifex updates. (#7651) +- Upgrade guidance for geonetwork 3 users (#7644) +- Documentation / Unify version numbers in doing a release page +- Remove unused Jeeves classes (#7612) +- Miscellaneous code cleanup with MetadataStatus and RelatedResponse Fix some incorrect comments Remove class prefix as it was not required. Added missing license. +- Move Direction as an reference object in the open api specification. +- Remove problematic migration to add a column +- Update GITHUB.md +- Bump actions/cache from 3 to 4 +- build release procedure updates to include docs in release tag (#7412) +- unpack schema sample data into folders, produce mef files at build time (#7457) +- Update CONTRIBUTING.md +- document `backport 4.2.x` label change required for bot +- Fix the grid on the homepage of the documentation (#7559) +- backport bot to respond to PR tags +- Fix error on edit page elements with non-unique id #gnRemoteRecordUrl (#7621) +- Record view / Display WFS downloads for WFS online resources without a name defined (#7626) +- Do not clean api docs out of src/main/webapp +- build fix: do not remove api docs during clean:clean@reset +- Bump actions/setup-java from 3.12.0 to 4.0.0 (#7522) +- Use Java 21 for Sonarcloud plugin (#7622) +- Build / release module build workflow improvements / fixes (#7619) +- Remove default response from open api specification. (#7609) +- Cleanup consumes from metadata insert api. (#7616) +- Add missing @ApiResponse status for successful api search response. (#7594) +- Fix SpringDoc duplicate OperationId (#7580) +- CSW GetRecords doesn't escape query values when creating the Elasticsearch query (#7529) +- Add missing import from commit 63cd59fb38df389694566d69459bcfbedb7ca89e (Service context null pointer (#7593)) +- Changed http to https for urls that appear in open api specification. (#7601) +- Fix duplicate API endpoint /feeds (#7581) +- Service context null pointer (#7593) +- Update files with Prettier formatting +- Preventing indexing error by limiting selection amount +- Fix linux specific file separator used for harvester transform option list +- Fix issue with @ResponseStatus and @ApiResponse being out of sync. (#7588) +- Spring doc - Set API enum as ref (#7595) +- Add missing swagger icons that were referenced in the index.html file. (#7597) +- using icon for call/phone +- feat: avoid race condition, resize map once target size ok (#7545) +- Configuration to restrict the hosts and ports accessible by the http proxy servlet (#7326) +- Search results / Configure related records type depending on template. (#7376) +- Fix duplicate operation id caused by use of 2 methods GET/POST method from getKeywordById api (#7586) +- Build info improvements. (#7400) +- Harvesting / WFS feature / Add WFS2 support for MapServer +- Github / PR template / Add funded by (#7554) +- INSPIRE Atom feeds / Fix link to atom search endpoint +- Fix add element attribute in the metadata editor, causing the element section is removed from the user interface until the metadata is saved +- fix duplicate check on uuid+initiative+association (#7567) +- Record view / Invalid timezone shift for years outside moment's 10 years range. +- Home page / sort topic categories and INSPIRE themes facets alphabetically (#7569) +- Metadata extents API / Make configurable to display the metadata bboxes using geodesic extents for local projections. (#7560) +- Spring doc API for link api should accept a structured object instead of JSONObject (#7585) +- Update SpringDoc json/yaml generator to make the results more deterministic. (#7574) +- Add missing apiResponse for group and map api (#7590) +- API should return a structured object instead of JSONObject (#7584) +- Fix initialization of SpringDoc so that it does not use null servername and null version (#7575) +- Fix duplicate spring doc tags. Ensure that all tags have the same description. +- Fix case of wrong use for HttpStatus.CREATED and HttpStatus.OK In some cases HttpStatus.CREATED was used when it should have been HttpStatus.OK and other cases it is the opposite. +- Overview not shown in PDF export when the overview image is stored in GeoNetwork and requires authentication to access it. Fixes #7540 (#7556) +- fix for empty language leading to spurious comma +- Add German codelist translations for scope code (#7566) +- Fix PULL_REQUEST_TEMPLATE.md link to contribution guidelines +- Remove ?debug from link to admin dashboard. (#7564) +- Update iso19139 csw-full.xsl (#7558) +- add icon to static pages, configurable +- cryptic parse exception +- Visual fix for icon text circles (firefox) +- Update authors.md +- Update authors.md +- Documentation / Update Elasticsearch installation page typos and remove the old elastic search documentation. Fixes #7551 (#7555) +- Restructure the 'composed of' block on the detail page (#7480) +- Metadata indexing - create an organisation name field that tracks the organisations of the different types of contacts +- Elasticsearch index creation - log the exception when a parsing error of the index configuration file occurs +- Add ownerId to geonet:info (#7547) +- Update PROCESS_FOR_DEPRECATION.md +- Create PROCESS_FOR_DEPRECATION.md +- Update CONTRIBUTING.md +- Don't display header menu and footer in single metadata PDF export (#7532) +- Edited small typos and text. Some link fixes. +- Use Apache Commons Text library to escape JSON content in xslt processing (#7525) +- Edited small typos and text. Some link fixes. +- OpenId / Use the user profile configured locally if the configuration option OPENIDCONNECT_USERPROFILEUPDATEENABLED is disabled (#7445) +- Bump actions/setup-python from 4 to 5 +- INSPIRE Validator - exception handling improvements (#7519) +- Automatic HTML formatting +- Fix check to verify if a group has enabled the workflow, checking if the workflow is also enabled (#7535) +- Admin console / Improve form checks for group, category and source (#7449) +- Administration form validation improvements (#7533) +- Reset user password dialog - don't display the field to request the old password for administrators - unify UI check with backend check (#7510) +- New property to define an alternate logo for pdf export (#7481) +- Metadata workflow / Record view / reload the page with the approved version when cancelling a working copy (#7503) +- consistent styling of recordgroup label +- Metadata indexing / Escape website and logo information for contacts +- Search / Add option to show less facet values (#7497) +- GeoNetwork 4.4.x minor versions library updates: +- Update CONTRIBUTING.md +- Update README.md +- Validation of INSPIRE ATOM services to return API exceptions instead of error 400 (#7490) +- INSPIRE Atom Search - add missing filter by feed dataset identifiers (#7492) +- Remote INSPIRE Atom Feeds harvester - Remove duplicates by dataset identifier (#7491) +- Fix language for region picker directives (#7495) +- When getting locale message, default locale to LocaleContextHolder when locale is null (#7516) +- Fix some cases that were not considering both message and description when displaying errors. (#7517) +- Elasticsearch / Update to 7.17.15 (#7368) +- Record view / DQ / Add measure date information +- Ensure only dataset are returned when linking dataset to service +- Record view / Add distributor contact. (#7473) +- Record view / Topic category / Translations +- Record view / Improve language list. +- Fix indexing of iso19110 metadata with cardinalities composed of multiple ranges (#7486) +- Harvesting / WFS / Cleaning comment (#7504) +- CSW Harvester / Don't set a default search filter field (#7494) +- Docs / Fix mike parameter with extra dash. Follow up of #7507 +- Docs / Fix the mike version to 2.0.0 and change the parameter --no-redirect to --alias-type=copy (changed in mike 2.0.0) (#7507) +- Update version 4.4.2-SNAPSHOT \ No newline at end of file diff --git a/docs/changes/changes4.4.3-0.txt b/docs/changes/changes4.4.3-0.txt new file mode 100644 index 00000000000..ce5661888d1 --- /dev/null +++ b/docs/changes/changes4.4.3-0.txt @@ -0,0 +1,117 @@ +================================================================================ +=== +=== GeoNetwork 4.4.3: List of changes +=== +================================================================================ +- Update linux workflow to maven 3.8.3 +- require maven 3.8.3 minimum for MNG-7214 fix +- Move version 3.12.x changelog to archive +- Release notes for GeoNetwork 4.4.3. +- Release notes for GeoNetwork 4.29 / 3.12.12 versions +- add necessary welsh language files for translating the application (#7851) +- Standard / ISO19115-3 / Batch edit may trigger error on creation date (#7712) +- Fix startup error. Follow up #7456 (#7858) +- i18n / Transifex update. (#7855) +- ISO19139 / Index online resources application profile element encoded as anchor (#7798) +- Extend proxy to manage duplicated parameters (#7456) +- Documentation / GeoNetwork 4.4 doing a release fixes (#7648) +- Indexing / ISO / Properly index all keywords even if in different thesaurus block +- Editor / Distribution / Properly refresh list link on last one (#7844) +- GeoNetwork harvester / Check if a resource exists to save it, instead of trying to retrieve the file details, to avoid confusing NoSuchFileException exception (#7577) +- Update README.md +- Update README.md +- Bump actions/upload-artifact from 3.1.0 to 4.3.1 +- Bump ossf/scorecard-action from 2.1.2 to 2.3.1 +- Harvesting / WFS Features / Do not skip attributes even if geom is invalid. +- Editor / Associated resource / Add button icon configuration. +- Editor / Distribution improvements - Update configuration for ISO19139 distributions as protocols are not categorized as ISO19115-3 protocols. (#7838) +- Standards / Formatter / Citation / Pick latest date +- INSPIRE / Add testsuite for IACS (#7756) +- Harvester / Localfilesystem / Log properly to harvester log file. (#7660) +- Harvester / WFS / No need to manually managed commit interval (#7737) +- Record view / ISO19139 / ISO19115-3.2008 display the unit part in @uom attribute, not the full url (#7791) +- Harvesters / Reset harvester history pagination when selecting a harvester +- Thesaurus / Improve support of EU publication office SKOS format (#7673) +- Create scorecard.yml +- Doc / Editor configuration improvements (#7776) +- Update lodash to version 4.17.21 +- Improve Elasticsearch manual installation to disable security for development +- Docker / Update docker compose in es module to Elasticsearch 8 (#7817) +- Trigger metadata unpublish event when removing the privileges to the ALL group in the privileges dialog +- Bump actions/setup-java from 4.0.0 to 4.1.0 (#7808) +- Translated the index warnings / errors. (#7531) +- minor typo fixes +- System setting for documentation url (#7782) +- Record view / Don't add the associated resources in the metadata static page, this page doesn't include JS libs +- Decouple metadata user feedback from metadata rating feature (#7770) +- Thesaurus / Add support for codelist described using SDMX +- Fix wrong manual links +- Standard / ISO19115-3 / Quality report / Index descriptive results +- Additional ISO19139 German translations (#7778) +- Update the `set privileges` popup with the new icon +- Replace the 'unlock' icon with the 'lock open' icon which is clearer. This new icon has more visual differences with the lock icon and it's therefore easier for a user to see the difference. +- Removed @RequestHeader for "Accept" headers as it is not supported by openAPI specification (#7572) +- Fix missing MetadataStatusResponse and MetadataWorkflowStatusResponse in open api spec (#7627) +- Fix SpringDoc duplicate Schema name Without this fix springdoc would randomly pick between 2 conflicting schemas and this could produce incorrect results in the open api spec. +- Merge getSubPortals into getSources so that there is only one GET api for the operation. This fixes the bug with 2 GET operation on /{portal}/api/sources +- Update services/src/main/java/org/fao/geonet/api/sources/SourcesApi.java +- Fix duplicate GET operation on /{portal}/api/sources Add missing /subportal endpoint. +- Spit getRecordAs @RequestMapping into getRecordAsJson and getRecordAsXML in order to fix duplicate operation Id - By having multiple @RequestMapping was causing to create operation id as getRecordAs and getRecordAs_1 +- Fix alignment of user enabled checkbox (#7764) +- Fix ISO19139 German labels (#7761) +- Remove handlebars.js v2.0.0 +- Fix query field name in OverviewIndexFieldUpdater to update the metadata overview in the index +- API / Category / Fix update fields +- Addressing docs glitch #7666 creating-group and authentication-mode +- Addressing docs glitch #7666 in installing-from-war-file, version-4.0.2 and tutorials/deployment/index +- addressing docs-glitch in install-guide/configuring-database +- addressing docs-glitch in search-ui/enrichview and search-ui/loadview +- addressing docs-glitch in install-guide/map-print-setup +- addressing docs-glitch in publishing/managing-privileges +- corrected minor typo in install-guide/map-print-setup +- Fix conversion errors after switching to MkDocs +- manual review of mkdocs glitches +- Reports / Fix extract user groups for non-admin users (#7742) +- Create a metadata / Add dynamic and download privileges to the users in the same group (#7679) +- Thesaurus / Add support for thesaurus described using OWL format +- Editor / Add view name class to facilitate custom styling +- Update SECURITY.md +- Index / Add danish language. (#7697) +- Standard / ISO19115-3 / Improve french translation for temporal extent (#7700) +- Standard / ISO19115-3 / Editor configuration / Improve date field configuration (#7702) +- Documentation / Elasticsearch query endpoint - query samples (#7722) +- remove mention of q query parameter +- Separate docs for _search and _msearch +- Map viewer / Remove Stamen background layers - no longer available +- Use the generated metadata UUID for resource links when importing metadata with the option 'Generate UUID' +- Elasticssearch 8 upgrade (#7599) +- Vertical extent label modification (#7604) +- Remove unused jslint-maven-plugin (#7725) +- Bump org.json:json from 20140107 to 20240205 (#7701) +- using gn- icon definitions for all types now +- Github Actions / Bump stCarolas/setup-maven from 4 to 5 (#7718) +- Enable preemptive for csw requests with credentials (#5497) (#7706) +- Add a role and feature matrix to the GeoNetwork documentation (#7686) +- Addressing docs translation glitch #7687- fixes adding-static-pages and configuring-search-fields (#7696) +- Automatic formatting +- Bump commons-fileupload from 1.3.3 to 1.5 (#6851) +- Remove empty class SourcesLib and deprecated/unused methods in ResourceLib / Sonarlint improvements (#7692) +- Fix spring doc for attachment and keyword to better identify files resources being returned. Update attachment api "Get a metadata resource" should indicate that gets a file resource Also "Create a new resource" should identify that it consumes any resources Update keywords api "Download a thesaurus by name" should indicate that gets a file resource +- Fix springdoc so that enums names are used instead of toString This fixes bug where some apis will not execute correctly from the swagger pager due to the wrong enum value being supplied. i.e. visibility should be using enum values PUBLIC/PRIVATE instead of public/private in formatters/zip api, the format should be SIMPLE/PARTIAL/FULL instead of simple/partial/full +- Update Springdoc so that it supports Map objects in the request parameters. By default injectable parameters are excluded from request parameters. Map is one of those object however it does occur where map objects are supplied as parameters and they should be added to open api spec. There are currently no cases where a map is injected on purpose into the request parameters. This will fix issues with missing request parameters documentation which are based on Map objects. +- Editor / Fix add element attribute (#7683) +- Metadata editor / Fix javascript error in the add thumbnail option when the metadata has 1 WMS layer (#7646) +- Add configuration to filter out Elasticsearch fields when download or dynamic privileges are not set +- Fix javascript error accessing the metadata detail page in gnMetadataSocialLink directive +- Metadata editor / Fix javascript error when editing a metadata, due to undefined property in gnLinkToMetadata directive +- Fix pdf link issue (#7667) +- Editor / Distribution improvements (#7468) +- Fix mimetypes on attachments as some were incorrect. (#7671) +- accidental localhost link in docs +- Docs / Update copyright year +- Bump github/codeql-action from 2 to 3 (#7552) +- Bump advanced-security/maven-dependency-submission-action from 3 to 4 (#7655) +- Formatter / Withheld element not always hidden. +- Change log for version 4.4.2 (#7654) +- Change log for version 4.2.8 +- Update version to 4.4.3-SNAPSHOT \ No newline at end of file diff --git a/docs/changes/changes4.4.4-0.txt b/docs/changes/changes4.4.4-0.txt new file mode 100644 index 00000000000..5e536738e30 --- /dev/null +++ b/docs/changes/changes4.4.4-0.txt @@ -0,0 +1,45 @@ +================================================================================ +=== +=== GeoNetwork 4.4.4-SNAPSHOT: List of changes +=== +================================================================================ +- documentation navigation update for 4.4.4 release +- Setup for release of 4.4.4 with gitignore for build scripts +- Transfix update for 4.4.4 release +- Fix sql syntax for migrate to 4.4.4 script (#7956) +- Enforce development environment instructions to Elasticsearch 8.11.3 (#7866) +- Adjust nav tree for batchupdate options +- Guidance on use of GeoNetwork 2.0 harvester +- Update revise use of empty or mostly empty pages +- Remove q service, used to query in previous versions that used Lucene as the search engine +- Modify csv search export to escape double-quotes with double-quotes instead of backslash (#7927) +- Fix harvester URIMapper to handle local metadata (#7946) +- CSW server / Use portal filter in GetRecordById requests (#7890) +- CSW / GetRecords / Number of matches is not total match +- metadata history viewing with user profile level (#7450) +- Map / WPS / Add support for predefined WPS list (#7842) +- Hide the typeahead search suggestions when hitting the ENTER key in the search field without selecting a suggested value +- Standard / ISO19115-3 / Editor / Uom encoding support (#7915) +- Search / May fail with random_score depending on ES config (#7912) +- API / Import does not overwrite metadata if any validation status (#7703) +- Standard / ISO19115-3 / Use anchor encoding for IACS keywords (#7853) +- Fix issue with saving metadata status causes indexing of metadata which causes issues for db rollbacks (#7514) +- move email notification at the end of status change transaction (#7864) +- Upgrade springdoc to 1.7.0 (#7596) +- Configure harvesters log to avoid application log duplicated in harvester_default.log file. Fixes #7895 (#7896) +- Fix typo in Messages.properties (#7892) +- Fix LinksApiTest integration test. Related to changes in #7878 to process the links in a thread +- [gn]: hibernate troubles with jeeves and persistance manager (harvesting mef) (#6840) +- Feedback / Fix email to multiple recipients (#7875) +- Passing key into update/remove process xslt for iso 19139 to fix issue with updating/deleting resources with same url (#7431) +- Metadata link analysis improvements (#7878) +- Indexing / Improve geometry indexing and display +- Editor / GeoNames search failing with space +- Fill in 4.2.x releases for maintenance page (#7879) +- Map / Extent API / Background image failure if matrixset is not SRS code +- Optimise query used to retrieve metadata links results (#7453) +- Standard / ISO19115-3 / Schema / Move from srv 2.1 to 2.0 +- fix regex for urls where ampersand follows the ID +- OpenID / Cleaning up cached tokens (#7810) +- Editor / Associated resources panel improvements (#7669) +- Update version to 4.4.4-SNAPSHOT \ No newline at end of file diff --git a/docs/changes/changes4.4.5-0.txt b/docs/changes/changes4.4.5-0.txt new file mode 100644 index 00000000000..ff6864c6166 --- /dev/null +++ b/docs/changes/changes4.4.5-0.txt @@ -0,0 +1,105 @@ +================================================================================ +=== +=== GeoNetwork 4.4.5-SNAPSHOT: List of changes +=== +================================================================================ +- Documentation / Release notes 4.2.10 (#8170) +- Release / 4.4.5 / Changelog. +- i18n / Transifex update. +- Map viewer / Add layer with styles from a metadata doesn't show the styles selector +- Map viewer / fix TMS layer persistence in map context (#8173) +- Record view / don't display the add to map button for WFS resources when the map viewer is disabled. +- Record view / display WMS resources button label to open the link when the map viewer is not enabled +- Fix issue with Map Attribution not being toggled correctly in data preview. (#8149) +- Fix html elements defined in javascript with wrong self-closing. (#8164) +- Analytics services integration (#7313) +- Improve tooltips for facet filter items (#8122) +- Database setup / Instead of declaring all SQL for each language, declare the language and load SQL files for each languages if available. +- i18n / Add armenian, azerbaijani, georgian, romanian and ukrainian languages +- fix #geonetwork/core-geonetwork/issues/7930 +- Editor / Remove wrong ERROR log message on multilingual records (#8049) +- Map list / Improve layout of card +- Map / Feature table / Missing translation +- Editor / Associated panel / CSS class by type +- Delete draft resource at the end of draft util transaction. (#8100) +- Editor / Associated resource / Avoid scrollbar (#8051) +- Fix issues with category icons in search results list view (#8099) +- Editor / CRS search / Fix duplicated icon (#8141) +- Translation provider / Fix pom version. +- Editor / Keywords / Add option to configure keyword encoding for a view. (#8118) +- Metadata workflow API / Update security exceptions to use translations +- Transfer ownership / fix translation key for 'Save' button +- Support for translation providers in harvesters (#7849) +- Fix copy xsd files from metadata schemas to the web application +- Update portal-configuration.md +- update last changed date when restore metadata (#8033) +- Editor / Associated resource / Update panel based on type config (#8052) +- Map / WPS / Add message for no recent process. (#8091) +- Harvesters / remove unused groupsCopyPolicy property +- Indexing / ISO19115-3 / Avoir error on multiple contact website (#8113) +- Make logo size bigger and set it to fixed position regardless of web pages (#7801) +- Deprecated BearerTokenAuthenticationToken (#8107) +- Update DOI exceptions to be multilingual exceptions (#8106) +- Editor / Add list mode (#7998) +- Remove link from admin-guide to schematron details as inappropriate +- Editor / Group owner change / Fix label on error (#8101) +- Editor / Groupowner change error (#8102) +- Be able to edit metadata when backend store is not available (#8060) +- Documentation / Add information about the type of users that can request a DOI +- Indicate 4.4 is latest (not outdated) +- how to update mkdoc env (removed instructions for docker mkdocs use) (#8089) +- flatten changelog into current release and release history for ease of maintenance (#7887) +- HTTP proxy servlet / update error messages. (#8009) +- Record view / ISO19139 / ISO19115-3.2008 display the unit part in @uom attribute - avoid duplicated value +- Add missing bootstrap-datepicker3.css.map that caused a wro4j error. (#8078) +- Map / Switch from GET to POST request improved in case of missing CORS header on HTTP errors (#8036) +- WMS GetMap HEAD request error response - check response status defined (#8023) +- GeoNetwork app as web components. (#6516) +- Users / reset form status when creating a user +- Cleanup onbeforeunload event when loading the editorboard controller +- search menu size (#8024) +- Record view / Fix JS error related to publication options display. +- XSL / Utility / Add multilingual support to getIndexField +- Editor / Map / Use main context to have a better default on new extent (#8046) +- Editor / Table mode / Add ordering control. (#8016) +- Standard / ISO19115-3 / Improve linking to parent (#8018) +- Search / Aggregations on related records. (#7939) +- Standard / ISO19115-3 / Avoid indexing error on multilingual feature catalogue (#8013) +- Standard / ISO19115-3 / Remove geographicElement when removing bounding box (#8048) +- Record view / Focus on organisation fix +- jQuery upgrade to version 3.7.1 (#8015) +- Formatter / ISO / Avoid error on invalid extent (#8035) +- Workflow / Edit action / Fix link in search results (#8031) +- Synchronize Messages.properties from web and test (#8011) +- Editor / Distributions / Feed icon for ATOM. +- Editor / Add custom element in distribution and associated record directive +- Mail / Log / Remove debug level +- Map viewer / ESRIREST layers / Scale the layer extent to show the symbology of the features in the corners of the extent. (#8027) +- Search tab map is blank on first page load. Fixes #7961 (#8026) +- Merge pull request from GHSA-52rf-25hq-5m33 +- ISO19139 metadata full view / display citation titles (#8003) +- Map / Add scale. (#7967) +- API / Extent / Add geometry collection support. (#7911) +- Status dashboard / Don't include indexing warnings as errors +- Record view / Metadata info / Add standard name and version. +- Record view / Service / Add service type, version and coupling type. +- Standard / ISO19115-3 / Feature catalogue improvements (#7919) +- Standard / ISO19115-3 / Ensure dqm namespace is on top of the document. Remove gts namespace which is ISO19139. (#7960) +- Standards / ISO19115-3 / Cleanup project specific template (#7940) +- Test / Fix formatter test. (#7993) +- French translation update for metadata_approved_published_record_text (#7974) +- Remove unused JeevesDelegatingFilterProxy servlet parameter 'loginService' configuration, related to multinode feature, removed from GeoNework 4.x +- Report users - Display profile for Administrator / Guest profiles that are not related to groups +- fix for nextrecord in csw getrecord response when using pagination +- Update the default sort field name in editor board and batch editor. +- API / XSL / Use XSL output configuration (formatter, editor). (#7929) +- Workflow / Editor board / Add search configuration to display draft, approved record or both (#7477) +- Support additional metadata processing when publishing / un-publishing metadata. (#7747) +- Update sort by fields configuration with language placeholder, to support sort by multilingual fields (#7902) +- WPS process parameters - support datetime / time formats (#7932) +- GeoNetwork 4.4.x minor versions library updates: - Spring Framework: 5.3.33 - Spring Security: 5.8.11 +- Editor board / Use metadata database change date instead of the metadata dateStamp (xml) (#7910) +- Doc / Editor configuration / Subtemplate insert mode (#7944) +- Update springdoc to 1.8.0 which required upgrade of jackson.version to version 2.16.2 Fix springdocs HashMap mapping in /db/translations using new additionalPropertiesSchema +- Update Jetty to version 9.4.54.v20240208 +- Update version to 4.4.5-SNAPSHOT \ No newline at end of file diff --git a/docs/changes/changes4.4.6-0.txt b/docs/changes/changes4.4.6-0.txt new file mode 100644 index 00000000000..636b5eb919c --- /dev/null +++ b/docs/changes/changes4.4.6-0.txt @@ -0,0 +1,133 @@ +================================================================================ +=== +=== GeoNetwork 4.4.6-SNAPSHOT: List of changes +=== +================================================================================ +- Release / 4.4.6 / Changelog. (#8462) +- update PSC details in user guide +- Delete date not being copied causing duplicate (#8454) +- Standard / DCAT (and profiles) export (#7600) +- Update home page "browse by" to display facet as label if there is only one (#8426) +- Avoid duplicate validation message when trying to register a user with existing email +- Add bootstrap datepicker language files for supported UI languages +- Add better logging when resources are deleted to make it clear what metadata record the resource was deleted from. (#8430) +- Record view / More like this / Add filter option. +- Fix saving UI settings without changes +- Harvester / Simple URL / Fix multiple URL alignement +- Elasticsearch / Update to 8.14.3. (#8337) +- Remove empty filename condition (#8436) +- Elasticsearch / API / Allow ndjson for _msearch endpoint +- Improve administrator guide UI configuration documentation +- Harvester / Simple URL / ODS improvement +- Editor / Geopublication / Misc fix. (#8092) +- WebDav harvester / Add support for XSLT filter process (#8243) +- Editor / Associated resource / Remote document / Add content type +- Fixed description for getIdentifiers in IdentifierApi (#8422) +- Formatter / Datacite / Default resource type (#8407) +- Remove spaces from the list of schema list of metadata import restrictions so that "iso19115-3.2018, dublin-core" will also work. (#8408) +- Thesaurus / OWL format / Mobility theme hierarchy (#8393) +- Record view / Does not display thesaurus block if no keywords. +- Map / Save your map improvements (#8155) +- Editor / Table mode / Fix field using directive (#8261) +- Thesaurus / Add inScheme property in concept of local thesaurus +- Standard / ISO19115-3 / Only search for associated record with UUID +- CSW / Fix parsing date values for filters. Fixes #8034 +- Javascript / HTML formatting fixes related to Prettier +- Update external management url Add {objectId} property in external management url (base64 unique identifier for the record) Change external management type url property {type} so that it is fixed values so that same value can be used in {objectId} CMIS Fixed property names used for validation fields to be consistent with other names. Jcloud Updgade from jcloud 2.3.0 to jcloud 2.5.0 Add support for external management named properties similar to cmis Fix bug with deleting all resources as it was failing to identify folders correctly for azure blob. +- Harvester / ISO19115-3 / Better support missing metadata date info +- Metadata indexing / ISO19139 / ISO19115-3.2018 / Escape graphic overview file name for JSON (#8412) +- Fixed spurious whitespace for gn-comma-list (#8398) +- Metadata editor / Add required indicator support to the keyword selector directive and fix its display for the field duration directive +- Fix the width of the projection switcher (#8399) +- Metadata editor / validation report improvements (#8395) +- Don't capitalize the labels for the facet filter values (#8133) +- Support multiple DOI servers (#8098) +- Thesaurus / Date improvements. (#8392) +- GeoNetwork harvester - avoid double counting of updated metadata. (#8389) +- Fix harvester execution logs added to previous logs (#8387) +- Visual and UX changes for WFS previews (#8284) +- Metadata detail page - hide history types selector when tasks (DOI) and workflow are disabled +- Fix the overlapping filter settings and the customize options (#8316) +- ISO19139 / ISO19115.3 / Index resource date fields as defined in the metadata. +- Fix the schema artifact name in add schema script +- Update configuring-faceted-search.md +- Aggregations / Temporal range / Avoid browser autocomplete on calendar field +- OpenAPI / Operation returning no content should not advertised a schema. +- Indexing / DCAT multilingual support (#8377) +- Xsl utility / Add a function to retrieve thesaurus title with its key (#8378) +- GIT / .gitignore +- Map viewer / WMS GetFeatureInfo support for application/json info format (#8372) +- Add build profile for MacOS ARM +- Editor / Associated resource / DOI search. (#8363) +- Standard / ISO19115-3 / Label improvement. (#8364) +- Harvester / Simple URL / ODS / Improve mapping +- Don't add file content to the exception when requesting XML documents, if the content is not XML (#8360) +- Put the image name in the `alt` attribute in the thumbnail on the metadata page. (#8290) +- CSW Harvester / Avoid increment 2 metrics for a single metadata in certain conditions (#8069) +- iso19139 - Update thumbnail add/update and remove to support index update/removal (#8348) +- publish status not refreshing fix (#8344) +- Editor / Associated resource / Avoid empty label (#8339) +- Editor / DOI search / Improve label (#8338) +- API / Improve parameter check for XSL conversion. (#8201) +- Admin / Source / Improve dirty state (#8222) +- Standard / ISO19115-3 / Formatters / ISO19139 / Ignore mcc linkage for overview (#8225) +- Fix Clipboard copy/paste on Firefox - use ES5 (#8332) +- Indexing / Draft field MUST not be an array (#8242) +- Editor / Dublin core / Fix extent coordinates (#8258) +- Workflow / update notification level based on user profile when cancelling a submission (#8264) +- INSPIRE Atom harvester / process only public datasets by resource identifier +- Special characters in the cookie causing 400 bad requests from Spring Security. Fixes #8275 +- Do not try to request clipboard permissions +- Social links in metadata page doesn't have the metadata page permalink. Fixes #8322 +- Repository Citation.cff metadata for DOI registration with Zenodo (#8317) +- Modify record not found message to only link to signin if user is not logged in (#8312) +- Modify GnMdViewController to set recordIdentifierRequested using the getUuid function +- harvesting CSW: changed loglevel for invalid metadata to info (#8303) +- Standard / ISO19139 / i18n / Missing french translation (#8298) +- Index / Add maintenance details. +- Record view / Improve layout of table (eg. quality measures) +- Update batch PDF export to skip working copies (#8292) +- Standard / ISO19139 / Fix removal of online source when multiple transfer options block are used. (#8281) +- Fix a problem with recaptcha not shown sometimes (#8285) +- Zoom to map popup remains active on non-map pages. (#8267) +- Use UI language for metadata selection export to CSV / PDF. Fixes #7969 (#8262) +- Fixed issue with working copy not being returned from /api/records/{metadataUuid}/formatters/{formatterId:.+} (#8269) +- Fixed issue with working copy not being returned from getRecordAS api (#8265) +- Standard / ISO19115-3 / Formatters / ISO19139 / Fix scope code (#8224) +- Standard / ISO19115-3 / Formatter / Fix namespace declaration (#8223) +- Editor / Configuration / Improve deletion in forEach section (#8244) +- Fix infinite "Please wait" message on error (#8249) +- Broadcasting error when delete record (#8212) +- ISO19115-3.2018 / Remove duplicated fields for metadata identifier and uuid in CSV export (#8238) +- Standard / ISO19139 / Formatter / Do not display extent if none available (#8229) +- Fix wrong HTML self closing tags (#8232) +- Editor / Polygon not saved (#8230) +- Add info logs to make transaction of working copy merge more traceable (#8178) +- API / Client code generation / Avoid reserved word (#8214) +- Double translation can lead to infinite stack (#8209) +- Fix canViewRecord function so that it returned the workflow record. (#8152) +- Automatic formatting +- Association type / Consistent labels (#8077) +- Multilingual Emails (#8044) +- Add support for multilingual thesaurus titles in the index (#8154) +- Bump actions/setup-java from 4.1.0 to 4.2.1 (#7870) +- Fix presence of duplicated geonet elements on partial metadata updates +- Fix user application feedback (#7769) +- Update SECURITY.md (#8172) +- Register user / allow to configured allowed email domains (#8186) +- docs: fix image links in change-log(version-3.8.0.md and 4.0.0-alpha.1 (#7938) +- Elasticsearch / Update to 8.14.0. +- Bump org.apache.maven.plugins:maven-dependency-plugin +- Release script improvement +- Cleaning / Remove transifex converting tools +- Indexing / Lower severity of getIndexField +- Metadata extents API - fix service for metadata with working copy - test (#8197) +- Register user / allow to select the group where the user wants to register (#8176) +- Metadata extents API - fix service for metadata with working copy +- Bump com.jayway.jsonpath:json-path from 2.4.0 to 2.9.0 in /services +- Bump org.owasp.esapi:esapi from 2.4.0.0 to 2.5.4.0 +- Bump org.postgresql:postgresql from 42.6.0 to 42.7.3 +- Bump org.xmlunit:xmlunit-core from 2.1.1 to 2.10.0 +- Bump com.google.guava:guava from 30.0-jre to 33.2.1-jre +- Update en-admin.json +- Update version to 4.4.6-SNAPSHOT \ No newline at end of file diff --git a/docs/manual/LICENSE b/docs/manual/LICENSE new file mode 100644 index 00000000000..1d658d6d376 --- /dev/null +++ b/docs/manual/LICENSE @@ -0,0 +1,319 @@ +Creative Commons Legal Code + +Attribution 3.0 Unported + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR + DAMAGES RESULTING FROM ITS USE. + +License + +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE +COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY +COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS +AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. + +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE +TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY +BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS +CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND +CONDITIONS. + +1. Definitions + + a. "Adaptation" means a work based upon the Work, or upon the Work and + other pre-existing works, such as a translation, adaptation, + derivative work, arrangement of music or other alterations of a + literary or artistic work, or phonogram or performance and includes + cinematographic adaptations or any other form in which the Work may be + recast, transformed, or adapted including in any form recognizably + derived from the original, except that a work that constitutes a + Collection will not be considered an Adaptation for the purpose of + this License. For the avoidance of doubt, where the Work is a musical + work, performance or phonogram, the synchronization of the Work in + timed-relation with a moving image ("synching") will be considered an + Adaptation for the purpose of this License. + b. "Collection" means a collection of literary or artistic works, such as + encyclopedias and anthologies, or performances, phonograms or + broadcasts, or other works or subject matter other than works listed + in Section 1(f) below, which, by reason of the selection and + arrangement of their contents, constitute intellectual creations, in + which the Work is included in its entirety in unmodified form along + with one or more other contributions, each constituting separate and + independent works in themselves, which together are assembled into a + collective whole. A work that constitutes a Collection will not be + considered an Adaptation (as defined above) for the purposes of this + License. + c. "Distribute" means to make available to the public the original and + copies of the Work or Adaptation, as appropriate, through sale or + other transfer of ownership. + d. "Licensor" means the individual, individuals, entity or entities that + offer(s) the Work under the terms of this License. + e. "Original Author" means, in the case of a literary or artistic work, + the individual, individuals, entity or entities who created the Work + or if no individual or entity can be identified, the publisher; and in + addition (i) in the case of a performance the actors, singers, + musicians, dancers, and other persons who act, sing, deliver, declaim, + play in, interpret or otherwise perform literary or artistic works or + expressions of folklore; (ii) in the case of a phonogram the producer + being the person or legal entity who first fixes the sounds of a + performance or other sounds; and, (iii) in the case of broadcasts, the + organization that transmits the broadcast. + f. "Work" means the literary and/or artistic work offered under the terms + of this License including without limitation any production in the + literary, scientific and artistic domain, whatever may be the mode or + form of its expression including digital form, such as a book, + pamphlet and other writing; a lecture, address, sermon or other work + of the same nature; a dramatic or dramatico-musical work; a + choreographic work or entertainment in dumb show; a musical + composition with or without words; a cinematographic work to which are + assimilated works expressed by a process analogous to cinematography; + a work of drawing, painting, architecture, sculpture, engraving or + lithography; a photographic work to which are assimilated works + expressed by a process analogous to photography; a work of applied + art; an illustration, map, plan, sketch or three-dimensional work + relative to geography, topography, architecture or science; a + performance; a broadcast; a phonogram; a compilation of data to the + extent it is protected as a copyrightable work; or a work performed by + a variety or circus performer to the extent it is not otherwise + considered a literary or artistic work. + g. "You" means an individual or entity exercising rights under this + License who has not previously violated the terms of this License with + respect to the Work, or who has received express permission from the + Licensor to exercise rights under this License despite a previous + violation. + h. "Publicly Perform" means to perform public recitations of the Work and + to communicate to the public those public recitations, by any means or + process, including by wire or wireless means or public digital + performances; to make available to the public Works in such a way that + members of the public may access these Works from a place and at a + place individually chosen by them; to perform the Work to the public + by any means or process and the communication to the public of the + performances of the Work, including by public digital performance; to + broadcast and rebroadcast the Work by any means including signs, + sounds or images. + i. "Reproduce" means to make copies of the Work by any means including + without limitation by sound or visual recordings and the right of + fixation and reproducing fixations of the Work, including storage of a + protected performance or phonogram in digital form or other electronic + medium. + +2. Fair Dealing Rights. Nothing in this License is intended to reduce, +limit, or restrict any uses free from copyright or rights arising from +limitations or exceptions that are provided for in connection with the +copyright protection under copyright law or other applicable laws. + +3. License Grant. Subject to the terms and conditions of this License, +Licensor hereby grants You a worldwide, royalty-free, non-exclusive, +perpetual (for the duration of the applicable copyright) license to +exercise the rights in the Work as stated below: + + a. to Reproduce the Work, to incorporate the Work into one or more + Collections, and to Reproduce the Work as incorporated in the + Collections; + b. to create and Reproduce Adaptations provided that any such Adaptation, + including any translation in any medium, takes reasonable steps to + clearly label, demarcate or otherwise identify that changes were made + to the original Work. For example, a translation could be marked "The + original work was translated from English to Spanish," or a + modification could indicate "The original work has been modified."; + c. to Distribute and Publicly Perform the Work including as incorporated + in Collections; and, + d. to Distribute and Publicly Perform Adaptations. + e. For the avoidance of doubt: + + i. Non-waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme cannot be waived, the Licensor + reserves the exclusive right to collect such royalties for any + exercise by You of the rights granted under this License; + ii. Waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme can be waived, the Licensor waives the + exclusive right to collect such royalties for any exercise by You + of the rights granted under this License; and, + iii. Voluntary License Schemes. The Licensor waives the right to + collect royalties, whether individually or, in the event that the + Licensor is a member of a collecting society that administers + voluntary licensing schemes, via that society, from any exercise + by You of the rights granted under this License. + +The above rights may be exercised in all media and formats whether now +known or hereafter devised. The above rights include the right to make +such modifications as are technically necessary to exercise the rights in +other media and formats. Subject to Section 8(f), all rights not expressly +granted by Licensor are hereby reserved. + +4. Restrictions. The license granted in Section 3 above is expressly made +subject to and limited by the following restrictions: + + a. You may Distribute or Publicly Perform the Work only under the terms + of this License. You must include a copy of, or the Uniform Resource + Identifier (URI) for, this License with every copy of the Work You + Distribute or Publicly Perform. You may not offer or impose any terms + on the Work that restrict the terms of this License or the ability of + the recipient of the Work to exercise the rights granted to that + recipient under the terms of the License. You may not sublicense the + Work. You must keep intact all notices that refer to this License and + to the disclaimer of warranties with every copy of the Work You + Distribute or Publicly Perform. When You Distribute or Publicly + Perform the Work, You may not impose any effective technological + measures on the Work that restrict the ability of a recipient of the + Work from You to exercise the rights granted to that recipient under + the terms of the License. This Section 4(a) applies to the Work as + incorporated in a Collection, but this does not require the Collection + apart from the Work itself to be made subject to the terms of this + License. If You create a Collection, upon notice from any Licensor You + must, to the extent practicable, remove from the Collection any credit + as required by Section 4(b), as requested. If You create an + Adaptation, upon notice from any Licensor You must, to the extent + practicable, remove from the Adaptation any credit as required by + Section 4(b), as requested. + b. If You Distribute, or Publicly Perform the Work or any Adaptations or + Collections, You must, unless a request has been made pursuant to + Section 4(a), keep intact all copyright notices for the Work and + provide, reasonable to the medium or means You are utilizing: (i) the + name of the Original Author (or pseudonym, if applicable) if supplied, + and/or if the Original Author and/or Licensor designate another party + or parties (e.g., a sponsor institute, publishing entity, journal) for + attribution ("Attribution Parties") in Licensor's copyright notice, + terms of service or by other reasonable means, the name of such party + or parties; (ii) the title of the Work if supplied; (iii) to the + extent reasonably practicable, the URI, if any, that Licensor + specifies to be associated with the Work, unless such URI does not + refer to the copyright notice or licensing information for the Work; + and (iv) , consistent with Section 3(b), in the case of an Adaptation, + a credit identifying the use of the Work in the Adaptation (e.g., + "French translation of the Work by Original Author," or "Screenplay + based on original Work by Original Author"). The credit required by + this Section 4 (b) may be implemented in any reasonable manner; + provided, however, that in the case of a Adaptation or Collection, at + a minimum such credit will appear, if a credit for all contributing + authors of the Adaptation or Collection appears, then as part of these + credits and in a manner at least as prominent as the credits for the + other contributing authors. For the avoidance of doubt, You may only + use the credit required by this Section for the purpose of attribution + in the manner set out above and, by exercising Your rights under this + License, You may not implicitly or explicitly assert or imply any + connection with, sponsorship or endorsement by the Original Author, + Licensor and/or Attribution Parties, as appropriate, of You or Your + use of the Work, without the separate, express prior written + permission of the Original Author, Licensor and/or Attribution + Parties. + c. Except as otherwise agreed in writing by the Licensor or as may be + otherwise permitted by applicable law, if You Reproduce, Distribute or + Publicly Perform the Work either by itself or as part of any + Adaptations or Collections, You must not distort, mutilate, modify or + take other derogatory action in relation to the Work which would be + prejudicial to the Original Author's honor or reputation. Licensor + agrees that in those jurisdictions (e.g. Japan), in which any exercise + of the right granted in Section 3(b) of this License (the right to + make Adaptations) would be deemed to be a distortion, mutilation, + modification or other derogatory action prejudicial to the Original + Author's honor and reputation, the Licensor will waive or not assert, + as appropriate, this Section, to the fullest extent permitted by the + applicable national law, to enable You to reasonably exercise Your + right under Section 3(b) of this License (right to make Adaptations) + but not otherwise. + +5. Representations, Warranties and Disclaimer + +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR +OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY +KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, +INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, +FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF +LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, +WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION +OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. + +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE +LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR +ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES +ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. Termination + + a. This License and the rights granted hereunder will terminate + automatically upon any breach by You of the terms of this License. + Individuals or entities who have received Adaptations or Collections + from You under this License, however, will not have their licenses + terminated provided such individuals or entities remain in full + compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will + survive any termination of this License. + b. Subject to the above terms and conditions, the license granted here is + perpetual (for the duration of the applicable copyright in the Work). + Notwithstanding the above, Licensor reserves the right to release the + Work under different license terms or to stop distributing the Work at + any time; provided, however that any such election will not serve to + withdraw this License (or any other license that has been, or is + required to be, granted under the terms of this License), and this + License will continue in full force and effect unless terminated as + stated above. + +8. Miscellaneous + + a. Each time You Distribute or Publicly Perform the Work or a Collection, + the Licensor offers to the recipient a license to the Work on the same + terms and conditions as the license granted to You under this License. + b. Each time You Distribute or Publicly Perform an Adaptation, Licensor + offers to the recipient a license to the original Work on the same + terms and conditions as the license granted to You under this License. + c. If any provision of this License is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this License, and without further action + by the parties to this agreement, such provision shall be reformed to + the minimum extent necessary to make such provision valid and + enforceable. + d. No term or provision of this License shall be deemed waived and no + breach consented to unless such waiver or consent shall be in writing + and signed by the party to be charged with such waiver or consent. + e. This License constitutes the entire agreement between the parties with + respect to the Work licensed here. There are no understandings, + agreements or representations with respect to the Work not specified + here. Licensor shall not be bound by any additional provisions that + may appear in any communication from You. This License may not be + modified without the mutual written agreement of the Licensor and You. + f. The rights granted under, and the subject matter referenced, in this + License were drafted utilizing the terminology of the Berne Convention + for the Protection of Literary and Artistic Works (as amended on + September 28, 1979), the Rome Convention of 1961, the WIPO Copyright + Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 + and the Universal Copyright Convention (as revised on July 24, 1971). + These rights and subject matter take effect in the relevant + jurisdiction in which the License terms are sought to be enforced + according to the corresponding provisions of the implementation of + those treaty provisions in the applicable national law. If the + standard suite of rights granted under applicable copyright law + includes additional rights not granted under this License, such + additional rights are deemed to be included in the License; this + License is not intended to restrict the license of any rights under + applicable law. + + +Creative Commons Notice + + Creative Commons is not a party to this License, and makes no warranty + whatsoever in connection with the Work. Creative Commons will not be + liable to You or any party on any legal theory for any damages + whatsoever, including without limitation any general, special, + incidental or consequential damages arising in connection to this + license. Notwithstanding the foregoing two (2) sentences, if Creative + Commons has expressly identified itself as the Licensor hereunder, it + shall have all rights and obligations of Licensor. + + Except for the limited purpose of indicating to the public that the + Work is licensed under the CCPL, Creative Commons does not authorize + the use by either party of the trademark "Creative Commons" or any + related trademark or logo of Creative Commons without the prior + written consent of Creative Commons. Any permitted use will be in + compliance with Creative Commons' then-current trademark usage + guidelines, as may be published on its website or otherwise made + available upon request from time to time. For the avoidance of doubt, + this trademark restriction does not form part of this License. + + Creative Commons may be contacted at http://creativecommons.org/. diff --git a/docs/manual/README.md b/docs/manual/README.md new file mode 100644 index 00000000000..d01313f1f47 --- /dev/null +++ b/docs/manual/README.md @@ -0,0 +1,159 @@ +# GeoNetwork Manual and Help + +Documentation for GeoNetwork opensource is available via https://docs.geonetwork-opensource.org. + +This documentation is written under the Creative Commons license [Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)](LICENSE). + +Reference: + +* [Documentation Writing Guide](docs/devel/docs/index.md) + +## Communication + +The [project issue tracker](https://github.com/geonetwork/core-geonetwork/issues) is used for communication, with ongoing topics tagged [documentation](https://github.com/geonetwork/core-geonetwork/issues?q=is%3Aissue+label%3Adocumenation). + +## Material for MkDocs + +Documentation is [MkDocs-material](https://squidfunk.github.io/mkdocs-material/) which is a Markdown documentation framework written on top of [MkDocs](https://www.mkdocs.org/). + +If you are using Python3: + +1. Install using ``pip3`` and build: + + ```bash + pip3 install -r requirements.txt + ``` + + In the future you can update using: + + ```bash + pip3 install -r requirements.txt -U + ``` + +2. Use ***mkdocs** to preview locally: + + ```bash + mkdocs serve + ``` + +3. Preview: http://localhost:8000 + + Preview uses a single version, so expect some warnings from version chooser: + ``` + "GET /versions.json HTTP/1.1" code 404 + ``` + +4. Optional: Preview online help: + + ```bash + mkdocs serve --config-file help.yml + ``` + +### VirtualEnv + +If you use a Python virtual environment: + +1. Activate virtual environment: + + ```bash + virtualenv venv + source venv/bin/activate + pip install -r requirements.txt + ``` + + In the future you can update with: + + ```bash + source venv/bin/activate + pip3 install -r requirements.txt + ``` + +2. Use ***mkdocs*** to preview from virtual environment: + + ```bash + mkdocs serve + ``` + +3. Preview: http://localhost:8000 + + Preview uses a single version, so expect some warnings from version chooser: + ``` + "GET /versions.json HTTP/1.1" code 404 + ``` + +4. Optional: Preview online help: + + ```bash + mkdocs serve --config-file help.yml + ``` + +## Maven Integration + +1. Build documentation with ``compile`` phase: + ``` + mvn compile + ``` + +2. Assemble ``zip`` with ``package`` phase: + ```bash + mvn package + ``` + +3. Both ``install`` and ``deploy`` are skipped (so ``mvn clean install`` is fine). + +4. Use default profile to only build the default English docs: + + ``` + mvn install -Pdefault + ``` + +## Publish Documentation + +We use ``mike`` for publishing (from the `gh-pages` branch). Docs are published by the ``.github/workflows/docs.yml`` automation each time pull-request is merged. + +If you wish to preview using your own `gh-pages` branch: + +1. To deploy 4.4 docs as latest from the `main` branch to website `gh-pages` branch: + + ```bash + mike deploy --title "4.4 Latest" --alias-type=copy --update-aliases 4.4 latest + ``` + +2. To deploy documentation for stable release: + + ```bash + mike deploy --push --alias-type=copy 4.2 stable + ``` + +3. When starting a new branch you can make it the default: + + ```bash + mike set-default --push 4.6 + ``` + + Hint: When starting a new branch update `overview/changelog/history/index.md` headings for latest, maintenance, stable (for prior branches also). + +4. To publish documentation for a maintenance release: + + ```bash + mike deploy --push --alias-type=copy 3.12 maintenance + ``` + +5. To show published versions: + + ```bash + + mike list + ``` + +6. To preview things locally (uses your local ``gh-pages`` branch): + + ```bash + mike serve + ``` + +Reference: + +* https://squidfunk.github.io/mkdocs-material/setup/setting-up-versioning/ +* https://github.com/squidfunk/mkdocs-material-example-versioning +* https://github.com/jimporter/mike diff --git a/docs/manual/docs/_static/GN3.png b/docs/manual/docs/_static/GN3.png new file mode 100644 index 00000000000..caee39b62de Binary files /dev/null and b/docs/manual/docs/_static/GN3.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/css-configuration.md b/docs/manual/docs/administrator-guide/configuring-the-catalog/css-configuration.md new file mode 100644 index 00000000000..d1c2c10f5ee --- /dev/null +++ b/docs/manual/docs/administrator-guide/configuring-the-catalog/css-configuration.md @@ -0,0 +1,13 @@ +# Configuring CSS & Style {#css-configuration} + +To get to the CSS & Style configuration, you must be logged on as administrator. Open 'Settings' from the Administration page and select ``CCS & Style`` configuration. + +![](img/css-screen.png) + +This page allows you to change various colors of page elements. Note that 'background' refers to the background color of elements, and 'color' to the font color used in the element. The above configuration will result in the visualization below: + +![](img/css-result.png) + +There is also an option to link to a background image. When linking to an image, make sure to use (the full web address to) an image from a https source if you're running GeoNetwork in https. Placing the image (upload as logo) on the same server is the best option to prevent potential browser blocks. + +Note that you can save a configuration locally for reuse later or on alternative servers. Saving a configuration will take a long time, because all scripts and styles will be rebuilt from sources. Temporary files are stored on the server in an application folder, you may need to revisit this page after an upgrade the system (or redeploy of a docker container). diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/csw-configuration.md b/docs/manual/docs/administrator-guide/configuring-the-catalog/csw-configuration.md new file mode 100644 index 00000000000..d352dc7fcd5 --- /dev/null +++ b/docs/manual/docs/administrator-guide/configuring-the-catalog/csw-configuration.md @@ -0,0 +1,108 @@ +# Configuring CSW {#csw-configuration} + +To get to the CSW server configuration, you must be logged on as administrator first. Open 'Settings' from the Administration page and select CSW Server configuration. + +![](img/csw.png) + +The CSW service provides a description of itself, the human who administers it, and other information through a `GetCapabilities` request (eg. ). This form allows you to configure the CSW server and fill out some of the properties returned in response to a GetCapabilities request. + +Configuration options: + +- *CSW Enabled*: By default CSW endpoint is enabled, but it can be disabled. + + ![](img/csw-off.png) + + The Open Geospatial Catalogue Service for the Web (OGC-CSW) service, is a self-describing service that allows query, update and insertion of metadata records. + +- *Record to use for GetCapabilities*: The capabilities document is created using the record selected here. + +- *Inserted metadata is public*: By default, metadata inserted with the CSW Harvest and CSW Transaction operations is not publicly viewable. A user with the appropriate access rights could do this after the CSW Harvest and CSW Transaction operations, but this is not always convenient. If this option is checked all metadata inserted using the CSW Harvest and CSW Transaction operations will be publicly viewable. + +- *Create element if it does not exist when using XPath in CSW transaction.*: If not checked, only existing elements can be updated. + +## Service Metadata Record {#csw-configuration_service_record} + +In order to create a custom capabilities, it is recommended to create a dedicated service metadata record (using ISO19115-3 or ISO19139 standards). This record is used to build the capabilities document using the template `web/src/main/webapp/xml/csw/capabilities.xml`. + +When creating such record, the following information will be used to create the capabilities: + +- title +- abstract +- keywords +- fees (from Distribution --> ordering instructions field) +- Access constraints (from Access constraints --> Other constraints field) +- Contact (from Identification --> First point of contact) + +The service record MUST be public. + +If an error occurred while building the capabilities document from the service record, a WARNING is reported using a comment and the default capabilities is used: + +![](img/csw-error.png) + +## CSW Configuration for INSPIRE {#csw-configuration_inspire} + +If your catalogue also focus on INSPIRE (see [Configuring for the INSPIRE Directive](inspire-configuration.md)), it may be relevant to also populate the following to properly configure your discovery service: + +- metadata language (+ additional languages if any) (use for SupportedLanguages, DefaultLanguage) +- INSPIRE themes +- temporal coverage +- metadata contact +- metadata conformity regarding Commission regulation 1089/2010 + +With this information the CSW can be validated using the INSPIRE validator. + +## CSW post processing + +In some situation, user may want to modify XML encoding of records when retrieved using CSW. For example: + +- to make record more consistent +- to adapt encoding in order to validate records with INSPIRE rules (eg. as a workaround for workaround for ) + +For this, user can add extra conversion step during output of GetRecords and GetRecordById operation: + +- Adding post process to srv/eng/csw by creating for each output schema a file eg. for gmd, present/csw/gmd-csw-postprocessing.xsl +- Adding post process to a portal inspire/eng/csw by creating for each output schema a file eg. for gmd, present/csw/gmd-inspire-postprocessing.xsl + +For a portal INSPIRE, create an "inspire" portal in the admin --> settings --> sources. User can then setup a post processing phase for the INSPIRE CSW of the portal. Create a post processing file gmd-inspire-postprocessing.xsl in yourschema/present/csw folder. The following example, remove contact with no email and link not starting with HTTP to conform to INSPIRE validator rules. + +``` xml + + + + + + + + + + + + + + + + + + + + +``` + +The service can be tested with: + +``` shell +curl 'http://localhost:8080/geonetwork/inspire/eng/csw' \ + -H 'Content-type: application/xml' \ + --data-binary $'full3de9790e-529f-431f-ac4f-e86d827bde8e\n' +``` diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/application-feedback-link.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/application-feedback-link.png new file mode 100644 index 00000000000..a52132a35dd Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/application-feedback-link.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/application-feedback.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/application-feedback.png new file mode 100644 index 00000000000..fa54aa2317b Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/application-feedback.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/css-result.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/css-result.png new file mode 100644 index 00000000000..2f077a63be0 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/css-result.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/css-screen.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/css-screen.png new file mode 100644 index 00000000000..678fe7513d3 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/css-screen.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/csw-error.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/csw-error.png new file mode 100644 index 00000000000..96fdbb238a4 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/csw-error.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/csw-off.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/csw-off.png new file mode 100644 index 00000000000..bae5454dd32 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/csw-off.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/csw.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/csw.png new file mode 100644 index 00000000000..9314c97407e Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/csw.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/geopublication-add-mapserver.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/geopublication-add-mapserver.png new file mode 100644 index 00000000000..a38da19aea5 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/geopublication-add-mapserver.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-configuration.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-configuration.png new file mode 100644 index 00000000000..4b32f20ede1 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-configuration.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-etf-test-configuration.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-etf-test-configuration.png new file mode 100644 index 00000000000..995b380c54d Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-etf-test-configuration.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-from-registry-config.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-from-registry-config.png new file mode 100644 index 00000000000..6ffa5161b76 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-from-registry-config.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-from-registry.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-from-registry.png new file mode 100644 index 00000000000..2ffce1bdc75 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-from-registry.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-keyword-editing.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-keyword-editing.png new file mode 100644 index 00000000000..c2dd7b92a0c Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-keyword-editing.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-keyword-encoding-type.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-keyword-encoding-type.png new file mode 100644 index 00000000000..87d0e963d00 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-keyword-encoding-type.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-portal.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-portal.png new file mode 100644 index 00000000000..a3cfae9d346 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-portal.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-validation-menu.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-validation-menu.png new file mode 100644 index 00000000000..3b75f591d6b Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-validation-menu.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-validation-report.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-validation-report.png new file mode 100644 index 00000000000..5488a2eb4a6 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/inspire-validation-report.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/log-view.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/log-view.png new file mode 100644 index 00000000000..45ef2998206 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/log-view.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/logos.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/logos.png new file mode 100644 index 00000000000..012c6d16ce5 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/logos.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/metadata-delete.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/metadata-delete.png new file mode 100644 index 00000000000..ae2be2dd2a9 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/metadata-delete.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/metadata-import.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/metadata-import.png new file mode 100644 index 00000000000..00d88f52b9c Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/metadata-import.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/metadata-publication.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/metadata-publication.png new file mode 100644 index 00000000000..f057dec1986 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/metadata-publication.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/metadata_history.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/metadata_history.png new file mode 100644 index 00000000000..a89837bfcbd Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/metadata_history.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/metadata_history_config.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/metadata_history_config.png new file mode 100644 index 00000000000..f6a4860342a Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/metadata_history_config.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/morelikethisconfig.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/morelikethisconfig.png new file mode 100644 index 00000000000..bc215c549b5 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/morelikethisconfig.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-access.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-access.png new file mode 100644 index 00000000000..47c8781dc09 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-access.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-geocatch.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-geocatch.png new file mode 100644 index 00000000000..5c18e4b4a61 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-geocatch.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-header.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-header.png new file mode 100644 index 00000000000..0b3d5c0c8d6 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-header.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-list.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-list.png new file mode 100644 index 00000000000..82def6b62d2 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-list.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-oca-newrecord.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-oca-newrecord.png new file mode 100644 index 00000000000..22a5ea85163 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-oca-newrecord.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-oca-privileges.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-oca-privileges.png new file mode 100644 index 00000000000..3df2e9b26df Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-oca-privileges.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-subportal.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-subportal.png new file mode 100644 index 00000000000..1fdbebb7e81 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-subportal.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-types.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-types.png new file mode 100644 index 00000000000..bbd7f36d3d9 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/portal-types.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/settings.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/settings.png new file mode 100644 index 00000000000..58f98a690ff Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/settings.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/standards.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/standards.png new file mode 100644 index 00000000000..ed742be8ab9 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/standards.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-filter.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-filter.png new file mode 100644 index 00000000000..d7b8699f15d Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-filter.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-footer.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-footer.png new file mode 100644 index 00000000000..16fb041e953 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-footer.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-gazzetteer.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-gazzetteer.png new file mode 100644 index 00000000000..1af02315645 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-gazzetteer.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-homepage.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-homepage.png new file mode 100644 index 00000000000..661ea58f12a Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-homepage.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-humanizedate.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-humanizedate.png new file mode 100644 index 00000000000..99078c8e839 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-humanizedate.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-indent.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-indent.png new file mode 100644 index 00000000000..cba6512f194 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-indent.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-json.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-json.png new file mode 100644 index 00000000000..8de039334a7 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-json.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mappage.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mappage.png new file mode 100644 index 00000000000..626ce0fad85 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mappage.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mappage2.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mappage2.png new file mode 100644 index 00000000000..e63e4ad3e40 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mappage2.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mapprojection.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mapprojection.png new file mode 100644 index 00000000000..5b878fe2bf3 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mapprojection.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mapprojection2.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mapprojection2.png new file mode 100644 index 00000000000..b779dcbca9c Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mapprojection2.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mapprojection3.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mapprojection3.png new file mode 100644 index 00000000000..300cffd40ee Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mapprojection3.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mapprojectionslist.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mapprojectionslist.png new file mode 100644 index 00000000000..3a079191202 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mapprojectionslist.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mapviewer.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mapviewer.png new file mode 100644 index 00000000000..8c2a64f000d Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mapviewer.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mapviewerlayers.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mapviewerlayers.png new file mode 100644 index 00000000000..eea99e98383 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-mapviewerlayers.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-optionaltools.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-optionaltools.png new file mode 100644 index 00000000000..114e5205932 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-optionaltools.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-searchpage.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-searchpage.png new file mode 100644 index 00000000000..c764f5d9244 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-searchpage.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-searchpage2.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-searchpage2.png new file mode 100644 index 00000000000..4fb9e53d575 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-searchpage2.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-searchpage3.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-searchpage3.png new file mode 100644 index 00000000000..55b0cf2d50f Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-searchpage3.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-searchpage4.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-searchpage4.png new file mode 100644 index 00000000000..71b7f3a8b9e Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-searchpage4.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-searchresults.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-searchresults.png new file mode 100644 index 00000000000..39613d720cb Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-searchresults.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-searchresults2.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-searchresults2.png new file mode 100644 index 00000000000..08b01fecdc8 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-searchresults2.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-searchresults3.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-searchresults3.png new file mode 100644 index 00000000000..668f6679ce7 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-searchresults3.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-toptoolbar.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-toptoolbar.png new file mode 100644 index 00000000000..2db6994d944 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-toptoolbar.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-toptoolbarlogo.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-toptoolbarlogo.png new file mode 100644 index 00000000000..b5e2704fd54 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings-toptoolbarlogo.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings.png new file mode 100644 index 00000000000..4a5732100b6 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/ui-settings.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/img/xlink-cache-clear.png b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/xlink-cache-clear.png new file mode 100644 index 00000000000..5966279b4b2 Binary files /dev/null and b/docs/manual/docs/administrator-guide/configuring-the-catalog/img/xlink-cache-clear.png differ diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/index.md b/docs/manual/docs/administrator-guide/configuring-the-catalog/index.md new file mode 100644 index 00000000000..0e84f5ea037 --- /dev/null +++ b/docs/manual/docs/administrator-guide/configuring-the-catalog/index.md @@ -0,0 +1,9 @@ +# Configuring the catalog + +- [System configuration](system-configuration.md) +- [User Interface Configuration](user-interface-configuration.md) +- [Configuring CSS & Style](css-configuration.md) +- [Configuring CSW](csw-configuration.md) +- [Portal configuration](portal-configuration.md) +- [Configuring for the INSPIRE Directive](inspire-configuration.md) +- [Map servers configuration for geopublication](map-server-configuration.md) diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/inspire-configuration.md b/docs/manual/docs/administrator-guide/configuring-the-catalog/inspire-configuration.md new file mode 100644 index 00000000000..b5d9afb4266 --- /dev/null +++ b/docs/manual/docs/administrator-guide/configuring-the-catalog/inspire-configuration.md @@ -0,0 +1,166 @@ +# Configuring for the INSPIRE Directive {#inspire-configuration} + +## Enabling INSPIRE + +From the **Admin console --> Settings** user can configure INSPIRE directive support. + +When enabled, the INSPIRE support activate the following: + +- Enable indexing of INSPIRE themes and annexes (INSPIRE themes thesaurus MUST be added to the list of thesaurus from the INSPIRE Registry - see [Managing thesaurus](../managing-classification-systems/managing-thesaurus.md)). + + ![image](img/inspire-configuration.png) + +To configure the discovery service, a dedicated service metadata record MUST be created in order to provide a complete GetCapabilities document ([CSW Configuration for INSPIRE](csw-configuration.md#csw-configuration_inspire)). + +## Loading INSPIRE codelists + +To describe INSPIRE datasets and series, it is recommended to load relevant codelists from the [INSPIRE Registry](https://inspire.ec.europa.eu/registry/), the following codelists are relevant in the scope of metadata guidelines v2.0: + +- [INSPIRE Theme](https://inspire.ec.europa.eu/theme) +- [Application schema](https://inspire.ec.europa.eu/applicationschema) +- [Media types](https://inspire.ec.europa.eu/media-types) +- Metadata codelist register --> [Protocols](https://inspire.ec.europa.eu/metadata-codelist/ProtocolValue) +- Metadata codelist register --> [Spatial scope](https://inspire.ec.europa.eu/metadata-codelist/SpatialScope) +- Metadata codelist register --> [INSPIRE priority data set](https://inspire.ec.europa.eu/metadata-codelist/PriorityDataset) +- Metadata codelist register --> [Spatial Data Service Category](https://inspire.ec.europa.eu/metadata-codelist/SpatialDataServiceCategory) +- Metadata codelist register --> [Conditions applying to Access and Use](https://inspire.ec.europa.eu/metadata-codelist/ConditionsApplyingToAccessAndUse) +- Metadata codelist register --> [Limitations on Public Access](https://inspire.ec.europa.eu/metadata-codelist/LimitationsOnPublicAccess) +- Metadata codelist register --> [OnLine Description Code](https://inspire.ec.europa.eu/metadata-codelist/OnLineDescriptionCode) +- Metadata codelist register --> [Quality of Service Criteria](https://inspire.ec.europa.eu/metadata-codelist/QualityOfServiceCriteria) + +From `Admin console` --> `Classification systems` --> `Thesaurus`, administrators can manage thesauri. One of the options is to load a thesaurus straight from the registry. + +![image](img/inspire-from-registry.png) + +Click `Use INSPIRE registry` to use the default INSPIRE registry but any instance of the [Registry software](https://joinup.ec.europa.eu/solution/re3gistry) can be used. + +![image](img/inspire-from-registry-config.png) + +Select one or more languages depending on your needs. Choose a category or directly a thesaurus, depending on the thesaurus. By default the type of thesaurus will be `Theme` but you can adapt it if needed. + +By clicking the `Upload` button the catalogue will contact the registry, download the files for each languages and combined them in a thesaurus in SKOS format supported by the catalogue. + +User can also use the well known [GEMET thesaurus](https://www.eionet.europa.eu/gemet/en/themes/). Some SKOS format version of the thesaurus are available [here](https://github.com/geonetwork/util-gemet/tree/master/thesauri). + +Once loaded, a thesaurus can be used in metadata records to select keywords from: + +![image](img/inspire-keyword-editing.png) + +The type of encoding of keywords can be defined using the gear icon (See validation section for more information): + +![image](img/inspire-keyword-encoding-type.png) + +Via the schema plugin form configuration it is an option to configure a thesaurus to be used for a specific `Anchor` element. The thesaures concepts are used to populate an auto complete text field for that element. + +## INSPIRE validation + +INSPIRE validation of metadata records is available at [the INSPIRE Validator](https://inspire.ec.europa.eu/validator/about/). It is using [ETF which is an open source testing framework for spatial data and services](https://github.com/etf-validator/etf-webapp). GeoNetwork is able to `remote validate` any record using a service provided by an instance of ETF. To configure remote validation, go to `Admin console` --> `Settings` and set the URL of the validator. The url of the main INSPIRE validator is `https://inspire.ec.europa.eu/validator/`. + +![image](img/inspire-configuration.png) + +Once enabled, the editor will show the remote validation option in the menu: + +![image](img/inspire-validation-menu.png) + +The standard validate option will use the internal validation system (ie. XSD, Schematron rules for ISO, INSPIRE, \... depending on the configuration). In the internal system the INSPIRE validation is based on INSPIRE Technical guidance version 1.3 and results will be different from ETF reports. + +The remote INSPIRE validation will open the validator in a popup. Choose one of the options depending on the level of validation and type of resource to validate. The list of options can be customized in [this configuration file](https://github.com/geonetwork/core-geonetwork/blob/master/services/src/main/resources/config-spring-geonetwork.xml#L61-L94). The configuration is made by selecting one or more test suite from the ETF options: + +![image](img/inspire-etf-test-configuration.png) + +During the validation, the record is sent to the ETF service and processed. Once ETF completes the validation, the catalogue will display a link to the validation report. + +![image](img/inspire-validation-report.png) + +Note, that if you are validating a private record, that record will be pushed to the validator. To secure this process we recommend to set up a local (private) installation of the validator. + +### Configure validation test suites + +The set of test that runs for each schema can be configured using the file [WEB-INF/config-etf-validator.xml](https://github.com/geonetwork/core-geonetwork/blob/5156bae32d549e6d09cd6a86065791265eb09027/web/src/main/webapp/WEB-INF/config-etf-validator.xml). + +The list of available test suites are defined in the `inspireEtfValidatorTestsuites` bean. It is a map with an entry for each test suite. The `key` attribute is the name of the test suite. Each map entry is an `array` with the tests to execute in the test suite. The value of each array item (``)is the test's title written exactly as defined in the remote INSPIRE validator service. For example: + +``` xml + + + + Conformance class: INSPIRE Profile based on EN ISO 19115 and EN ISO 19119 + Conformance class: XML encoding of ISO 19115/19119 metadata + Conformance class: Conformance class: Metadata for interoperability + + + + + Common Requirements for ISO/TC 19139:2007 based INSPIRE metadata records. + Conformance Class 1: INSPIRE data sets and data set series baseline metadata. + Conformance Class 2: INSPIRE data sets and data set series interoperability metadata. + + + + + Common Requirements for ISO/TC 19139:2007 based INSPIRE metadata records. + + Conformance Class 3: INSPIRE Spatial Data Service baseline metadata. + Conformance Class 4: INSPIRE Network Services metadata. + + + + +``` + +Array's `value-type` attribute must be defined as Java strings: ``. + +To define which test suites will be executed when using the editor dashboard's INSPIRE validation option you can modify the `inspireEtfValidatorTestsuitesConditions` bean. It's a map with an entry for each schema and test suite to execute. The map entry key attribute must be in the format `SCHEMA_ID::TEST_SUITE_NAME`, where `TEST_SUITE_NAME` is one of the `inspireEtfValidatorTestsuites` map entry key. For each entry you can define a XPath condition that the metadata must pass to be sent to the validator. + +!!! note + + If a metadata schema doesn't match, the schema dependency hierarchy is checked to verify if any parent schema matches any rules. + + +!!! warning + + The Xpath must return a node-set or a node to work. XPaths returning a boolean `true` or `false` value will be interpreted as always matching by GeoNetwork. + + +``` xml + + + + + + + +``` + +## INSPIRE access point + +In many cases only a part of the metadata records in a catalog are related to the INSPIRE Directive. In that case, it may be relevant to filter the set of records falling in the scope of the Directive and promote them through a sub portal. In this way a European portal can easily harvest the records related to INSPIRE. + +First define a filtering mechanism to identify the records in the scope of the directive. Frequently used method are: + +- Create a group `INSPIRE` and publish those record in that group (or a category). +- Add a specific keyword in the metadata record. +- Filter based on the conformance quality report having a reference to the EU directive. + +From the `Admin console` --> `Settings` --> `Sources`, an administrator can create a sub portal. Create a portal `inspire` and set the filter to select only records related to INSPIRE (eg. `+_groupPublished:INSPIRE` to select all records published in group INSPIRE). + +![image](img/inspire-portal.png) + +Once saved, the portal is accessible at and the CSW service at . + +## INSPIRE reference documents + +- [INSPIRE IR](https://inspire.ec.europa.eu/) +- [INSPIRE Technical Guidelines Metadata v2.0.1](https://inspire.ec.europa.eu/sites/default/files/documents/metadata/inspire-tg-metadata-iso19139-2.0.1.pdf) +- [INSPIRE validator](https://inspire.ec.europa.eu/validator/) +- [GeoNetwork at the INSPIRE forum](https://inspire.ec.europa.eu/forum/search?q=geonetwork) diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/map-server-configuration.md b/docs/manual/docs/administrator-guide/configuring-the-catalog/map-server-configuration.md new file mode 100644 index 00000000000..07924ce61f8 --- /dev/null +++ b/docs/manual/docs/administrator-guide/configuring-the-catalog/map-server-configuration.md @@ -0,0 +1,21 @@ +# Map servers configuration for geopublication {#map-server-configuration} + +To publish information from the catalog as OGC services (WMS, WFS, WCS), catalog administrator need to register one or more map servers to publish on. Map servers MUST support the GeoServer REST API in order to work with the catalog. The 2 following implementations have been tested: + +- [GeoServer](https://geoserver.org) +- [Mapserver](https://mapserver.org) and [Mapserver REST API](https://github.com/neogeo-technologies/mra) + +Setup you map server and then register it from the administration interface: + +![](img/geopublication-add-mapserver.png) + +The following parameters are required: + +- Name: The map server label which will be displayed when geopublishing information. +- Description: The map server description. +- REST API configuration: The URL of the service providing access to the remote configuration using the REST API. +- Username and password to be used to connect to the REST API. +- Workspace prefix and URL: The workspace information in which data will be pushed into. +- WMS/WFS/WCS service URL: URLs of services which will be used when adding references to the services in the metadata record after publication. + +See [Publishing GIS data in a map server](../../user-guide/workflow/geopublication.md). diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/portal-configuration.md b/docs/manual/docs/administrator-guide/configuring-the-catalog/portal-configuration.md new file mode 100644 index 00000000000..817698f063b --- /dev/null +++ b/docs/manual/docs/administrator-guide/configuring-the-catalog/portal-configuration.md @@ -0,0 +1,110 @@ +# Portal configuration + +Portals can be configured under the `sources` section in `admin console` --> `settings`. + +![](img/portal-access.png) + +There are 3 types of sources: + +- the main catalogue, +- sub-portal, which can be a subset of the main catalogue +- harvesters. + +![](img/portal-types.png) + +The main catalogue corresponds to the current installation. + +When harvesting, at least one source is created to represent the harvester. When harvesting from another GeoNetwork node, sources from the target catalogue are also harvested to keep track of the true origin of records. This only applies to the GeoNetwork protocols which use MEF ([Metadata Exchange Format (MEF)](../../annexes/mef-format.md)) which contain the source catalogue information. + +The last type is sub-portal, which is described in details below. + +## Configuring a sub-portal + +Sub-portals can be used to create a space in the main catalogue only focusing on a subset of records. + +A sub-portal is defined by: + +![](img/portal-subportal.png) + +When creating a sub-portal with an identifier `ìnspire` for example, a new entry point on your catalogue will be available: . Accessing the catalogue through it will only provide access to records matching the filter defined for this sub-portal. The `search filter` parameter value uses the Lucene query parser syntax (see ) and is applied to all searches. + +User privileges apply as in the main instance. + +The logo and name of the sub-portal will be displayed instead of the main instance information in case the option `Display in the portal switcher` is selected: + +![](img/portal-header.png) + +A CSW service is also available for this sub-portal (and replacing the virtual CSW feature). + +A sub-portal can also use a specific user interface configuration. + +The list of sub-portal available is at + +![](img/portal-list.png) + +## Example of usage + +To find the lucene element terms available for filtering you can query a record in your ElasticSearch instance: + +`POST /gn-records*/_search +{"query":{"query_string":{"query":"+uuid:\"EXT_DS120344\""}}}` + +This shows elements such as keywords are grouped together under a "tag" element. A tag element in a multilingual catalogue looks something like this: +``` +"tag" : [ + { + "default" : "BIRDS", + "langeng" : "BIRDS" + }, + { + "default" : "MARINE", + "langeng" : "MARINE", + "key" : "https://registry.geonetwork-opensource.org/theme/nrw-keywords/marine-uc" + }, +... +] +``` + +You can use the lucene search `+tag.default:"BIRDS"` as the filter for a sub-portal. + +### Creating an INSPIRE directive sub-portal + +For the INSPIRE directive, a catalogue administrator needs to publish an entry point providing access only to INSPIRE related records. An INSPIRE sub-portal can be created with a filter on keywords `+thesaurusName:"GEMET - INSPIRE themes, version 1.0"`. + +### Creating a sub-portal for partners + +Some organizations need to open the catalogue to a set of partners. In such cases, each partner generally accesses the catalogue and creates their records in dedicated groups. A good example is providing a main search filter `catalogue`. + +![](img/portal-geocatch.png) + +The concept of a sub-portal allows the possibility of creating a dedicated URL for each partner. The header can contain the partner identification with name and logo. Optionally the user interface can also be customized (see [User Interface Configuration](user-interface-configuration.md)). + +To setup this kind of configuration, the basic principle is to have: + +- One group for each partner with one or more users +- One sub-portal for each partner with a filter matching records in that group + +To configure this, apply the following steps: + +- Create a group for the partner eg. `oca` (see [Creating group](../managing-users-and-groups/creating-group.md)). +- Create at least one user for the partner (see [Creating user](../managing-users-and-groups/creating-user.md)). The user must be member of the group `oca`. If you want the user to be able to configure the sub-portal (eg. change the name, choose a logo), the user must have at least the `UserAdmin` profile for the group `oca`. +- Create a sub-portal. This can have the same name as the group, eg. `oca` but this is not essential. The filter can be created using the fact that a record published in the group `oca` should be in this sub-portal, using the syntax `+_groupPublished:oca`. Once created the sub-portal is accessible at . +- (Optional) Link the sub-portal to a user admin group to allow `UserAdmin` to configure their sub-portal. + +With this type configuration, ie. one partner = one group = one sub-portal and users are only member of one group, then when connecting to a partner sub-portal: + +- user will only see records published in that group in the entire application +- when creating new records, no group selection is provided because user is member of one group only + +![](img/portal-oca-newrecord.png) + +Remember that a record is visible in the `oca` sub-portal because it is published in the group `oca`: + +![](img/portal-oca-privileges.png) + +If the `publish` operation is removed from `oca` group, then records will not longer be visible in that sub-portal. + +In some situations, you also want to share templates among partners. There are 2 options for this: + +- Publish the template in all partner's groups. The main drawback in this case is that if a new group is added, the templates need to be published to that new group. +- Create a dedicated group for shared records eg. `sharedGroup`. Publish templates in that shared space. Alter the sub-portal filter to match either the partner group or the shared one. `+groupPublished:(oca OR sharedGroup)`. diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/system-configuration.md b/docs/manual/docs/administrator-guide/configuring-the-catalog/system-configuration.md new file mode 100644 index 00000000000..d56eb454ffa --- /dev/null +++ b/docs/manual/docs/administrator-guide/configuring-the-catalog/system-configuration.md @@ -0,0 +1,254 @@ +# System configuration + +Most of the system configuration parameters can be changed by administrator users using the web interface in `Admin console` --> `Settings`. + +!!! info "Important" + + Configuration of these parameters is critically important for the catalog in an operational context. Misunderstanding some settings may result in a system that does not function as expected. For example, downloads may fail to be correctly processed, or metadata harvesting from other servers may not work. + + +![](img/settings.png) + +Since the settings form is a long form, the `save` button is repeated between the sections and will save all settings. + +## Catalog description + +- **Catalog name** The name of the node. Information that helps identify the catalogue to a human user. The name is displayed on the banner, in the CSW GetCapabilities. +- **Catalog identifier** A universally unique identifier (uuid) that distinguishes your catalog from any other catalog. This a unique identifier for your catalogue and its best to leave it as a uuid. It will be used by harvester using GeoNetwork protocol to identify the source catalog. +- **Organization** The organization the node belongs to. Again, this is information that helps identify the catalogue to a human user. +- **SVN UUID** Subversion repository attached to the node. This identifier is created and/or checked on startup to verify that the database match the SVN repository. The repository is used for metadata versioning. + +## Catalog + +- **Version** The version of the catalog (readonly, version of the database) +- **Minor version** The minor version of the catalog (readonly, version of the database) + +## Catalog Server {#system-config-server} + +- **Host** The node's name or IP number (without ). For example, they are used during metadata editing to create resource links and when returning the server's capabilities during a CSW request. + - If your node is publicly accessible from the Internet, you have to use the domain name. + - If your node is hidden inside your private network and you have a firewall or web server that redirects incoming requests to the node, you have to enter the public address of the firewall or web server. A typical configuration is to have an Apache web server on address A that is publicly accessible and redirects the requests to a Tomcat server on a private address B. In this case you have to enter A in the host parameter. +- **Port** The server's port number (usually 80 or 8080). If using HTTP, set it to 80. +- **Preferred Protocol** Defined the protocol to access the catalog. The HTTP protocol used to access the server. Choosing http means that all communication with the catalog will be visible to anyone listening to the protocol. Since this includes usernames and passwords this is not secure. Choosing https means that all communication with the catalog will be encrypted and thus much harder for a listener to decode. +- **Log level** Define the logging level of the application. After modification, log can be checked in the `Statistics & status` section under `Activity`. + +![](img/log-view.png) + +## Intranet parameters + +A common need for an organisation is to automatically discriminate between anonymous internal users that access the node from within an organisation (Intranet) and anonymous external users from the Internet. The catalog defines anonymous users from inside the organisation as belonging to the group *Intranet*, while anonymous users from outside the organisation are defined by the group *All*. To automatically distinguish users that belong to the Intranet group you need to tell the catalog the intranet IP address and netmask. + +- **Network** The intranet address in IP form (eg. 147.109.100.0). It can be a comma separated list of IP addresses. +- **Netmask** The intranet netmask (eg. 255.255.255.0). Define as many netmask and IP addresses. + +If intranet parameters are empty, the group *Intranet* will not be displayed in the sharing panel. + +## Proxy server + +The settings page offers to set the configuration of a proxy server. This configuration is used by the application to access the internet to get online resources, for example as part of a harvest process. + +- **Use proxy** Enable the proxy in case the catalog is behind a proxy and need to use it to access remote resources. +- **Proxy Host** The proxy IP address or name +- **Port** The proxy port +- **Proxy username** The username +- **Proxy user password** The username password +- **Ignore host list** To bypass specific hosts enter a specific IP address or host name such as www.mydomain.com or an address range using wildcards, such as 192.168.2.*. Use | to separate the different host values. + +JVM proxy parameters may also be required to properly set the proxy for all remote access. + +## Feedback {#system-config-feedback} + +Email may be sent by the catalog. + +- you are using the User Self-registration system +- you are using the metadata status workflow (See [Life cycle](../../user-guide/workflow/life-cycle.md)) +- a file uploaded with a metadata record is downloaded and notify privilege is selected + +This section configure the mail server to use. + +- **Email** This is the administrator's email address used to send feedback. +- **SMTP host** The mail server name or IP address to use for sending emails. +- **SMTP port** The SMTP port. +- **Use SSL** Enable SSL mode +- **User name** Username if connection is required on the SMTP server +- **Password** Username password if connection is required on the SMTP server + +## Metadata search results + +Configuration settings in this group determine what the limits are on user interaction with the search results. + +- **Maximum Selected Records** The maximum number of search results that a user can select and process with the batch operations eg. Set Privileges, Categories etc. This parameter avoid to trigger long action which could generate out of memory error. + +## Catalog Service for the Web (CSW) + +See [Configuring CSW](csw-configuration.md). + +## Shibboleth + +See [Configuring Shibboleth](../managing-users-and-groups/authentication-mode.md#authentication-shibboleth). + +## User self-registration + +Enable the self registration form. See [User Self-Registration](../managing-users-and-groups/user-self-registration.md). + +You can configure optionally re-Captcha, to protect you and your users from spam and abuse. And a list of email domains (separated by commas) +that can request an account. If not configured any email address is allowed. + +## User application feedback + +Enabling the setting, displays in the application footer a link to a page that allows sending comments about the application. + +![](img/application-feedback-link.png) + +![](img/application-feedback.png) + +It requires an email server configured. + +## Link in metadata records + +!!! warning "Deprecated" + + 3.0.0 Defined by the formatter. + + +## Metadata rating + +If enabled, the catalog will calculate user ratings for metadata from this node only (not distributed among other GeoNetwork nodes). This only applies to records harvested using the GeoNetwork protocol. + +## Metadata XLink {#xlink_config} + +The XLink resolver replaces the content of elements with an attribute @xlink:href (except for some elements like srv:operatesOn) with the content obtained from the URL content of @xlink:href. The XLink resolver should be enabled if you want to harvest metadata fragments or reuse fragments of metadata in your metadata records (eg. when using a contact directory). + +- **Enable XLink resolution**: Enables/disables the XLink resolver. +- **Enable local XLink** Local XLinks are using local:/// URL to make references to related sections instead of HTTP URL. Local XLinks are usually faster than HTTP XLinks. + +!!! info "See Also" + + To improve performance the catalog will cache content that is not in the local catalog. Clear the cache of XLink from the `Admin console` --> `Tools` if the fragments were updated. + + +![](img/xlink-cache-clear.png) + +## Metadata update + +For each metadata schema, the catalog has an XSL transformation (`update-fixed-info.xsl`) that it can apply to a metadata record belonging to that schema. The aim of this transformation is to allow fixed schema, site and catalog information to be applied to a metadata record every time the metadata record is saved in the editor. As an example, this transformation is used to build and store the URL of any files uploaded and stored with the metadata record in the editor. + +- **Automatic Fixes**: Enabled by default. It is recommended you do not use the metadata editor when auto-fixing is disabled. See for more details. + +## Search Statistics {#search_stats_config} + +Enables/disables search statistics capture. Search statistics are stored in the database and can be queried using the `Search Statistics` page. + +There is very little compute overhead involved in storing search statistics as they are written to the database in a background thread. However database storage for a very busy site must be carefully planned. + +## Open Archive Initiative (OAI-PMH) Provider + +Options in this group control the way in which the OAI Server responds to OAIPMH harvest requests from remote sites. + +- **Datesearch**: OAI Harvesters may request records from GeoNetwork in a date range. GeoNetwork can use one of two date fields from the metadata to check for a match with this date range. The default choice is *Temporal extent*, which is the temporal extent from the metadata record. The other option, *Modification date*, uses the modification date of the metadata record in the GeoNetwork database. The modification date is the last time the metadata record was updated in or harvested by GeoNetwork. +- **Resumption Token Timeout**: Metadata records that match an OAI harvest search request are usually returned to the harvester in groups with a fixed size (eg. in groups of 10 records). With each group a resumption token is included so that the harvester can request the next group of records. The resumption token timeout is the time (in seconds) that GeoNetwork OAI server will wait for a resumption token to be used. If the timeout is exceeded GeoNetwork OAI server will drop the search results and refuse to recognize the resumption token. The aim of this feature is to ensure that resources in the GeoNetwork OAI server are released. +- **Cache size**: The maximum number of concurrent OAI harvests that the GeoNetwork OAI server can support. + +Restart the catalog to take all OAI settings into account. + +## INSPIRE Directive configuration + +See [Configuring for the INSPIRE Directive](inspire-configuration.md). + +## INSPIRE Atom Feed + +Allows to define the configuration of Atom Feeds referenced by the metadata to provide services related to the [INSPIRE technical guidance for download services](https://inspire.ec.europa.eu/documents/Network_Services/Technical_Guidance_Download_Services_3.0.pdf): + +- Select the type of atom feed: + + - Remote: retrieve the atom feeds referenced by the metadata in the online resources. + - Local (to implement in future versions): create the atom feed using the metadata content. + +- Schedule for feed retrieval: the retrieval of the atom feeds can be scheduled to be done periodically. + +- Atom protocol value: value of the protocol in the metadata online resources to identify the atom feed resources (the default value is INSPIRE Atom). GeoNetwork identifies an Atom file from other resources by looking at the protocol value of the onlineresource. Since there is no general accepted value for this protocol, GeoNetwork allows an administrator to set the value to be used as protocol identifying Atom resources: + + + + + + + http://geodata.nationaalgeoregister.nl/atom/index.xml + + + INSPIRE Atom + + + + + + +The following services are available: + +- +- +- +- +- + +In above URLs {UUID} is the fileidentifier of the download service metadata. + +In the service feed of your download service make sure to add the GeoNetwork OpenSearch endpoint as the OpenSearchDescription for the service: + + + +The INSPIRE Atom/OpenSearch implementation can be verified with the Atom tests in Esdin Test Framework () or INSPIRE metadata validator (). + +## Multi-Threaded Indexing + +Configuration settings in this group determine how many processor threads are allocated to indexing tasks in GeoNetwork. If your machine has many processor cores, you can now determine how many to allocate to GeoNetwork indexing tasks. This can bring dramatic speed improvements on large indexing tasks (eg. changing the privileges on 20,000 records) because GeoNetwork can split the indexing task into a number of pieces and assign them to different processor cores. + +*Number of processing threads* The maximum number of processing threads that can be allocated to an indexing task. + +Note: this option is only available for databases that have been tested. Those databases are PostGIS and Oracle. You should also carefully consider how many connections to the database you allocate in the database configuration as each thread could tie up one database connection for the duration of a long indexing session (for example). See the advanced configuration for more details of how to configure the number of connections in the database connection pool. + +## Metadata Privileges + +*Only set privileges to user's groups*: If enabled then only the groups that the user belongs to will be displayed in the metadata privileges page (unless the user is an Administrator). At the moment this option cannot be disabled and is likely to be deprecated in the next version of GeoNetwork. + +## Metadata import {#editing_harvested_records} + +- **Restrict import to schemas** List of all allowed schemas for metadata to be imported. If the metadata schema is not allowed, then the import is not done. Use an empty value to allow all schemas. +- **Minimum user profile allowed to import metadata** Minimum user profile allowed to import metadata (`Editor`, `Reviewer` or `Administrator`). The default value is `Editor`. + +![](img/metadata-import.png) + +## Metadata delete + +Allows to configure the user profile allowed to delete published metadata. + +- **Minimum user profile allowed to delete published metadata** Minimum user profile allowed to delete metadata (`Editor`, `Reviewer` or `Administrator`). The default value is `Editor`. + +![](img/metadata-delete.png) + +## Metadata publication + +Allows to configure the user profile allowed to publish and un-publish metadata. + +- **Minimum user profile allowed to publish metadata** Minimum user profile allowed to publish metadata (`Reviewer` or `Administrator`). The default value is `Reviewer`. +- **Minimum user profile allowed to un-publish metadata** Minimum user profile allowed to un-publish metadata (`Reviewer` or `Administrator`). The default value is `Reviewer`. + +![](img/metadata-publication.png) + +## Metadata History + +Allows to view metadata history + +![](img/metadata_history.png) + +- **Minimum user profile allowed to view metadata history** Minimum user profile allowed to delete metadata (`Registered User`, `Editor` or `Administrator`). The default value is `Editor`. +![](img/metadata_history_config.png) + +- **Registered User Configuration** The user who has granted view permission to the metadata record can view the history. +- **Editor Configuration** The user who has granted editing permission to the metadata record can view the history. +- **Administrator Configuration** The user who has granted system administrator permission can view the history. + +## Harvesting + +*Allow editing on harvested records*: Enables/Disables editing of harvested records in the catalogue. By default, harvested records cannot be edited. diff --git a/docs/manual/docs/administrator-guide/configuring-the-catalog/user-interface-configuration.md b/docs/manual/docs/administrator-guide/configuring-the-catalog/user-interface-configuration.md new file mode 100644 index 00000000000..9f3072a7657 --- /dev/null +++ b/docs/manual/docs/administrator-guide/configuring-the-catalog/user-interface-configuration.md @@ -0,0 +1,259 @@ +# User Interface Configuration + +Most of the configuration parameters for the user interface can be changed by an administrator using the web interface in `Admin console` --> `Settings` --> `User Interface`. + +!!! info "Important" + + Configuration of these parameters is critically important for the catalog in an operational context. Misunderstanding some settings may result in a system that does not function as expected. For example, the map can become unusable. + + +![](img/ui-settings.png) + +By default the catalog will use the default UI configuration, named `srv`. To view and edit the settings for this configuration, choose `Create a default UI configuration`. + +To add a new configuration, such as for a sub-portal (see [Portal configuration](portal-configuration.md)) choose `Add new UI configuration` and choose one or more portal identifiers from the dropdown list `UI Configuration identifier`. Additional configurations can also be used for building an external JS application, which is able to load a specific configuration. + +!!! note + + Since the settings form is a long form, the `save` button is repeated at the base of the page. In either case, all settings are saved. + + +- **Filter settings**: This search box can be used to filter settings in the form, for example searching for "social" will show only the settings related to the Social bar. + +![](img/ui-settings-filter.png) + +## General options + +- **Humanize dates**: check this box to show dates in a human-friendly format. If not set, the full date will be shown. + +![](img/ui-settings-humanizedate.png) + +## Footer {#user-interface-config-footer} + +- **Footer**: Select this checkbox to determine whether the GeoNetwork footer is shown. If not set, no footer will be visible. +- **Social bar**: Select this check box to show the social media bar in the footer. + +![](img/ui-settings-footer.png) + +## Top Toolbar {#user-interface-config-toptoolbar} + +- **Top toolbar**: Select this check box to determine whether the GeoNetwork top toolbar will be shown. If not set, no toolbar will be visible. +- **List of languages**: Choose the languages from the list that should be available for translating the interface strings (available from the dropdown list in the top toolbar). If only one language remains, then no dropdown will be shown. Note that additional languages can be added, if translations are available, by selecting the `+` button below the list and adding the appropriate ISO codes. + +![](img/ui-settings-toptoolbar.png) + +- **Show the logo in the header**: This determines where the catalog logo should be positioned. If selected, the logo will be positioned in the header, above the top toolbar and the toolbar logo (default) removed. If unset, the logo will appear in the top toolbar. +- **Position of logo**: These options determine where on the header the logo will be positioned. + +![](img/ui-settings-toptoolbarlogo.png) + +## Home Page {#user-interface-config-homepage} + +- **Home page**: Select this check box to determine whether the Logo and Link to the Home Page are visible in the top toolbar. If not set, no logo and link is shown. +- **Application URL**: Define the URL for the home page. In the majority of cases this can be left as the default. +- **Fluid container for Home and Search**: Select this check box to determine whether the search box is full width in the browser page or if it is fixed width and centred. + +![](img/ui-settings-homepage.png) + +## Search application {#user-interface-config-searchpage} + +- **Search application**: Select this check box to determine whether the search application is visible in the top toolbar. If not set, no link is shown. +- **Application URL**: Define the URL for the search application. In the majority of cases this can be left as the default. +- **Number of records per page**: Define the options to determine the number of records shown per page of results, and the default. +- **Facet configuration**: See [Configuring faceted search](../../customizing-application/configuring-faceted-search.md)). The configuration are defined using JSON following Elasticsearch API (See . + +![](img/ui-settings-searchpage.png) + +- **Facet field to display using tabs**: This option creates a tab for each configured facet above the search results. This can be used to further narrow down the search results. +- **Filters**: Define additional search criteria added to all searches and again are used primarily for external applications and sub-portals. +- **Type of sort options**: Define the different ways by which a user can sort a set of search results. The **default sort by option** is shown below. Note that to search for example on `title` in alphabetical order it is necessary to set the order to `reverse`. +- **List of templates for search results**: This section allows the administrator to configure templates for the layout of the search results. The default is `grid` whereas `list` is the default for the editor board. + +![](img/ui-settings-searchpage3.png) + + +- **Similar records** or **More like this**: Define the query used to search for similar records that are displayed at the bottom of the record view. + +![](img/morelikethisconfig.png) + + +- **Default template used for search results**: Define the template page for the search. Generally this can be left as the default. +- **List of formatter for record view**: Determine the formatter used to display the search results. See [Customizing metadata views](../../customizing-application/creating-custom-view.md) for information on creating a new formatter. To add an additional view, click the blue `+` button below the list and provide a name and a URL. + +![](img/ui-settings-searchpage3.png) + +### Search results configuration {#user-interface-config-searchresults} + +- **Related metadata types to query**: Use this section to define the metadata types displayed when showing search results in the grid. format To add additional types, click the blue `+` button. The possible types are shown below the form. + +![](img/ui-settings-searchresults.png) + +### List of link types {#user-interface-config-linktypes} + +- **Links**: This section determines the types of links displayed when showing search results in the grid format. They are separated into `links`, `downloads`, `layers` and `maps` and for each type, a new entry can be added by clicking the blue `+` button below the list. + +![](img/ui-settings-searchresults2.png) + +- **Display filter tags in the search results**: When checked, the filter tags are visible above the search results. The default is to not show them. + +### User custom searches {#user-interface-customsearches} + +- **Enabled**: If checked the user will have the ability to create and save custom searches in the search tab. This functionality will be visible above the facets list on the left. +- **Display featured user searches panel in home page**: If this is also enabled, an additional tab will be shown on the home page alongside `Latest news` and `Most popular`. + +### Saved Selections + +- **Enabled**: If checked the user will have the ability to save a selection of records in the search tab. + +![](img/ui-settings-searchresults3.png) + +## Map Application {#user-interface-config-mappage} + +This section describes how an administrator can configure the different maps in the user interface (the main map, the mini map displayed on the search result page, and the map used in the editor to draw an extent). + +- **Map Application**: The initial checkbox allows the main map tab to be disabled. In this case there will be no map tab shown in the top toolbar but the mini map and extent map described above will still be visible. +- **Application URL**: This defines the URL for the map tab. In the majority of cases this can be left as the default. + +### External viewer + +- **Use an external viewer**: This option allows a third party mapping application to be used in place of the default GeoNetwork map. In this case, most of the settings below will no longer be used. +- **Allow 3D mode**: If enabled, the user has the option to switch to 3D mode in the main map (see [Quick start](../../user-guide/quick-start/index.md)). +- **Allow users to save maps as metadata record**: This option enables users to save layers and base maps configuration as a record in the catalog. Optionally users can add a title and an abstract. +- **Export map as image**: If enabled, users can export the map as an image but requires CORS to be enabled on any external WMS services displayed on the map. This option is disabled by default to avoid issues with WMS layers. + +![](img/ui-settings-mappage.png) + +- **User preference persistence**: This option determines the behaviour of cookies related to the map. The various options are listed below. +- **Bing Map Key**: If this option is filled in, then it is possible to use Bing Maps as base layers within the map application. You must get your own key for this to work. + +![](img/ui-settings-mappage2.png) + +### List of preferred OGC services + +Default **wms** and **wmts** services can be defined here that will be available by default to the end user. New services can be added using the blue `+` button below the protocol lists. + +You can configure each map with different layers and projections. + +- **Map Projection** This is the default projection of the map. Make sure the projection is defined in **Projections to display maps into** below. + + ![](img/ui-settings-mapprojection.png) + +- **List of map projections to display bounding box coordinates in** This is used in the map when editing a record and defining the bounding box extent. Make sure the listed projections are defined in **Projections to display maps into** below. Note that the coordinates will be stored in WGS84 regardless of the projection used to draw them. + + ![](img/ui-settings-mapprojectionslist.png) + +- **Projections to display maps into** This is where the different projections available to the map are defined. All projections will be shown in the `Projection Switcher` tool of the map. + + ![](img/ui-settings-mapprojection2.png) + + In order to enable a new projection it must be defined here using the **proj4** syntax, which can be found for many EPSG-listed projections at, for example, . Additionall, the default bounding box extent, maximum bounding box extent and allowed resolutions (if required) can be defined. + + Ensure that the coordinates inserted are in the correct units for the projection and are local to the projection. A list of resolutions is only relevant if the main map layer has a XYZ source that does not follow the common tiling pattern. + + Check that this configuration is valid by opening the map. + + ![](img/ui-settings-mapprojection3.png) + + !!! info "Important" + + If the configuration of a projection is incomplete or invalid, the map may fail to load. + + + If a projection is defined which is not supported by the source of the map layer, the map application will reproject map images at the client side. This may cause unexpected behaviour, such as rotated or distorted labels. + +- **Optional Map Viewer Tools** The checkboxes in this section define the tools available to the user in the right toolbar of the main map. Elements that are not checked are not visible. +- **OGC Service to use as a graticule**: This is optional and allows the use of an external service to display the graticule on the map. + +### Viewer Map Configuration {#user-interface-config-viewermap} + +This section is for configuring the map shown when viewing a record. + +- **Path to the context file (XML)**: An optional path to an XML file defining base layers and other configuration options. See `web/src/main/webapp/WEB-INF/data/data/resources/map/config-viewer.xml` for an example. +- **Extent, expressed in current projection**: Use this option to override the extent defined in the context file. + +![](img/ui-settings-mapviewer.png) + +- **Layer objects in JSON**: Define additional layers to be shown on the map using JSON syntax. The supported types are: + - **wms**: generic WMS layer, required properties: `name, url`. + - **wmts**: generic WMTS layer, required properties: `name, url`. + - **tms**: generic TMS layer, required property: `url`. + - **osm**: OpenStreetMap default layer, no other property required. + - **bing_aerial**: Bing Aerial background, required property: `key` containing the license key. + +![](img/ui-settings-mapviewerlayers.png) + +All layers can also have some optional extra properties: + +- **title** The title/label of the layer. +- **projectionList** Projection array to restrict this layer to certain projections on the map. + +Examples of layers: + + +This WMS layer will be shown but only when the map is on `EPSG:4326`: + +``` json +{"type":"wms","title":"OI.OrthoimageCoverage","name":"OI.OrthoimageCoverage", +"url":"http://www.ign.es/wms-inspire/pnoa-ma?request=GetCapabilities&service=WMS", +"projectionList":["EPSG:4326"]} +``` + +### Search Map Configuration + +This section defines the configuration for the mini map shown on the search page. It uses the same options as in [Viewer Map Configuration](user-interface-configuration.md#user-interface-config-viewermap). + +### Editor Map Configuration + +This section defines the configuration for the map shown when editing a record. It uses the same options as in [Viewer Map Configuration](user-interface-configuration.md#user-interface-config-viewermap). + +## Gazetteer + +- **Gazetteer**: If enabled a gazetteer will be shown in the top left of the main map. +- **Application URL**: Set the application URL used for the gazetteer. In general this should be left as the default, but additional filtering can be applied using the syntax described at , for example to restrict results to a particular country (`country=FR`). + +![](img/ui-settings-gazzetteer.png) + +## Record View + +- **Record view**: +- **Show Social bar**: If enabled, the social media bar is enabled in record view. + +## Editor Application + +- **Editor application**: If enabled the editor page, or contribute tab is available to users with the appropriate privileges. If not enabled the contribute tab is not shown in the top toolbar. +- **Application URL**: This is the URL to the editor application and can generally be left as the default. +- **Only my records**: If this checkbox is enabled then the "Only my records" checkbox in the editor dashboard will be checked by default. +- **Display filters in dashboard**: If enabled, the currently selected facets will be shown above the search results in both the editor dashboard the batch editor page. +- **Fluid container for the Editor**: If enabled, the editor application will have a full width container. If disabled it will have a fixed width and centered container. +- **New metadata page layout**: Choose from the options for the layout of the `add new metadata` page. The default is `Horizontal` but a vertical layout can be chosen, or a custom layout based on a supplied template. +- **Editor page indent type**: Choose from the options for the indent style when editing a record. The default is for minimal indents, select `Colored indents` to use the style shown below: + +![](img/ui-settings-indent.png) + +## Admin console + +- **Admin console**: +- **Application URL**: Set the application URL for the admin console. In general this should be left as the default. + +## Sign in application + +- **Sign in application**: +- **Application URL**: Set the application URL for the sign in page. In general this should be left as the default. + +## Sign out application + +- **Application URL**: Set the application URL for the sign out. In general this should be left as the default. + +## Search application + +- **Search application**: +- **Application URL**: Set the application URL for the search page. In general this should be left as the default. + +## JSON Configuration + +This section shows the JSON configuration for the currently applied User Interface settings. From here, the JSON can be saved to a file (by copying and pasting). + +- **Test client configuration**: Click this button to test the configuration in a new browser tab. +- **Reset configuration**: Click this button to reset the configuration back to the default. Note that this will revert any changes you have made in the above page. + +![](img/ui-settings-json.png) diff --git a/docs/manual/docs/administrator-guide/img/admin.png b/docs/manual/docs/administrator-guide/img/admin.png new file mode 100644 index 00000000000..ff06c848dbb Binary files /dev/null and b/docs/manual/docs/administrator-guide/img/admin.png differ diff --git a/docs/manual/docs/administrator-guide/index.md b/docs/manual/docs/administrator-guide/index.md new file mode 100644 index 00000000000..7d2a75603e7 --- /dev/null +++ b/docs/manual/docs/administrator-guide/index.md @@ -0,0 +1,10 @@ +# Administrator guide + +- [Configuring the catalog](configuring-the-catalog/index.md) +- [Managing users and groups](managing-users-and-groups/index.md) +- [Managing classification system](managing-classification-systems/index.md) +- [Managing metadata & template](managing-metadata-standards/index.md) + +![](img/admin.png) + +All Admin functions are available from the Admin Dashboard from the main menu. On the Admin Dashboard you will find shortcuts to any administration option your role can access. diff --git a/docs/manual/docs/administrator-guide/managing-classification-systems/img/categories.png b/docs/manual/docs/administrator-guide/managing-classification-systems/img/categories.png new file mode 100644 index 00000000000..60919d7be78 Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-classification-systems/img/categories.png differ diff --git a/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-api-collect.png b/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-api-collect.png new file mode 100644 index 00000000000..d5a2f913eed Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-api-collect.png differ diff --git a/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-api-synch.png b/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-api-synch.png new file mode 100644 index 00000000000..dbb4244b346 Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-api-synch.png differ diff --git a/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-cache.png b/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-cache.png new file mode 100644 index 00000000000..c1bb06ffe0f Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-cache.png differ diff --git a/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-editor-popup.png b/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-editor-popup.png new file mode 100644 index 00000000000..02c293c383c Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-editor-popup.png differ diff --git a/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-editor-popupopen.png b/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-editor-popupopen.png new file mode 100644 index 00000000000..6a01da316e8 Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-editor-popupopen.png differ diff --git a/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-import.png b/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-import.png new file mode 100644 index 00000000000..efd3373fe80 Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-import.png differ diff --git a/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-manager.png b/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-manager.png new file mode 100644 index 00000000000..0b0242abeed Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-manager.png differ diff --git a/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-search.png b/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-search.png new file mode 100644 index 00000000000..b10d8fba12c Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-classification-systems/img/directories-search.png differ diff --git a/docs/manual/docs/administrator-guide/managing-classification-systems/index.md b/docs/manual/docs/administrator-guide/managing-classification-systems/index.md new file mode 100644 index 00000000000..b7cbca16ebe --- /dev/null +++ b/docs/manual/docs/administrator-guide/managing-classification-systems/index.md @@ -0,0 +1,5 @@ +# Managing classification system + +- [Managing categories](managing-categories.md) +- [Managing directories](managing-directories.md) +- [Managing thesaurus](managing-thesaurus.md) diff --git a/docs/manual/docs/administrator-guide/managing-classification-systems/managing-categories.md b/docs/manual/docs/administrator-guide/managing-classification-systems/managing-categories.md new file mode 100644 index 00000000000..6afc42ce6fe --- /dev/null +++ b/docs/manual/docs/administrator-guide/managing-classification-systems/managing-categories.md @@ -0,0 +1,9 @@ +# Managing categories + +GeoNetwork has a concept of categories that can be assigned to metadata documents, but these are not represented in the metadata. So when the metadata is exported, the category will be lost. You can use these categories to separate documents into groups, without changing the actual content of the metadata. Categories can be used to filter a search result, or limit the output of a custom csw endpoint. + +To assign a category to a metadata document. Go to the metadata modification form and select the requested category from the pull down in the menu. Then save your metadata. + +To modify the available categories in the catalog, from the admin page, open the "classification systems" and then the "category" tab. + +Note: If you add or modify categories, they may not obtain an appropriate icon. These icon are managed in `/catalog/style/gn_icons.less`. In this file category-classes are mapped to font-awesome variables that map to a certain [font-awesome icon](https://fontawesome.io). diff --git a/docs/manual/docs/administrator-guide/managing-classification-systems/managing-directories.md b/docs/manual/docs/administrator-guide/managing-classification-systems/managing-directories.md new file mode 100644 index 00000000000..19ffb269aac --- /dev/null +++ b/docs/manual/docs/administrator-guide/managing-classification-systems/managing-directories.md @@ -0,0 +1,196 @@ +# Managing directories + +The catalog supports metadata records that are composed from fragments of metadata. The idea is that the fragments of metadata can be used in more than one metadata record. + +Here is a typical example of a fragment. This is a responsible party and it could be used in the same metadata record more than once or in more than one metadata record if applicable. + +``` xml + + + John D'Ath + + + Mulligan & Sons, Funeral Directors + + + Undertaker + + + + + +``` + +Metadata fragments that are saved in the catalogue database are called subtemplates. This is mainly for historical reasons as a subtemplate is like a template metadata record in that it can be used as a 'template' for constructing a new metadata record. + +Fragments can be inserted in metadata record in 2 modes: + +- by copy/paste +- by link (if xlink support is enabled. See [Metadata XLink](../configuring-the-catalog/system-configuration.md#xlink_config)) + +When using XLinks, if the fragment is updated, then the related fragment in all metadata records will also be updated (check the XLink cache). + +Fragments may be created by harvesting (see [Harvesting Fragments of Metadata to support re-use](../../user-guide/harvesting/index.md#harvesting_fragments)) or imported using the metadata import page. + +This section of the manual describes: + +- how to manage directories of subtemplates +- how to extract fragments from an existing set of metadata records and store them as subtemplates +- how to manage the fragment cache used to speed up access to fragments that are not in the local catalogue + +## Managing Directories of subtemplates + +There are some differences between the handling of subtemplates and metadata records. Unlike metadata records, subtemplates do not have a consistent root element, the metadata schema they use may not be recognizable, they do not appear in the main search results (unless they are part of a metadata record). Therefore, the editor board allows you to search and manage privileges for directory entries. + +![](img/directories-search.png) + +From the editor board, choose `Manage directory` to access the editor for directory entries: + +![](img/directories-manager.png) + +If you do not see the `Organizations and Contacts` tab then ensure that you have created subtemplates for contacts for your metadata profile, and that you have loaded them using the `Metadata and Templates` section. + +From this page, editors can choose a type of directory using the top tabs, edit/remove/import new subtemplates. + +To import new entries, use the metadata import page and choose the appropriate type of record: + +![](img/directories-import.png) + +Like metadata records, they are allocated an integer id and are stored in the catalog metadata table (with template field set to "y"). + +## Insert a directory entry in a metadata record + +From the metadata editor, the directory can be used to populate contacts for example. + +![](img/directories-editor-popup.png) + +Open the directory selector, choose a contact and then choose the contact role. + +![](img/directories-editor-popupopen.png) + +## Extracting subtemplates from metadata records + +Many sites have existing metadata records with common information eg. contact information in an ISO CI_Contact element. Directory entries such as these can be extracted from a selected set of metadata records using the "Extract subtemplates" API. + +To use this function the following set of steps should be followed: + +- Make sure you understand what an XPath is - see for example. +- Identify fragments of metadata that they would like to manage as reusable subtemplates in the metadata record. This can be done using an XPath. eg. the XPath `.//gmd:CI_ResponsibleParty` identifies all responsible party in a records. An example of such a fragment (taken from one of the sample records) is shown in the following example: + +``` xml + + + Jippe Hoogeveen + + + FAO - NRCW + + + Technical Officer + + + + + + + + + + + + + + + + + Viale delle Terme di Caracalla + + + Rome + + + + + + 00153 + + + Italy + + + jippe.hoogeveen@fao.org + + + + + + + + + +``` + +- Identify and record the XPath of a field or fields within the fragment which text content will be used as the id of the subtemplate. This XPath should be relative to the root element of the fragment identified in the previous step. So for example, in the fragment above we could choose `.//gmd:electronicMailAddress/gco:CharacterString/text()` as the id for the fragments to be created. +- On the API page, choose the registries / collect operation: + +![](img/directories-api-collect.png) + +- Fill in the form with the information collected in the previous steps. +- Extracted subtemplates can be previewed using the GET mode and once validated, use the PUT method to save results in the catalog. + +Finally, go to the subtemplate directory management interface and you should be able to select the root element of your subtemplates to examine the extracted subtemplates. + +Subtemplate indexing is based on the schema (see index-fields folder for details). Currently ISO19139 index subtemplates using as root element: + +- gmd:CI_ResponsibleParty +- gmd:MD_Distribution +- gmd:CI_OnlineResource +- gmd:EX_Extent + +In ISO19115-3 + +- cit:CI_Responsibility +- *[mdq:result] +- gex:EX_Extent + +Other configuration examples to collect: + +- Parties in ISO19115-3 + - `xpath`: `.//cit:CI_Responsibility` + - `identifierXpath`: `.//cit:electronicMailAddress/*/text()` +- Quality specifications in ISO19115-3 + - `xpath`: `.//*[mdq:result]` + - `identifierXpath`: `.//cit:title/*/text()` +- Extent in ISO19115-3 + - `xpath`: `.//gex:EX_Extent` + - `identifierXpath`: `concat(.//gex:westBoundLongitude/*/text(), ', ', .//gex:eastBoundLongitude/*/text(), ', ', .//gex:southBoundLatitude/*/text(), ', ',.//gex:northBoundLatitude/*/text())` or `gex:description/*/text()` +- Constraints in ISO19115-3 + - `xpath`: `.//mri:resourceConstraints/*` + +## Synchronizing subtemplates with metadata records + +Once created, the catalog provides the capability to synchronize metadata records with directory entries. For this, use the API testing page. + +The synchronize process use the same parameters as the collecting process with 2 optionals arguments: + +- `propertiesToCopy` to preserve some element which may be defined in the fragment in the metadata (eg. contact role) +- `substituteAsXLink` to indicate if copy/paste mode or XLink mode should be used. + +![](img/directories-api-synch.png) + +## Managing the fragment cache + +If metadata records in your catalog link in fragments from external sites, the catalog caches these fragments after the first look up so as to reduce the amount of network traffic and speed up the display of metadata records in search results. + +The cache is handled automatically using the Java Cache System (JCS). JCS handles large caches intelligently by: + +- defining a maximum number of cached objects +- using as much main memory as possible before moving to secondary storage (disk) +- providing cache persistence: the cache is saved to disk when the web application is shutdown and restores the cache from disk when restarting + +You can configure JCS parameters in GeoNetwork using the JCS configuration file in **INSTALL_DIR/web/geonetwork/WEB-INF/classes/cache.ccf**. + +Some operations in the catalog (such as harvesting) that generate metadata fragments, will automatically refresh the XLink cache when a new fragment is generated. However, if you are linking fragments from an external site, then depending on how often the change, you will need to manually refresh the XLink cache. To do this you should navigate to the Administration page and select the "Clear XLink Cache and Rebuild Index of Records with XLinks" function as highlighted in the following screenshot of the "Administration" page. + +![](img/directories-cache.png) diff --git a/docs/manual/docs/administrator-guide/managing-classification-systems/managing-thesaurus.md b/docs/manual/docs/administrator-guide/managing-classification-systems/managing-thesaurus.md new file mode 100644 index 00000000000..ca161024dd9 --- /dev/null +++ b/docs/manual/docs/administrator-guide/managing-classification-systems/managing-thesaurus.md @@ -0,0 +1,207 @@ +# Managing thesaurus + +## Introduction + +A thesaurus is a list of concepts from a specialized field of knowledge. In a metadata catalog, concepts from a thesaurus can be assigned to a metadata record (as keywords) as a way of associating it with one or more concepts from a field of knowledge. For example, a record may be assigned a keyword 'AGRICULTURE - Crops' meaning that the record describes a resource or activity relating to crops in the field of Agriculture. It's a good practice to look for existing thesauri before creating your own thesaurus. + +In GeoNetwork, the process of assigning keywords to a metadata record takes place in the metadata editor. The user can choose concepts from one or more thesauri to associate the record with the concepts described by those concepts. This process is supported for both ISO19115/19139 and dublin core metadata records using an thesaurus picker. + +Concepts within a field of knowledge or in different fields of knowledge may be related or even be equivalent. For example, in a thesaurus describing geographic regions, the Australian state of 'Tasmania' is a specialization of the country of Australia. As an example of overlapping concepts in different fields, a thesaurus describing science activities in the field of global change may have concepts relating to agricultural activities that will be equivalent to terms from a thesaurus that describes the themes used in a map series. + +In GeoNetwork, thesauri are represented as SKOS () and stored in an application/xml+rdf encoding. SKOS captures concepts and relationships between concepts. SKOS thesauri can be imported from standalone files or they can be generated from ISO19135 register records in a GeoNetwork catalog. ISO19135 (more on this below) not only captures the concepts and relationships between the concepts, but (amongst other things) how the concepts have evolved and most importantly, who has contributed to and managed the evolution of the concepts and the thesauri itself. + +## External, Local and Register Thesauri + +There are three types of thesaurus in GeoNetwork. The different types are based on where the thesaurus comes from: + +- *External*: A thesaurus managed by an external organisation and imported as a SKOS file. It is flagged to `external` which means that users are not allowed to edit the thesaurus. +- *Local*: A thesaurus built in the GeoNetwork thesaurus editor and stored as a SKOS file. It is flagged as `local` which means that users are allowed to edit the thesaurus. +- *Register*: A SKOS thesaurus created from an ISO19135 register record. Users can edit the thesaurus by changing the content of the ISO19135 register record in the GeoNetwork metadata editor and then regenerating the thesaurus. Users cannot edit the thesaurus in thesaurus manager. + +## ISO19115/19139 Thesaurus Categories + +All thesauri in GeoNetwork are categorized using the code list values for the gmd:MD_KeywordTypeCode element from ISO19115/19139. The categories and their meanings are given below but can also be found in : + +| ISO Thesaurus Category | Description | +|------------------------|------------------------------------------------------------------------------------| +| place | Thesaurus has concepts identifying a location | +| stratum | Thesaurus has concepts identifying layers of any deposited substance | +| temporal | Thesaurus has concepts identifying a time period | +| theme | Thesaurus has concepts identifying a particular subject or topic | +| discipline | Thesaurus has concepts identifying a branch of instruction or specialized learning | + +## SKOS format + +The Simple Knowledge Organisation Systems (SKOS) is an area of work developing specifications and standards to support the use of knowledge organisation systems (KOS) such as thesauri, classification schemes. This format is used by GeoNetwork to store thesaurus information. + +A concept is defined by an identifier, a preferred label, a definition and links with other concepts. Labels and definitions could be stored in multiple languages (using the xml:lang attributes). Three type of links between concepts have been defined in the SKOS format: + +- related terms +- broader terms +- narrower terms + +For example, a concept `ABLETTE` could be defined as follow with a label in French and English, linked to broader concept: + + + ABLETTE + BLEAK + + + +GeoNetwork supports multilingual thesauri (e.g. Agrovoc). Search and editing takes place in the current user interface language (i.e. if the interface is in English, when editing metadata, GeoNetwork will only search for concept in English). + +We use SKOS to represent thesauri in GeoNetwork because: + +- it provides a simple and compact method of describing concepts and relationships between concepts from a field of knowledge +- SKOS concepts can be queried and managed by the sesame/openRDF software used by GeoNetwork + +## ISO19135 register format + +ISO19135 is an ISO standard that describes procedures for registering an item and the schema for describing a list (or register) of items and the processes by which the items can be created and evolve. This schema is available as a plugin for use in GeoNetwork. To use it, you must download and load the iso19135 plugin schema into GeoNetwork. FIXME: We need a standard way of referring to plugin schemas and a standard place from which they can be downloaded. + +A typical ISO19135 register record describes: + +- the name and a description of the register +- version and language information +- contact information of those that have a role in the register (eg. manager, contributor, custodian, publisher etc) +- the elements used to describe an item in the register +- the items + +The standard information used to describe a register item includes: + +- identifier +- name and description of item +- field of application +- lineage and references to related register items + +An example of a register item from register of the NASA GCMD (Global Change Master Directory) science keywords is shown below. + + + + 7 + + + Aquaculture + + + valid + + + 2006 + + + + + + + 5 + + + + + + + + +As mentioned earlier, to use a thesaurus described by an ISO19135 register record, GeoNetwork uses an XSLT called xml_iso19135ToSKOS.xsl (from the convert subdirectory in the iso19135 plugin schema) to extract the following from the ISO19135 register record: + +- valid concepts (grg:itemIdentifier, grg:name, grg:status) +- relationships to other concepts (grg:specificationLineage) +- title, version and other management info + +This information is used build a SKOS file. The SKOS file is then available for query and management by the sesame/openRDF software used in GeoNetwork. + +## Creating or Importing a Thesaurus + +External and local thesauri are created or imported using the thesaurus manager. You can use the thesaurus manager by: + +- logging in as an administrator +- navigating to the 'Administration' page and clicking on the link `Manage thesauri` + +The thesaurus manager page will show a list of thesauri that have been created or imported. The upper part of the page provides the user with functions to edit, add, modify or search a thesaurus. The lower part provides a function to upload an external thesaurus in SKOS format. + +### Creating a local thesaurus + +To create a local thesaurus, click the `+` sign on the category you want your thesaurus to be in. Once created, the thesaurus can be updated through the edit interface. The meaning of each column is as follows: + +- **Type** - This is an identifier assigned to the thesaurus in GeoNetwork. It is composed of the ISO category to which the thesaurus has been assigned (see the codelist for the gmd:MD_KeywordTypeCode element in ), whether the thesaurus is a local, external or register thesaurus and the filename of the SKOS file that holds the thesaurus. (Note: the name of the file used to hold a register thesaurus is the uuid of the ISO19135 register record that describes the thesaurus). +- **Name** - This is the name of the thesaurus which is the administrator on creation or the filename if the thesaurus is ting a thesaurus, the name of the thesaurus will be the filename of the thesaurus. + +For each thesaurus the following buttons are available: + +- **Download** - Link to the SKOS RDF file. +- **Delete** - Remove thesaurus from the current node. +- **View** - If type is external, the view button allows to search and view concepts. +- **Edit** - If type is local, the edit button allows to search, add, remove and view concepts. + +### Import an external thesaurus + +GeoNetwork allows thesaurus import in SKOS format. Once uploaded, an external thesaurus cannot be updated. Select the category, browse for the thesaurus file and click upload. The SKOS file will be in `GEONETWORK_DATA_DIR/config/codelist/external/thesauri/`. + +At the bottom of the page there are the following buttons: + +1. *Back*: Go back to the main administration page. +2. *Upload*: Upload the selected RDF file to the node. Then it will list all thesaurus available on the node. + +### Creating a register thesaurus + +An ISO19135 record in the local GeoNetwork catalog can be turned into a SKOS file and used as a thesaurus in GeoNetwork. ISO19135 records not in the local catalog can be harvested from other catalogs (eg. the catalog of the organisation that manages the register). Once the ISO19135 register record is in the local catalog, the process of turning it into a thesaurus for use in the keywords selector begins a search for the record. Having located the record in the search results, one of the actions on the record is to 'Create/Update Thesaurus'. + +> *Search results showing ISO19135 record with thesaurus creation action* + +After selecting this action, you can choose the ISO thesaurus category appropriate for this thesaurus: + +> *Selecting the ISO thesaurus category when creating a thesaurus* + +After selecting the ISO thesaurus category, the ISO19135 register record is converted to a SKOS file and installed as a thesaurus ready for use in the metadata editor. As described above in the section on ISO19135, only the valid register items are included in the thesaurus. This behaviour and any of the mappings between ISO19135 register items and the SKOS thesaurus file can be changed or inspected by looking at the XSLT xml_iso19135TOSKOS.xsl in the convert subdirectory of the iso19135 schema plugin. + +## Editing/browsing a local or external thesaurus: add/remove/browse keywords + +From the thesaurus administration interface, click on the edit button for a local thesaurus or the view button for an external thesaurus. This interface allows: + +- keywords search +- add/remove keywords for local thesaurus. + +Use the textbox and the type of search in order to search for keywords. + +## Editing a register thesaurus + +A register thesaurus is created from an ISO19135 metadata record as described above, so a register thesaurus is updated by editing the ISO19135 metadata record and then regenerating the register thesaurus. The ISO19135 metadata record can be created and edited in the GeoNetwork editor. + +### Preparing to edit an ISO19135 register record {#xlinks_thesaurus} + +Register records can be very large. For example, a register record describing the ANZLIC Geographic Extent Names register has approx 1800 register items. Each register item holds not only the name of the geographic extent, but also its geographic extent and details of the lineage, relationships to other terms and potentially, the evolution of the extent (changes to name, geographic extent) including the details of changes and why those changes occurred. Editing such a large record in the GeoNetwork editor can cause performance problems for both the browser and the server because the editor constructs an HTML form describing the entire record. Fortunately, a much more scalable approach exists which is based on extracting the register items from the ISO19135 register record, storing them as subtemplates (essentially small metadata records with just the content of the register item). The process for extracting register items from an ISO19135 register record is as follows: + +- search for and select the register record +- choose 'Extract register items' from the 'Actions on selected set' menu +- After the register items have been extracted, you should see a results summary like the following. +- The figure for 'Subtemplates extracted' is the number of register items extracted from the ISO19135 register record. + +### Editing a register item + +To edit/change any of the register items that have been extracted as subtemplates, you can use the Directory management interface. This interface is accessed from the 'Administration' menu, under 'Manage Directories'. In this interface: + +- select 'Register Item (GeoNetwork)' as the type of subtemplate to edit as follows. +- enter a search term or just select the search option to return the first 50 register items. +- register items will appear in the left hand side bar, selecting on one will open an editing interface in the right hand panel. + +### Editing global register information + +To edit/change any of the global register information (eg. register owner, manager, version, languages), edit the register record in the normal GeoNetwork metadata editing interface. + +## Metadata editing: adding keywords + +When editing an ISO metadata record, a keyword (or concept) picker can be used which allows the editor to: + +- do searches for keywords in one or more thesauri in the catalog (search results are displayed on the left). +- select one or more keywords and add them to the selected items list (using arrows or drag & drop) on the right. +- add the selected keywords directly into metadata, grouping keywords by thesaurus. + +The editor can also control how many keywords from searches are displayed in the keyword picker (default is 50). + +Notice that a URL pointing to the source thesaurus is included in the Thesaurus Name citation (the actual element used for this is gmd:otherCitationDetails/gmx:FileName). The thesaurus can be downloaded as a SKOS file if it is a local or external thesaurus. For register thesauri the URL refers to the ISO19135 register record from which the thesaurus was created. + +## Search criteria: keywords + +You can search on keywords using the facet panel. All keywords are stored in the index field `tag` and are also available in field depending on thesaurus name eg. `th_theme` for INSPIRE themes. The field name is based on the thesaurus type and filename. diff --git a/docs/manual/docs/administrator-guide/managing-metadata-standards/configure-validation.md b/docs/manual/docs/administrator-guide/managing-metadata-standards/configure-validation.md new file mode 100644 index 00000000000..d5381b6f347 --- /dev/null +++ b/docs/manual/docs/administrator-guide/managing-metadata-standards/configure-validation.md @@ -0,0 +1,27 @@ +# Configuring validation levels {#configure-validation} + +Each standard defines validation levels. By default, ISO19139 proposes validation using: + +- ISO rules +- INSPIRE rules (TG v1.3) +- GeoNetwork rules (only related to multilingual records) +- URL checker + +All levels will be applied by default during validation and the admin interface allows customization if a rule: + +- is required to be valid (will be reported in green/red depending on the status) +- is for information only (will be reported in blue) +- is ignored. + +![](img/validation-level.png) + +Also conditions can be set to only apply rules to specific records. The condition can be defined on: + +- XPath +- Group +- User profile +- Keyword + +For example, [geocat.ch](https://www.geocat.ch/) defines for the GM03 ISO19139 profile rules depending on groups (ie. partners) and the type of dataset eg. a basic geodata. + +![](img/validation-level-example.png) diff --git a/docs/manual/docs/administrator-guide/managing-metadata-standards/img/mit-choice.png b/docs/manual/docs/administrator-guide/managing-metadata-standards/img/mit-choice.png new file mode 100644 index 00000000000..764dfe7e58d Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-metadata-standards/img/mit-choice.png differ diff --git a/docs/manual/docs/administrator-guide/managing-metadata-standards/img/mit-config.png b/docs/manual/docs/administrator-guide/managing-metadata-standards/img/mit-config.png new file mode 100644 index 00000000000..678d75bfbb6 Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-metadata-standards/img/mit-config.png differ diff --git a/docs/manual/docs/administrator-guide/managing-metadata-standards/img/mit-custom.png b/docs/manual/docs/administrator-guide/managing-metadata-standards/img/mit-custom.png new file mode 100644 index 00000000000..bcbfa61e436 Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-metadata-standards/img/mit-custom.png differ diff --git a/docs/manual/docs/administrator-guide/managing-metadata-standards/img/mit-customform.png b/docs/manual/docs/administrator-guide/managing-metadata-standards/img/mit-customform.png new file mode 100644 index 00000000000..bc40fa9752e Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-metadata-standards/img/mit-customform.png differ diff --git a/docs/manual/docs/administrator-guide/managing-metadata-standards/img/mit-setting.png b/docs/manual/docs/administrator-guide/managing-metadata-standards/img/mit-setting.png new file mode 100644 index 00000000000..c28c31fe2db Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-metadata-standards/img/mit-setting.png differ diff --git a/docs/manual/docs/administrator-guide/managing-metadata-standards/img/validation-level-example.png b/docs/manual/docs/administrator-guide/managing-metadata-standards/img/validation-level-example.png new file mode 100644 index 00000000000..d538765be4d Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-metadata-standards/img/validation-level-example.png differ diff --git a/docs/manual/docs/administrator-guide/managing-metadata-standards/img/validation-level.png b/docs/manual/docs/administrator-guide/managing-metadata-standards/img/validation-level.png new file mode 100644 index 00000000000..110e18e3450 Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-metadata-standards/img/validation-level.png differ diff --git a/docs/manual/docs/administrator-guide/managing-metadata-standards/index.md b/docs/manual/docs/administrator-guide/managing-metadata-standards/index.md new file mode 100644 index 00000000000..4b5c7cb1d90 --- /dev/null +++ b/docs/manual/docs/administrator-guide/managing-metadata-standards/index.md @@ -0,0 +1,5 @@ +# Managing metadata & template {#metadata-and-template} + +- [Managing metadata standards](standards.md) +- [Configuring validation levels](configure-validation.md) +- [Configuring metadata identifier](metadata-identifier.md) diff --git a/docs/manual/docs/administrator-guide/managing-metadata-standards/metadata-identifier.md b/docs/manual/docs/administrator-guide/managing-metadata-standards/metadata-identifier.md new file mode 100644 index 00000000000..b45b2049f88 --- /dev/null +++ b/docs/manual/docs/administrator-guide/managing-metadata-standards/metadata-identifier.md @@ -0,0 +1,34 @@ +# Configuring metadata identifier {#metadata_identifier} + +Some organisations require the definition of metadata identifiers using [URN](https://en.wikipedia.org/wiki/Uniform_Resource_Name) templates. + +From the `admin console` --> `metadata and template` --> `Metadata identifier templates` users can customise the behaviour of the catalog when creating new metadata: + +- Create a random UUID. This is the "standard" behaviour of GeoNetwork and it's set as default. +- Use metadata URN templates to define the metadata identifiers. This option allows the user to enter a metadata identifier from the metadata URN templates defined by an administrator user. + +To enable the usage of metadata URN templates for the metadata identifiers, the user should disable the following setting: + +![](img/mit-setting.png) + +Once enabled the metadata create page displays a new panel, that allows the user to select the metadata identifier template: + +![](img/mit-choice.png) + +- Custom identifier: Allows the user to enter a free-text value for the metadata identifier. + +![](img/mit-custom.png) + +- Autogenerated identifier: the catalog creates a random UUID. +- A list of custom templates: A list of the metadata identifier templates. When the user selects one of these templates, the form request the different template values. + +![](img/mit-customform.png) + +New templates can be added in the configuration interface: + +![](img/mit-config.png) + +For each template a user can define some parameters to fill in the metadata create form. Parameters are defined between curly braces. For example: + +- ::{TT}{AA}{II}{CCCC} +- au.gov.bom::{IDCODE} diff --git a/docs/manual/docs/administrator-guide/managing-metadata-standards/standards.md b/docs/manual/docs/administrator-guide/managing-metadata-standards/standards.md new file mode 100644 index 00000000000..63fe7a73e40 --- /dev/null +++ b/docs/manual/docs/administrator-guide/managing-metadata-standards/standards.md @@ -0,0 +1,52 @@ +# Managing metadata standards + +Metadata records in GeoNetwork are described by a schema. The schema sets out the structuring of the metadata record and provides all the ancillary data and functions to use the schema in GeoNetwork. + +A metadata schema plugin capability was introduced in GeoNetwork 2.8.0. In 3.0.0 the plugin capability was expanded to facilitate the fact that plugins can contain java-code. + +!!! note + + Adding a metadata schema to GeoNetwork that is incorrect or invalid can thoroughly break your GeoNetwork instance. This section is for catalogue administrators who are confident about metadata schemas and understand the different technologies involved with a GeoNetwork metadata schema. + + +A detailed description of what constitutes a metadata schema for GeoNetwork can be found in the GeoNetwork Developers Manual. This section will describe how to access the schema add, update and delete functions and how those functions should be used. + +!!! note + + Metadata schemas should be thoroughly tested in a development instance of GeoNetwork **before** they are deployed in a production instance. Errors in a schema plugin (particularly in the presentation XSLTs) may make your GeoNetwork instance unusable. + + +## Adding a schema + +To add a metadata schema to the catalog, a rebuild of the sources is required. In a source-code tree there are 4 actions to be done in the settings (database). + +- Place the schema-folder in /schemas + +- Verify and if compatible update the version of GeoNetwork (parent) referenced from the pom.xml file in the schema plugin. + +- Add a reference in /schemas/pom.xml to the newly added schema + + ``` xml + {myschema} + ``` + +- Add references to the newly added schema in /web/pom.xml + + ``` xml + + ${project.groupId} + {myschema} + ${project.version} + + ``` + +- and + + ``` xml + + ${project.basedir}/../schemas/{myschema}/src/main/plugin + ${basedir}/src/main/webapp/WEB-INF/data/config/schema_plugins + + ``` + +Then Build and deploy your instance of GeoNetwork. diff --git a/docs/manual/docs/administrator-guide/managing-users-and-groups/authentication-mode.md b/docs/manual/docs/administrator-guide/managing-users-and-groups/authentication-mode.md new file mode 100644 index 00000000000..efc095df787 --- /dev/null +++ b/docs/manual/docs/administrator-guide/managing-users-and-groups/authentication-mode.md @@ -0,0 +1,845 @@ +# Authentication mode + +By default the catalog uses the internal database for user management and authentication. However there are some other authentication mechanisms available: + +- [Configuring LDAP](authentication-mode.md#authentication-ldap) +- [Configuring LDAP - Hierarchy](authentication-mode.md#authentication-ldap-hierarchy) +- [Configuring CAS](authentication-mode.md#authentication-cas) +- [Configuring OAUTH2 OpenID Connect](authentication-mode.md#authentication-openid) +- [Configuring Keycloak](authentication-mode.md#authentication-keycloak) +- [Configuring Shibboleth](authentication-mode.md#authentication-shibboleth) + +Which mode to use is configured in **`WEB-INF/config-security/config-security.xml`** or via an environment variable `geonetwork.security.type`. + +Uncomment the relevant line in **`WEB-INF/config-security/config-security.xml`**: + +``` xml + +``` + +## Configuring LDAP {#authentication-ldap} + +[Lightweight Directory Access Protocol (LDAP)](https://en.wikipedia.org/wiki/Ldap) enables GeoNetwork to verify usernames and passwords to a remote identity store. LDAP implementation uses the default GeoNetwork Login User Interface elements. + +GeoNetwork currently has 2 approaches to configure LDAP. Verify also the alternative approach in [Configuring LDAP - Hierarchy](authentication-mode.md#authentication-ldap-hierarchy). + +The LDAP configuration is defined in `WEB-INF/config-security/config-security.properties`, you can then configure your environment updating the previous file or overriding the properties in the file `WEB-INF/config-security/config-security-overrides.properties`. + +1. Define the LDAP connection: + + - `ldap.base.provider.url`: This tells the portal where the LDAP server is located. Make sure that the computer with the catalog can hit the computer with the LDAP server. Check to make sure that the appropriate ports are opened, etc. + - `ldap.base.dn`: this will usually look something like: "dc=[organizationnamehere],dc=org" + - `ldap.security.principal` / `ldap.security.credentials`: Define LDAP administrator user to use to bind to LDAP. If not define, an anonymous bind is made. Principal is the username and credentials property the password. + + ``` text + # LDAP security properties + ldap.base.provider.url=ldap://localhost:389 + ldap.base.dn=dc=fao,dc=org + ldap.security.principal=cn=admin,dc=fao,dc=org + ldap.security.credentials=ldap + ``` + + To verify that you have the correct settings, try to connect to the LDAP server using an LDAP browser application. + +2. Define where to find users in LDAP structure for authentication: + + - `ldap.base.search.base`: this is where the catalog will look for users for authentication. + - `ldap.base.dn.pattern`: this is the distinguished name for the user to bind with. `{0}` is replaced by the user name typed in the sign in screen. + + ``` text + ldap.base.search.base=ou=people + ldap.base.dn.pattern=uid={0},${ldap.base.search.base} + #ldap.base.dn.pattern=mail={0},${ldap.base.search.base} + ``` + +### Authorization Settings + +When using LDAP, the user information and privileges for GeoNetwork could be defined from the LDAP attributes. + +#### User information + +The user information could be retrieved from the LDAP configuring for each user attribute in the catalog database which LDAP attributes match. If the attribute is empty or not defined, a default value could be defined. The property value is composed by two parts separated by `,` character. The first part is the attribute name and the second part is the default value in case the attribute name is not define or the attribute value in LDAP is empty. + +The configuration is the following: + +``` text +# Map user information to LDAP attributes and default values +# ldapUserContextMapper.mapping[name]=ldap_attribute,default_value +ldapUserContextMapper.mapping[name]=cn, +ldapUserContextMapper.mapping[surname]=givenName, +ldapUserContextMapper.mapping[mail]=mail,data@myorganization.org +ldapUserContextMapper.mapping[organisation]=,myorganization +ldapUserContextMapper.mapping[kind]=, +ldapUserContextMapper.mapping[address]=, +ldapUserContextMapper.mapping[zip]=, +ldapUserContextMapper.mapping[state]=, +ldapUserContextMapper.mapping[city]=, +ldapUserContextMapper.mapping[country]=, +``` + +#### Privileges configuration + +User groups and user profiles could be set optionally from LDAP information or not. By default user privileges are managed from the local database. If LDAP information should be used to define user privileges, set the `ldap.privilege.import` property `true`: + +``` text +ldap.privilege.import=true +``` + +When importing privileges from LDAP, the catalog administrator could decide to create groups defined in the LDAP and not defined in local database. For this set the following property to true: + +``` text +ldap.privilege.create.nonexisting.groups=false +``` + +In order to define which groups the user is member of and which profile is the user: + +``` text +ldapUserContextMapper.mapping[privilege]=groups,sample +# If not set, the default profile is RegisteredUser +# Valid profiles are ADMINISTRATOR, USER_ADMIN, REVIEWER, EDITOR, REGISTERED_USER, GUEST +ldapUserContextMapper.mapping[profile]=privileges,RegisteredUser +``` + +Attributes configuration: + +- privilege attribute contains the group this user is member of. More than one group is allowed. +- profile attribute contains the profile of the user. + +User valid profiles are: + +- Administrator +- UserAdmin +- Reviewer +- Editor +- RegisteredUser +- Guest + +If LDAP attribute containing profiles does not match the catalog profile list, a mapping could be defined: + +``` text +# Map LDAP custom profiles to catalog profiles. Not used if ldap.privilege.pattern is defined. +ldapUserContextMapper.profileMapping[Admin]=Administrator +ldapUserContextMapper.profileMapping[Editor]=Reviewer +ldapUserContextMapper.profileMapping[Public]=RegisteredUser +``` + +For example, in the previous configuration, the attribute value `Admin` will be mapped to `Administrator` (which is a valid profile for the catalog). + +An attribute could define both the profile and the group for a user. To extract this information, a custom pattern could be defined to populate user privileges according to that attribute: + +1. Define one attribute for the profile and one for groups in `WEB-INF/config-security/config-security-overrides.properties` + + ``` text + # In config-security-overrides.properties + ldapUserContextMapper.mapping[privilege]=cat_privileges,sample + ``` + +2. Define one attribute for the privilege and define a custom pattern: + + ``` text + # In config-security.properties + ldap.privilege.pattern=CAT_(.*)_(.*) + ldap.privilege.pattern.idx.group=1 + ldap.privilege.pattern.idx.profil=2 + ``` + + Enable the bean `ldapUserContextMapper` for `LDAPUserDetailsContextMapperWithPattern` ( in `WEB-INF/config-security/config-security-ldap.xml`). + + ``` xml + + + + + + + + + + + + + + + + + + + + + + ``` + +3. Define custom location for extracting group and role (no support for group/role combination) (use LDAPUserDetailsContextMapperWithProfileSearch in **`config-security.xml`**). + + ``` text + ldap.privilege.search.group.attribute=cn + ldap.privilege.search.group.object=ou=groups + #ldap.privilege.search.group.query=(&(objectClass=*)(memberUid=uid={0},${ldap.base.search.base},${ldap.base.dn})(cn=EL_*)) + ldap.privilege.search.group.queryprop=memberuid + ldap.privilege.search.group.query=(&(objectClass=*)(memberUid=uid={0},${ldap.base.search.base},${ldap.base.dn})(|(cn=SP_*)(cn=EL_*))) + ldap.privilege.search.group.pattern=EL_(.*) + ldap.privilege.search.privilege.attribute=cn + ldap.privilege.search.privilege.object=ou=groups + ldap.privilege.search.privilege.query=(&(objectClass=*)(memberUid=uid={0},${ldap.base.search.base},${ldap.base.dn})(cn=SV_*)) + ldap.privilege.search.privilege.pattern=SV_(.*) + ``` + + The LDAP attribute can contains the following configuration to define the different type of users, for example: + + ``` text + cat_privileges=CAT_ALL_Administrator + + -- Define a reviewer for the group GRANULAT + cat_privileges=CAT_GRANULAT_Reviewer + + -- Define a reviewer for the group GRANULAT and editor for MIMEL + cat_privileges=CAT_GRANULAT_Reviewer + cat_privileges=CAT_MIMEL_Editor + + -- Define a reviewer for the group GRANULAT and editor for MIMEL and RegisteredUser for NATURA2000 + cat_privileges=CAT_GRANULAT_Reviewer + cat_privileges=CAT_MIMEL_Reviewer + cat_privileges=CAT_NATURA2000_RegisteredUser + + -- Only a registered user for GRANULAT + cat_privileges=CAT_GRANULAT_RegisteredUser + ``` + +#### Synchronization + +A synchronization task is taking care of removing LDAP users that may be deleted. For example: + +- T0: User A signs in to the catalog. A local user A is created in the user database. +- T1: User A is deleted from the LDAP (User A cannot sign in to the catalog anymore). +- T2: The synchronization task will check that all local LDAP users exist in LDAP: + - If the user does not own any records, it will be deleted. + - If the user owns metadata records, a warning message will be written to the catalog logging system. The owner of the record should be changed to another user before the task can remove the current owner. + +By default the task runs once every day. This can be changed in the following property: + +``` text +# Run LDAP sync every day at 23:30 +ldap.sync.cron=0 30 23 * * ? +``` + +The following properties allow advanced configuration of the synchronisation process: + +``` text +ldap.sync.user.search.base=${ldap.base.search.base} +ldap.sync.user.search.filter=(&(objectClass=*)(mail=*@*)(givenName=*)) +ldap.sync.user.search.attribute=uid +ldap.sync.group.search.base=ou=groups +ldap.sync.group.search.filter=(&(objectClass=posixGroup)(cn=EL_*)) +ldap.sync.group.search.attribute=cn +ldap.sync.group.search.pattern=EL_(.*) +``` + +#### Debugging + +If the connection fails, try to increase the logging level for LDAP in `WEB-INF/classes/log4j.xml`: + +``` xml + + + +``` + +Or from the Configuration Settings set the `Log level` to `DEV` temporarily: + +![](img/setting-log-level.png) + +## Configuring LDAP - Hierarchy {#authentication-ldap-hierarchy} + +A slightly different method for LDAP configuration was introduced in mid-2020. + +This extends the original configuration infrastructure (original configurations still work without any changes). + +Before you start configuring, you will need to know; + +1. URL to your LDAP Server +2. Username/password to login to the LDAP Server (to execute queries) +3. LDAP query to find a user (given what they type in on the login screen) +4. Details of how to convert the LDAP user's attributes to GeoNetwork user attributes +5. LDAP query to find groups a user is a member of +6. How to convert a LDAP group to a GeoNetwork Group/Profile + +!!! note + + There is a [video developer chat](https://www.youtube.com/watch?v=f8rvbEdnE-g) that goes into details for how to configure LDAP including setting up a pre-configured LDAP server (using Apache Directory Studio) for testing/debugging/learning. + + +!!! note + + Should I use the Hierarchy or Original configuration? + + If you already have an existing (Original) configuration, there's no need to move to the new one. Most of the code between the two is the same. + + If you are starting a new configuration, I would recommend the Hierarchy configuration. It's a little simpler and supported by test cases and test infrastructure. It also supports LDAPs where users/groups are in multiple directories. + + +### Configuring LDAP Beans (Hierarchy) + +GeoNetwork comes with a sample LDAP configuration that you can use in Apache Directory Studio to create the same LDAP server used in the test cases. There is also a sample GeoNetwork configuration that connects to this LDAP server. Please see `core-geonetwork/blob/master/core/src/test/resources/org/fao/geonet/kernel/security/ldap/README.md`{.interpreted-text role="repo"} or the [video developer chat](https://www.youtube.com/watch?v=f8rvbEdnE-g) for instructions. + +!!! note + + To use this configuration, uncomment the "" line in ``web/src/main/webapp/WEB-INF/config-security/config-security.xml`` + + +1. Configure the `contextSource` bean with a reference to your LDAP server and a user that can execute LDAP queries. + + ``` xml + + + + + + + ``` + +2. Configure the `ldapUserSearch` bean with the query used to find the user (given what was typed in the login page). + + NOTE: Set `searchSubtree` to `true` to do a recursive search of the LDAP. Use `searchBase` to control which directory the search starts in ("" means start from the root). + + ``` xml + + + + + + + + ``` + +3. Configure the `ldapUserContextMapper` bean with how to convert the LDAP user's attributes to GeoNetwork user attributes (see the original configuration documentation, above). + + NOTE: The `value` portion has two parts. The first part is the name of LDAP attribute (can be blank). The second part is the default value if the LDAP attribute is missing or empty (see the original configuration documentation, above). + + ``` xml + + + + + + + + + + + + + + + + + + + + + ``` + +4. Continue configuring the `ldapUserContextMapper` bean so the LDAP can also provide group/profile roles for the user. + + NOTE: The `ldapMembershipQuery` is the LDAP directory where the membership query will be start ("" means start at the root of the LDAP). + + ``` xml + + + + + + + + + + + + + + ``` + +5. Continue configuring the `ldapUserContextMapper` bean so the LDAP roles can be converted to GeoNetwork Groups/Profiles. + + NOTE: You can use multiple `ldapRoleConverters`. + + ``` xml + + + + + + + + + + ``` + +There are currently two ways to convert an LDAP group to GeoNetwork Groups/Profiles. + +- The `LDAPRoleConverterGroupNameParser`, which works the same as the original LDAP configuration. It uses a regular expression to parse the LDAP group name into a GeoNetwork Group/Profile. This will convert the LDAP role `GCAT_GENERAL_EDITOR` into the GeoNetwork group `GENERAL` with Profile `Editor`. + + ``` xml + + + + + + + + + + + + + + + ``` + +- There is also a more direct way using `LDAPRoleConverterGroupNameConverter`. This directly converts the LDAP group name into a list of GeoNetwork Groups/Profiles. + + ``` xml + + + + + + + + HGIS_GeoNetwork_Admin + + + + + + + + + + + + + HGIS_GeoNetwork_Editor + + + + + + + + + + + + + + ``` + +## Configuring CAS {#authentication-cas} + +To enable CAS, set up authentication by including `WEB-INF/config-security/config-security-cas.xml` in `WEB-INF/config-security/config-security.xml`, uncommenting the following lines: + +``` xml + + +``` + +CAS can use either LDAP or a database for user management. To use a database uncomment the following lines instead: + +``` xml + + +``` + +The CAS configuration is defined in `WEB-INF/config-security/config-security.properties`. You can configure your environment by updating the previous file or by defining property overrides in the file `WEB-INF/config-security/config-security-overrides.properties`: + +``` text +cas.baseURL=https://localhost:8443/cas +cas.ticket.validator.url=${cas.baseURL} +cas.login.url=${cas.baseURL}/login +cas.logout.url=${cas.baseURL}/logout?url=${geonetwork.https.url}/ +``` + +## Configuring OAUTH2 OpenID Connect {#authentication-openid} + +[OAUTH2 OpenID Connect](https://openid.net/connect/) is an authentication and authorization system based on OAUTH2. Geonetwork's OpenID Connect plugin has been tested with [Keycloak](https://keycloak.org) and [Azure AD](https://azure.microsoft.com/en-ca/services/active-directory/), but should work with any provider. + +Basic Setup Steps: + +1. Configure your IDP Server (i.e. Keycloak or Azure AD) + 1. Ensure that the ID Token provides role/group information + 2. Authorize your Geonetwork URLs for redirects (i.e. `http://localhost:8080/geonetwork/login/oauth2/code/geonetwork-oicd`) + 3. Record the Client ID + 4. Record the Client Secret + 5. Get the Server's JSON metadata document +2. Configure Geonetwork via environment variables + 1. ``GEONETWORK_SECURITY_TYPE=openidconnect`` + 2. ``OPENIDCONNECT_CLIENTSECRET=\...`` (from your IDP server) + 3. ``OPENIDCONNECT_CLIENTID=\...`` (from your IDP server) + 4. ``OPENIDCONNECT_SERVERMETADATA_JSON_TEXT='\...'`` (the text of your Server's JSON metadata document) + 5. ``OPENIDCONNECT_IDTOKENROLELOCATION=\...`` (location of the user's roles in the ID Token) + +Geonetwork's Open ID Connect plugin has a lot of configuration options - please see the `WEB-INF/config-security/config-security-openidconnect.xml` and `WEB-INF/config-security/config-security-openidconnect-overrides.properties` files. + +### Environment Variable and Meaning + +**GEONETWORK_SECURITY_TYPE** + +Should be `openidconnect`. + +**OPENIDCONNECT_CLIENTID** + +The name of the client/application you configured on your OpenID server. + +**OPENIDCONNECT_CLIENTSECRET** + +The `client secret` you configured on your OpenID server. + +**OPENIDCONNECT_SERVERMETADATA_CONFIG_URL** + +URL to the external OIDC server's JSON metadata document. This is typically at ``/.well-known/openid-configuration`` on the IDP server. + +!!! note + + This will download the server's configuration everytime GeoNetwork starts up, which could be a security concern. For security, use a `https` URL. + + +**OPENIDCONNECT_SERVERMETADATA_JSON_TEXT** + +Should be the text of your OpenID server's metadata configuration (JSON). + +**OPENIDCONNECT_SERVERMETADATA_FNAME** + +Instead of putting the OpenID server's metadata configuration as text in a variable (``OPENIDCONNECT_SERVERMETADATA_JSON_TEXT``), you can put the JSON contents in a file and reference it with this variable (ie. `/WEB-INF/config-security/openid-configuration.json`) + +**OPENIDCONNECT_IDTOKENROLELOCATION** + +Where, in the ID Token, are the users roles/groups stored (i.e. "groups", "roles", or "resource_access.gn-key.roles") + +**OPENIDCONNECT_ROLECONVERTER** + +This provides simple role conversion from the OpenID server to Geonetwork roles. + +ie. ``"GeonetworkAdmin=Administrator,GeonetworkEditor=Editor"`` + +This will convert "GeonetworkAdmin" (from the OpenID Server) to the Geonetwork "Administrator" role. + +!!! note + + Like the keycloak plugin, you can use role/group names of the form "group:role" to assign a user to Geonetwork group and permission level. + + +**OPENIDCONNECT_MINIMUMPROFILE** + +Every user who authenticates against the OpenID server will be given this role. + +Default is ``"RegisteredUser"``. + +**OPENIDCONNECT_USERPROFILEUPDATEENABLED** + +When a user logs on, update their Geotwork profile from the OpenID server's ID Token. + +Default is ``"true"``. + +**OPENIDCONNECT_USERGROUPUPDATEENABLED** + +When a user logs on, update their Geotwork group/role permissions. + +Default is ``"true"``. + +**OPENIDCONNECT_SCOPES** + +Limit the requested scope access to the OpenID server. + +Default "openid email profile", and "openid email profile offline_access" (for bearer tokens). + +**OPENIDCONNECT_LOGINTYPE** + +How Geonetwork deals with users who are not logged on. + +Default is "LINK" - users can click on the "login" link on the main page. + +"AUTOLOGIN" - No login form provided which will automatically login the user when possible. + +**OPENIDCONNECT_LOGSENSITIVE_INFO** + +"true" or "false" (default) + +Logs: CODE, ACCESS TOKEN, ID TOKEN, userinfo endpoint result, and calculated GeoNetwork authorities. + +LOGGING THIS INFORMATION IS PROBABLY A SECURITY AND PERSONAL INFORMATION RISK. DO NOT TURN THIS ON IN A SYSTEM THAT IS ACTUALLY BEING USED. + +We try not to log very sensitive information - we don't log the full access or id token (just the claims part). We log the single-use CODE, but it should have already been deactivated by the server before we log it. + +The access token, userinfo, and id token contain sensitive information (i.e. real names, email address, etc\...) + +### Configuration for a Keycloak Server + +It's outside the scope of this document to fully describe the steps to configure keycloak, but this should serve as a guide. + +This will configure keycloak backed by **another OpenID IDP** (for example, by an Azure AD). In keycloak: + +1. Create a realm (i.e. `myrealm`) +2. Create an openid client (i.e. `myclient`). This is your ClientID. + 1. Root URL: ``http://localhost:7777/geonetwork`` (this is the GN root URL) + 2. Valid Redirect URIs: ``http://localhost:7777/geonetwork/*`` + 3. Access Type: Confidential + 4. On the `Credentials` tab, get the secret (this is your Client Secret) + 5. On the `Roles` tab, create some roles: Administrator, Editor, Reviewer, RegisteredGuest +3. Create your backing Identity Provider (i.e. to another OpenID server). Or you can configure users directly in keycloak. + 1. At the bottom of the page, choose "import from URL" and import the backing server's configuration location. + 2. Add the Client Secret (from the backing service) + 3. Add the Client ID (from the backing service) + 4. set "Client Authentication" to "Client secret sent as post" +4. Configure role translation + 1. Edit the "Identity Provider" you just created, and go to the "Mappers" tab. + 2. Press "Create" and and add a "Claim to Role". + 3. Set Sync Mode Override to "Force" + 4. Claim: `roles` + 5. Claim Value: `name of the administrator role in the backing IDP` + 6. Role: choose the "Administrator" role from the `myclient` client. + 7. Repeat the above for Administrator, Editor, Reviewer, and RegisteredGuest +5. Configure details for your backing IDP + 1. Edit the "Identity Provider" you just configured + 2. On the Mappers tab, "Add Builtin" and tick "client roles (User Client Role)" then "Add selected" + 3. Edit the "client roles" mapper and make sure "Add to ID token" and "Add to userinfo" are on + +You should have Keycloak's Client id ("myclient") and the client secret. The configuration JSON is available at `https://YOUR_KEYCLOAK_HOST/realms/{YOUR REALM NAME}/.well-known/openid-configuration` + +Your environment variables will looks like this: + +``` properties +GEONETWORK_SECURITY_TYPE=openidconnect +OPENIDCONNECT_CLIENTSECRET='...' +OPENIDCONNECT_CLIENTID='...' +OPENIDCONNECT_SERVERMETADATA_JSON_TEXT='...big json text...' +OPENIDCONNECT_IDTOKENROLELOCATION='resource_access.{your client id}.roles' +``` + +### Azure AD Configuration + +There are two ways to setup Azure AD. The first is with user and groups (a more traditional LDAP method) or with Application Roles. + +#### With Users and Groups + +Setup the Azure Application: + +1. Create a new `App Registration` +2. use `http://localhost:8080/geonetwork/login/oauth2/code/geonetwork-oicd` as a redirect URIs +3. On the "Certificates & Secrets" add a new secret and record it (make sure you get the secret value and NOT the object id) +4. Make sure the groups are in the ID token - on the "Manifest" tab, edit the JSON so that "groupMembershipClaims": "SecurityGroup" is set +5. On the summary page, get the Application (client) ID +6. On the summary page, choose "Endpoints" (at the top) and get the JSON text from the "OpenID Connect metadata document" Endpoints + +Setup users and groups: + +1. In Azure AD, go to groups +2. Add new Groups - "geonetworkAdmin", "geonetworkReviewer", etc\... Record the name and the group's **Object ID** +3. Edit a User, and choose Groups, and add them to appropriate group. + +Your environment variables will looks like this: + +``` properties +GEONETWORK_SECURITY_TYPE=openidconnect +OPENIDCONNECT_CLIENTSECRET='...' +OPENIDCONNECT_CLIENTID='...' +OPENIDCONNECT_SERVERMETADATA_JSON_TEXT='...big json text...' +OPENIDCONNECT_IDTOKENROLELOCATION='groups' +OPENIDCONNECT_ROLECONVERTER='3a94275f-7d53-4205-8d78-11f39e9ffa5a=Administrator,d93c6444-feee-4b67-8c0f-15d6796370cb=Reviewer' +``` + +!!! note + + The roles are in the "roles" part of the ID Token. + + +!!! note + + The OPENIDCONNECT_ROLECONVERTER converts the Azure AD Group's Object ID to a Geonetwork Role. + + +#### With Application Roles + +Setup the Azure Application: + +1. Create a new Enterprise application +2. use `http://localhost:8080/geonetwork/login/oauth2/code/geonetwork-oicd` as a redirect URIs +3. On the "Certificates & Secrets" add a new secret and record it (make sure you get the secret value and NOT the object id) +4. Make sure the groups are in the ID token - on the "Manifest" tab, edit the JSON so that "groupMembershipClaims": "ApplicationGroup" is set +5. On the summary page, get the Application (client) ID +6. On the summary page, choose "Endpoints" (at the top) and get the JSON text from the "OpenID Connect metadata document" Endpoints + +Setup Application Roles: + +1. In Application you created, go to "App Roles". +2. Add new Groups - "Editor", "Reviewer", etc\... + +Assign Users: + +1. Go to Azure AD, Enterprise Application, then the application you created +2. Choose "Assign users and groups" +3. Press the "Add user/group" (top) +4. Press "None Selected" (under Users) and choose some users +5. Press "None Selected" (Under Select a Role) and choose some roles +6. Configure all your users with roles + +Your environment variables will looks like this: + +``` properties +GEONETWORK_SECURITY_TYPE=openidconnect +OPENIDCONNECT_CLIENTSECRET='...' +OPENIDCONNECT_CLIENTID='...' +OPENIDCONNECT_SERVERMETADATA_JSON_TEXT='...big json text...' +OPENIDCONNECT_IDTOKENROLELOCATION='roles' +``` + +!!! note + + The roles are in the "roles" part of the ID Token. + + +!!! note + + You don't typically have to do any role conversion since the role name will be used in the ID Token. + + +### OIDC Bearer Tokens {#oidc_bearer_tokens} + +Bearer Tokens are also supported - you can attach the JWT Bearer token to any request by setting the HTTP header like this: + +``` properties +Authorization: Bearer: +``` + +Bearer Tokens are mostly used for automated (desktop or application) API calls - real users should just login normally using OIDC. + +1. Setup your OIDC configuration (see [Configuring OAUTH2 OpenID Connect](authentication-mode.md#authentication-openid)) +2. Setup the OIDC Bearer token configuration (see [Configuration](authentication-mode.md#bearer_token_configuration)) +3. Obtain a Bearer token from the OIDC server. This is the hard part and there are several ways to do this. One way that is used is via the OAuth 2.0 Device Authorization Grant ("Device Flow") workflow. +4. Attach it to your request headers (see [OIDC Bearer Tokens](authentication-mode.md#oidc_bearer_tokens)) +5. Make protected requests to the Geonetwork API + +This has been tested with Keycloak and with Azure AD. It should work with other JWT-based OIDC services. + +#### Validation + +The token is validated in three major ways: + +1. The bearer token will be used to access the `userinfo` ("token validation") endpoint specified in the OIDC configuration. This means the IDP validates the token (at the very least its signature and expiry). +2. The bearer token (JWT) will be checked that the audience for it is the same as our configurated OIDC configuration. This will ensure that someone isn't getting a token from a different service and attempting to use it here. See ``AudienceAccessTokenValidator.java`` +3. The bearer token (JWT) will be checked that the subject of the JWT and the `userinfo` (returned from the IDP) are the same. This shouldnt be a problem in our use-case, but the OAUTH2 specification recommends this check. See ``SubjectAccessTokenValidator.java`` + +#### Configuration {#bearer_token_configuration} + +Configure OIDC as above - ensure this is working. + +Instead of using `GEONETWORK_SECURITY_TYPE=openidconnect`, use `GEONETWORK_SECURITY_TYPE=openidconnectbearer`. + +Inside `WEB-INF/config-security/config-security-openidconnectbearer.xml`: + +1. If you are using keycloak (configured with Groups in the `userinfo` response), then uncomment the `UserInfoAccessTokenRolesResolver` bean and comment out the `MSGraphUserRolesResolver` bean. +2. If you are using Azure AD (MS Graph API for the user's groups), then then uncomment the `MSGraphUserRolesResolver` bean and comment out the `UserInfoAccessTokenRolesResolver` bean. + +The easiest way to test is to obtain a Bearer Token, and then use a browser plugin to add the ``Authorization: Bearer `` header to all requests. When you visit the Geonetwork website, you should see yourself logged in with the appropriate permissions. + +#### Other Providers + +This has been tested with Azure AD (groups in the MS Graph API) and KeyCloak (groups in the `userinfo`). + +For other IDP, you might have to make some modifications. + +1. Make sure the `AudienceAccessTokenValidator` and `SubjectAccessTokenValidator` work correctly for your JWT bearer tokens. +2. Make sure that the user's groups are available - see the `UserRolesResolver` interface and its two implementations - `UserInfoAccessTokenRolesResolver` and `MSGraphUserRolesResolver`. + +## Configuring Keycloak {#authentication-keycloak} + +[Keycloak](https://keycloak.org) is a software solution to facilitate storage of authentication details, user federation, identity brokering and social login. GeoNetwork can be set up to use a keycloak instance for authentication. + +Install keycloak from its instructions or use this example setup in docker + +Keycloak details are defined via environment variables + +``` text +KEYCLOAK_AUTH_SERVER_URL={keycloak url} +KEYCLOAK_REALM={realm name} +KEYCLOAK_RESOURCE={client name} +KEYCLOAK_SECRET={client secret} +KEYCLOAK_DISABLE_TRUST_MANAGER={true|false} +``` + +You can setup more advance keycloak settings by editing the file **`WEB-INF/config-security/keycloak.json`** + +### Geonetwork client URL configuration + +Ensure that when you configure your client that you setup the valid redirect uris to your geonetwork installation. i.e. `https://localhost:8443/geonetwork/*`. If this is not setup correctly you may get and error indicating that a wrong redirect uri was supplied. Also if wanting to test the client backchannel logout then ensure that the admin URL is also set to the geonetwork installation. + +### Sample user/role/group setup + +#### Sample Role setup + +In your client role settings (clients -> myclient -> roles). Add the following roles + +``` text +Administrator +RegisteredUser +Guest +sample:UserAdmin +sample:Reviewer +sample:Editor +sample:RegisteredUser +``` + +#### Sample Group configuration + +1. Go to keycloak groups (left menu). +2. Create a new group called "Administrator" +3. Edit the group. Go to Role Mappings -> Client Roles (myclient) -> select the administrator roles and click on "Add selected" Any user joined to the Administrator group will be a geonetwork administrator. + +#### Sample User configuration + +1. Go to keycloak users (left menu) +2. Add or select existing user. Then go to that user. +3. Go to role Mappings -> Client Roles (myclient) -> select the available roles to be applied and click on "Add selected" or go to Groups -> Available Groups -> Click on the Administrator Group and then click on "Join" + +A similar setup is described for geoserver in the [geoserver documentation](https://docs.geoserver.org/latest/en/user/community/keycloak/index.html). + +## Configuring EU Login {#authentication-ecas} + +EU Login is the central login mechanism of the European Commission. You can enable login against that central service in case your intended users have ar can acquire a EU Login. + +To enable EU Login, set up authentication by including `WEB-INF/config-security/config-security-ecas.xml` in `WEB-INF/config-security/config-security.xml`, uncommenting the following line: + +``` xml + +``` + +EU-login requires an ecas-plugin provided by the European Union. The ecas plugin is available via [CITnet](https://citnet.tech.ec.europa.eu/CITnet/nexus) for various java containers, such as Tomcat and JBoss. + +For tomcat, add two files to the tomcat lib folder: ecas-tomcat-x.y.z.jar and log4j-x.y.z.jar. Inside the lib folder copy two folders from **`eulogin-tomcat-x.y.z-config.zip`**: **`org/apache/catalina/authenticator`** and **`org/apache/catalina/startup`**. The mbeans folder contains a file **`mbeans-descriptors.xml`**. The startup folder contains a file **`Authenticators.properties`**. Verify that the JDK trusts the [ECAS certificates](https://webgate.ec.europa.eu/CITnet/confluence/display/IAM/Downloads-Certificates) else import them on the keystore of the JVM. + +The EU Login configuration is defined in **`WEB-INF/config-security/config-security.properties`**. You can configure your environment by updating the previous file or by defining property overrides in the file **`WEB-INF/config-security/config-security-overrides.properties`**: + +``` text +cas.baseURL=https://webgate.ec.europa.eu/cas +``` + +Restart the service and check the authentication menchanism. + +## Configuring Shibboleth {#authentication-shibboleth} + +The catalog can operate in a SAML secured federation. Shibboleth should be installed in Apache as described [here](https://wiki.shibboleth.net/confluence/display/SHIB2/Installation). The catalog is accessed via Apache. Setup Shibboleth authentication by including `WEB-INF/config-security/config-security-shibboleth.xml` in `WEB-INF/config-security/config-security.xml`. You can then configure your environment in `config-security-shibboleth-overrides.properties`. diff --git a/docs/manual/docs/administrator-guide/managing-users-and-groups/creating-group.md b/docs/manual/docs/administrator-guide/managing-users-and-groups/creating-group.md new file mode 100644 index 00000000000..857df1f970d --- /dev/null +++ b/docs/manual/docs/administrator-guide/managing-users-and-groups/creating-group.md @@ -0,0 +1,28 @@ +# Creating group + +The administrator can create new groups of users. User groups could correspond to logical units within an organisation, for example `Fisheries`, `Agriculture`, `Land`, `Water`, `Health` and so on. + +To create new groups you should be logged on with an account that has administrative privileges. + +1. Select the *Administration* button in the menu. On the Administration page, select *Group management*. + +2. Select *Add a new group*. You may want to remove the *Sample* group; + +3. Fill out the details. The email address will be used to send feedback on data downloads when they occur for resources that are part of the Group. + + !!! warning + + The Name should *NOT* contain spaces! You can use the Localization panel to provide localized names for groups. + + +4. Click *Save* + +Access privileges can be set per metadata record. You can define privileges on a per Group basis. + +Privileges that can be set relate to visibility of the Metadata (*Publish*), data *Download*, *Interactive Map* access and display of the record in the *Featured* section of the home page. + +*Editing* defines the groups for which editors can edit the metadata record. + +*Notify* defines what Groups are notified when a file managed by GeoNetwork is downloaded. + +Below is an example of the privileges management table related to a dataset. diff --git a/docs/manual/docs/administrator-guide/managing-users-and-groups/creating-user.md b/docs/manual/docs/administrator-guide/managing-users-and-groups/creating-user.md new file mode 100644 index 00000000000..240fac6944b --- /dev/null +++ b/docs/manual/docs/administrator-guide/managing-users-and-groups/creating-user.md @@ -0,0 +1,10 @@ +# Creating user + +To add a new user to the GeoNetwork system, please do the following: + +1. Select the *Administration* button in the menu. On the Administration page, select *User management*. +2. Click the button *Add a new user*; +3. Provide the *information* required for the new user; +4. Assign the correct *profile* (see [Users, Groups and Roles](index.md#user_profiles)); +5. Assign the user to a *group* (see [Creating group](creating-group.md)); +6. Click *Save*. diff --git a/docs/manual/docs/administrator-guide/managing-users-and-groups/img/password-forgot.png b/docs/manual/docs/administrator-guide/managing-users-and-groups/img/password-forgot.png new file mode 100644 index 00000000000..d1bc512667d Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-users-and-groups/img/password-forgot.png differ diff --git a/docs/manual/docs/administrator-guide/managing-users-and-groups/img/selfregistration-form.png b/docs/manual/docs/administrator-guide/managing-users-and-groups/img/selfregistration-form.png new file mode 100644 index 00000000000..d718b94a019 Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-users-and-groups/img/selfregistration-form.png differ diff --git a/docs/manual/docs/administrator-guide/managing-users-and-groups/img/selfregistration-start.png b/docs/manual/docs/administrator-guide/managing-users-and-groups/img/selfregistration-start.png new file mode 100644 index 00000000000..7e9a6f8084f Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-users-and-groups/img/selfregistration-start.png differ diff --git a/docs/manual/docs/administrator-guide/managing-users-and-groups/img/session-about-to-be-cancelled.png b/docs/manual/docs/administrator-guide/managing-users-and-groups/img/session-about-to-be-cancelled.png new file mode 100644 index 00000000000..9dfe2b17dbe Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-users-and-groups/img/session-about-to-be-cancelled.png differ diff --git a/docs/manual/docs/administrator-guide/managing-users-and-groups/img/session-has-expired.png b/docs/manual/docs/administrator-guide/managing-users-and-groups/img/session-has-expired.png new file mode 100644 index 00000000000..d449d7b6c5e Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-users-and-groups/img/session-has-expired.png differ diff --git a/docs/manual/docs/administrator-guide/managing-users-and-groups/img/session-will-expire-soon.png b/docs/manual/docs/administrator-guide/managing-users-and-groups/img/session-will-expire-soon.png new file mode 100644 index 00000000000..ead6a368e00 Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-users-and-groups/img/session-will-expire-soon.png differ diff --git a/docs/manual/docs/administrator-guide/managing-users-and-groups/img/setting-log-level.png b/docs/manual/docs/administrator-guide/managing-users-and-groups/img/setting-log-level.png new file mode 100644 index 00000000000..4c694145e1b Binary files /dev/null and b/docs/manual/docs/administrator-guide/managing-users-and-groups/img/setting-log-level.png differ diff --git a/docs/manual/docs/administrator-guide/managing-users-and-groups/index.md b/docs/manual/docs/administrator-guide/managing-users-and-groups/index.md new file mode 100644 index 00000000000..aa0408ce3f4 --- /dev/null +++ b/docs/manual/docs/administrator-guide/managing-users-and-groups/index.md @@ -0,0 +1,200 @@ +# Managing users and groups + +- [Creating group](creating-group.md) +- [Creating user](creating-user.md) +- [User Self-Registration](user-self-registration.md) +- [Authentication mode](authentication-mode.md) + +## Default user {#user-defaults} + +Upon installation a default user with name `admin` and password `admin` is created. It is recommended to log in with these credentials directly after the installation has completed and to change the default password. + +## User session + +After the authentication process, a user session is created. This session will be closed automatically at some point by the server for security reasons. The default session timeout is set to 35 min (see [User session timeout configuration](../../customizing-application/advanced-configuration.md#session-timeout-configuration) for details). + +When there is no activity in the browser and the session is about to expire, a warning is displayed next to the user details 3 minutes before the timeout takes place: + +![](img/session-will-expire-soon.png) + +One (1) minute before the timeout, another message is displayed: + +![](img/session-about-to-be-cancelled.png) + +When the session seems to have been destroyed by the catalog, a message recommends to refresh the page and sign in again if needed: + +![](img/session-has-expired.png) + +## Users, Groups and Roles {#user_profiles} + +The catalog uses the concept of Users, Groups and User Profiles. + +- A User can be part of one or more Groups. +- A User has a Role in a Group. +- The Administrator Role is not related to a Group. + +The combination of Role and Group defines what tasks the User can perform on the system or on specific metadata records. + +Users can have different roles in different groups. A role defines what tasks the user can perform. + +Roles are hierarchical and based on inheritance. This means that a user with an Editor profile can create and modify new metadata records, but can also use all functions a Registered user can use. + +Rights associated with the roles are illustrated in detail in the list below: + +1. **Administrator Profile** + + The Administrator has special privileges that give access to all available functions. + + These include: + + - Full rights for creating new groups and new users. + - Rights to change users/groups profiles. + - Full rights for creating/editing/deleting new/old metadata. + - Perform system administration and configuration tasks. + +2. **User Administrator Profile** + + The user administrator is the administrator of his/her own group(s) with the following privileges: + + - Full rights on creating new users within their own groups. + - Rights to change users profiles within their own groups. + +3. **Content Reviewer Profile** + + The content reviewer is the only person allowed to give final clearance on the metadata publication on the Intranet and/or on the Internet: + + - Rights on reviewing metadata content within their own groups and authorising its approval and publication. + +4. **Editor Profile** + + The editor works on metadata with following privileges: + + - Full rights on creating/editing/ deleting new/old data within their own groups. + +5. **Registered User Profile** + + The Registered User has more access privileges than non-authenticated Guest users: + + - Right to download protected data. + +## Role and feature Matrix + +The tables below show a comprehensive overview of Roles and Features, it explains in detail what role can do what in GeoNetwork. + +| Code | Description | +| ----- | ----- | +| UI | Feature visible in the UI, but not usable by the user profile | +| EDIT | The user can edit the metadata imported by the user | +| DEL | The user can delete the metadata imported by the user | + +=== "Search" + + | | Anonymous user | Registered User | Editor| Reviewer| User Admin | Admini- strator | + |---------------------------------------------| :---: |:-----------------------:| :---: | :---: |:-----------------------:|:-----------------------:| + | Metadata selection / Export (ZIP) | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Metadata selection / Export (PDF) | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Metadata selection / Export (CSV) | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Metadata selection / Selection only | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Metadata selection / Update privileges | | | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Metadata selection / Publish | | | | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Metadata selection / Unpublish | | | | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Metadata selection / Approve | | | | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Metadata selection / Transfer Ownership | | | | | :material-check-circle: | :material-check-circle: | + | Metadata selection / Validate | | | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Metadata selection / Validate records links | | | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Metadata selection / Updates categories | | | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Metadata selection / Delete | | | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Metadata selection / Index records | | | | | :material-check-circle: | :material-check-circle: | + | Preferred Records | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Watch list | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | "Sorted by relevancy, modified, title..." | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + +=== "Metadata Page" + + | | Anonymous user | Registered User | Editor| Reviewer| User Admin | Admini- strator | + |---------------------------------------------| :---: |:-----------------------:| :---: | :---: |:-----------------------:|:-----------------------:| + | Edit| | | :material-check-circle: | :material-check-circle: | EDIT | :material-check-circle: | + | Delete| | | :material-check-circle: | :material-check-circle: | DEL | :material-check-circle: | + | Cancel working copy| | | :material-check-circle: | :material-check-circle: | | :material-check-circle: | + | Manage Record / Privileges| | | :material-check-circle: | :material-check-circle: | | :material-check-circle: | + | Manage Record / Transfer Ownership| | | | | | :material-check-circle: | + | Manage Record / Unpublish| | | | :material-check-circle: | | :material-check-circle: | + | Manage Record / Publish| | | | :material-check-circle: | | :material-check-circle: | + | Manage Record / Work flow / submit for review| | | :material-check-circle: | :material-check-circle: | | :material-check-circle: | + | Manage Record / Work flow / directly approve metadata| | | | :material-check-circle: | | :material-check-circle: | + | Manage Record / Work flow / approve metadata | | | | :material-check-circle: | | :material-check-circle: | + | Manage Record / Work flow / reject approval submision| | | | :material-check-circle: | | :material-check-circle: | + | Manage Record / Work flow / cancel approval submission| | | :material-check-circle: | | | :material-check-circle: | + | Manage Record / DOI Creation request| | | :material-check-circle: | :material-check-circle: | UI | :material-check-circle: | + | Manage Record / Duplicate| | | :material-check-circle: | :material-check-circle: | UI | :material-check-circle: | + | Download record / Permalink| :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Download record / Export (ZIP)| :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Download record / Export (PDF)| :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Download record / Export (XML)| :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Download record / EXport (RDF)| :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + +=== "Editor" + + | | Anonymous user | Registered User | Editor| Reviewer| User Admin | Admini- strator | + |---------------------------------------------| :---: |:-----------------------:| :---: | :---: |:-----------------------:|:-----------------------:| + | Editor board| | | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Add new record| | | :material-check-circle: | :material-check-circle: | UI | :material-check-circle: | + | Import new records| | | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Manage directory| | | :material-check-circle: | :material-check-circle: | UI | :material-check-circle: | + | Batch editing| | | :material-check-circle: | :material-check-circle: | EDIT | :material-check-circle: | + | Access rights| | | | | | :material-check-circle: | + | Editor board / Export (ZIP)| | | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Editor board / EXport (PDF)| | | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Editor board / Export (CSV)| | | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Editor board / Selection only| | | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Editor board / Updates privileges| | | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Editor board / Publish| | | | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Editor board / Unpublish| | | | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Editor board / Approve| | | | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Editor board / Transfer Ownership| | | | | :material-check-circle: | :material-check-circle: | + | Editor board / Validate| | | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Editor board / Validate record links| | | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Editor board / Updates categories| | | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | | | | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Editor board / Delete| | | :material-check-circle: | :material-check-circle: | :material-check-circle: | :material-check-circle: | + | Editor board / Index records| | | | | :material-check-circle: | :material-check-circle: | + +=== "Administration" + + | | Anonymous user | Registered User | Editor| Reviewer| User Admin | Admini- strator | + |---------------------------------------------| :---: |:-----------------------:| :---: | :---: |:-----------------------:|:-----------------------:| + | Summary| | | | | | :material-check-circle: | + | Metadata and Templates| | | | | | :material-check-circle: | + | Metadata and Templates / Standards| | | | | | :material-check-circle: | + | Metadata and Templates / Formatter| | | | | | :material-check-circle: | + | Metadata and Templates / Validation| | | | | | :material-check-circle: | + | Metadata and Templates / Metadata Identifier templates| | | | | | :material-check-circle: | + | Users and groups / Manage groups| | | | | :material-check-circle: | :material-check-circle: | + | Users and groups / Manage users| | | | | :material-check-circle: | :material-check-circle: | + | Harvesting / Catalogo harvesters| | | | | :material-check-circle: | :material-check-circle: | + | Harvesting / Catalogo harvesters report| | | | | :material-check-circle: | :material-check-circle: | + | Harvesting / Feature harvesters| | | | | :material-check-circle: | :material-check-circle: | + | Statistics and status / Status| | | | | | :material-check-circle: | + | Statistics and status / Record links analysis| | | | | :material-check-circle: | :material-check-circle: | + | Statistics and status / Information| | | | | | :material-check-circle: | + | Statistics and status / Versioning| | | | | | :material-check-circle: | + | Statistics and status / Content statistics| | | | | :material-check-circle: | :material-check-circle: | + | Reports / Update matadata| | | | | :material-check-circle: | :material-check-circle: | + | Reports / Internal metadata| | | | | :material-check-circle: | :material-check-circle: | + | Reports / Metadata file uploads| | | | | :material-check-circle: | :material-check-circle: | + | Reports / Metadata file dowloads| | | | | :material-check-circle: | :material-check-circle: | + | Reports / Users access| | | | | :material-check-circle: | :material-check-circle: | + | Classification systems / Theaurus| | | | | | :material-check-circle: | + | Classification systems / Category| | | | | | :material-check-circle: | + | Settings / Settings| | | | | | :material-check-circle: | + | Settings / User interface| | | | | :material-check-circle: | :material-check-circle: | + | Settings / CSS and Style| | | | | | :material-check-circle: | + | Settings / Logo| | | | | | :material-check-circle: | + | Settings / Sources| | | | | :material-check-circle: | :material-check-circle: | + | Settings / CSW| | | | | | :material-check-circle: | + | Settings / CSW test| | | | | | :material-check-circle: | + | Settings / Map servers| | | | | | :material-check-circle: | + | Settings / Static pages| | | | | | :material-check-circle: | + | Tools / Catalogue admin tools| | | | | | :material-check-circle: | + | Tools / Batch process| | | | | | :material-check-circle: | + | Tools / Transfer ownership| | | | | | :material-check-circle: | diff --git a/docs/manual/docs/administrator-guide/managing-users-and-groups/user-self-registration.md b/docs/manual/docs/administrator-guide/managing-users-and-groups/user-self-registration.md new file mode 100644 index 00000000000..fe3cb2d0142 --- /dev/null +++ b/docs/manual/docs/administrator-guide/managing-users-and-groups/user-self-registration.md @@ -0,0 +1,110 @@ +# User Self-Registration {#user_self_registration} + +To enable the self-registration functions, see [System configuration](../configuring-the-catalog/system-configuration.md). When self-registration is enabled, for users that are not logged in, an additional link is shown on the login page: + +![](img/selfregistration-start.png) + +Click the `Create an account` button and fill out the registration form: + +![](img/selfregistration-form.png) + +The fields in this form are self-explanatory except for the following: + +- **Email**: The user's email address. This is mandatory and will be used as the username. +- **Requested profile**: By default, self-registered users are given the `Registered User` profile (see previous section). If any other profile is selected: + - the user will still be given the `Registered User` profile + - an email will be sent to the Email address nominated in the Feedback section of the 'System Administration' menu, informing them of the request for a more privileged profile +- **Requested group**: By default, self-registered users are not assigned to any group. If a group is selected: + - the user will still not be assigned to any group + - an email will be sent to the Email address nominated in the Feedback section of the 'System Administration' menu, informing them of the requested group. + +## What happens when a user self-registers? + +When a user self-registration occurs, the user receives an email with the new account details that looks something like the following: + + Dear User, + + Your registration at The Greenhouse GeoNetwork Site was successful. + + Your account is: + username : dubya.shrub@greenhouse.gov + password : 0110O3 + usergroup: GUEST + usertype : REGISTEREDUSER + + You've told us that you want to be "Editor", you will be contacted by our office soon. + + To log in and access your account, please click on the link below. + http://greenhouse.gov/geonetwork + + Thanks for your registration. + + Yours sincerely, + The team at The Greenhouse GeoNetwork Site + +Notice that the user has requested an 'Editor' profile. As a result an email will be sent to the Email address nominated in the Feedback (see [Feedback](../configuring-the-catalog/system-configuration.md#system-config-feedback)) section of the `System Administration` menu which looks something like the following: + +Notice also that the user has been added to the built-in user group 'GUEST'. This is a security restriction. An administrator/user-administrator can add the user to other groups if that is required later. + +If you want to change the content of this email, you should modify `xslt/service/account/registration-pwd-email.xsl`. + + Dear Admin, + + Newly registered user dubya.shrub@greenhouse.gov has requested "Editor" access for: + + Instance: The Greenhouse GeoNetwork Site + Url: http://greenhouse.gov/geonetwork + + User registration details: + + Name: Dubya + Surname: Shrub + Email: dubya.shrub@greenhouse.gov + Organisation: The Greenhouse + Type: gov + Address: 146 Main Avenue, Creationville + State: Clerical + Post Code: 92373 + Country: Mythical + + Please action. + + The Greenhouse GeoNetwork Site + +If you want to change the content of this email, you should modify `xslt/service/account/registration-prof-email.xsl`. + +## The 'Forgot your password?' function + +This function allows users who have forgotten their password to request a new one. Go to the sign in page to access the form: + +![](img/password-forgot.png) + +For security reasons, only users that have the `Registered User` profile can request a new password. + +If a user takes this option they will receive an email inviting them to change their password as follows: + + You have requested to change your Greenhouse GeoNetwork Site password. + + You can change your password using the following link: + + http://localhost:8080/geonetwork/srv/en/password.change.form?username=dubya.shrub@greenhouse.gov&changeKey=635d6c84ddda782a9b6ca9dda0f568b011bb7733 + + This link is valid for today only. + + Greenhouse GeoNetwork Site + +The catalog has generated a changeKey from the forgotten password and the current date and emailed that to the user as part of a link to a change password form. + +If you want to change the content of this email, you should modify `xslt/service/account/password-forgotten-email.xsl`. + +When the user clicks on the link, a change password form is displayed in their browser and a new password can be entered. When that form is submitted, the changeKey is regenerated and checked with the changeKey supplied in the link, if they match then the password is changed to the new password supplied by the user. + +The final step in this process is a verification email sent to the email address of the user confirming that a change of password has taken place: + + Your Greenhouse GeoNetwork Site password has been changed. + + If you did not change this password contact the Greenhouse GeoNetwork Site helpdesk + + The Greenhouse GeoNetwork Site team + +If you want to change the content of this email, you should modify `xslt/service/account/password-changed-email.xsl`. diff --git a/docs/manual/docs/annexes/gallery/img/agroenvgeo_data_inra_fr_geonetwork.png b/docs/manual/docs/annexes/gallery/img/agroenvgeo_data_inra_fr_geonetwork.png new file mode 100644 index 00000000000..d776bbfff43 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/agroenvgeo_data_inra_fr_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/catalogue-imos_aodn_org_au_geonetwork.png b/docs/manual/docs/annexes/gallery/img/catalogue-imos_aodn_org_au_geonetwork.png new file mode 100644 index 00000000000..31d355a5b07 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/catalogue-imos_aodn_org_au_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/catalogue_ec_gc_ca_geonetwork.png b/docs/manual/docs/annexes/gallery/img/catalogue_ec_gc_ca_geonetwork.png new file mode 100644 index 00000000000..775347e1e60 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/catalogue_ec_gc_ca_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/catalogue_geo-ide_developpement-durable_gouv_fr_catalogue.png b/docs/manual/docs/annexes/gallery/img/catalogue_geo-ide_developpement-durable_gouv_fr_catalogue.png new file mode 100644 index 00000000000..6d6302d4e2d Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/catalogue_geo-ide_developpement-durable_gouv_fr_catalogue.png differ diff --git a/docs/manual/docs/annexes/gallery/img/cdgp_u-strasbg_fr_geonetwork.png b/docs/manual/docs/annexes/gallery/img/cdgp_u-strasbg_fr_geonetwork.png new file mode 100644 index 00000000000..d4ed9dea306 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/cdgp_u-strasbg_fr_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/doterr_fr_accueil.png b/docs/manual/docs/annexes/gallery/img/doterr_fr_accueil.png new file mode 100644 index 00000000000..5ab95a954c4 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/doterr_fr_accueil.png differ diff --git a/docs/manual/docs/annexes/gallery/img/download_data_grandlyon_com_catalogue.png b/docs/manual/docs/annexes/gallery/img/download_data_grandlyon_com_catalogue.png new file mode 100644 index 00000000000..9e401ad00d8 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/download_data_grandlyon_com_catalogue.png differ diff --git a/docs/manual/docs/annexes/gallery/img/ecat_ga_gov_au_geonetwork.png b/docs/manual/docs/annexes/gallery/img/ecat_ga_gov_au_geonetwork.png new file mode 100644 index 00000000000..9b1b122e3f5 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/ecat_ga_gov_au_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/fao_org_geonetwork.png b/docs/manual/docs/annexes/gallery/img/fao_org_geonetwork.png new file mode 100644 index 00000000000..cac6dbe78b6 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/fao_org_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/gatt_lmi_is_geonetwork.png b/docs/manual/docs/annexes/gallery/img/gatt_lmi_is_geonetwork.png new file mode 100644 index 00000000000..23126e28fb0 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/gatt_lmi_is_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/gdk_gdi-de_org_gdi-de.png b/docs/manual/docs/annexes/gallery/img/gdk_gdi-de_org_gdi-de.png new file mode 100644 index 00000000000..96ab86e3f38 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/gdk_gdi-de_org_gdi-de.png differ diff --git a/docs/manual/docs/annexes/gallery/img/geo2france_fr_geonetwork.png b/docs/manual/docs/annexes/gallery/img/geo2france_fr_geonetwork.png new file mode 100644 index 00000000000..0ed098a8e0f Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/geo2france_fr_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/geo_be_catalogs_1_resources.png b/docs/manual/docs/annexes/gallery/img/geo_be_catalogs_1_resources.png new file mode 100644 index 00000000000..c64aee29c6a Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/geo_be_catalogs_1_resources.png differ diff --git a/docs/manual/docs/annexes/gallery/img/geo_gob_bo_geonetwork.png b/docs/manual/docs/annexes/gallery/img/geo_gob_bo_geonetwork.png new file mode 100644 index 00000000000..37770c934c2 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/geo_gob_bo_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/geocat_ch_geonetwork.png b/docs/manual/docs/annexes/gallery/img/geocat_ch_geonetwork.png new file mode 100644 index 00000000000..3884e9b4274 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/geocat_ch_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/geocatalog_webservice-energy_org_geonetwork.png b/docs/manual/docs/annexes/gallery/img/geocatalog_webservice-energy_org_geonetwork.png new file mode 100644 index 00000000000..f9880c7e29b Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/geocatalog_webservice-energy_org_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/geocatalogue_apur_org_catalogue.png b/docs/manual/docs/annexes/gallery/img/geocatalogue_apur_org_catalogue.png new file mode 100644 index 00000000000..f5902e67194 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/geocatalogue_apur_org_catalogue.png differ diff --git a/docs/manual/docs/annexes/gallery/img/geocatalogue_geoportail_lu.png b/docs/manual/docs/annexes/gallery/img/geocatalogue_geoportail_lu.png new file mode 100644 index 00000000000..9f0ce89fb88 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/geocatalogue_geoportail_lu.png differ diff --git a/docs/manual/docs/annexes/gallery/img/geodata_nz_geonetwork.png b/docs/manual/docs/annexes/gallery/img/geodata_nz_geonetwork.png new file mode 100644 index 00000000000..33447750289 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/geodata_nz_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/geograndest_fr_geonetwork.png b/docs/manual/docs/annexes/gallery/img/geograndest_fr_geonetwork.png new file mode 100644 index 00000000000..42866e34e35 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/geograndest_fr_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/geoguyane_fr_catalogue.png b/docs/manual/docs/annexes/gallery/img/geoguyane_fr_catalogue.png new file mode 100644 index 00000000000..bdf3ca710fd Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/geoguyane_fr_catalogue.png differ diff --git a/docs/manual/docs/annexes/gallery/img/geomartinique_fr_accueil.png b/docs/manual/docs/annexes/gallery/img/geomartinique_fr_accueil.png new file mode 100644 index 00000000000..d4d34a9e381 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/geomartinique_fr_accueil.png differ diff --git a/docs/manual/docs/annexes/gallery/img/geometadatensuche_inspire_gv_at.png b/docs/manual/docs/annexes/gallery/img/geometadatensuche_inspire_gv_at.png new file mode 100644 index 00000000000..9736daebc93 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/geometadatensuche_inspire_gv_at.png differ diff --git a/docs/manual/docs/annexes/gallery/img/geonorge_no_geonetwork.png b/docs/manual/docs/annexes/gallery/img/geonorge_no_geonetwork.png new file mode 100644 index 00000000000..a2026372215 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/geonorge_no_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/geonormandie_fr_accueil.png b/docs/manual/docs/annexes/gallery/img/geonormandie_fr_accueil.png new file mode 100644 index 00000000000..ac7a6998450 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/geonormandie_fr_accueil.png differ diff --git a/docs/manual/docs/annexes/gallery/img/geopal_org_accueil.png b/docs/manual/docs/annexes/gallery/img/geopal_org_accueil.png new file mode 100644 index 00000000000..d4f8f1e3845 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/geopal_org_accueil.png differ diff --git a/docs/manual/docs/annexes/gallery/img/geoportail_lepuyenvelay_fr_geonetwork.png b/docs/manual/docs/annexes/gallery/img/geoportail_lepuyenvelay_fr_geonetwork.png new file mode 100644 index 00000000000..650fb9a973d Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/geoportail_lepuyenvelay_fr_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/geoportal_kscnet_ru_geonetwork.png b/docs/manual/docs/annexes/gallery/img/geoportal_kscnet_ru_geonetwork.png new file mode 100644 index 00000000000..9f6a3ad65ff Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/geoportal_kscnet_ru_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/georep_nc.png b/docs/manual/docs/annexes/gallery/img/georep_nc.png new file mode 100644 index 00000000000..2c39b830f5f Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/georep_nc.png differ diff --git a/docs/manual/docs/annexes/gallery/img/gis_ices_dk_geonetwork.png b/docs/manual/docs/annexes/gallery/img/gis_ices_dk_geonetwork.png new file mode 100644 index 00000000000..fdf1efe6dea Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/gis_ices_dk_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/iandc_pnra_aq.png b/docs/manual/docs/annexes/gallery/img/iandc_pnra_aq.png new file mode 100644 index 00000000000..94a5cb9d9fa Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/iandc_pnra_aq.png differ diff --git a/docs/manual/docs/annexes/gallery/img/ide_cat_en_catalogue.png b/docs/manual/docs/annexes/gallery/img/ide_cat_en_catalogue.png new file mode 100644 index 00000000000..768cc7c01e0 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/ide_cat_en_catalogue.png differ diff --git a/docs/manual/docs/annexes/gallery/img/idee_es_csw-codsi-idee.png b/docs/manual/docs/annexes/gallery/img/idee_es_csw-codsi-idee.png new file mode 100644 index 00000000000..4e95630b82e Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/idee_es_csw-codsi-idee.png differ diff --git a/docs/manual/docs/annexes/gallery/img/ids_craig_fr_geocat.png b/docs/manual/docs/annexes/gallery/img/ids_craig_fr_geocat.png new file mode 100644 index 00000000000..e2129485ce4 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/ids_craig_fr_geocat.png differ diff --git a/docs/manual/docs/annexes/gallery/img/indores_fr_geonetwork.png b/docs/manual/docs/annexes/gallery/img/indores_fr_geonetwork.png new file mode 100644 index 00000000000..6015af6e5e7 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/indores_fr_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/inspire_gov_hu_geonetwork.png b/docs/manual/docs/annexes/gallery/img/inspire_gov_hu_geonetwork.png new file mode 100644 index 00000000000..6c05423ef28 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/inspire_gov_hu_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/karugeo_fr_accueil.png b/docs/manual/docs/annexes/gallery/img/karugeo_fr_accueil.png new file mode 100644 index 00000000000..233fbe77584 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/karugeo_fr_accueil.png differ diff --git a/docs/manual/docs/annexes/gallery/img/meta_data-za_org_catalogue.png b/docs/manual/docs/annexes/gallery/img/meta_data-za_org_catalogue.png new file mode 100644 index 00000000000..869c8215284 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/meta_data-za_org_catalogue.png differ diff --git a/docs/manual/docs/annexes/gallery/img/metadados_snirh_gov_br_geonetwork.png b/docs/manual/docs/annexes/gallery/img/metadados_snirh_gov_br_geonetwork.png new file mode 100644 index 00000000000..faa9f636d85 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/metadados_snirh_gov_br_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/metadata_geopunt_be_zoekdienst.png b/docs/manual/docs/annexes/gallery/img/metadata_geopunt_be_zoekdienst.png new file mode 100644 index 00000000000..c4fa4fb230b Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/metadata_geopunt_be_zoekdienst.png differ diff --git a/docs/manual/docs/annexes/gallery/img/metadata_vlaanderen_be.png b/docs/manual/docs/annexes/gallery/img/metadata_vlaanderen_be.png new file mode 100644 index 00000000000..d17b8050766 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/metadata_vlaanderen_be.png differ diff --git a/docs/manual/docs/annexes/gallery/img/metadata_vlaanderen_be_metadatacenter.png b/docs/manual/docs/annexes/gallery/img/metadata_vlaanderen_be_metadatacenter.png new file mode 100644 index 00000000000..62dfbb7f8c3 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/metadata_vlaanderen_be_metadatacenter.png differ diff --git a/docs/manual/docs/annexes/gallery/img/metawal_wallonie_be.png b/docs/manual/docs/annexes/gallery/img/metawal_wallonie_be.png new file mode 100644 index 00000000000..cea6dfc456c Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/metawal_wallonie_be.png differ diff --git a/docs/manual/docs/annexes/gallery/img/mongeosource_fr_geosource.png b/docs/manual/docs/annexes/gallery/img/mongeosource_fr_geosource.png new file mode 100644 index 00000000000..f2ceb587b2d Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/mongeosource_fr_geosource.png differ diff --git a/docs/manual/docs/annexes/gallery/img/msdi_data_gov_mt_geonetwork.png b/docs/manual/docs/annexes/gallery/img/msdi_data_gov_mt_geonetwork.png new file mode 100644 index 00000000000..c601779bf0b Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/msdi_data_gov_mt_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/nationaalgeoregister_nl_geonetwork.png b/docs/manual/docs/annexes/gallery/img/nationaalgeoregister_nl_geonetwork.png new file mode 100644 index 00000000000..32e66f9c815 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/nationaalgeoregister_nl_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/opendata_zuid-holland_nl_geonetwork.png b/docs/manual/docs/annexes/gallery/img/opendata_zuid-holland_nl_geonetwork.png new file mode 100644 index 00000000000..4bb65ef66e0 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/opendata_zuid-holland_nl_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/paikkatietohakemisto_fi.png b/docs/manual/docs/annexes/gallery/img/paikkatietohakemisto_fi.png new file mode 100644 index 00000000000..2c18932666c Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/paikkatietohakemisto_fi.png differ diff --git a/docs/manual/docs/annexes/gallery/img/picto-occitanie_fr_accueil.png b/docs/manual/docs/annexes/gallery/img/picto-occitanie_fr_accueil.png new file mode 100644 index 00000000000..ce3a2dd248d Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/picto-occitanie_fr_accueil.png differ diff --git a/docs/manual/docs/annexes/gallery/img/pigma_org_geonetwork.png b/docs/manual/docs/annexes/gallery/img/pigma_org_geonetwork.png new file mode 100644 index 00000000000..03e94e4ecad Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/pigma_org_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/prodige_cerema_fr.png b/docs/manual/docs/annexes/gallery/img/prodige_cerema_fr.png new file mode 100644 index 00000000000..ed1834f6067 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/prodige_cerema_fr.png differ diff --git a/docs/manual/docs/annexes/gallery/img/santegraphie_fr_geonetwork.png b/docs/manual/docs/annexes/gallery/img/santegraphie_fr_geonetwork.png new file mode 100644 index 00000000000..864a7ab900b Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/santegraphie_fr_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/services_data_shom_fr_geonetwork.png b/docs/manual/docs/annexes/gallery/img/services_data_shom_fr_geonetwork.png new file mode 100644 index 00000000000..be83c3bb1d3 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/services_data_shom_fr_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/sextant_ifremer_fr_eng.png b/docs/manual/docs/annexes/gallery/img/sextant_ifremer_fr_eng.png new file mode 100644 index 00000000000..b3e9b0e4d34 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/sextant_ifremer_fr_eng.png differ diff --git a/docs/manual/docs/annexes/gallery/img/sigloire_fr.png b/docs/manual/docs/annexes/gallery/img/sigloire_fr.png new file mode 100644 index 00000000000..f799c5d8ea7 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/sigloire_fr.png differ diff --git a/docs/manual/docs/annexes/gallery/img/www_cdata_cerema_fr_geonetwork.png b/docs/manual/docs/annexes/gallery/img/www_cdata_cerema_fr_geonetwork.png new file mode 100644 index 00000000000..29cb719ff76 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/www_cdata_cerema_fr_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/img/www_metadados_geo_ibge_gov_br_geonetwork_ibge.png b/docs/manual/docs/annexes/gallery/img/www_metadados_geo_ibge_gov_br_geonetwork_ibge.png new file mode 100644 index 00000000000..b057834f737 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/www_metadados_geo_ibge_gov_br_geonetwork_ibge.png differ diff --git a/docs/manual/docs/annexes/gallery/img/www_metadados_idesp_sp_gov_br_catalogo.png b/docs/manual/docs/annexes/gallery/img/www_metadados_idesp_sp_gov_br_catalogo.png new file mode 100644 index 00000000000..c287616928c Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/www_metadados_idesp_sp_gov_br_catalogo.png differ diff --git a/docs/manual/docs/annexes/gallery/img/www_sandre_eaufrance_fr_atlas.png b/docs/manual/docs/annexes/gallery/img/www_sandre_eaufrance_fr_atlas.png new file mode 100644 index 00000000000..c80b9d02319 Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/www_sandre_eaufrance_fr_atlas.png differ diff --git a/docs/manual/docs/annexes/gallery/img/www_wodgik_katowice_pl_8080_geonetwork.png b/docs/manual/docs/annexes/gallery/img/www_wodgik_katowice_pl_8080_geonetwork.png new file mode 100644 index 00000000000..891abf8986f Binary files /dev/null and b/docs/manual/docs/annexes/gallery/img/www_wodgik_katowice_pl_8080_geonetwork.png differ diff --git a/docs/manual/docs/annexes/gallery/index.md b/docs/manual/docs/annexes/gallery/index.md new file mode 100644 index 00000000000..5fc50ed761e --- /dev/null +++ b/docs/manual/docs/annexes/gallery/index.md @@ -0,0 +1,243 @@ +# Some GeoNetwork nodes {#gallery} + +- + + ![](img/catalogue_geo-ide_developpement-durable_gouv_fr_catalogue.png) + +- + + ![](img/geocatalog_webservice-energy_org_geonetwork.png) + +- + + ![](img/geometadatensuche_inspire_gv_at.png) + +- + + ![](img/geoportal_kscnet_ru_geonetwork.png) + +- + + ![](img/inspire_gov_hu_geonetwork.png) + +- + + ![](img/meta_data-za_org_catalogue.png) + +- + + ![](img/metadata_geopunt_be_zoekdienst.png) + +- + + ![](img/metawal_wallonie_be.png) + +- + + ![](img/services_data_shom_fr_geonetwork.png) + +- + + ![](img/fao_org_geonetwork.png) + +- + + ![](img/geoguyane_fr_catalogue.png) + +- + + ![](img/geonorge_no_geonetwork.png) + +- + + ![](img/geopal_org_accueil.png) + +- + + ![](img/idee_es_csw-codsi-idee.png) + +- + + ![](img/www_metadados_geo_ibge_gov_br_geonetwork_ibge.png) + +- + + ![](img/www_metadados_idesp_sp_gov_br_catalogo.png) + +- + + ![](img/nationaalgeoregister_nl_geonetwork.png) + +- + + ![](img/www_sandre_eaufrance_fr_atlas.png) + +- + + ![](img/sigloire_fr.png) + +- + + ![](img/www_wodgik_katowice_pl_8080_geonetwork.png) + +- + + ![](img/agroenvgeo_data_inra_fr_geonetwork.png) + +- + + ![](img/catalogue-imos_aodn_org_au_geonetwork.png) + +- + + ![](img/catalogue_ec_gc_ca_geonetwork.png) + +- + + ![](img/cdgp_u-strasbg_fr_geonetwork.png) + +- + + ![](img/download_data_grandlyon_com_catalogue.png) + +- + + ![](img/ecat_ga_gov_au_geonetwork.png) + +- + + ![](img/gatt_lmi_is_geonetwork.png) + +- + + ![](img/gdk_gdi-de_org_gdi-de.png) + +- + + ![](img/geo_gob_bo_geonetwork.png) + +- + + ![](img/geocatalogue_apur_org_catalogue.png) + +- + + ![](img/geocatalogue_geoportail_lu.png) + +- + + ![](img/geodata_nz_geonetwork.png) + +- + + ![](img/geoportail_lepuyenvelay_fr_geonetwork.png) + +- + + ![](img/georep_nc.png) + +- + + ![](img/gis_ices_dk_geonetwork.png) + +- + + ![](img/iandc_pnra_aq.png) + +- + + ![](img/ide_cat_en_catalogue.png) + +- + + ![](img/ids_craig_fr_geocat.png) + +- + + ![](img/metadados_snirh_gov_br_geonetwork.png) + +- + + ![](img/metadata_vlaanderen_be.png) + +- + + ![](img/metadata_vlaanderen_be_metadatacenter.png) + +- + + ![](img/msdi_data_gov_mt_geonetwork.png) + +- + + ![](img/opendata_zuid-holland_nl_geonetwork.png) + +- + + ![](img/prodige_cerema_fr.png) + +- + + ![](img/santegraphie_fr_geonetwork.png) + +- + + ![](img/sextant_ifremer_fr_eng.png) + +- + + ![](img/www_cdata_cerema_fr_geonetwork.png) + +- + + ![](img/doterr_fr_accueil.png) + +- + + ![](img/geo_be_catalogs_1_resources.png) + +- + + ![](img/geo2france_fr_geonetwork.png) + +- + + ![](img/geocat_ch_geonetwork.png) + +- + + ![](img/geograndest_fr_geonetwork.png) + +- + + ![](img/geomartinique_fr_accueil.png) + +- + + ![](img/geonormandie_fr_accueil.png) + +- + + ![](img/indores_fr_geonetwork.png) + +- + + ![](img/karugeo_fr_accueil.png) + +- + + ![](img/mongeosource_fr_geosource.png) + +- + + ![](img/paikkatietohakemisto_fi.png) + +- + + ![](img/picto-occitanie_fr_accueil.png) + +- + + ![](img/pigma_org_geonetwork.png) + +To add your catalog to this list, add it to [this list](https://github.com/geonetwork/doc/tree/develop/source/annexes/gallery/gallery-urls.csv). diff --git a/docs/manual/docs/annexes/index.md b/docs/manual/docs/annexes/index.md new file mode 100644 index 00000000000..5ac9b9c66c6 --- /dev/null +++ b/docs/manual/docs/annexes/index.md @@ -0,0 +1,5 @@ +# Annexes + +- [Metadata Exchange Format (MEF)](mef-format.md) +- [Some GeoNetwork nodes](gallery/index.md) +- [Standards](standards/index.md) diff --git a/docs/manual/docs/annexes/mef-format.md b/docs/manual/docs/annexes/mef-format.md new file mode 100644 index 00000000000..f550478e1b1 --- /dev/null +++ b/docs/manual/docs/annexes/mef-format.md @@ -0,0 +1,148 @@ +# Metadata Exchange Format (MEF) {#mef_format} + +## Introduction + +The metadata exchange format (MEF in short) is a specially designed file format for the purpose of metadata exchange between different platforms. A metadata exported as a MEF can be imported by any platform which is able to understand MEF. This format has been developed with GeoNetwork in mind so the information it contains is mainly related to GeoNetwork. Nevertheless, it can be used as an interoperability format between different platforms. + +This format has been designed with the following needs in mind: + +1. Export a metadata record for backup purposes +2. Import a metadata record from a previous backup +3. Import a metadata record from a different GeoNetwork version to allow a smooth migration from one version to another. +4. Capture metadata plus thumbnails and any data uploaded with the metadata record. + +In the paragraphs below, some terms should be intended as follows: + +1. the term actor is used to indicate any system (application, service etc\...) that operates on metadata. +2. the term reader will be used to indicate any actor that can import metadata from a MEF file. +3. the term writer will be used to indicate any actor that can generate a MEF file. + +## MEF v1 file format + +A MEF file is simply a ZIP file which contains the following files: + +``` text +Root + | + +--- metadata.xml + +--- info.xml + +--- public + | +---- all public documents and thumbnails + +--- private + +---- all private documents and thumbnails +``` + +1. *metadata.xml*: this file contains the metadata itself, in XML format. The text encoding of the metadata (eg. UTF-8) is specified in the XML declaration. +2. *info.xml*: this is a special XML file which contains information related to the metadata (metadata about the metadata). Examples of the information in the info.xml file are: creation date, modification date, privileges This information is needed by GeoNetwork. +3. *public*: this is a directory used to store the metadata thumbnails and other public files. There are no restrictions on the image format but it is strongly recommended to use the portable network graphics (PNG), JPEG or GIF format. +4. *private*: this is a directory used to store all data (maps, shape files etc\...) uploaded with the metadata in the GeoNetwork editor. Files in this directory are *private* in the sense that authorisation is required to access them. There are no restrictions on the file types that can be stored into this directory. + +Any other file or directory present in the MEF file should be ignored by readers that don't recognise them. This allows actors to add custom extensions to the MEF file. + +A MEF file can have empty public and private folders depending upon the export format, which can be: + +- *simple*: both public and private are omitted. +- *partial*: only public files are provided. +- *full*: both public and private files are provided. + +It is recommended to use the .mef extension when naming MEF files. + +## MEF v2 file format + +MEF version 2 support the following: + +- multi-metadata support: more than one metadata record and data can be stored in a single MEF file. +- multi-schema support: be able to store in a single MEF n formats (eg. for an ISO profile, also store a version of that record in the base ISO19115/ISO19139 schema). + +Current export services that create MEF files from a metadata record with related records (eg. paent, feature catalog etc), can include these related metadata records in the MEF. + +MEF v2 format structure is the following: + +``` text +Root + | + + 0..n metadata + | + +--- metadata + | +--- metadata.xml + | +--- (optional) metadata.iso19139.xml + +--- info.xml + +--- applschema + | +--- (optional) metadata.xml (ISO19110 Feature Catalog) + +--- public + | +---- all public documents and thumbnails + +--- private + +---- all private documents and thumbnails +``` + +!!! note + + metadata.iso19139.xml is generated by GeoNetwork actors on export if the metadata record in metadata.xml is an ISO19115/19139 profile. On import, this record may be selected for loading if the ISO19115/19139 profile is not present. + + +## The info.xml file + +This file contains general information about a metadata. It must have an info root element with a mandatory version attribute. This attribute must be in the X.Y form, where X represents the major version and Y the minor one. The purpose of this attribute is to allow future changes of this format maintaining compatibility with older readers. The policy behind the version is this: + +1. A change to Y means a minor change. All existing elements in the previous version must be left unchanged: only new elements or attributes may be added. A reader capable of reading version X.Y is also capable of reading version X.Y' with Y'>Y. +2. A change to X means a major change. Usually, a reader of version X.Y is not able to read version X'.Y with X'>X. + +The root element must have the following children: + +1. *general*: a container for general information. It must have the following children: + - *uuid*: this is the universally unique identifier assigned to the metadata and must be a valid UUID. This element is optional and, when omitted, the reader should generate one. A metadata without a UUID can be imported several times into the same system without breaking uniqueness constraints. When missing, the reader should also generate the siteId value. + - *createDate*: This date indicates when the metadata was created. + - *changeDate*: This date keeps track of the most recent change to the metadata. + - *siteId*: This is an UUID that identifies the actor that created the metadata and must be a valid UUID. When the UUID element is missing, this element should be missing too. If present, it will be ignored. + - *siteName*: This is a human readable name for the actor that created the metadata. It must be present only if the siteId is present. + - *schema*: The name of the schema for the metadata record in metadata.xml. When the MEF is imported by a GeoNetwork actor, this name should be the name of a metadata schema handled by the actor (eg. iso19139). If the GeoNetwork actor does not have such a schema, it may try and select another metadata with a schema that is present (eg. the metadata in metadata-iso19139.xml could be loaded because the iso19139 schema is present). + - *format*: Indicates the MEF export format. The element's value must belong to the following set: { *simple*, *partial*, *full* }. + - *localId*: This is an optional element. If present, indicates the id used locally by the sourceId actor to store the metadata. Its purpose is just to allow the reuse of the same local id when reimporting a metadata. + - *isTemplate*: A boolean field that indicates if this metadata is a template used to create new ones. There is no real distinction between a real metadata and a template but some actors use it to allow fast metadata creation. The value must be: { *true*, *false* }. + - *rating*: This is an optional element. If present, indicates the users' rating of the metadata ranging from 1 (a bad rating) to 5 (an excellent rating). The special value 0 means that the metadata has not been rated yet. Can be used to sort search results. + - *popularity*: Another optional value. If present, indicates the popularity of the metadata. The value must be positive and high values mean high popularity. The criteria used to set the popularity is left to the writer. Its main purpose is to provide a metadata ordering during a search. +2. *categories*: a container for categories associated to this metadata. A category is just a name, like 'audio-video' that classifies the metadata to allow an easy search. Each category is specified by a category element which must have a name attribute. This attribute is used to store the category's name. If there are no categories, the categories element will be empty. +3. *privileges*: a container for privileges associated to this metadata. Privileges are operations that a group (which represents a set of users) can do on a metadata and are specified by a set of group elements. Each one of these, has a mandatory name attribute to store the group's name and a set of operation elements used to store the operations allowed on the metadata. Each operation element must have a name attribute which value must belong to the following set: { *view*, *download*, *notify*, *dynamic*, *featured* }. If there are no groups or the actor does not have the concept of group, the privileges element will be empty. A group element without any operation element must be ignored by readers. +4. *public*: All metadata thumbnails (and any other public file) must be listed here. This container contains a file element for each file. Mandatory attributes of this element are name, which represents the file's name and changeDate, which contains the date of the latest change to the file. The public element is optional but, if present, must contain all the files present in the metadata's public directory and any reader that imports these files must set the latest change date on these using the provided ones. The purpose of this element is to provide more information in the case the MEF format is used for metadata harvesting. +5. *private*: This element has the same purpose and structure of the public element but is related to maps and all other private files. + +Any other element or attribute should be ignored by readers that don't understand them. This allows actors to add custom attributes or subtrees to the XML. + +### Date format {#info_xml} + +Unless differently specified, all dates in this file must be in the ISO/8601 format. The pattern must be ``YYYY-MM-DDTHH:mm:SS`` and the timezone should be the local one. + +Example of info file: + +``` xml + + + 0619abc0-708b-eeda-8202-000d98959033 + 2006-12-11T10:33:21 + 2006-12-14T08:44:43 + 0619cc50-708b-11da-8202-000d9335906e + FAO main site + iso19139 + full + 204 + false + + + + + + + + + + + + + + + + + + + +``` diff --git a/docs/manual/docs/annexes/standards/dublin-core.md b/docs/manual/docs/annexes/standards/dublin-core.md new file mode 100644 index 00000000000..0550f369ebd --- /dev/null +++ b/docs/manual/docs/annexes/standards/dublin-core.md @@ -0,0 +1,1193 @@ +# Dublin core (dublin-core) {#dublin-core} + +The Dublin Core Metadata Element Set is a vocabulary of fifteen properties for + +: use in resource description. The name "Dublin" is due to its origin at a 1995 invitational workshop in Dublin, Ohio; "core" because its elements are broad and generic, usable for describing a wide range of resources. + +More details: + +## Metadata editor + +This standard can be encoded using 3 view(s). + +- [View: Simple (default)](dublin-core.md#dublin-core-view-default) +- [View: Full (advanced)](dublin-core.md#dublin-core-view-advanced) +- [View: XML (xml)](dublin-core.md#dublin-core-view-xml) + +### View: Simple (default) {#dublin-core-view-default} + +This view is composed of1tab(s). + +- [Tab: Simple (default)](dublin-core.md#dublin-core-tab-default) + +This view also allows to add the following element even if not in the current record: + +- Subject and Keywords (dc:subject) + +#### Tab: Simple (default) {#dublin-core-tab-default} + +![](img/dublin-core-tab-default.png) + +This tab display elements from the XML metadata record. + +##### Section: Metadata + +See [Metadata](dublin-core.md#dublin-core-elem-simpledc-8506dd4a73872a53513368db419204a3) + +### View: Full (advanced) {#dublin-core-view-advanced} + +This view is composed of1tab(s). + +- [Tab: Full (advanced)](dublin-core.md#dublin-core-tab-advanced) + +#### Tab: Full (advanced) {#dublin-core-tab-advanced} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Metadata + +See [Metadata](dublin-core.md#dublin-core-elem-simpledc-8506dd4a73872a53513368db419204a3) + +### View: XML (xml) {#dublin-core-view-xml} + +This view is composed of1tab(s). + +- [Tab: XML (xml)](dublin-core.md#dublin-core-tab-xml) + +#### Tab: XML (xml) {#dublin-core-tab-xml} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +## Schema technical details + +Standard identifier + +: + +> dublin-core + +Version + +: + +> 1.0 + +Schema location + +: + +Schema namespaces + +: + +- +- +- + +Schema detection mode + +: + +> gns:elements (root) + +Schema detection elements + +: + +- simpledc + +## Standard elements + +List of all elements available in the standard. + +### Contributor {#dublin-core-elem-dc-contributor-0974cafd6cf5302fe8501874dbe3b3ac} + +Name + +: + +> dc:contributor + +Description + +: + +```{=html} +An entity responsible for making contributions to the content of the resource. +``` +### Coverage {#dublin-core-elem-dc-coverage-8a3ad050a5c9949ad92271f646817e10} + +Name + +: + +> dc:coverage + +Description + +: + +```{=html} +The extent or scope of the content of the resource. Typically, Coverage will + include spatial location (a place name or geographic coordinates), temporal period (a period + label, date, or date range), or jurisdiction (such as a named administrative entity). +``` +``` xml + + North 45.668, South 45.635, East 4.805, West 4.768. CHARLY + +``` + +### Creator {#dublin-core-elem-dc-creator-f6d71ca3a0b4e9aeb0e518f195f8256e} + +Name + +: + +> dc:creator + +Description + +: + +```{=html} +An entity primarily responsible for making the content of the resource. +``` +``` xml + + Métropole de Lyon / Direction Innovation Numérique et Systèmes d'Information + (DINSI) (Géomatique et données métropolitaines) + +``` + +### Date {#dublin-core-elem-dc-date-23c64254f66925f9eb6e3bd19c442233} + +Name + +: + +> dc:date + +Description + +: + +```{=html} +A date of an event in the lifecycle of the resource. Typically, Date will be + associated with the creation or availability of the resource. +``` +### Description {#dublin-core-elem-dc-description-8918d5eea5202286bfa9ceaac948b704} + +Name + +: + +> dc:description + +Description + +: + +```{=html} +An account of the content of the resource. +``` +``` xml + + La maquette 3D de la commune (2009 ou 2012) est composée de deux à six + couches de données. A minima, toutes les maquettes se composent des deux + couches suivantes : - Le Modèle numérique de terrain (TIN) et ses textures + associées ; - Les bâtiments 3D texturés (BATIS). Elle est complétée par une + ou plusieurs des couches ci-dessous : - Les surfaces en eau (WATER) et leurs + textures associées ; - Les bâtiments « remarquables » (Mairies, Eglises + etc…) ; - Les ponts « remarquables » ; - Les objets « remarquables » + (Statues, Fontaines etc…). Ces données sont modélisées suivant la norme + CityGML et fournies dans ce format. Ces maquettes sont produites avec le + logiciel RhinoTerrain/RhinoCity. + +``` + +### Format {#dublin-core-elem-dc-format-3842730cdb5c8559fe6f2737815429ea} + +Name + +: + +> dc:format + +Description + +: + +```{=html} +The physical or digital manifestation of the resource. Typically, Format will + include the media-type or dimensions of the resource. Format may be used to identify the + software, hardware, or other equipment needed to display or operate the resource. +``` +### Resource Identifier {#dublin-core-elem-dc-identifier-7d64a0a5c40868491c49bf7df7574752} + +Name + +: + +> dc:identifier + +Description + +: + +```{=html} +An unambiguous reference to the resource within a given context. +``` +``` xml +a806d3e1-c240-43a9-bbc3-643e8c93b10d +``` + +### Language {#dublin-core-elem-dc-language-74e0ef625be0b45d0e6c64d5f76e1895} + +Name + +: + +> dc:language + +Description + +: + +```{=html} +A language of the intellectual content of the resource. Recommended best practice + is to use RFC 3066, which, in conjunction with ISO 639, defines two- and three-letter primary + language tags with optional subtags. +``` +``` xml +fre +``` + +### Publisher {#dublin-core-elem-dc-publisher-5534d3efaa13b75c3aa34c379dd91025} + +Name + +: + +> dc:publisher + +Description + +: + +```{=html} +An entity responsible for making the resource available. +``` +``` xml + + Métropole de Lyon / Direction Innovation Numérique et Systèmes d'Information + (DINSI) (Géomatique et données métropolitaines) + +``` + +### Relation {#dublin-core-elem-dc-relation-3772ef19f1f075e519d2d0a60ec6f05a} + +Name + +: + +> dc:relation + +Description + +: + +```{=html} +A reference to a related resource. +``` +### Rights Management {#dublin-core-elem-dc-rights-32dce43ec1342a098287b03b6a5cb72f} + +Name + +: + +> dc:rights + +Description + +: + +```{=html} +Information about rights held in and over the resource. +``` +### Source {#dublin-core-elem-dc-source-104607b158c41c5855de1ed62ae223dd} + +Name + +: + +> dc:source + +Description + +: + +```{=html} +A Reference to a resource from which the present resource is derived. The present + resource may be derived from the Source resource in whole or in part. +``` +``` xml + + Le Modèle numérique de terrain est issu d’une saisie photogrammétrique + réalisée à partir de la prise de vue aérienne (2009 ou 2012). Les fichiers + des textures associées plaquées sur le MNT correspondent à + l’orthophotographie aérienne qui possède une résolution de 10 cm pour 2012 + et 16 cm pour 2009. - Les surfaces en eau (WATER) ont été identifiées à + partir d’une saisie photogrammétrique réalisée à partir de la même prise de + vue aérienne. - Les bâtiments 3D proviennent de la saisie photogrammétrique + réalisée à partir de la prise de vue aérienne. Les textures plaquées sur ces + bâtiments proviennent des clichés issus de la prise de vue aérienne. - Les + bâtiments « remarquables » (Mairies, Eglises etc…), les ponts « remarquables + » et les objets « remarquables » (Statues, Fontaines etc…) ont été texturés + à partir de photographies terrestres. + +``` + +### Subject and Keywords {#dublin-core-elem-dc-subject-a88bd90b4991695f8c45fe01df3f64d6} + +Name + +: + +> dc:subject + +Description + +: + +```{=html} +A topic of the content of the resource. Typically, Subject will be expressed as + keywords, key phrases, or classification codes that describe a topic of the resource. +``` +``` xml +Localisation +``` + +### Title {#dublin-core-elem-dc-title-18e3be863c870257c8b70d577038ee5f} + +Name + +: + +> dc:title + +Description + +: + +```{=html} +A name given to the resource. Typically, Title will be a name by which the resource + is formally known. +``` +``` xml + + Maquette 3D texturée de la commune de Charly (la Métropole de Lyon) + +``` + +### Resource Type {#dublin-core-elem-dc-type-15bbc75f8dbe617d6ed609fcf1202ee1} + +Name + +: + +> dc:type + +Description + +: + +```{=html} +The nature or genre of the content of the resource. Type includes terms describing + general categories, functions, genres, or aggregation levels for content. +``` +Recommended values + +| code | label | +|---------|---------| +| dataset | Dataset | +| service | Service | + +``` xml +nonGeographicDataset +``` + +### URI {#dublin-core-elem-dc-URI-8f2cb1e27778e1b1977e670ca7e7a282} + +Name + +: + +> dc:URI + +Description + +: + +### Abstract {#dublin-core-elem-dct-abstract-a48c3a17636153c58749c5fc29d1bd28} + +Name + +: + +> dct:abstract + +Description + +: + +```{=html} +A summary of the content of the resource. +``` +### Access Rights {#dublin-core-elem-dct-accessRights-972cd1c89a0274325b1a3b99e34c95be} + +Name + +: + +> dct:accessRights + +Description + +: + +```{=html} +Information about who can access the resource or an indication of its security + status. +``` +### Accrual Method {#dublin-core-elem-dct-accrualMethod-6fa8ea67638a1578c231025e31dd40e9} + +Name + +: + +> dct:accrualMethod + +Description + +: + +```{=html} +The method by which items are added to a collection. +``` +### Accrual Periodicity {#dublin-core-elem-dct-accrualPeriodicity-2a4c9a8426dd588e960559174a3df263} + +Name + +: + +> dct:accrualPeriodicity + +Description + +: + +```{=html} +The frequency with which items are added to a collection. +``` +Recommended values + +| code | label | +|-------------|-------------| +| continual | Continual | +| daily | Daily | +| weekly | Weekly | +| fortnightly | Fortnightly | +| monthly | Monthly | +| quarterly | Quarterly | +| biannually | Biannually | +| annually | Annually | +| asNeeded | As needed | +| irregular | Irregular | +| notPlanned | Not planned | +| unknown | Unknown | + +``` xml +Irregular +``` + +### Accrual Policy {#dublin-core-elem-dct-accrualPolicy-0ae937a1f9081db219a5dd04ed4610d4} + +Name + +: + +> dct:accrualPolicy + +Description + +: + +```{=html} +The policy governing the addition of items to a collection. +``` +### Alternative Title {#dublin-core-elem-dct-alternative-2518e8fc9fa67f5a10348016aae8bb0f} + +Name + +: + +> dct:alternative + +Description + +: + +```{=html} +An alternative name for the resource. +``` +### Audience {#dublin-core-elem-dct-audience-a610cbdc155d7cd9c87c8f22ef245521} + +Name + +: + +> dct:audience + +Description + +: + +```{=html} +A class of entity for whom the resource is intended or useful. +``` +### Bibliographic Citation {#dublin-core-elem-dct-bibliographicCitation-0d3ba175bdb84be48dec71bdb6b318da} + +Name + +: + +> dct:bibliographicCitation + +Description + +: + +```{=html} +A bibliographic reference for the resource. +``` +### Conforms To {#dublin-core-elem-dct-conformsTo-703d80b57bd6629b2bff3f57efd52dc5} + +Name + +: + +> dct:conformsTo + +Description + +: + +```{=html} +An established standard to which the described resource conforms. +``` +### Date Created {#dublin-core-elem-dct-created-9aebe20151c1c962d66737fcb9b87c2c} + +Name + +: + +> dct:created + +Description + +: + +```{=html} +Date of creation of the resource. +``` +``` xml +2014-12-19 +``` + +### Date Accepted {#dublin-core-elem-dct-dateAccepted-9f6f7b46bae794b317c939c75170b0f1} + +Name + +: + +> dct:dateAccepted + +Description + +: + +```{=html} +Date of acceptance of the resource. +``` +### Date Copyrighted {#dublin-core-elem-dct-dateCopyrighted-1a3940c001fd2db761829940957d8bf7} + +Name + +: + +> dct:dateCopyrighted + +Description + +: + +```{=html} +Date of copyright. +``` +### Date Submitted {#dublin-core-elem-dct-dateSubmitted-0e038c3b8ac6daca57211a938eca6154} + +Name + +: + +> dct:dateSubmitted + +Description + +: + +```{=html} +Date of submission of the resource +``` +``` xml +2015-01-23 +``` + +### Audience Education Level {#dublin-core-elem-dct-educationLevel-fa33466d34d56fb066753a6d97089631} + +Name + +: + +> dct:educationLevel + +Description + +: + +```{=html} +A class of entity, defined in terms of progression through an educational or + training context, for which the described resource is intended. +``` +### Extent {#dublin-core-elem-dct-extent-8a3a9adeaaac054e64dff722ad23c776} + +Name + +: + +> dct:extent + +Description + +: + +```{=html} +The size or duration of the resource. +``` +### Has Format {#dublin-core-elem-dct-hasFormat-d136ed16dc44af39fdf1b98b9fb4bc33} + +Name + +: + +> dct:hasFormat + +Description + +: + +```{=html} +A related resource that is substantially the same as the pre-existing described + resource, but in another format. +``` +### Has Part {#dublin-core-elem-dct-hasPart-f251f156dd8774a81f44c13c7b4a9e7d} + +Name + +: + +> dct:hasPart + +Description + +: + +```{=html} +A related resource that is included either physically or logically in the described + resource. +``` +### Has Version {#dublin-core-elem-dct-hasVersion-b8dc08cd4fc15cf1df605c2905b0c5e3} + +Name + +: + +> dct:hasVersion + +Description + +: + +```{=html} +A related resource that is a version, edition, or adaptation of the described + resource. +``` +### Instructional Method {#dublin-core-elem-dct-instructionalMethod-d220d889250a4a0f7e3efe29fc0f0ada} + +Name + +: + +> dct:instructionalMethod + +Description + +: + +```{=html} +A process, used to engender knowledge, attitudes and skills, that the resource is + designed to support. +``` +### Is Format Of {#dublin-core-elem-dct-isFormatOf-8378903643254b5b83ae2acdc251b6a6} + +Name + +: + +> dct:isFormatOf + +Description + +: + +```{=html} +A related resource that is substantially the same as the described resource, but in + another format. +``` +### Is part of {#dublin-core-elem-dct-isPartOf-6697c98943756abf56d4c2a50f9dc9a2} + +Name + +: + +> dct:isPartOf + +Description + +: + +```{=html} +A related resource in which the described resource is physically or logically + included. +``` +``` xml +8017c69a-5b17-404f-acdd-d9c37a0afac4 +``` + +### Is Referenced By {#dublin-core-elem-dct-isReferencedBy-4cf2c75a368a7773ec781eaa6f4a7c03} + +Name + +: + +> dct:isReferencedBy + +Description + +: + +```{=html} +A related resource that references, cites, or otherwise points to the described + resource. +``` +### Is Replaced By {#dublin-core-elem-dct-isReplacedBy-1e391e071c75e45dcf0a309285a642a0} + +Name + +: + +> dct:isReplacedBy + +Description + +: + +```{=html} +A related resource that supplants, displaces, or supersedes the described + resource. +``` +### Is Required By {#dublin-core-elem-dct-isRequiredBy-def534523d854e3440e36701bea47cc4} + +Name + +: + +> dct:isRequiredBy + +Description + +: + +```{=html} +A related resource that requires the described resource to support its function, + delivery, or coherence. +``` +### Date Issued {#dublin-core-elem-dct-issued-9f6ad8cb4b5e6225c1cb755489adb774} + +Name + +: + +> dct:issued + +Description + +: + +```{=html} +Date of formal issuance (e.g., publication) of the resource. +``` +### Is Version Of {#dublin-core-elem-dct-isVersionOf-d1658a9e84f777d0a335528e82921417} + +Name + +: + +> dct:isVersionOf + +Description + +: + +```{=html} +A related resource of which the described resource is a version, edition, or + adaptation. +``` +### License {#dublin-core-elem-dct-license-865405c25292b886c12f7d056ebaabda} + +Name + +: + +> dct:license + +Description + +: + +```{=html} +A legal document giving official permission to do something with the resource. +``` +### Mediator {#dublin-core-elem-dct-mediator-ab02c72730e6dbccbfb74b07e00edf10} + +Name + +: + +> dct:mediator + +Description + +: + +```{=html} +An entity that mediates access to the resource and for whom the resource is + intended or useful. +``` +### Medium {#dublin-core-elem-dct-medium-95f834fde8ee306293ebebcfd7a3aba5} + +Name + +: + +> dct:medium + +Description + +: + +```{=html} +The material or physical carrier of the resource. +``` +### Date Modified {#dublin-core-elem-dct-modified-66ecff9b0ec74fad28c5babebc1eec7d} + +Name + +: + +> dct:modified + +Description + +: + +```{=html} +Data metadata was modified +``` +``` xml +2016-02-03T21:33:45 +``` + +### Provenance {#dublin-core-elem-dct-provenance-4ec9c18f260230d4455195d6a6f28c17} + +Name + +: + +> dct:provenance + +Description + +: + +```{=html} +A statement of any changes in ownership and custody of the resource since its + creation that are significant for its authenticity, integrity and interpretation. +``` +### Related resource {#dublin-core-elem-dct-references-3a44416fcd20eea0684aad2fd3228fdd} + +Name + +: + +> dct:references + +Description + +: + +```{=html} +A related resource that is referenced, cited, or otherwise pointed to by the + described resource. +``` +### Replaces {#dublin-core-elem-dct-replaces-c5b09017642a464af7a04db426f6d74f} + +Name + +: + +> dct:replaces + +Description + +: + +```{=html} +A related resource that is supplanted, displaced, or superseded by the described + resource. +``` +### Requires {#dublin-core-elem-dct-requires-2ad52ab491717dc624f79f92303f4679} + +Name + +: + +> dct:requires + +Description + +: + +```{=html} +A related resource that is required by the described resource to support its + function, delivery, or coherence. +``` +### Rights Holder {#dublin-core-elem-dct-rightsHolder-0f4304cc1135f8fc29f7a0ede8daa268} + +Name + +: + +> dct:rightsHolder + +Description + +: + +```{=html} +A person or organization owning or managing rights over the resource. +``` +### Spatial {#dublin-core-elem-dct-spatial-5100d679492a6f79fd3e53db624bcab2} + +Name + +: + +> dct:spatial + +Description + +: + +```{=html} +Spatial characteristics of the intellectual content of the resource. +``` +``` xml +RGF93 / CC46 (EPSG:3946) +``` + +### Table Of Contents {#dublin-core-elem-dct-tableOfContents-c20c496386cad7aa48ad05ca41a6340b} + +Name + +: + +> dct:tableOfContents + +Description + +: + +```{=html} +A list of subunits of the resource. +``` +### Temporal Coverage {#dublin-core-elem-dct-temporal-0a2abb1d37421418cafeb48bd21e6854} + +Name + +: + +> dct:temporal + +Description + +: + +```{=html} +Temporal characteristics of the resource. +``` +### Date Valid {#dublin-core-elem-dct-valid-343768fccc581bc0822c69e6ca19c70c} + +Name + +: + +> dct:valid + +Description + +: + +```{=html} +Date (often a range) of validity of a resource. +``` +### Metadata {#dublin-core-elem-simpledc-8506dd4a73872a53513368db419204a3} + +Name + +: + +> simpledc + +Description + +: + +``` xml + + + Maquette 3D texturée de la commune de Charly (la Métropole de Lyon) + + + Métropole de Lyon / Direction Innovation Numérique et Systèmes d'Information + (DINSI) (Géomatique et données métropolitaines) + + Localisation + + La maquette 3D de la commune (2009 ou 2012) est composée de deux à six + couches de données. A minima, toutes les maquettes se composent des deux + couches suivantes : - Le Modèle numérique de terrain (TIN) et ses textures + associées ; - Les bâtiments 3D texturés (BATIS). Elle est complétée par une + ou plusieurs des couches ci-dessous : - Les surfaces en eau (WATER) et leurs + textures associées ; - Les bâtiments « remarquables » (Mairies, Eglises + etc…) ; - Les ponts « remarquables » ; - Les objets « remarquables » + (Statues, Fontaines etc…). Ces données sont modélisées suivant la norme + CityGML et fournies dans ce format. Ces maquettes sont produites avec le + logiciel RhinoTerrain/RhinoCity. + + + Métropole de Lyon / Direction Innovation Numérique et Systèmes d'Information + (DINSI) (Géomatique et données métropolitaines) + + nonGeographicDataset + application/zip + CityGML (taille : 260.0 Mo) + application/zip + executable (taille : 829.2 Mo) + application/zip + CityGML (taille : 113.5 Mo) + application/zip + executable (taille : 339.2 Mo) + application/pdf + pdf (taille : 315 Ko) + + Le Modèle numérique de terrain est issu d’une saisie photogrammétrique + réalisée à partir de la prise de vue aérienne (2009 ou 2012). Les fichiers + des textures associées plaquées sur le MNT correspondent à + l’orthophotographie aérienne qui possède une résolution de 10 cm pour 2012 + et 16 cm pour 2009. - Les surfaces en eau (WATER) ont été identifiées à + partir d’une saisie photogrammétrique réalisée à partir de la même prise de + vue aérienne. - Les bâtiments 3D proviennent de la saisie photogrammétrique + réalisée à partir de la prise de vue aérienne. Les textures plaquées sur ces + bâtiments proviennent des clichés issus de la prise de vue aérienne. - Les + bâtiments « remarquables » (Mairies, Eglises etc…), les ponts « remarquables + » et les objets « remarquables » (Statues, Fontaines etc…) ont été texturés + à partir de photographies terrestres. + + fre + + https://download.data.grandlyon.com/files/grandlyon/localisation/bati3d/CHARLY_2012.zip + + + https://download.data.grandlyon.com/files/grandlyon/localisation/bati3d/_EXE_CHARLY_2012.zip + + + https://download.data.grandlyon.com/files/grandlyon/localisation/bati3d/CHARLY_2009.zip + + + https://download.data.grandlyon.com/files/grandlyon/localisation/bati3d/_EXE_CHARLY_2009.zip + + + https://download.data.grandlyon.com/files/grandlyon/localisation/bati3d/Maquettes_3D_CityGML.pdf + + + https://download.data.grandlyon.com/files/grandlyon/LicenceOuverte.pdf + + + North 45.668, South 45.635, East 4.805, West 4.768. CHARLY + + Licence Ouverte + Pas de restriction d'accès public selon INSPIRE + 2014-12-19 + 2015-01-23 + 8017c69a-5b17-404f-acdd-d9c37a0afac4 + RGF93 / CC46 (EPSG:3946) + Irregular + 2016-02-03T21:33:45 + a806d3e1-c240-43a9-bbc3-643e8c93b10d + +``` + +## Standard codelists + +List of all codelists available in the standard. + +No codelist defined. diff --git a/docs/manual/docs/annexes/standards/img/dublin-core-tab-default.png b/docs/manual/docs/annexes/standards/img/dublin-core-tab-default.png new file mode 100644 index 00000000000..5b4fc460099 Binary files /dev/null and b/docs/manual/docs/annexes/standards/img/dublin-core-tab-default.png differ diff --git a/docs/manual/docs/annexes/standards/img/iso19110-tab-default.png b/docs/manual/docs/annexes/standards/img/iso19110-tab-default.png new file mode 100644 index 00000000000..cd8909c6217 Binary files /dev/null and b/docs/manual/docs/annexes/standards/img/iso19110-tab-default.png differ diff --git a/docs/manual/docs/annexes/standards/img/iso19139-tab-dataQualityInfo.png b/docs/manual/docs/annexes/standards/img/iso19139-tab-dataQualityInfo.png new file mode 100644 index 00000000000..064802f8923 Binary files /dev/null and b/docs/manual/docs/annexes/standards/img/iso19139-tab-dataQualityInfo.png differ diff --git a/docs/manual/docs/annexes/standards/img/iso19139-tab-default.png b/docs/manual/docs/annexes/standards/img/iso19139-tab-default.png new file mode 100644 index 00000000000..32c64280131 Binary files /dev/null and b/docs/manual/docs/annexes/standards/img/iso19139-tab-default.png differ diff --git a/docs/manual/docs/annexes/standards/img/iso19139-tab-identificationInfo.png b/docs/manual/docs/annexes/standards/img/iso19139-tab-identificationInfo.png new file mode 100644 index 00000000000..7e5b536046c Binary files /dev/null and b/docs/manual/docs/annexes/standards/img/iso19139-tab-identificationInfo.png differ diff --git a/docs/manual/docs/annexes/standards/img/iso19139-tab-inspire.png b/docs/manual/docs/annexes/standards/img/iso19139-tab-inspire.png new file mode 100644 index 00000000000..30a57aa728f Binary files /dev/null and b/docs/manual/docs/annexes/standards/img/iso19139-tab-inspire.png differ diff --git a/docs/manual/docs/annexes/standards/img/iso19139-tab-referenceSystemInfo.png b/docs/manual/docs/annexes/standards/img/iso19139-tab-referenceSystemInfo.png new file mode 100644 index 00000000000..b7ab16adb50 Binary files /dev/null and b/docs/manual/docs/annexes/standards/img/iso19139-tab-referenceSystemInfo.png differ diff --git a/docs/manual/docs/annexes/standards/img/metawal-tramedesaxes.png b/docs/manual/docs/annexes/standards/img/metawal-tramedesaxes.png new file mode 100644 index 00000000000..2be2d504954 Binary files /dev/null and b/docs/manual/docs/annexes/standards/img/metawal-tramedesaxes.png differ diff --git a/docs/manual/docs/annexes/standards/img/sextant-checkpoint.png b/docs/manual/docs/annexes/standards/img/sextant-checkpoint.png new file mode 100644 index 00000000000..937e3b5521a Binary files /dev/null and b/docs/manual/docs/annexes/standards/img/sextant-checkpoint.png differ diff --git a/docs/manual/docs/annexes/standards/img/standardlist.png b/docs/manual/docs/annexes/standards/img/standardlist.png new file mode 100644 index 00000000000..bda4e3c7191 Binary files /dev/null and b/docs/manual/docs/annexes/standards/img/standardlist.png differ diff --git a/docs/manual/docs/annexes/standards/index.md b/docs/manual/docs/annexes/standards/index.md new file mode 100644 index 00000000000..6216f402afd --- /dev/null +++ b/docs/manual/docs/annexes/standards/index.md @@ -0,0 +1,16 @@ +# Standards + +The catalog support the following standards: + +![](img/standardlist.png) + +- [Geographic information -- Metadata (iso19115-3.2018)](iso19115-3.2018.md) +- [Geographic information -- Metadata (iso19139:2007) (iso19139)](iso19139.md) +- [Geographic information -- Methodology for feature cataloguing (Deprecated - use ISO19115-3) (iso19110)](iso19110.md) +- [Dublin core (dublin-core)](dublin-core.md) + +ISO19110 can be used to encode feature catalogue (but ISO19115-3 is recommended). + +Dublin core (for CSW only) is only used to test OGC CSW testsuites. + +Others standards and community profiles are available on . diff --git a/docs/manual/docs/annexes/standards/iso19110.md b/docs/manual/docs/annexes/standards/iso19110.md new file mode 100644 index 00000000000..dea7a09042e --- /dev/null +++ b/docs/manual/docs/annexes/standards/iso19110.md @@ -0,0 +1,1877 @@ +# Geographic information -- Methodology for feature cataloguing (Deprecated - use ISO19115-3) (iso19110) {#iso19110} + +More details: + +## Metadata editor + +This standard can be encoded using 3 view(s). + +- [View: Simple (default)](iso19110.md#iso19110-view-default) +- [View: Full (advanced)](iso19110.md#iso19110-view-advanced) +- [View: XML (xml)](iso19110.md#iso19110-view-xml) + +### View: Simple (default) {#iso19110-view-default} + +This view is composed of1tab(s). + +- [Tab: Simple (default)](iso19110.md#iso19110-tab-default) + +This view also allows to add the following element even if not in the current record: + +- Code (gfc:code) +- Codelist (gfc:listedValue) + +#### Tab: Simple (default) {#iso19110-tab-default} + +![](img/iso19110-tab-default.png) + +This tab display elements from the XML metadata record. + +##### Name + +```{=html} +Feature catalogue name +``` + +XPath + +: + +> /gfc:FC_FeatureCatalogue/gmx:name + +See [Name](iso19110.md#iso19110-elem-gmx-name-5ec0c4442ad2b94944636103e556d401) + +##### Name + +```{=html} +Feature catalogue name +``` + +XPath + +: + +> /gfc:FC_FeatureCatalogue/gfc:name + +See [Name](iso19110.md#iso19110-elem-gfc-name-134285dc9b9a3268556039e2fe3f370e) + +##### Scope + +```{=html} +Scope definition +``` + +XPath + +: + +> /gfc:FC_FeatureCatalogue/gmx:scope + +See [Scope](iso19110.md#iso19110-elem-gmx-scope-14efac6982297b09ba1324e80138092f) + +##### Scope + +```{=html} +Scope definition +``` + +XPath + +: + +> /gfc:FC_FeatureCatalogue/gfc:scope + +See [Scope](iso19110.md#iso19110-elem-gfc-scope-4f044fce55b8e0b6dd0d77516ad9e66d) + +##### Field of application + +```{=html} +Field of application +``` + +XPath + +: + +> /gfc:FC_FeatureCatalogue/gmx:fieldOfApplication + +See [Field of application](iso19110.md#iso19110-elem-gmx-fieldOfApplication-66508d1f139317e01e1decd095915428) + +##### Field of application + +```{=html} +Field of application +``` + +XPath + +: + +> /gfc:FC_FeatureCatalogue/gfc:fieldOfApplication + +See [Field of application](iso19110.md#iso19110-elem-gfc-fieldOfApplication-548e0631e3ea92f7dd05ac533b6c14d2) + +##### Version + +```{=html} +Catalogue version +``` + +XPath + +: + +> /gfc:FC_FeatureCatalogue/gmx:versionNumber + +See [Version](iso19110.md#iso19110-elem-gmx-versionNumber-075201f18225aec432b46c75a93589a2) + +##### Version + +```{=html} +Catalogue version +``` + +XPath + +: + +> /gfc:FC_FeatureCatalogue/gfc:versionNumber + +See [Version](iso19110.md#iso19110-elem-gfc-versionNumber-d66ec9fd5c22c70a69dd2b759d66cc4f) + +##### Date + +```{=html} +Catalogue date +``` + +XPath + +: + +> /gfc:FC_FeatureCatalogue/gmx:versionDate + +See [Date](iso19110.md#iso19110-elem-gmx-versionDate-6c27e2ee0b2daa4ab1aea9ef374bc08f) + +##### Catalogue producer + +```{=html} +Catalogue responsible +``` + +XPath + +: + +> /gfc:FC_FeatureCatalogue/gfc:producer + +See [Catalogue producer](iso19110.md#iso19110-elem-gfc-producer-5a13bfab8b07441bc9f9f71dcfdf7f6c) + +##### Functional language + +XPath + +: + +> /gfc:FC_FeatureCatalogue/gfc:functionalLanguage + +See [Functional language](iso19110.md#iso19110-elem-gfc-functionalLanguage-7a21d9c35ed9c400c40959ede97b8d76) + +##### Property description + +```{=html} +Property description +``` + +XPath + +: + +> /gfc:FC_FeatureCatalogue/gfc:featureType + +See [Property description](iso19110.md#iso19110-elem-gfc-featureType-d6099a684b15337451388dd46048c48f) + +Type + +: + +> suggest + +### View: Full (advanced) {#iso19110-view-advanced} + +This view is composed of1tab(s). + +- [Tab: Full (advanced)](iso19110.md#iso19110-tab-advanced) + +#### Tab: Full (advanced) {#iso19110-tab-advanced} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Feature Catalogue description + +See [Feature Catalogue description](iso19110.md#iso19110-elem-gfc-FC_FeatureCatalogue-a4de444fdd9a6e86e8ba63bb96be363c) + +### View: XML (xml) {#iso19110-view-xml} + +This view is composed of1tab(s). + +- [Tab: XML (xml)](iso19110.md#iso19110-tab-xml) + +#### Tab: XML (xml) {#iso19110-tab-xml} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +## Schema technical details + +Standard identifier + +: + +> iso19110 + +Version + +: + +> 1.0 + +Schema location + +: + +> + +Schema namespaces + +: + +- +- +- +- + +Schema detection mode + +: + +> elements (root) + +Schema detection elements + +: + +- gfc:FC_FeatureCatalogue +- gfc:FC_FeatureType + +## Standard elements + +List of all elements available in the standard. + +### Text {#iso19110-elem-gco-CharacterString-44f4a753bad9d1df04d0611f28f05110} + +Name + +: + +> gco:CharacterString + +Description + +: + +### Lower cardinality {#iso19110-elem-gco-lower-52bfcbb528e9aaefc2e33f4fdc55aa5f} + +Name + +: + +> gco:lower + +Description + +: + +```{=html} +Lower cardinality +``` +``` xml + + 1 + +``` + +### Nil reason {#iso19110-elem-gco-nilReason-59d9c7937eb12ff82e61921ee335d062} + +Name + +: + +> gco:nilReason + +Description + +: + +### Range {#iso19110-elem-gco-range-6709132eada2bd317e3ad342849df5ef} + +Name + +: + +> gco:range + +Description + +: + +``` xml + + + + 1 + + + 1 + + + + +``` + +### Upper cardinality {#iso19110-elem-gco-upper-a58d7645455b8f20c0d2608c5bc1b6ab} + +Name + +: + +> gco:upper + +Description + +: + +```{=html} +Upper cardinality +``` +``` xml + + 1 + + +``` + +### Affects value of {#iso19110-elem-gfc-affectsValueOf-3cc26e7cd38219c7bb06fbe8e5438598} + +Name + +: + +> gfc:affectsValueOf + +Description + +: + +### Aliases {#iso19110-elem-gfc-aliases-7ec87797f5b619c461f2acf995b56b2e} + +Name + +: + +> gfc:aliases + +Description + +: + +### Cardinalities {#iso19110-elem-gfc-cardinality-36c218fd045f824ca4f9d1ceb6ffbcc2} + +Name + +: + +> gfc:cardinality + +Description + +: + +```{=html} +Cardinalities +``` +``` xml + + + + + + 1 + + + 1 + + + + + + +``` + +### Elements {#iso19110-elem-gfc-carrierOfCharacteristics-c804ac9130fc47e8753b8d2e3776840b} + +Name + +: + +> gfc:carrierOfCharacteristics + +Description + +: + +```{=html} +Association, attribute, operation, ... +``` +``` xml + + + + VALUE + + + + + + + + + + 1 + + + 1 + + + + + + + + + + + + + + + + + Low coasts + + + 1 + + + Areas within 10km from the coastline and with an elevation + below 50m. + + + + + + + + High coasts + + + 2 + + + Areas within 10km from the coastline and with an elevation + above 50m. + + + + + + + + Inlands + + + 3 + + + Areas between 0 and 200 m outside the coastal strip. + + + + + + + + Uplands + + + 4 + + + Zones between 200 and 500 m plus the flat areas between 500 and + 1000m. + + + + + + + + Mountains + + + 5 + + + Slopy areas between 500 and 1000m and all the areas over + 1000m. + + + + + + + + INTEGER + + + + + +``` + +### Code {#iso19110-elem-gfc-code-c62e74de82d004d4ec09d403e4b59c3b} + +Name + +: + +> gfc:code + +Description + +: + +### Constrained by {#iso19110-elem-gfc-constrainedBy-5e5ace57efe55c1890bec294427a780a} + +Name + +: + +> gfc:constrainedBy + +Description + +: + +### Definition {#iso19110-elem-gfc-definition-4bc2a8f5046951fa9e77311ef6d927f2} + +Name + +: + +> gfc:definition + +Description + +: + +```{=html} +Property definition +``` +### Definition reference {#iso19110-elem-gfc-definitionReference-30806ed7d5bf82b19c877082a919216e} + +Name + +: + +> gfc:definitionReference + +Description + +: + +### Definition source {#iso19110-elem-gfc-definitionSource-7f9ab04b040daf81d7d761ea83101e88} + +Name + +: + +> gfc:definitionSource + +Description + +: + +### Description {#iso19110-elem-gfc-description-87db9aea10cf7281b199782a15b17015} + +Name + +: + +> gfc:description + +Description + +: + +### Association role {#iso19110-elem-gfc-FC_AssociationRole-48c91ffbc9251a3377010490882da453} + +Name + +: + +> gfc:FC_AssociationRole + +Description + +: + +### Constraint {#iso19110-elem-gfc-FC_Constraint-8b0503c998a5c3cfd079077286bcc18c} + +Name + +: + +> gfc:FC_Constraint + +Description + +: + +### Feature association {#iso19110-elem-gfc-FC_FeatureAssociation-7bfc562c6ffccb3dd540692bd8c0fda7} + +Name + +: + +> gfc:FC_FeatureAssociation + +Description + +: + +### Attribute {#iso19110-elem-gfc-FC_FeatureAttribute-f3f350a00639f88ab53dd23d5ad5724e} + +Name + +: + +> gfc:FC_FeatureAttribute + +Description + +: + +``` xml + + + VALUE + + + + + + + + + + 1 + + + 1 + + + + + + + + + + + + + + + + + Low coasts + + + 1 + + + Areas within 10km from the coastline and with an elevation + below 50m. + + + + + + + + High coasts + + + 2 + + + Areas within 10km from the coastline and with an elevation + above 50m. + + + + + + + + Inlands + + + 3 + + + Areas between 0 and 200 m outside the coastal strip. + + + + + + + + Uplands + + + 4 + + + Zones between 200 and 500 m plus the flat areas between 500 and + 1000m. + + + + + + + + Mountains + + + 5 + + + Slopy areas between 500 and 1000m and all the areas over + 1000m. + + + + + + + + INTEGER + + + + +``` + +### Feature Catalogue description {#iso19110-elem-gfc-FC_FeatureCatalogue-a4de444fdd9a6e86e8ba63bb96be363c} + +Name + +: + +> gfc:FC_FeatureCatalogue + +Description + +: + +``` xml + + + Elevation breakdown feature catalogue + + + Dataset elevation breakdown (raster 1 km) + + + 1.0 + + + 2012-11-05T10:56:11 + + + + + European Environment Agency + + + + + + + + + + + + + Kongens Nytorv 6 + + + Copenhagen + + + K + + + 1050 + + + Denmark + + + mauro.michielon@eea.europa.eu + + + + + + + + + + + + + + Elevation breakdown + + + The Elevation breakdown is used to allocate Land cover changes into + homogeneous areas as function of height, slope and distance to the sea. + + + + false + + + + + + VALUE + + + + + + + + + + 1 + + + 1 + + + + + + + + + + + + + + + + + Low coasts + + + 1 + + + Areas within 10km from the coastline and with an elevation + below 50m. + + + + + + + + High coasts + + + 2 + + + Areas within 10km from the coastline and with an elevation + above 50m. + + + + + + + + Inlands + + + 3 + + + Areas between 0 and 200 m outside the coastal strip. + + + + + + + + Uplands + + + 4 + + + Zones between 200 and 500 m plus the flat areas between 500 and + 1000m. + + + + + + + + Mountains + + + 5 + + + Slopy areas between 500 and 1000m and all the areas over + 1000m. + + + + + + + + INTEGER + + + + + + + + +``` + +### Feature operation {#iso19110-elem-gfc-FC_FeatureOperation-637b82bc0e9951563005e479a9e1d152} + +Name + +: + +> gfc:FC_FeatureOperation + +Description + +: + +### Attribute table description {#iso19110-elem-gfc-FC_FeatureType-38ad06d5e87d9bf33d5f111e7bca0eb4} + +Name + +: + +> gfc:FC_FeatureType + +Description + +: + +```{=html} +Attribute table description +``` +``` xml + + + Elevation breakdown + + + The Elevation breakdown is used to allocate Land cover changes into + homogeneous areas as function of height, slope and distance to the sea. + + + + false + + + + + + VALUE + + + + + + + + + + 1 + + + 1 + + + + + + + + + + + + + + + + + Low coasts + + + 1 + + + Areas within 10km from the coastline and with an elevation + below 50m. + + + + + + + + High coasts + + + 2 + + + Areas within 10km from the coastline and with an elevation + above 50m. + + + + + + + + Inlands + + + 3 + + + Areas between 0 and 200 m outside the coastal strip. + + + + + + + + Uplands + + + 4 + + + Zones between 200 and 500 m plus the flat areas between 500 and + 1000m. + + + + + + + + Mountains + + + 5 + + + Slopy areas between 500 and 1000m and all the areas over + 1000m. + + + + + + + + INTEGER + + + + + + +``` + +### Heritance relation {#iso19110-elem-gfc-FC_InheritanceRelation-fe8bfb4f25b16151bf7dc241c0bb800c} + +Name + +: + +> gfc:FC_InheritanceRelation + +Description + +: + +### Codelist {#iso19110-elem-gfc-FC_ListedValue-281cee06b2347acc7c485783eb4cf22f} + +Name + +: + +> gfc:FC_ListedValue + +Description + +: + +### Role type {#iso19110-elem-gfc-FC_RoleType-8f835d500036f8c773643298ee9a1287} + +Name + +: + +> gfc:FC_RoleType + +Description + +: + +### Feature catalogue {#iso19110-elem-gfc-featureCatalogue-747a0827bf295f6d27168cd2b274929b} + +Name + +: + +> gfc:featureCatalogue + +Description + +: + +``` xml + +``` + +### Property description {#iso19110-elem-gfc-featureType-d6099a684b15337451388dd46048c48f} + +Name + +: + +> gfc:featureType + +Description + +: + +```{=html} +Property description +``` +### Field of application {#iso19110-elem-gfc-fieldOfApplication-548e0631e3ea92f7dd05ac533b6c14d2} + +Name + +: + +> gfc:fieldOfApplication + +Description + +: + +```{=html} +Field of application +``` +### Formal definition {#iso19110-elem-gfc-formalDefinition-61fbbceaf2b0eca25754ba29528ac201} + +Name + +: + +> gfc:formalDefinition + +Description + +: + +### Functional language {#iso19110-elem-gfc-functionalLanguage-7a21d9c35ed9c400c40959ede97b8d76} + +Name + +: + +> gfc:functionalLanguage + +Description + +: + +### Inherits from {#iso19110-elem-gfc-inheritsFrom-d48c2429ef37a9f7001c4c78b3185ad8} + +Name + +: + +> gfc:inheritsFrom + +Description + +: + +### Inherits to {#iso19110-elem-gfc-inheritsTo-21e907a9a6f03374cf39958e940d6c04} + +Name + +: + +> gfc:inheritsTo + +Description + +: + +### Abstract {#iso19110-elem-gfc-isAbstract-108adb5fd93bc80097796cf3e185145e} + +Name + +: + +> gfc:isAbstract + +Description + +: + +```{=html} +Is this element an abstract element ? +``` +``` xml + + false + +``` + +### Is navigable {#iso19110-elem-gfc-isNavigable-ee77efa13eb047461f3d1b10eb057ad2} + +Name + +: + +> gfc:isNavigable + +Description + +: + +### Is ordered {#iso19110-elem-gfc-isOrdered-99dd774d6527b2e2a6714029b3d85562} + +Name + +: + +> gfc:isOrdered + +Description + +: + +### Label {#iso19110-elem-gfc-label-f039ffb9cb376d0473d7be6326b20fd7} + +Name + +: + +> gfc:label + +Description + +: + +### Codelist {#iso19110-elem-gfc-listedValue-10921452105d681cb7bcb8c2851416f9} + +Name + +: + +> gfc:listedValue + +Description + +: + +```{=html} +List of values for this element. +``` +### Member name {#iso19110-elem-gfc-memberName-3bd14590c8d90557f5d48e886a3ebef7} + +Name + +: + +> gfc:memberName + +Description + +: + +``` xml + + VALUE + +``` + +### Name {#iso19110-elem-gfc-name-134285dc9b9a3268556039e2fe3f370e} + +Name + +: + +> gfc:name + +Description + +: + +```{=html} +Feature catalogue name +``` +``` xml + + Elevation breakdown feature catalogue + +``` + +### Observes value of {#iso19110-elem-gfc-observesValueOf-b236ed68892a516373f72b89b397cde4} + +Name + +: + +> gfc:observesValueOf + +Description + +: + +### Catalogue producer {#iso19110-elem-gfc-producer-5a13bfab8b07441bc9f9f71dcfdf7f6c} + +Name + +: + +> gfc:producer + +Description + +: + +```{=html} +Catalogue responsible +``` +``` xml + + + + European Environment Agency + + + + + + + + + + + + + Kongens Nytorv 6 + + + Copenhagen + + + K + + + 1050 + + + Denmark + + + mauro.michielon@eea.europa.eu + + + + + + + + + + +``` + +### Relation {#iso19110-elem-gfc-relation-aacba568eb3b35bd7b8432488f11bf69} + +Name + +: + +> gfc:relation + +Description + +: + +### Role name {#iso19110-elem-gfc-roleName-75ef0d862fac206908f78b9ecd526c65} + +Name + +: + +> gfc:roleName + +Description + +: + +### Role type {#iso19110-elem-gfc-roleType-e11e8dd83ce112d38151e4c5d41f5e57} + +Name + +: + +> gfc:roleType + +Description + +: + +### Scope {#iso19110-elem-gfc-scope-4f044fce55b8e0b6dd0d77516ad9e66d} + +Name + +: + +> gfc:scope + +Description + +: + +```{=html} +Scope definition +``` +``` xml + + Dataset elevation breakdown (raster 1 km) + +``` + +### Signature {#iso19110-elem-gfc-signature-a322fc9fc498999771ea25d75eeadb92} + +Name + +: + +> gfc:signature + +Description + +: + +### Triggered by value of {#iso19110-elem-gfc-triggeredByValueOf-f9c78e57b38ecbf17a07eae27ddceb25} + +Name + +: + +> gfc:triggeredByValueOf + +Description + +: + +### Type {#iso19110-elem-gfc-type-8d417215d65176688a81728103dee9d4} + +Name + +: + +> gfc:type + +Description + +: + +### Property name {#iso19110-elem-gfc-typeName-5eb6a83793b5f1865c0a10bc6d3cb399} + +Name + +: + +> gfc:typeName + +Description + +: + +``` xml + + Elevation breakdown + +``` + +### Unique instance {#iso19110-elem-gfc-uniqueInstance-b0b6a49f0189dc2499564de5cdfd25a0} + +Name + +: + +> gfc:uniqueInstance + +Description + +: + +### Value measurement unit {#iso19110-elem-gfc-valueMeasurementUnit-3722d826b1a00b71bfae6cd7eefff3cd} + +Name + +: + +> gfc:valueMeasurementUnit + +Description + +: + +``` xml + + + + + + +``` + +### Value type {#iso19110-elem-gfc-valueType-faeb30b744a5e7aa19f43cb83bf2a9ab} + +Name + +: + +> gfc:valueType + +Description + +: + +``` xml + + + + INTEGER + + + +``` + +### Date {#iso19110-elem-gfc-versionDate-536720beffcbb11d9da8bd041ad7a762} + +Name + +: + +> gfc:versionDate + +Description + +: + +```{=html} +Catalogue date +``` +``` xml + + 2012-11-05T10:56:11 + +``` + +### Version {#iso19110-elem-gfc-versionNumber-d66ec9fd5c22c70a69dd2b759d66cc4f} + +Name + +: + +> gfc:versionNumber + +Description + +: + +```{=html} +Catalogue version +``` +``` xml + + 1.0 + +``` + +### Responsible party {#iso19110-elem-gmd-CI_ResponsibleParty-f8269ab6464cabb0bc5d4b5d8e2d410c} + +Name + +: + +> gmd:CI_ResponsibleParty + +Description + +: + +```{=html} +Responsible party +``` +``` xml + + + European Environment Agency + + + + + + + + + + + + + Kongens Nytorv 6 + + + Copenhagen + + + K + + + 1050 + + + Denmark + + + mauro.michielon@eea.europa.eu + + + + + + + + + +``` + +### Responsible party {#iso19110-elem-gmd-responsibleParty-7352aaa3187b52425f19d3f567e8b88a} + +Name + +: + +> gmd:responsibleParty + +Description + +: + +```{=html} +Responsible party +``` +### Anchor {#iso19110-elem-gmx-Anchor-4e506485badff59411e1cb2c1f5031e3} + +Name + +: + +> gmx:Anchor + +Description + +: + +### Field of application {#iso19110-elem-gmx-fieldOfApplication-66508d1f139317e01e1decd095915428} + +Name + +: + +> gmx:fieldOfApplication + +Description + +: + +```{=html} +Field of application +``` +### File name {#iso19110-elem-gmx-FileName-2a19fe714b24f0a417598321882eef7f} + +Name + +: + +> gmx:FileName + +Description + +: + +### Name {#iso19110-elem-gmx-name-5ec0c4442ad2b94944636103e556d401} + +Name + +: + +> gmx:name + +Description + +: + +```{=html} +Feature catalogue name +``` +### Scope {#iso19110-elem-gmx-scope-14efac6982297b09ba1324e80138092f} + +Name + +: + +> gmx:scope + +Description + +: + +```{=html} +Scope definition +``` +### Date {#iso19110-elem-gmx-versionDate-6c27e2ee0b2daa4ab1aea9ef374bc08f} + +Name + +: + +> gmx:versionDate + +Description + +: + +```{=html} +Catalogue date +``` +### Version {#iso19110-elem-gmx-versionNumber-075201f18225aec432b46c75a93589a2} + +Name + +: + +> gmx:versionNumber + +Description + +: + +```{=html} +Catalogue version +``` +## Standard codelists + +List of all codelists available in the standard. + +### Standard codelists (gmd:CI_RoleCode) {#iso19110-cl-gmd-CI_RoleCode} + +| code | label | description | +|-----------------------|------------------------|--------------------------------------------------------------------------------------------------------------------------------| +| resourceProvider | Resource provider | Party that supplies the resource | +| custodian | Custodian | Party that accepts accountability and responsibility for the data and ensures appropriate care and maintenance of the resource | +| owner | Owner | Party that owns the resource | +| user | User | Party who uses the resource | +| distributor | Distributor | Party who distributes the resource | +| originator | Originator | Party who created the resource | +| pointOfContact | Point of contact | Party who can be contacted for acquiring knowledge about or acquisition of the resource | +| principalInvestigator | Principal investigator | Key party responsible for gathering information and conducting research | +| processor | Processor | Party that has processed the data in a manner such that the resource has been modified | +| publisher | Publisher | Party who published the resource | +| author | Author | Party who authored the resource | diff --git a/docs/manual/docs/annexes/standards/iso19115-3.2018.md b/docs/manual/docs/annexes/standards/iso19115-3.2018.md new file mode 100644 index 00000000000..baaabc077f1 --- /dev/null +++ b/docs/manual/docs/annexes/standards/iso19115-3.2018.md @@ -0,0 +1,20114 @@ +# Geographic information -- Metadata (iso19115-3.2018) {#iso19115-3.2018} + +The objective of ISO 19115 is to provide a model for describing information or resources that can have geographic extents. This part of ISO 19115 is intended to be used by information system analysts, program planners, and developers of information systems, as well as others in order to define basic principles and requirements for standardized description of information resources. This part of ISO 19115 defines metadata elements, their properties, and the relationships between elements, and establishes a common set of metadata terminology, definitions, and extension procedures. + +Although the primary purpose of this part of ISO 19115 is to describe digital information that has a geographic extent, it can be used to describe all types of resources including textual documents, initiatives, software, sensors, non-geographic information, product specifications and repositories, i.e. it can be used to describe information resources that do not have geographic extent. Some domains have their own metadata standards, such as the Dublin Core for libraries. If necessary such standards and this part of ISO 19115 could be profiled to create a Community Schema. + +This schema also includes: + +- Describe imagery data (covered by ISO19115-2) +- Embed data model (feature catalogue) in the dataset record (covered by ISO19110) +- Data quality described using ISO19157 + +More information: + +- [Using the latest ISO Standard for Geographic Information (ISO19115-1) for an INSPIRE Discovery Service](https://www.iso.org/standard/53798.html) + +This standard is maintained on and is available by default in GeoNetwork. The TC211 is maintaining the XSD for this standard on . + +Example of catalogues using this standard: + +- [Metawal - Catalogue pour l'information géographique de Wallonie](https://metawal.wallonie.be/) is using ISO19115-3 as the default standard for all records. Main advantages are: categorizations of related documents (eg. online sources, DQ reports, GIS styles, Data models), better description of organization / parties and roles, remain compliant to the INSPIRE directive by converting to ISO19139 through CSW. + +![](img/metawal-tramedesaxes.png) + +- [Sextant - Checkpoints](https://sextant.ifremer.fr/) is using ISO19115-3 for data quality description of Specification / Products and upstream data. + +![](img/sextant-checkpoint.png) + +More details: + +## Metadata editor + +This standard can be encoded using 3 view(s). + +- `iso19115-3.2018-view-default`{.interpreted-text role="ref"} +- `iso19115-3.2018-view-advanced`{.interpreted-text role="ref"} +- `iso19115-3.2018-view-xml`{.interpreted-text role="ref"} + +### View: Simple (default) {#iso19115-3.2018-view-default} + +This view is composed of1tab(s). + +- `iso19115-3.2018-tab-default`{.interpreted-text role="ref"} + +This view also allows to add the following element even if not in the current record: + +- Descriptive keywords (mri:descriptiveKeywords) +- Processor (mrl:processor) +- Cited responsible party (cit:citedResponsibleParty) +- Point of contact (mri:pointOfContact) +- Contact (mdb:contact) +- (mcc:processor) +- Elements (gfc:carrierOfCharacteristics) +- Party (cit:party) +- Individual (cit:CI_Individual) +- Organisation (cit:CI_Organisation) +- Codelist (gfc:listedValue) + +#### Tab: Simple (default) {#iso19115-3.2018-tab-default} + +This tab display elements from the XML metadata record. + +##### Section: Identification info + +```{=html} +Basic information about the resource(s) to which the metadata applies +``` +See `iso19115-3.2018-elem-mdb-identificationInfo-7b3f7b7fbb8a986c92658058fe54f876`{.interpreted-text role="ref"} + +##### Section: Content Information + +```{=html} +Provides information about the feature catalogue and describes the coverage and image data characteristics +``` +See `iso19115-3.2018-elem-mdb-contentInfo-477f3b1af76890ee3158c66524002fd8`{.interpreted-text role="ref"} + +##### Section: Distribution Information + +```{=html} +Provides information about the distributor of and options for obtaining the resource(s) +``` +See `iso19115-3.2018-elem-mdb-distributionInfo-26e7e205c5605edb7225b0aa5c3950f1`{.interpreted-text role="ref"} + +##### Section: Data quality info + +```{=html} +Provides overall assessment of quality of a resource(s) +``` +See `iso19115-3.2018-elem-mdb-dataQualityInfo-05c1cd27fb52b7bc5c361a03fb962e72`{.interpreted-text role="ref"} + +##### Section: Resource lineage + +```{=html} +Information about the provenance, source(s), and/or the production process(es) applied to the resource +``` +See `iso19115-3.2018-elem-mdb-resourceLineage-b38f8fe2e0d2dee771b11f2dfcb77937`{.interpreted-text role="ref"} + +##### Section: Spatial representation info + +```{=html} +Digital representation of spatial information in the dataset +``` +See `iso19115-3.2018-elem-mdb-spatialRepresentationInfo-fa98674c3f9afa7324634c07cda62b3b`{.interpreted-text role="ref"} + +##### Section: Reference System Information + +```{=html} +Description of the spatial and temporal reference systems used in the dataset +``` +See `iso19115-3.2018-elem-mdb-referenceSystemInfo-6e40de8cf9dbe75d0601aedf78756344`{.interpreted-text role="ref"} + +##### Section: Acquisition information + +See `iso19115-3.2018-elem-mdb-acquisitionInformation-ce87174a305975fd6ab50c76fa062e87`{.interpreted-text role="ref"} + +##### Section: Portrayal catalogue info + +```{=html} +Provides information about the catalogue of rules defined for the portrayal of a resource(s) +``` +See `iso19115-3.2018-elem-mdb-portrayalCatalogueInfo-f6c73fdd3d7c18f1e90d4a8853986230`{.interpreted-text role="ref"} + +##### Section: Metadata constraints + +```{=html} +Provides restrictions on the access and use of metadata +``` +See `iso19115-3.2018-elem-mdb-metadataConstraints-cd13aab243e8cf8b0009f3c2cc6288a6`{.interpreted-text role="ref"} + +##### Section: Metadata maintenance + +```{=html} +Provides information about the frequency of metadata updates, and the scope of those updates +``` +See `iso19115-3.2018-elem-mdb-metadataMaintenance-f31a9a9880a6a939b8125c2505a04439`{.interpreted-text role="ref"} + +##### Section: Application schema info + +```{=html} +Provides information about the conceptual schema of a dataset +``` +See `iso19115-3.2018-elem-mdb-applicationSchemaInfo-6e29d5e06caa68d593c2abc867db859e`{.interpreted-text role="ref"} + +##### Section: Metadata + +##### Metadata identifier + +```{=html} +Unique identifier for this metadata file +``` + +XPath + +: + +> /mdb:MD_Metadata/mdb:metadataIdentifier + +See `iso19115-3.2018-elem-mdb-metadataIdentifier-a4b2a53a6ba91300cd824aaa32dced12`{.interpreted-text role="ref"} + +##### Default locale + +```{=html} +Language and character set used for documenting metadata +``` + +XPath + +: + +> /mdb:MD_Metadata/mdb:defaultLocale + +See `iso19115-3.2018-elem-mdb-defaultLocale-dd848d0de1837131c70510c4ab1253b4`{.interpreted-text role="ref"} + +##### Other locale + +```{=html} +Provides information about alternatively used localised character strings +``` + +XPath + +: + +> /mdb:MD_Metadata/mdb:otherLocale + +See `iso19115-3.2018-elem-mdb-otherLocale-f4f26265136a3b0812c2ce9d90c0c17f`{.interpreted-text role="ref"} + +##### Contact + +```{=html} +Party responsible for the metadata information +``` + +XPath + +: + +> /mdb:MD_Metadata/mdb:contact + +See `iso19115-3.2018-elem-mdb-contact-bd86ee4331a33e4a09966e9d3837b346`{.interpreted-text role="ref"} + +##### Parent metadata + +```{=html} +Identification of the parent metadata record +``` + +XPath + +: + +> /mdb:MD_Metadata/mdb:parentMetadata + +See `iso19115-3.2018-elem-mdb-parentMetadata-d82be96796ed0eaaa63a697cfec1287a`{.interpreted-text role="ref"} + +##### Type of resource + +```{=html} +Type of resource for which metadata is provided +``` + +XPath + +: + +> /mdb:MD_Metadata/mdb:metadataScope + +See `iso19115-3.2018-elem-mdb-metadataScope-85ce83354003a98ad94f8f749af858f7`{.interpreted-text role="ref"} + +##### Alternative metadata reference + +```{=html} +Reference to alternative metadata, e.g Dublin Core, FGDC, or metadata in a non-ISO standard for the same resource +``` + +XPath + +: + +> /mdb:MD_Metadata/mdb:alternativeMetadataReference + +See `iso19115-3.2018-elem-mdb-alternativeMetadataReference-d658e4e78b4bb85f325070dac38656f2`{.interpreted-text role="ref"} + +##### Metadata linkage + +```{=html} +Online location where the metadata is available +``` + +XPath + +: + +> /mdb:MD_Metadata/mdb:metadataLinkage + +See `iso19115-3.2018-elem-mdb-metadataLinkage-582ff009f1d12392ca0be7e310ace58b`{.interpreted-text role="ref"} + +##### Date info + +```{=html} +Date(s) associated with the metadata. NOTE Creation” date must be provided, others can also be provided +``` + +XPath + +: + +> /mdb:MD_Metadata/mdb:dateInfo + +See `iso19115-3.2018-elem-mdb-dateInfo-74b8e273fbd6b264ff0c70ca542b6fa3`{.interpreted-text role="ref"} + +##### Metadata standard + +```{=html} +Citation for the standard to which the metadata conforms. NOTE Metadata standard citations should include an identifier. +``` + +XPath + +: + +> /mdb:MD_Metadata/mdb:metadataStandard + +See `iso19115-3.2018-elem-mdb-metadataStandard-317906f5ed0893d367c6a78ab2d68812`{.interpreted-text role="ref"} + +##### Metadata profile + +XPath + +: + +> /mdb:MD_Metadata/mdb:metadataProfile + +See `iso19115-3.2018-elem-mdb-metadataProfile-92627fbcc80493116a75b90146bcf055`{.interpreted-text role="ref"} + +### View: Full (advanced) {#iso19115-3.2018-view-advanced} + +This view is composed of13tab(s). + +- `iso19115-3.2018-tab-identificationInfo`{.interpreted-text role="ref"} +- `iso19115-3.2018-tab-contentInfo`{.interpreted-text role="ref"} +- `iso19115-3.2018-tab-distributionInfo`{.interpreted-text role="ref"} +- `iso19115-3.2018-tab-dataQualityInfo`{.interpreted-text role="ref"} +- `iso19115-3.2018-tab-resourceLineage`{.interpreted-text role="ref"} +- `iso19115-3.2018-tab-spatialRepresentationInfo`{.interpreted-text role="ref"} +- `iso19115-3.2018-tab-referenceSystemInfo`{.interpreted-text role="ref"} +- `iso19115-3.2018-tab-acquisitionInformation`{.interpreted-text role="ref"} +- `iso19115-3.2018-tab-metadata`{.interpreted-text role="ref"} +- `iso19115-3.2018-tab-portrayalCatalogueInfo`{.interpreted-text role="ref"} +- `iso19115-3.2018-tab-metadataConstraints`{.interpreted-text role="ref"} +- `iso19115-3.2018-tab-metadataMaintenance`{.interpreted-text role="ref"} +- `iso19115-3.2018-tab-applicationSchemaInfo`{.interpreted-text role="ref"} + +#### Tab: Identification (identificationInfo) {#iso19115-3.2018-tab-identificationInfo} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Identification info + +```{=html} +Basic information about the resource(s) to which the metadata applies +``` +See `iso19115-3.2018-elem-mdb-identificationInfo-7b3f7b7fbb8a986c92658058fe54f876`{.interpreted-text role="ref"} + +#### Tab: Content (contentInfo) {#iso19115-3.2018-tab-contentInfo} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Content Information + +```{=html} +Provides information about the feature catalogue and describes the coverage and image data characteristics +``` +See `iso19115-3.2018-elem-mdb-contentInfo-477f3b1af76890ee3158c66524002fd8`{.interpreted-text role="ref"} + +#### Tab: Distribution (distributionInfo) {#iso19115-3.2018-tab-distributionInfo} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Distribution Information + +```{=html} +Provides information about the distributor of and options for obtaining the resource(s) +``` +See `iso19115-3.2018-elem-mdb-distributionInfo-26e7e205c5605edb7225b0aa5c3950f1`{.interpreted-text role="ref"} + +#### Tab: Quality (dataQualityInfo) {#iso19115-3.2018-tab-dataQualityInfo} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Data quality info + +```{=html} +Provides overall assessment of quality of a resource(s) +``` +See `iso19115-3.2018-elem-mdb-dataQualityInfo-05c1cd27fb52b7bc5c361a03fb962e72`{.interpreted-text role="ref"} + +#### Tab: Lineage (resourceLineage) {#iso19115-3.2018-tab-resourceLineage} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Resource lineage + +```{=html} +Information about the provenance, source(s), and/or the production process(es) applied to the resource +``` +See `iso19115-3.2018-elem-mdb-resourceLineage-b38f8fe2e0d2dee771b11f2dfcb77937`{.interpreted-text role="ref"} + +#### Tab: Spatial rep. (spatialRepresentationInfo) {#iso19115-3.2018-tab-spatialRepresentationInfo} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Spatial representation info + +```{=html} +Digital representation of spatial information in the dataset +``` +See `iso19115-3.2018-elem-mdb-spatialRepresentationInfo-fa98674c3f9afa7324634c07cda62b3b`{.interpreted-text role="ref"} + +#### Tab: Ref. system (referenceSystemInfo) {#iso19115-3.2018-tab-referenceSystemInfo} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Reference System Information + +```{=html} +Description of the spatial and temporal reference systems used in the dataset +``` +See `iso19115-3.2018-elem-mdb-referenceSystemInfo-6e40de8cf9dbe75d0601aedf78756344`{.interpreted-text role="ref"} + +#### Tab: Acquisition info (acquisitionInformation) {#iso19115-3.2018-tab-acquisitionInformation} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Acquisition information + +See `iso19115-3.2018-elem-mdb-acquisitionInformation-ce87174a305975fd6ab50c76fa062e87`{.interpreted-text role="ref"} + +#### Tab: Metadata (metadata) {#iso19115-3.2018-tab-metadata} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Metadata + +##### Metadata identifier + +```{=html} +Unique identifier for this metadata file +``` + +XPath + +: + +> /mdb:MD_Metadata/mdb:metadataIdentifier + +See `iso19115-3.2018-elem-mdb-metadataIdentifier-a4b2a53a6ba91300cd824aaa32dced12`{.interpreted-text role="ref"} + +##### Default locale + +```{=html} +Language and character set used for documenting metadata +``` + +XPath + +: + +> /mdb:MD_Metadata/mdb:defaultLocale + +See `iso19115-3.2018-elem-mdb-defaultLocale-dd848d0de1837131c70510c4ab1253b4`{.interpreted-text role="ref"} + +##### Other locale + +```{=html} +Provides information about alternatively used localised character strings +``` + +XPath + +: + +> /mdb:MD_Metadata/mdb:otherLocale + +See `iso19115-3.2018-elem-mdb-otherLocale-f4f26265136a3b0812c2ce9d90c0c17f`{.interpreted-text role="ref"} + +##### Contact + +```{=html} +Party responsible for the metadata information +``` + +XPath + +: + +> /mdb:MD_Metadata/mdb:contact + +See `iso19115-3.2018-elem-mdb-contact-bd86ee4331a33e4a09966e9d3837b346`{.interpreted-text role="ref"} + +##### Parent metadata + +```{=html} +Identification of the parent metadata record +``` + +XPath + +: + +> /mdb:MD_Metadata/mdb:parentMetadata + +See `iso19115-3.2018-elem-mdb-parentMetadata-d82be96796ed0eaaa63a697cfec1287a`{.interpreted-text role="ref"} + +##### Type of resource + +```{=html} +Type of resource for which metadata is provided +``` + +XPath + +: + +> /mdb:MD_Metadata/mdb:metadataScope + +See `iso19115-3.2018-elem-mdb-metadataScope-85ce83354003a98ad94f8f749af858f7`{.interpreted-text role="ref"} + +##### Alternative metadata reference + +```{=html} +Reference to alternative metadata, e.g Dublin Core, FGDC, or metadata in a non-ISO standard for the same resource +``` + +XPath + +: + +> /mdb:MD_Metadata/mdb:alternativeMetadataReference + +See `iso19115-3.2018-elem-mdb-alternativeMetadataReference-d658e4e78b4bb85f325070dac38656f2`{.interpreted-text role="ref"} + +##### Metadata linkage + +```{=html} +Online location where the metadata is available +``` + +XPath + +: + +> /mdb:MD_Metadata/mdb:metadataLinkage + +See `iso19115-3.2018-elem-mdb-metadataLinkage-582ff009f1d12392ca0be7e310ace58b`{.interpreted-text role="ref"} + +##### Date info + +```{=html} +Date(s) associated with the metadata. NOTE Creation” date must be provided, others can also be provided +``` + +XPath + +: + +> /mdb:MD_Metadata/mdb:dateInfo + +See `iso19115-3.2018-elem-mdb-dateInfo-74b8e273fbd6b264ff0c70ca542b6fa3`{.interpreted-text role="ref"} + +##### Metadata standard + +```{=html} +Citation for the standard to which the metadata conforms. NOTE Metadata standard citations should include an identifier. +``` + +XPath + +: + +> /mdb:MD_Metadata/mdb:metadataStandard + +See `iso19115-3.2018-elem-mdb-metadataStandard-317906f5ed0893d367c6a78ab2d68812`{.interpreted-text role="ref"} + +##### Metadata profile + +XPath + +: + +> /mdb:MD_Metadata/mdb:metadataProfile + +See `iso19115-3.2018-elem-mdb-metadataProfile-92627fbcc80493116a75b90146bcf055`{.interpreted-text role="ref"} + +#### Tab: Portrayal (portrayalCatalogueInfo) {#iso19115-3.2018-tab-portrayalCatalogueInfo} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Portrayal catalogue info + +```{=html} +Provides information about the catalogue of rules defined for the portrayal of a resource(s) +``` +See `iso19115-3.2018-elem-mdb-portrayalCatalogueInfo-f6c73fdd3d7c18f1e90d4a8853986230`{.interpreted-text role="ref"} + +#### Tab: Md. constraints (metadataConstraints) {#iso19115-3.2018-tab-metadataConstraints} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Metadata constraints + +```{=html} +Provides restrictions on the access and use of metadata +``` +See `iso19115-3.2018-elem-mdb-metadataConstraints-cd13aab243e8cf8b0009f3c2cc6288a6`{.interpreted-text role="ref"} + +#### Tab: Md. maintenance (metadataMaintenance) {#iso19115-3.2018-tab-metadataMaintenance} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Metadata maintenance + +```{=html} +Provides information about the frequency of metadata updates, and the scope of those updates +``` +See `iso19115-3.2018-elem-mdb-metadataMaintenance-f31a9a9880a6a939b8125c2505a04439`{.interpreted-text role="ref"} + +#### Tab: Schema info (applicationSchemaInfo) {#iso19115-3.2018-tab-applicationSchemaInfo} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Application schema info + +```{=html} +Provides information about the conceptual schema of a dataset +``` +See `iso19115-3.2018-elem-mdb-applicationSchemaInfo-6e29d5e06caa68d593c2abc867db859e`{.interpreted-text role="ref"} + +### View: XML (xml) {#iso19115-3.2018-view-xml} + +This view is composed of1tab(s). + +- `iso19115-3.2018-tab-xml`{.interpreted-text role="ref"} + +#### Tab: XML (xml) {#iso19115-3.2018-tab-xml} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +## Schema technical details + +Standard identifier + +: + +> iso19115-3.2018 + +Version + +: + +> 1.0 + +Schema location + +: + +> + +Schema namespaces + +: + +- +- +- +- +- +- +- +- +- +- +- + +Schema detection mode + +: + +> elements (root) + +Schema detection elements + +: + +- cit:CI_Organisation +- cit:CI_Responsibility +- mcc:MD_BrowseGraphic +- mco:MD_Constraints +- mco:MD_LegalConstraints +- mco:MD_SecurityConstraints +- mdb:MD_Metadata +- mdq:DQ_AbsoluteExternalPositionalAccuracy +- mdq:DQ_AccuracyOfATimeMeasurement +- mdq:DQ_CompletenessCommission +- mdq:DQ_CompletenessOmission +- mdq:DQ_ConceptualConsistency +- mdq:DQ_Confidence +- mdq:DQ_DomainConsistency +- mdq:DQ_FormatConsistency +- mdq:DQ_GriddedDataPositionalAccuracy +- mdq:DQ_Homogeneity +- mdq:DQ_NonQuantitativeAttributeCorrectness +- mdq:DQ_QuantitativeAttributeAccuracy +- mdq:DQ_RelativeInternalPositionalAccuracy +- mdq:DQ_Representativity +- mdq:DQ_TemporalConsistency +- mdq:DQ_TemporalValidity +- mdq:DQ_ThematicClassificationCorrectness +- mdq:DQ_TopologicalConsistency +- mdq:DQ_UsabilityElement +- mrd:MD_Format +- mrs:MD_ReferenceSystem + +## Standard elements + +List of all elements available in the standard. + +### Name of the calendar era {#iso19115-3.2018-elem-calendarEraName-ec7b1c5ffbce0e1b8ddb7e74376c0b6e} + +Name + +: + +> calendarEraName + +Description + +: + +### Character set {#iso19115-3.2018-elem-cat-characterSet-52f1baf6f54b3997a8466c8f0bf097be} + +Name + +: + +> cat:characterSet + +Description + +: + +### Field of application {#iso19115-3.2018-elem-cat-fieldOfApplication-5bc58fccff6401611fa893189aceaaba} + +Name + +: + +> cat:fieldOfApplication + +Description + +: + +```{=html} +Field of application +``` +### Language {#iso19115-3.2018-elem-cat-language-c1b6596a8773519ed974661112541469} + +Name + +: + +> cat:language + +Description + +: + +### Language (locale) {#iso19115-3.2018-elem-cat-locale-885b210b8fd2b91d64ac8933002875c0} + +Name + +: + +> cat:locale + +Description + +: + +### Name {#iso19115-3.2018-elem-cat-name-1fcd08e54b352d11b28503ec22b0f840} + +Name + +: + +> cat:name + +Description + +: + +```{=html} +Feature catalogue name +``` +### Scope {#iso19115-3.2018-elem-cat-scope-ab251abb91bc86162e5e3909c4ea453a} + +Name + +: + +> cat:scope + +Description + +: + +```{=html} +Scope definition +``` +### Date {#iso19115-3.2018-elem-cat-versionDate-87cadc81f222434772d4afbc70202647} + +Name + +: + +> cat:versionDate + +Description + +: + +```{=html} +Catalogue date +``` +### Version {#iso19115-3.2018-elem-cat-versionNumber-cc9ba326c564cc1cd3dfe1d5f48c56ef} + +Name + +: + +> cat:versionNumber + +Description + +: + +```{=html} +Catalogue version +``` +### Address {#iso19115-3.2018-elem-cit-address-CI_Contact-97d82fe84f0b58d25ab4a3bc467b682e} + +Name + +: + +> cit:address + +Context + +: + +> CI_Contact + +Description + +: + +```{=html} +Physical and email address at which the organization or + individual may be + contacted +``` +### Adresse {#iso19115-3.2018-elem-cit-address-855032095c3291ece299ab89936fbd31} + +Name + +: + +> cit:address + +Description + +: + +```{=html} +Adresse physique et électronique à laquelle la personne ou + l'organisation responsable peut être contactée +``` +```{=html} +Adresse postale ou électronique d'un premier niveau de contact (par + exemple un secrétariat). Ces informations sont du type CI_Address et sont + gérées dans la classe du même nom. +``` +### Administrative area {#iso19115-3.2018-elem-cit-administrativeArea-b8c4ff9a4088ccf36d86a7844f6ee578} + +Name + +: + +> cit:administrativeArea + +Description + +: + +```{=html} +State, province of the location +``` +### Alternate title {#iso19115-3.2018-elem-cit-alternateTitle-11081d54ab21175ab27ed26bd70f1318} + +Name + +: + +> cit:alternateTitle + +Description + +: + +```{=html} +Short name or other language name by which the cited + information is known. + Example: "DCW" as an alternative title for "Digital Chart of the World +``` +### Application profile {#iso19115-3.2018-elem-cit-applicationProfile-cc4b32b3780fe5ec9c452cc5cadd0991} + +Name + +: + +> cit:applicationProfile + +Description + +: + +```{=html} +Name of an application profile that can be used with the online + resource +``` +### Address {#iso19115-3.2018-elem-cit-CI_Address-5ae5f6aeaca8c394467355c580134ce5} + +Name + +: + +> cit:CI_Address + +Description + +: + +```{=html} +Location of the responsible individual or organization +``` +### Citation {#iso19115-3.2018-elem-cit-CI_Citation-07ef81205ee846bbc18cc8483d63b488} + +Name + +: + +> cit:CI_Citation + +Description + +: + +```{=html} +Standardised resource reference +``` +### Contact {#iso19115-3.2018-elem-cit-CI_Contact-9c64730242278628f7068b237dc2e3ba} + +Name + +: + +> cit:CI_Contact + +Description + +: + +```{=html} +Information required to enable contact with the responsible + person and/or + organization +``` +### Date {#iso19115-3.2018-elem-cit-CI_Date-d1dcaf53cc1f919898b4cb1f2716d465} + +Name + +: + +> cit:CI_Date + +Description + +: + +```{=html} +Reference date and event used to describe it (YYYY-MM-DD) +``` +### Individual {#iso19115-3.2018-elem-cit-CI_Individual-f6229448aa872e50835de3e9bf949386} + +Name + +: + +> cit:CI_Individual + +Description + +: + +```{=html} +Class of information about the party if the party is + an individual +``` +### OnLine resource {#iso19115-3.2018-elem-cit-CI_OnlineResource-44959d6b329db39e0b0fc7fe8776471b} + +Name + +: + +> cit:CI_OnlineResource + +Description + +: + +```{=html} +Information about on-line sources from which the dataset, + specification, or + community profile name and extended metadata elements can be obtained +``` +### Organisation {#iso19115-3.2018-elem-cit-CI_Organisation-053268e94a93caf2bca99e2e34be8ecd} + +Name + +: + +> cit:CI_Organisation + +Description + +: + +```{=html} +Class of information about the party if the party is + an organization +``` +### Responsibility {#iso19115-3.2018-elem-cit-CI_Responsibility-071c0ed4ea21aca2435009ff6d74ca00} + +Name + +: + +> cit:CI_Responsibility + +Description + +: + +```{=html} +Class of information about the party and their + role +``` +### Role code {#iso19115-3.2018-elem-cit-CI_RoleCode-4d462a9e57560b8f52a159210fb7a409} + +Name + +: + +> cit:CI_RoleCode + +Description + +: + +### Standard codelists Role code (cit:CI_RoleCode) + +| code | label | description | +|-----------------------|------------------------|--------------------------------------------------------------------------------------------------------------------------------| +| resourceProvider | Resource provider | Party that supplies the resource | +| custodian | Custodian | Party that accepts accountability and responsibility for the data and ensures appropriate care and maintenance of the resource | +| owner | Owner | Party that owns the resource | +| user | User | Party who uses the resource | +| distributor | Distributor | Party who distributes the resource | +| originator | Originator | Party who created the resource | +| pointOfContact | Point of contact | Party who can be contacted for acquiring knowledge about or acquisition of the resource | +| principalInvestigator | Principal investigator | Key party responsible for gathering information and conducting research | +| processor | Processor | Party that has processed the data in a manner such that the resource has been modified | +| publisher | Publisher | Party who published the resource | +| author | Author | Party who authored the resource | +| sponsor | Sponsor | Party who speaks for the resource | +| coAuthor | Co-author | Party who jointly authors the resource | +| collaborator | Collaborator | Party who assists with the generation of the resource other than the principal investigator | +| editor | Editor | Party who reviewed or modified the resource to improve the content | +| mediator | Mediator | A class of entity that mediates access to the resource and for whom the resource is intended or useful | +| rightsHolder | Rights holder | Party owning or managing rights over the resource | +| contributor | Contributor | Party contributing to the resource | +| funder | Funder | Party providing monetary support for the resource | +| stakeholder | Stakeholder | Party who has an interest in the resource or the use of the resource | + +### Séries {#iso19115-3.2018-elem-cit-CI_Series-05997b3c9b5a88806c44ec019dd105f6} + +Name + +: + +> cit:CI_Series + +Description + +: + +```{=html} +Class of information about the series, or aggregate + resource, to which a resource belongs +``` +### Telephone {#iso19115-3.2018-elem-cit-CI_Telephone-57584ba11ae4721360c06e9f1a980082} + +Name + +: + +> cit:CI_Telephone + +Description + +: + +```{=html} +Telephone numbers for contacting the responsible individual or + organization +``` +### Cited responsible party {#iso19115-3.2018-elem-cit-citedResponsibleParty-12711cd21eb7ccd8be6d15ff06b1fecc} + +Name + +: + +> cit:citedResponsibleParty + +Description + +: + +```{=html} +Name and position information for an individual or organization + that is + responsible for the resource +``` +### City {#iso19115-3.2018-elem-cit-city-64053d57bd74c4e93afb69989ee49cb4} + +Name + +: + +> cit:city + +Description + +: + +```{=html} +City of the location +``` +### Contact Information {#iso19115-3.2018-elem-cit-contactInfo-5c594c4932c99a4158471697d7f84f18} + +Name + +: + +> cit:contactInfo + +Description + +: + +```{=html} +Address of the responsible party +``` +### Contact instructions {#iso19115-3.2018-elem-cit-contactInstructions-28da1ff5a0492d67e13453f2a39ca9e2} + +Name + +: + +> cit:contactInstructions + +Description + +: + +```{=html} +Supplemental instructions on how or when to contact the + individual or + organization +``` +### Contact type {#iso19115-3.2018-elem-cit-contactType-20fe26a0025843f8389415944deb170c} + +Name + +: + +> cit:contactType + +Description + +: + +```{=html} +Type of the contact +``` +### Country {#iso19115-3.2018-elem-cit-country-8569b7d15373c7d51d73fe19899ddc47} + +Name + +: + +> cit:country + +Description + +: + +```{=html} +Country of the physical address +``` +### Country {#iso19115-3.2018-elem-cit-country-cit-CI_Address-2e0d29619005dfe74c7a6d24b38058f3} + +Name + +: + +> cit:country + +Context + +: + +> cit:CI_Address + +Description + +: + +```{=html} +Country of the address +``` + +Condition + +: + +> optional + +### Date {#iso19115-3.2018-elem-cit-date-c960311cb0c208a0574cc6c1189e291b} + +Name + +: + +> cit:date + +Description + +: + +```{=html} +Formatted as 2007-09-12 (YYYY-MM-DD) +``` +```{=html} +reference date and event used to describe it +``` +### Date {#iso19115-3.2018-elem-cit-date-cit-CI_Citation-f920bf44c6e3baee883e7de01175e514} + +Name + +: + +> cit:date + +Context + +: + +> cit:CI_Citation + +Description + +: + +```{=html} +Reference date for the cited resource +``` + +Condition + +: + +> mandatory + +### Date {#iso19115-3.2018-elem-cit-date-cit-CI_Date-ba0770057c4e9ec8eb2d52e7d0b2c59f} + +Name + +: + +> cit:date + +Context + +: + +> cit:CI_Date + +Description + +: + +```{=html} +Reference date for the cited resource +``` + +Condition + +: + +> mandatory + +### Date type {#iso19115-3.2018-elem-cit-dateType-441176555042ce6ede97954a98eb7b83} + +Name + +: + +> cit:dateType + +Description + +: + +```{=html} +Event used for reference date +``` + +Condition + +: + +> mandatory + +### Delivery point {#iso19115-3.2018-elem-cit-deliveryPoint-81ad23bd0554b46cfbd1f7dfa20f81ea} + +Name + +: + +> cit:deliveryPoint + +Description + +: + +```{=html} +Address line for the location (as described in ISO 11180, annex + A) +``` +```{=html} +Address line for the location. Example Street number + and name, Suite number, etc. +``` +### Description {#iso19115-3.2018-elem-cit-description-cit-CI_OnlineResource-01ddc3b7f9794277399a2c56f4e7f0aa} + +Name + +: + +> cit:description + +Context + +: + +> cit:CI_OnlineResource + +Description + +: + +```{=html} +Detailed text description of what the online resource is/does +``` +``` xml + + Ce service de téléchargement ATOM Feed permet de télécharger la série de couches de + données conforme au thème INSPIRE "Sites protégés". Cliquez sur le lien correspondant aux couches de + données Natura 2000 pour télécharger les informations relatives à ce mécanisme de désignation. + +``` + +### Edition {#iso19115-3.2018-elem-cit-edition-04e1813c8da877a03f60df27a3b69ab2} + +Name + +: + +> cit:edition + +Description + +: + +```{=html} +Version of the cited resource +``` +### Edition date {#iso19115-3.2018-elem-cit-editionDate-2fe8af778725aaaa1c77f6f5094c2c27} + +Name + +: + +> cit:editionDate + +Description + +: + +```{=html} +Date of the edition (YYYY-MM-DD) +``` +### Electronic mail address {#iso19115-3.2018-elem-cit-electronicMailAddress-8abe82c5c90b49acb18508577ddf6f95} + +Name + +: + +> cit:electronicMailAddress + +Description + +: + +```{=html} +Address of the electronic mailbox of the responsible + organization or + individual +``` +### Extent {#iso19115-3.2018-elem-cit-extent-cit-CI_Responsibility-cafbc635a55f5453157ec2cc54c624f8} + +Name + +: + +> cit:extent + +Context + +: + +> cit:CI_Responsibility + +Description + +: + +```{=html} +Spatial or temporal extent of the role +``` +### Function {#iso19115-3.2018-elem-cit-function-d1ccd71b112690a7ae7f187d2b1286b9} + +Name + +: + +> cit:function + +Description + +: + +```{=html} +Code for function performed by the online resource +``` +### Graphic {#iso19115-3.2018-elem-cit-graphic-cit-CI_Citation-a71bc47c4468f216fac662acedf06ff2} + +Name + +: + +> cit:graphic + +Context + +: + +> cit:CI_Citation + +Description + +: + +```{=html} +Citation graphic or logo for the cited resource +``` + +Condition + +: + +> optional + +### Hours of service {#iso19115-3.2018-elem-cit-hoursOfService-005f6a6884104abc1caeff5be47c98b8} + +Name + +: + +> cit:hoursOfService + +Description + +: + +```{=html} +Time period (including time zone) when individuals can contact + the organization + or individual +``` +### Citation identifier {#iso19115-3.2018-elem-cit-identifier-cit-CI_Citation-39034d5cd7f284b1b393efdee0580e49} + +Name + +: + +> cit:identifier + +Context + +: + +> cit:CI_Citation + +Description + +: + +```{=html} +Identifier of the citation +``` +### Individual {#iso19115-3.2018-elem-cit-individual-55ac5c7a0365c3cc796a297e2f6bdf73} + +Name + +: + +> cit:individual + +Description + +: + +```{=html} +An individual in the named organization +``` +### ISBN {#iso19115-3.2018-elem-cit-ISBN-32066ff442c8b0e2dbb3b0885a94976a} + +Name + +: + +> cit:ISBN + +Description + +: + +```{=html} +International Standard Book Number +``` +### ISSN {#iso19115-3.2018-elem-cit-ISSN-1e3a944a9bd57fddb021ebdd8d9e882a} + +Name + +: + +> cit:ISSN + +Description + +: + +```{=html} +International Standard Serial Number +``` +### Issue identification {#iso19115-3.2018-elem-cit-issueIdentification-d6144f3517e8dca0a71cfcdac7907efa} + +Name + +: + +> cit:issueIdentification + +Description + +: + +```{=html} +Information identifying the issue of the series +``` +### Linkage {#iso19115-3.2018-elem-cit-linkage-72b815e56327f02e8c718dfc3c53955c} + +Name + +: + +> cit:linkage + +Description + +: + +```{=html} +Location (address) for on-line access using a Uniform Resource + Locator address + or similar addressing scheme such as http://www.statkart.no/isotc211 +``` + +Condition + +: + +> mandatory + +### Logo {#iso19115-3.2018-elem-cit-logo-aafda1f3a41ecfe3fa4c4dcc6a4f4c34} + +Name + +: + +> cit:logo + +Description + +: + +```{=html} +Graphic identifying the organization +``` +### Name of the resource {#iso19115-3.2018-elem-cit-name-cit-CI_OnlineResource-ab7fb0a1840b8534cbf9f4b41530ae35} + +Name + +: + +> cit:name + +Context + +: + +> cit:CI_OnlineResource + +Description + +: + +```{=html} +Name of the online resource +``` +### Name {#iso19115-3.2018-elem-cit-name-cit-CI_Series-0266f984b84af8225a054d8f77cbf48a} + +Name + +: + +> cit:name + +Context + +: + +> cit:CI_Series + +Description + +: + +```{=html} +Name of the series, or aggregate dataset, of which the dataset + is a + part +``` +### Organisation name {#iso19115-3.2018-elem-cit-name-cit-CI_Organisation-35d4282d04316174623d834f8a425bba} + +Name + +: + +> cit:name + +Context + +: + +> cit:CI_Organisation + +Description + +: + +```{=html} +Name of the responsible organization +``` + +Condition + +: + +> conditional + +### Individual name {#iso19115-3.2018-elem-cit-name-cit-CI_Individual-652968a35c18c887fd63b5a8f0623dd8} + +Name + +: + +> cit:name + +Context + +: + +> cit:CI_Individual + +Description + +: + +```{=html} +Name of the responsible person- surname, given name, title +``` +### Name {#iso19115-3.2018-elem-cit-name-ebbdb582d68421b99463b31059d63b5a} + +Name + +: + +> cit:name + +Description + +: + +### Number {#iso19115-3.2018-elem-cit-number-be212daea0ac64953b2c7b1ef5e8c0d5} + +Name + +: + +> cit:number + +Description + +: + +```{=html} +Telephone number by which individuals can contact + responsible organisation or individual +``` +### Number type {#iso19115-3.2018-elem-cit-numberType-528a01ad72f823205c2faaeb99a60907} + +Name + +: + +> cit:numberType + +Description + +: + +```{=html} +Type of telephone number +``` +### Online resource {#iso19115-3.2018-elem-cit-onlineResource-cit-CI_Contact-1f4b0cbdb455e04f053de4187d716280} + +Name + +: + +> cit:onlineResource + +Context + +: + +> cit:CI_Contact + +Description + +: + +```{=html} +On-line information that can be used to contact the + individual or organisation +``` +### Website {#iso19115-3.2018-elem-cit-onlineResource-2ed916ad0165783c0e00cd631a2fa9e4} + +Name + +: + +> cit:onlineResource + +Description + +: + +```{=html} +Define URL to access the website +``` +```{=html} +On-line information that can be used to contact the individual + or + organisation +``` +### Other citation details {#iso19115-3.2018-elem-cit-otherCitationDetails-12cf58786723aa5bbbb5768a566120b7} + +Name + +: + +> cit:otherCitationDetails + +Description + +: + +```{=html} +Other information required to complete the citation that is not + recorded + elsewhere +``` +### Page {#iso19115-3.2018-elem-cit-page-8f0b8d638ea1b8990cc7a78128a246d1} + +Name + +: + +> cit:page + +Description + +: + +```{=html} +Details on which pages of the publication the article was + published +``` +### Party {#iso19115-3.2018-elem-cit-party-cit-CI_Responsibility-21218621f3c4fc5f48c55804f5a14d2e} + +Name + +: + +> cit:party + +Context + +: + +> cit:CI_Responsibility + +Description + +: + +```{=html} +Information about the party +``` +### Identifier for the party {#iso19115-3.2018-elem-cit-partyIdentifier-cd101436a544472459e8b848a2eb8e56} + +Name + +: + +> cit:partyIdentifier + +Description + +: + +### Telephone {#iso19115-3.2018-elem-cit-phone-29b2e78f752a094113d95c28083ead50} + +Name + +: + +> cit:phone + +Description + +: + +```{=html} +Telephone numbers at which the organisation or + individual may be contacted +``` +### Position name {#iso19115-3.2018-elem-cit-positionName-77a4db52c54386c39c3267bb69aad17a} + +Name + +: + +> cit:positionName + +Description + +: + +```{=html} +Role or position of the responsible person +``` + +Condition + +: + +> conditional + +### Postal code {#iso19115-3.2018-elem-cit-postalCode-103d77a2e1d3eb6891052449be62520e} + +Name + +: + +> cit:postalCode + +Description + +: + +```{=html} +ZIP or other postal code +``` +### Presentation form {#iso19115-3.2018-elem-cit-presentationForm-9b37d87116e709efbd758957d7ddbb34} + +Name + +: + +> cit:presentationForm + +Description + +: + +```{=html} +Mode in which the resource is represented +``` +### Protocol {#iso19115-3.2018-elem-cit-protocol-56ba71e5a9e6ae87797545a296a791f2} + +Name + +: + +> cit:protocol + +Description + +: + +```{=html} +Connection protocol to be used +``` +Recommended values + +| code | label | +|----------------------------------|------------------------------------------------| +| OGC API - Coverages | OGC API - Coverages | +| OGC API - Features | OGC API - Features | +| OGC API - Maps | OGC API - Maps | +| OGC API - Records | OGC API - Records | +| OGC:CSW | OGC-CSW Catalogue Service for the Web | +| OGC:KML | OGC-KML Keyhole Markup Language | +| OGC:GML | OGC-GML Geography Markup Language | +| OGC:ODS | OGC-ODS OpenLS Directory Service | +| OGC:OGS | OGC-ODS OpenLS Gateway Service | +| OGC:OUS | OGC-ODS OpenLS Utility Service | +| OGC:OPS | OGC-ODS OpenLS Presentation Service | +| OGC:ORS | OGC-ODS OpenLS Route Service | +| OGC:SOS | OGC-SOS Sensor Observation Service | +| OGC:SPS | OGC-SPS Sensor Planning Service | +| OGC:SAS | OGC-SAS Sensor Alert Service | +| OGC:WCS | OGC-WCS Web Coverage Service | +| OGC:WCTS | OGC-WCTS Web Coordinate Transformation Service | +| OGC:WFS | OGC-WFS Web Feature Service | +| INSPIRE Atom | INSPIRE Atom | +| OGC:WMS | OGC-WMS Web Map Service | +| OGC:WMTS | OGC-WMS Web Map Tile Service | +| OGC:WNS | OGC-WNS Web Notification Service | +| OGC:WPS | OGC-WPS Web Processing Service | +| WWW:DOWNLOAD-1.0-ftp--download | File for download through FTP | +| WWW:DOWNLOAD-1.0-http--download | File for download | +| ESRI:REST | ESRI REST Service | +| ESRI:REST-TILED | ESRI REST Tiled Service | +| | GIS file | +| | GIS RASTER file | +| WWW:LINK-1.0-http--link | Web address (URL) | +| WWW:LINK-1.0-http--rss | RSS News feed (URL) | +| DB:POSTGIS | PostGIS database table | +| DB:ORACLE | ORACLE database table | +| WWW:LINK-1.0-http--opendap | OPeNDAP URL | +| RBNB:DATATURBINE | Data Turbine | +| UKST | Unknown Service Type | + +``` xml + + atom:feed + +``` + +### Protocol request {#iso19115-3.2018-elem-cit-protocolRequest-e58550e17f9baca9aaa1dc62bec847d1} + +Name + +: + +> cit:protocolRequest + +Description + +: + +```{=html} +Request used to access the resource depending on the protocol + (to be used mainly for POST requests) +``` +### Role {#iso19115-3.2018-elem-cit-role-8e99af312ea1dbd228b50677ba6b9fd7} + +Name + +: + +> cit:role + +Description + +: + +### Role {#iso19115-3.2018-elem-cit-role-cit-CI_Responsibility-e5aa9d82909db5e5beb67eb483f8bdc4} + +Name + +: + +> cit:role + +Context + +: + +> cit:CI_Responsibility + +Description + +: + +```{=html} +Function performed by the responsible party +``` + +Condition + +: + +> mandatory + +### Role {#iso19115-3.2018-elem-cit-role-mri-MD_Association-9fb15da4e2c1795eed15ad17f6b508bb} + +Name + +: + +> cit:role + +Context + +: + +> mri:MD_Association + +Description + +: + +```{=html} +Reference to the ends (roles) of a concrete association +``` +### Series {#iso19115-3.2018-elem-cit-series-33d7a9a9d8aab2b7285884917cc0368c} + +Name + +: + +> cit:series + +Description + +: + +```{=html} +Information about the series, or aggregate resource, + of which the resource is a part +``` +### Format name {#iso19115-3.2018-elem-cit-title-/mdb-MD_Metadata/mdb-distributionInfo/mrd-MD_Distribution/mrd-distributionFormat/mrd-MD_Format/mrd-formatSpecificationCitation/cit-CI_Citation/cit-title-11140ae1a791f8912ad78af979af4a3a} + +Name + +: + +> cit:title + +Context + +: + +> /mdb:MD_Metadata/mdb:distributionInfo/mrd:MD_Distribution/mrd:distributionFormat/mrd:MD_Format/mrd:formatSpecificationCitation/cit:CI_Citation/cit:title + +Description + +: + +```{=html} +Name of the data transfer format(s) +``` +```{=html} +File or link format name +``` +Recommended values + +| code | label | +|-----------------|-----------------| +| Text | Text | +| XLS | XLS | +| ESRI Shapefile | ESRI Shapefile | +| Mapinfo MIF/MID | Mapinfo MIF/MID | +| Mapinfo TAB | Mapinfo TAB | +| KML | KML | +| GML | GML | +| XYZ Ascii | XYZ Ascii | +| NetCDF | NetCDF | +| GeoTIFF | GeoTIFF | +| TIFF | TIFF | +| ECW | ECW | +| JPEG2000 | JPEG2000 | +| ZIP | ZIP | +| PDF | PDF | +| PNG | PNG | +| JPEG | JPEG | +| OGC:WMC | OGC:WMC | +| OGC:OWS-C | OGC OWS Context | + +### Specification {#iso19115-3.2018-elem-cit-title-/mdb-MD_Metadata/mdb-dataQualityInfo/mdq-DQ_DataQuality/mdq-report/mdq-DQ_DomainConsistency/mdq-result/mdq-DQ_ConformanceResult/mdq-specification/cit-CI_Citation/cit-title-b03759562aa7906e72e843780b064c77} + +Name + +: + +> cit:title + +Context + +: + +> /mdb:MD_Metadata/mdb:dataQualityInfo/mdq:DQ_DataQuality/mdq:report/mdq:DQ_DomainConsistency/mdq:result/mdq:DQ_ConformanceResult/mdq:specification/cit:CI_Citation/cit:title + +Description + +: + +Recommended values + +| code | label | +|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| COMMISSION REGULATION (EU) No 1089/2010 of 23 November 2010 implementing Directive 2007/2/EC of the European Parliament and of the Council as regards interoperability of spatial data sets and services | COMMISSION REGULATION (EU) No 1089/2010 of 23 November 2010 implementing Directive 2007/2/EC of the European Parliament and of the Council as regards interoperability of spatial data sets and services | +| INSPIRE Data Specification on Administrative Units - Guidelines v3.0.1 | Guide INSPIRE sur les unités administratives | +| INSPIRE Data Specification on Cadastral Parcels - Guidelines v 3.0.1 | Guide INSPIRE sur les parcelles cadastrales | +| INSPIRE Data Specification on Geographical Names - Guidelines v 3.0.1 | Guide INSPIRE sur les dénominations géographiques | +| INSPIRE Data Specification on Hydrography - Guidelines v 3.0.1 | Guide INSPIRE sur l'hydrographie | +| INSPIRE Data Specification on Protected Sites - Guidelines v 3.1.0 | Guide INSPIRE sur les sites protégés | +| INSPIRE Data Specification on Transport Networks - Guidelines v 3.1.0 | Guide INSPIRE sur les réseaux de transport | +| INSPIRE Data Specification on Addresses - Guidelines v 3.0.1 | Guide INSPIRE sur les adresses | +| INSPIRE Specification on Coordinate Reference Systems - Guidelines v 3.1 | Guide INSPIRE sur les référentiels de coordonnées | +| INSPIRE Specification on Geographical Grid Systems - Guidelines v 3.0.1 | Guide INSPIRE sur les systèmes de maillage géographique | + +Recommended values + +| code | label | +|-----------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------| +| RÈGLEMENT (UE) N° 976/2009 | Règlement service en réseau INSPIRE (service de recherche et de consultation) - RÈGLEMENT (UE) N° 976/2009 | +| RÈGLEMENT (UE) N° 1088/2010 | Règlement service en réseau INSPIRE (service de téléchargement et de transformation) - RÈGLEMENT (UE) N° 1088/2010 | +| Technical Guidance for the implementation of INSPIRE Discovery Services -- v.3.1 | Guide INSPIRE sur les services de recherche | +| Technical Guidance for the implementation of INSPIRE View Services - v3.1 -- part 4 | Guide INSPIRE sur les services de consultation -- profil ISO 19128 (WMS) | +| Technical Guidance for the implementation of INSPIRE View Services - v3.1 -- part 5 | Guide INSPIRE sur les services de consultation -- profil ISO WMTS 1.0.0 | +| Technical Guidance for the INSPIRE Schema Transformation Network Service - v3.0 | Guide INSPIRE sur les services de transformation de schéma | +| Technical Guidance for the implementation of INSPIRE Download Services -- level1 - v3.0 | Guide INSPIRE sur les services de téléchargement -- classe de conformité 1 (ATOM pré-défini) | +| Technical Guidance for the implementation of INSPIRE Download Services -- level2 - v3.0 | Guide INSPIRE sur les services de téléchargement -- classe de conformité 2 (WFS pré-défini) | +| Technical Guidance for the implementation of INSPIRE Download Services -- level3 - v3.0 | Guide INSPIRE sur les services de téléchargement -- classe de conformité 3 (WFS direct) | + +### Title {#iso19115-3.2018-elem-cit-title-/mdb-MD_Metadata/mdb-identificationInfo/mri-MD_DataIdentification/mri-citation/cit-CI_Citation/cit-title-5084206f0cda801f58faf7204c09b3d1} + +Name + +: + +> cit:title + +Context + +: + +> /mdb:MD_Metadata/mdb:identificationInfo/mri:MD_DataIdentification/mri:citation/cit:CI_Citation/cit:title + +Description + +: + +```{=html} +Name by which the cited resource is known +``` +### Title {#iso19115-3.2018-elem-cit-title-7dfafb62cad1555c0ee6d132f1e775fd} + +Name + +: + +> cit:title + +Description + +: + +```{=html} +Name by which the cited resource is known +``` + +Condition + +: + +> mandatory + +### Code {#iso19115-3.2018-elem-code-mri-MD_Identifier-67258785530ff4b1ebf28f28ce66d33b} + +Name + +: + +> code + +Context + +: + +> mri:MD_Identifier + +Description + +: + +```{=html} +Alphanumeric value identifying an instance in the namespace +``` +```{=html} +alphanumeric value identifying an instance in the namespace +``` +### System code {#iso19115-3.2018-elem-code-5d6344f28f37d0f73c2cb79145f5668d} + +Name + +: + +> code + +Description + +: + +```{=html} +Code. i.e. EPSG code. +``` +### Code {#iso19115-3.2018-elem-code-mri-MD_CodeValue-e885cdcb9c42da39e0093542b4865e30} + +Name + +: + +> code + +Context + +: + +> mri:MD_CodeValue + +Description + +: + +```{=html} +Value code +``` +```{=html} +Value code (i.e. numeric) +``` +### Reference Authority {#iso19115-3.2018-elem-codeSpace-c90144a092543c4117eb54a71d33ac63} + +Name + +: + +> codeSpace + +Description + +: + +```{=html} +Authority responsible for codification. i.e. EPSG +``` +### Date et heure {#iso19115-3.2018-elem-dqc-dateTime-440241ab056365dcafe4e74d8e833374} + +Name + +: + +> dqc:dateTime + +Description + +: + +### Related element {#iso19115-3.2018-elem-dqc-relatedElement-8807300908c0949ebb1329e3e7a3eacc} + +Name + +: + +> dqc:relatedElement + +Description + +: + +### Factor {#iso19115-3.2018-elem-factor-5afe00178e76b0c48a70e7bc76d88080} + +Name + +: + +> factor + +Description + +: + +### Frame {#iso19115-3.2018-elem-frame-495bc4e6402da158707765fec6ad81e3} + +Name + +: + +> frame + +Description + +: + +```{=html} +Frame attribute provides a URI reference that identifies a + description of the reference system +``` +### Name {#iso19115-3.2018-elem-gco-aName-ec573ab870f9406d1373cd7815dbaf97} + +Name + +: + +> gco:aName + +Description + +: + +### Type name {#iso19115-3.2018-elem-gco-aName-gco-TypeName-9aedcb12c741bbbd96004346261c4dda} + +Name + +: + +> gco:aName + +Context + +: + +> gco:TypeName + +Description + +: + +Recommended values + +| code | label | +|-----------|-----------| +| BOOLEAN | BOOLEAN | +| BYTE | BYTE | +| CHARACTER | CHARACTER | +| DATE | DATE | +| DATETIME | DATETIME | +| DOUBLE | DOUBLE | +| FLOAT | FLOAT | +| INTEGER | INTEGER | +| NUMERIC | NUMERIC | +| REAL | REAL | +| SERIAL | SERIAL | +| VARCHAR | VARCHAR | +| TEXT | TEXT | + +### Angle {#iso19115-3.2018-elem-gco-Angle-7ce2d1a5c0a7c675bf50204696f97212} + +Name + +: + +> gco:Angle + +Description + +: + +```{=html} +Angle +``` +### Attribute type {#iso19115-3.2018-elem-gco-attributeType-8d0028999602c0fc0861c3e2cdfd3ba4} + +Name + +: + +> gco:attributeType + +Description + +: + +### Binary {#iso19115-3.2018-elem-gco-Binary-fae8ca1153637dd8df3141b8d77f0b88} + +Name + +: + +> gco:Binary + +Description + +: + +### Text {#iso19115-3.2018-elem-gco-CharacterString-b1698de198f86561c868ca9fb4242d60} + +Name + +: + +> gco:CharacterString + +Description + +: + +### Usage Date / Time {#iso19115-3.2018-elem-gco-DateTime-mri-MD_Usage-354630792f5d24d7c5134ae38f654663} + +Name + +: + +> gco:DateTime + +Context + +: + +> mri:MD_Usage + +Description + +: + +```{=html} +Formatted as 2007-09-12T15:00:00 (YYYY-MM-DDTHH:mm:ss) +``` +```{=html} +date and time of the first use or range of uses of the resource and/or + resource + series +``` +### Planned Available Date / Time {#iso19115-3.2018-elem-gco-DateTime-mrd-MD_StandardOrderProcess-16e3d91c2572d6377e06810858b43450} + +Name + +: + +> gco:DateTime + +Context + +: + +> mrd:MD_StandardOrderProcess + +Description + +: + +```{=html} +Formatted as 2007-09-12T15:00:00 (YYYY-MM-DDTHH:mm:ss) +``` +```{=html} +date and time when theresource will be available +``` +### Date and time {#iso19115-3.2018-elem-gco-DateTime-e6a33d377eb75a1ef5224b35ce0810da} + +Name + +: + +> gco:DateTime + +Description + +: + +```{=html} +Date and time or range of date and time on or over which the + process step occurred + (YYYY-MM-DDThh:mm:ss) +``` +### Distance {#iso19115-3.2018-elem-gco-Distance-02d18ba9c09dae7b4a4ee648ca1afd68} + +Name + +: + +> gco:Distance + +Description + +: + +```{=html} +Distance +``` +### Length {#iso19115-3.2018-elem-gco-Length-fc950d15ea62227f0431a5fe64f47d48} + +Name + +: + +> gco:Length + +Description + +: + +```{=html} +Length +``` +### Name {#iso19115-3.2018-elem-gco-localName-7c3666b9b35b4cde01f4a7c8f51c0fb9} + +Name + +: + +> gco:localName + +Description + +: + +### Local name {#iso19115-3.2018-elem-gco-LocalName-08c97bf6632239439f713537c5d5ecda} + +Name + +: + +> gco:LocalName + +Description + +: + +### Lower cardinality {#iso19115-3.2018-elem-gco-lower-aeb71a259de3a9b79e057b2587339450} + +Name + +: + +> gco:lower + +Description + +: + +```{=html} +Lower cardinality +``` +### Measure {#iso19115-3.2018-elem-gco-Measure-7fd8ef9f27cda91ac9513456c11a7fef} + +Name + +: + +> gco:Measure + +Description + +: + +```{=html} +Measure +``` +### Name of Measure {#iso19115-3.2018-elem-gco-Measure-mri-DQ_Element-9093d47a462e74a70a172237586f2f36} + +Name + +: + +> gco:Measure + +Context + +: + +> mri:DQ_Element + +Description + +: + +```{=html} +Name of the test applied to the data +``` +### Unit of Measure {#iso19115-3.2018-elem-gco-Measure-mri-EX_VerticalExtent-11f2ea0a92433742e4b068e8aa6c5e87} + +Name + +: + +> gco:Measure + +Context + +: + +> mri:EX_VerticalExtent + +Description + +: + +```{=html} +Vertical units used for vertical extent information Examples: + metres, feet, + millimetres, hectopascals +``` +### Member name {#iso19115-3.2018-elem-gco-MemberName-029e1a339fbce38a70a42b617c003ece} + +Name + +: + +> gco:MemberName + +Description + +: + +### Multiplicity {#iso19115-3.2018-elem-gco-Multiplicity-0dca80c90498a1272be725fe1b99baba} + +Name + +: + +> gco:Multiplicity + +Description + +: + +### Multiplicity range {#iso19115-3.2018-elem-gco-MultiplicityRange-5d8f76d1c4cd389c59b4d736b2301979} + +Name + +: + +> gco:MultiplicityRange + +Description + +: + +### Nil reason {#iso19115-3.2018-elem-gco-nilReason-69d908b4be9b96c2663ae9726ae2b787} + +Name + +: + +> gco:nilReason + +Description + +: + +### Range {#iso19115-3.2018-elem-gco-range-3b2d2f387c5ecf91d053fa864086b9b4} + +Name + +: + +> gco:range + +Description + +: + +### Record {#iso19115-3.2018-elem-gco-Record-c95feb94990445212e6d0234fdfdb79f} + +Name + +: + +> gco:Record + +Description + +: + +### Record type {#iso19115-3.2018-elem-gco-RecordType-baa419e16ebadaef186f5d1d4378d1db} + +Name + +: + +> gco:RecordType + +Description + +: + +### Scoped name {#iso19115-3.2018-elem-gco-ScopedName-1edc4de3e2fd49cb8bfddd8e85a4a987} + +Name + +: + +> gco:ScopedName + +Description + +: + +### Period duration {#iso19115-3.2018-elem-gco-TM_PeriodDuration-f702b95baf47dfb1a87c02f15a5dd639} + +Name + +: + +> gco:TM_PeriodDuration + +Description + +: + +```{=html} +The duration data type is used to specify a time interval. + +The time interval is specified in the following form "PnYnMnDTnHnMnS" +where: + +* P indicates the period (required) +* nY indicates the number of years +* nM indicates the number of months +* nD indicates the number of days +* T indicates the start of a time section (required if you are going to +specify hours, minutes, or seconds) +* nH indicates the number of hours +* nM indicates the number of minutes +* nS indicates the number of seconds +``` +### Type name {#iso19115-3.2018-elem-gco-TypeName-4009cb017635c2d3ff82934005a4ff9b} + +Name + +: + +> gco:TypeName + +Description + +: + +### Upper cardinality {#iso19115-3.2018-elem-gco-upper-0d20822ffdc1ca6563de53fd87a067c2} + +Name + +: + +> gco:upper + +Description + +: + +```{=html} +Upper cardinality +``` +### Anchor {#iso19115-3.2018-elem-gcx-Anchor-064e20d9f65a23dc450f791da24017aa} + +Name + +: + +> gcx:Anchor + +Description + +: + +```{=html} +Supports hyper-linking capabilities and ensures a web-like + implementation of CharacterStrings +``` +### File name {#iso19115-3.2018-elem-gcx-FileName-0bd7e76cc1295f6aa4aebc92c3448842} + +Name + +: + +> gcx:FileName + +Description + +: + +```{=html} +File name and source URL. +``` +### Mime file type {#iso19115-3.2018-elem-gcx-MimeFileType-a1cd8621fdd682eaee51c6582ba01ed4} + +Name + +: + +> gcx:MimeFileType + +Description + +: + +### Description {#iso19115-3.2018-elem-gex-description-gex-EX_Extent-28ac6cc0d81cbece1978a8620e803fad} + +Name + +: + +> gex:description + +Context + +: + +> gex:EX_Extent + +Description + +: + +```{=html} +Spatial and temporal extent for the referring object +``` +### Bounding Polygon {#iso19115-3.2018-elem-gex-EX_BoundingPolygon-3014dd690ec865ffc1790c19f4d93efd} + +Name + +: + +> gex:EX_BoundingPolygon + +Description + +: + +```{=html} +Boundary enclosing the dataset, expressed as the closed set of + (x,y) + coordinates of the polygon (last point replicates first point) +``` +### Extent {#iso19115-3.2018-elem-gex-EX_Extent-f2e723e195c26ffd1f6db79524409843} + +Name + +: + +> gex:EX_Extent + +Description + +: + +```{=html} +Information about spatial, vertical, and temporal extent +``` +``` xml + + + + + 2.78 + + + 6.41 + + + 49.46 + + + 50.85 + + + + +``` + +### Geographic bounding box {#iso19115-3.2018-elem-gex-EX_GeographicBoundingBox-b271c47a118602d36a5450570a2f6b30} + +Name + +: + +> gex:EX_GeographicBoundingBox + +Description + +: + +```{=html} +Geographic position of the dataset +``` +``` xml + + + 2.78 + + + 6.41 + + + 49.46 + + + 50.85 + + +``` + +### Geographic description {#iso19115-3.2018-elem-gex-EX_GeographicDescription-1d22aba992d17d899cc84e108455ef36} + +Name + +: + +> gex:EX_GeographicDescription + +Description + +: + +```{=html} +Description of the geographic area using identifiers +``` +### Spatial temporal extent {#iso19115-3.2018-elem-gex-EX_SpatialTemporalExtent-95530705e6fbad209cc29205102c0888} + +Name + +: + +> gex:EX_SpatialTemporalExtent + +Description + +: + +```{=html} +Extent with respect to date/time and spatial boundaries +``` +### Temporal extent {#iso19115-3.2018-elem-gex-EX_TemporalExtent-d2db3333e80d49d8a458007ff3838015} + +Name + +: + +> gex:EX_TemporalExtent + +Description + +: + +```{=html} +Time period covered by the content of the dataset +``` +### Vertical extent {#iso19115-3.2018-elem-gex-EX_VerticalExtent-cbd5924052cb1b8e0bf8f5416ece44a2} + +Name + +: + +> gex:EX_VerticalExtent + +Description + +: + +```{=html} +Vertical domain of dataset +``` +### Extent {#iso19115-3.2018-elem-gex-extent-gex-EX_TemporalExtent-eb6cbcb83beb909bff900f1169937ce4} + +Name + +: + +> gex:extent + +Context + +: + +> gex:EX_TemporalExtent + +Description + +: + +```{=html} +Date and time for the content of the dataset +``` +### Extent {#iso19115-3.2018-elem-gex-extent-396cb78192c906d06c8014fd67c5a704} + +Name + +: + +> gex:extent + +Description + +: + +```{=html} +Geographic/Temporal Extent of Service +``` +### Extent type code {#iso19115-3.2018-elem-gex-extentTypeCode-36b0ae6983fbd52220a364b33650402b} + +Name + +: + +> gex:extentTypeCode + +Description + +: + +```{=html} +Indication of whether the bounding polygon encompasses an area + covered by the data or an area where data is not present. Possible values: '1' for + inclusion or '0' for exclusion +``` +### Geographic element {#iso19115-3.2018-elem-gex-geographicElement-a738fb045db07afd86c8631512cdfcd0} + +Name + +: + +> gex:geographicElement + +Description + +: + +```{=html} +Provides geographic component of the extent of the referring + object +``` +``` xml + + + + 2.78 + + + 6.41 + + + 49.46 + + + 50.85 + + + +``` + +### Geographic identifier {#iso19115-3.2018-elem-gex-geographicIdentifier-c6240129281eca8d905c5e34faad841d} + +Name + +: + +> gex:geographicIdentifier + +Description + +: + +```{=html} +Identifier used to represent a geographic area +``` + +Condition + +: + +> mandatory + +### Maximum value {#iso19115-3.2018-elem-gex-maximumValue-afcaee5c22764eaa540b44ed5a0d7662} + +Name + +: + +> gex:maximumValue + +Description + +: + +```{=html} +Highest vertical extent contained in the dataset +``` + +Condition + +: + +> mandatory + +### Minimum value {#iso19115-3.2018-elem-gex-minimumValue-83e87d76db1e018a13bb2a6649e2daf0} + +Name + +: + +> gex:minimumValue + +Description + +: + +```{=html} +Lowest vertical extent contained in the dataset +``` + +Condition + +: + +> mandatory + +### Polygon {#iso19115-3.2018-elem-gex-polygon-9e8a179ed9d619370d2aa0a543d1d3f9} + +Name + +: + +> gex:polygon + +Description + +: + +```{=html} +Sets of points defining the bounding polygon +``` + +Condition + +: + +> mandatory + +### Spatial extent {#iso19115-3.2018-elem-gex-spatialExtent-26a397b1ac7439d895ca7bfee22eb379} + +Name + +: + +> gex:spatialExtent + +Description + +: + +```{=html} +Spatial extent component of composite spatial and temporal + extent +``` + +Condition + +: + +> mandatory + +### Temporal element {#iso19115-3.2018-elem-gex-temporalElement-7a393c950f34c06f559b8d7e9179e623} + +Name + +: + +> gex:temporalElement + +Description + +: + +```{=html} +Provides temporal component of the extent of the referring + object +``` + +Condition + +: + +> conditional + +### Vertical CRS {#iso19115-3.2018-elem-gex-verticalCRS-b1977041fc95ed539e434436c2103f79} + +Name + +: + +> gex:verticalCRS + +Description + +: + +```{=html} +Provides information about the origin from which the maximum + and minimum elevation values are measured +``` +### Vertical CRS identifier {#iso19115-3.2018-elem-gex-verticalCRSId-ed97e16f10262e33a28e43ad10d84eb7} + +Name + +: + +> gex:verticalCRSId + +Description + +: + +```{=html} +Provides information about the origin from which the maximum + and minimum elevation values are measured +``` +### Vertical element {#iso19115-3.2018-elem-gex-verticalElement-36d7efb1213f5644ea5903878e0c6f91} + +Name + +: + +> gex:verticalElement + +Description + +: + +```{=html} +Provides vertical component of the extent of the referring + object +``` + +Condition + +: + +> conditional + +### Vertical extent {#iso19115-3.2018-elem-gex-verticalExtent-2536a2a55f2bab6e63bb5fca185b08a4} + +Name + +: + +> gex:verticalExtent + +Description + +: + +```{=html} +Vertical extent component +``` +### Affects value of {#iso19115-3.2018-elem-gfc-affectsValueOf-4e1acc1c69d17604f8ea2ec18fd8aac2} + +Name + +: + +> gfc:affectsValueOf + +Description + +: + +### Aliases {#iso19115-3.2018-elem-gfc-aliases-1f3ecb3fce2e8b73e3b5404492fd5e4e} + +Name + +: + +> gfc:aliases + +Description + +: + +### Cardinalities {#iso19115-3.2018-elem-gfc-cardinality-54aa6718c034715f68366669d9c257df} + +Name + +: + +> gfc:cardinality + +Description + +: + +```{=html} +Cardinalities +``` +Recommended values + +| code | label | +|------|-------| +| 0..1 | 0..1 | +| 1..n | 0..n | +| 1..1 | 1..1 | +| 1..n | 1..n | + +### Elements {#iso19115-3.2018-elem-gfc-carrierOfCharacteristics-682149d26e0b5d9590e5d0c646422c67} + +Name + +: + +> gfc:carrierOfCharacteristics + +Description + +: + +```{=html} +Association, attribute, operation, ... +``` +### Code {#iso19115-3.2018-elem-gfc-code-1b6f547562a07b95ab72fddc20aca409} + +Name + +: + +> gfc:code + +Description + +: + +### Constrained by {#iso19115-3.2018-elem-gfc-constrainedBy-a7116446b2c586c6d8a70e2cf940932b} + +Name + +: + +> gfc:constrainedBy + +Description + +: + +### Definition {#iso19115-3.2018-elem-gfc-definition-1f7a798ac46834d7201d94001a371a2b} + +Name + +: + +> gfc:definition + +Description + +: + +```{=html} +Property definition +``` +### Definition reference {#iso19115-3.2018-elem-gfc-definitionReference-330ee93d4b59935b32ddcf04e41bc6f1} + +Name + +: + +> gfc:definitionReference + +Description + +: + +### Definition source {#iso19115-3.2018-elem-gfc-definitionSource-c33b1dd8d05c8122a1e066717bbe01b5} + +Name + +: + +> gfc:definitionSource + +Description + +: + +### Description {#iso19115-3.2018-elem-gfc-description-76104ba864ae4643a9a538027b8a0704} + +Name + +: + +> gfc:description + +Description + +: + +### Designation {#iso19115-3.2018-elem-gfc-designation-10a4f05fcab681ae1738c886134eb754} + +Name + +: + +> gfc:designation + +Description + +: + +### Association role {#iso19115-3.2018-elem-gfc-FC_AssociationRole-54c0b4b36dcbbbf887cfb6edfdda0582} + +Name + +: + +> gfc:FC_AssociationRole + +Description + +: + +### Binding {#iso19115-3.2018-elem-gfc-FC_Binding-8a7dd41a834377a6bd72a8dbb1f5f350} + +Name + +: + +> gfc:FC_Binding + +Description + +: + +### Bound association role {#iso19115-3.2018-elem-gfc-FC_BoundAssociationRole-b4754a7a6f41689a055280d5d2d05cc5} + +Name + +: + +> gfc:FC_BoundAssociationRole + +Description + +: + +### Bound feature attribute {#iso19115-3.2018-elem-gfc-FC_BoundFeatureAttribute-898e24636ada22d18a56641a7dcabd7a} + +Name + +: + +> gfc:FC_BoundFeatureAttribute + +Description + +: + +### Constraint {#iso19115-3.2018-elem-gfc-FC_Constraint-1d48e37a33b2ef6abacdb535438af2c5} + +Name + +: + +> gfc:FC_Constraint + +Description + +: + +### Definition reference {#iso19115-3.2018-elem-gfc-FC_DefinitionReference-fbb7ecc7c5c5b257ab9491fd4ee28e39} + +Name + +: + +> gfc:FC_DefinitionReference + +Description + +: + +### Definition source {#iso19115-3.2018-elem-gfc-FC_DefinitionSource-14e171ff3f78bdf3d634d1ba925d3d36} + +Name + +: + +> gfc:FC_DefinitionSource + +Description + +: + +### Feature association {#iso19115-3.2018-elem-gfc-FC_FeatureAssociation-baa21e2722e293fddbc3037c64118776} + +Name + +: + +> gfc:FC_FeatureAssociation + +Description + +: + +### Attribute {#iso19115-3.2018-elem-gfc-FC_FeatureAttribute-f9e32c08dc1c646c7b52c4cceec296f5} + +Name + +: + +> gfc:FC_FeatureAttribute + +Description + +: + +### Feature Catalogue description {#iso19115-3.2018-elem-gfc-FC_FeatureCatalogue-a85c1d0f43b46f8451f4c40daf0bc705} + +Name + +: + +> gfc:FC_FeatureCatalogue + +Description + +: + +### Feature operation {#iso19115-3.2018-elem-gfc-FC_FeatureOperation-e6ef41cdc09cdb4283da0094259ca585} + +Name + +: + +> gfc:FC_FeatureOperation + +Description + +: + +### Attribute table description {#iso19115-3.2018-elem-gfc-FC_FeatureType-807cb5c8e0cef875eaeb1111deebb772} + +Name + +: + +> gfc:FC_FeatureType + +Description + +: + +```{=html} +Attribute table description +``` +### Heritance relation {#iso19115-3.2018-elem-gfc-FC_InheritanceRelation-7e2a5d36b54c948ee7498bd5d828044f} + +Name + +: + +> gfc:FC_InheritanceRelation + +Description + +: + +### Codelist {#iso19115-3.2018-elem-gfc-FC_ListedValue-167a17d6b51fe41652abde46b836c975} + +Name + +: + +> gfc:FC_ListedValue + +Description + +: + +### Multilingual definition reference {#iso19115-3.2018-elem-gfc-FC_LocalisedDefinitionReference-18e0e9f983507db8496dad6d98da596c} + +Name + +: + +> gfc:FC_LocalisedDefinitionReference + +Description + +: + +### Role type {#iso19115-3.2018-elem-gfc-FC_RoleType-d046a278232203a2c540d3302274ee88} + +Name + +: + +> gfc:FC_RoleType + +Description + +: + +### Standard codelists Role type (gfc:FC_RoleType) + +| code | label | description | +|-------------|-------------|------------------------------------------| +| ordinary | Ordinary | Indicates an ordinary association. | +| aggregation | Aggregation | Indicates a UML aggregation (part role). | +| composition | Composition | Indicates a UML composition (part role). | + +### Feature catalogue {#iso19115-3.2018-elem-gfc-featureCatalogue-2b9e65b7ec8057df6a5468181ecbf3a3} + +Name + +: + +> gfc:featureCatalogue + +Description + +: + +### Property description {#iso19115-3.2018-elem-gfc-featureType-a588b6f71d43e8be637aa765477a74d2} + +Name + +: + +> gfc:featureType + +Description + +: + +```{=html} +Property description +``` +### Field of application {#iso19115-3.2018-elem-gfc-fieldOfApplication-91b54a5961930c2b79e37217649551b7} + +Name + +: + +> gfc:fieldOfApplication + +Description + +: + +```{=html} +Field of application +``` +### Formal definition {#iso19115-3.2018-elem-gfc-formalDefinition-9bfd839d612e02d56624fd469562f8cb} + +Name + +: + +> gfc:formalDefinition + +Description + +: + +### Functional language {#iso19115-3.2018-elem-gfc-functionalLanguage-e4caa81d46aea92c7c5c84574fc281eb} + +Name + +: + +> gfc:functionalLanguage + +Description + +: + +### Global property {#iso19115-3.2018-elem-gfc-globalProperty-2576ecf5bb2d911abe673a5626b23316} + +Name + +: + +> gfc:globalProperty + +Description + +: + +### Identifier {#iso19115-3.2018-elem-gfc-identifier-17f8eb8d6427c71971e22ffdd78ccb9d} + +Name + +: + +> gfc:identifier + +Description + +: + +### Inheritance relation {#iso19115-3.2018-elem-gfc-inheritanceRelation-6d26d325e36d277b7f1d330ac39bfbb9} + +Name + +: + +> gfc:inheritanceRelation + +Description + +: + +### Inherits from {#iso19115-3.2018-elem-gfc-inheritsFrom-18bd2dbc3edecade14d5894004fd60f0} + +Name + +: + +> gfc:inheritsFrom + +Description + +: + +### Inherits to {#iso19115-3.2018-elem-gfc-inheritsTo-a417363112776608dbf84d83d3fb67ef} + +Name + +: + +> gfc:inheritsTo + +Description + +: + +### Abstract {#iso19115-3.2018-elem-gfc-isAbstract-62461dcfba818df55568584e01173415} + +Name + +: + +> gfc:isAbstract + +Description + +: + +```{=html} +Is this element an abstract element ? +``` +### Is navigable {#iso19115-3.2018-elem-gfc-isNavigable-a831d2a69ea24f3e933ff219c14aaedf} + +Name + +: + +> gfc:isNavigable + +Description + +: + +### Is ordered {#iso19115-3.2018-elem-gfc-isOrdered-c203a60136a7c3943c35a82e53c031eb} + +Name + +: + +> gfc:isOrdered + +Description + +: + +### Label {#iso19115-3.2018-elem-gfc-label-447cd3024c5921db22777d687b3d4d17} + +Name + +: + +> gfc:label + +Description + +: + +### Codelist {#iso19115-3.2018-elem-gfc-listedValue-4fac52554c89276cf08dc3f966a665cf} + +Name + +: + +> gfc:listedValue + +Description + +: + +```{=html} +List of values for this element. +``` +### Member name {#iso19115-3.2018-elem-gfc-memberName-8e8235a1cdd6868a4af054b03fe96350} + +Name + +: + +> gfc:memberName + +Description + +: + +### Name {#iso19115-3.2018-elem-gfc-name-54b5c264e311ea93b097ceebb8b6befa} + +Name + +: + +> gfc:name + +Description + +: + +```{=html} +Feature catalogue name +``` +### Observes value of {#iso19115-3.2018-elem-gfc-observesValueOf-a157ab4b39a2131d1b4ec430005d70fc} + +Name + +: + +> gfc:observesValueOf + +Description + +: + +### Catalogue producer {#iso19115-3.2018-elem-gfc-producer-ecb58d02ce17a2079eb9665aa1e9a441} + +Name + +: + +> gfc:producer + +Description + +: + +```{=html} +Catalogue responsible +``` +### Relation {#iso19115-3.2018-elem-gfc-relation-ea980be9c74952068db1b1d008ea08df} + +Name + +: + +> gfc:relation + +Description + +: + +### Role name {#iso19115-3.2018-elem-gfc-roleName-ff1b162ef6ce9c374ba1681aa15691f6} + +Name + +: + +> gfc:roleName + +Description + +: + +### Role type {#iso19115-3.2018-elem-gfc-roleType-77146288bea15becb410a880f16d04c3} + +Name + +: + +> gfc:roleType + +Description + +: + +### Scope {#iso19115-3.2018-elem-gfc-scope-92c0cc9eb4b0d3fe850346a9d741c495} + +Name + +: + +> gfc:scope + +Description + +: + +```{=html} +Scope definition +``` +### Signature {#iso19115-3.2018-elem-gfc-signature-6d40a2368f5c5b76921d7c51b1b7cb70} + +Name + +: + +> gfc:signature + +Description + +: + +### Source {#iso19115-3.2018-elem-gfc-source-49d8df7454dfdb2caae5ec3f70fed1ee} + +Name + +: + +> gfc:source + +Description + +: + +### Source identifier {#iso19115-3.2018-elem-gfc-sourceIdentifier-69e2dff11c6fe458930d27876a77c6ed} + +Name + +: + +> gfc:sourceIdentifier + +Description + +: + +### Subtype {#iso19115-3.2018-elem-gfc-subtype-947c0bc7e4d45ff82b8afa6c6fdf9132} + +Name + +: + +> gfc:subtype + +Description + +: + +### Supertype {#iso19115-3.2018-elem-gfc-supertype-47d00c276a785fb966b84370e7820d40} + +Name + +: + +> gfc:supertype + +Description + +: + +### Translation {#iso19115-3.2018-elem-gfc-translation-3668f7d14cd3e2fe636e67ced85f40b2} + +Name + +: + +> gfc:translation + +Description + +: + +### Triggered by value of {#iso19115-3.2018-elem-gfc-triggeredByValueOf-f3b11de6224235f1982818f79e33bbb4} + +Name + +: + +> gfc:triggeredByValueOf + +Description + +: + +### Type {#iso19115-3.2018-elem-gfc-type-b70cc9bafe6869c97eef915521895006} + +Name + +: + +> gfc:type + +Description + +: + +### Property name {#iso19115-3.2018-elem-gfc-typeName-b1641f3126adf6d82ee4f50601aeb631} + +Name + +: + +> gfc:typeName + +Description + +: + +### Unique instance {#iso19115-3.2018-elem-gfc-uniqueInstance-3faf7b4ff9a9af53dfd0b6d8b2e95b98} + +Name + +: + +> gfc:uniqueInstance + +Description + +: + +### Value measurement unit {#iso19115-3.2018-elem-gfc-valueMeasurementUnit-2380f4c62edf6c737e875281fb4be44e} + +Name + +: + +> gfc:valueMeasurementUnit + +Description + +: + +### Value type {#iso19115-3.2018-elem-gfc-valueType-9d3e77e2649b5cc3dab7232c7d02d891} + +Name + +: + +> gfc:valueType + +Description + +: + +### Date {#iso19115-3.2018-elem-gfc-versionDate-6bbeb2519dec6ad3b9bb84ea49e53458} + +Name + +: + +> gfc:versionDate + +Description + +: + +```{=html} +Catalogue date +``` +### Version {#iso19115-3.2018-elem-gfc-versionNumber-f09ca54eb78c0633a010eefa907291de} + +Name + +: + +> gfc:versionNumber + +Description + +: + +```{=html} +Catalogue version +``` +### Axis {#iso19115-3.2018-elem-gml-axis-ee4896c6d7c2f971473c33b8a5bb7364} + +Name + +: + +> gml:axis + +Description + +: + +### Axis abbreviation {#iso19115-3.2018-elem-gml-axisAbbrev-06f07ba235d694508081df9b1f650243} + +Name + +: + +> gml:axisAbbrev + +Description + +: + +### Axis direction {#iso19115-3.2018-elem-gml-axisDirection-9e24abc19c9f9a5de788584d548e728c} + +Name + +: + +> gml:axisDirection + +Description + +: + +### Base unit {#iso19115-3.2018-elem-gml-BaseUnit-6c9bea4b727b4bf13d9cd293271472dd} + +Name + +: + +> gml:BaseUnit + +Description + +: + +### Begin {#iso19115-3.2018-elem-gml-begin-9267d72967877bb18ec2ee804105e8f8} + +Name + +: + +> gml:begin + +Description + +: + +### Begin date {#iso19115-3.2018-elem-gml-beginPosition-f00b219677910b0a7663831bcae4a837} + +Name + +: + +> gml:beginPosition + +Description + +: + +```{=html} +Formatted as 2007-09-12T15:00:00 (YYYY-MM-DDTHH:mm:ss) +``` +### Catalog symbol {#iso19115-3.2018-elem-gml-catalogSymbol-20debf93163e22b85511488caf7de721} + +Name + +: + +> gml:catalogSymbol + +Description + +: + +### Coordinates {#iso19115-3.2018-elem-gml-coordinates-93bba1ad2afcfd7886ad123ead5134b9} + +Name + +: + +> gml:coordinates + +Description + +: + +```{=html} +Used to record an array of tuples or coordinates. +``` +### Coordinate system axis {#iso19115-3.2018-elem-gml-CoordinateSystemAxis-3ad068d898bdac7b95af25206b91e31e} + +Name + +: + +> gml:CoordinateSystemAxis + +Description + +: + +### Description {#iso19115-3.2018-elem-gml-description-2600f7b526a347a9b798b8cce5449036} + +Name + +: + +> gml:description + +Description + +: + +```{=html} +Text description of the element +``` +### Description reference {#iso19115-3.2018-elem-gml-descriptionReference-578284e505af5531320c6e14a708a760} + +Name + +: + +> gml:descriptionReference + +Description + +: + +### Domain of validity {#iso19115-3.2018-elem-gml-domainOfValidity-1a276165942a51b46610456025c67328} + +Name + +: + +> gml:domainOfValidity + +Description + +: + +### Duration {#iso19115-3.2018-elem-gml-duration-048a2eb087c6f51866b129ff32bfd626} + +Name + +: + +> gml:duration + +Description + +: + +```{=html} +Conforms to the ISO 8601 syntax for temporal length as + implemented by the XML Schema duration type. +``` +### End {#iso19115-3.2018-elem-gml-end-52f9f66d3851e2c0326222a2a447ef52} + +Name + +: + +> gml:end + +Description + +: + +### End date {#iso19115-3.2018-elem-gml-endPosition-9f8aaba04b72980299ec61c0b8d2d646} + +Name + +: + +> gml:endPosition + +Description + +: + +```{=html} +Formatted as 2007-09-12T15:00:00 (YYYY-MM-DDTHH:mm:ss) +``` +### Outer boundary {#iso19115-3.2018-elem-gml-exterior-5721530d7165b757db1c8601fe7a24e6} + +Name + +: + +> gml:exterior + +Description + +: + +```{=html} +The outer boundary of a solid. +``` +### Identifier {#iso19115-3.2018-elem-gml-id-42de2c4c8a671cebba710db1b18c0107} + +Name + +: + +> gml:id + +Description + +: + +```{=html} +Unique identifier +``` +### Ellipsoid {#iso19115-3.2018-elem-gml-id-mri-MD_CRS-c97605d29328beea996712b90459c4b0} + +Name + +: + +> gml:id + +Context + +: + +> mri:MD_CRS + +Description + +: + +```{=html} +Identity of the ellipsoid used +``` +```{=html} +identity of the ellipsoid used +``` +### Identifier {#iso19115-3.2018-elem-gml-identifier-ee45781f2ae3fc17f684139652109a84} + +Name + +: + +> gml:identifier + +Description + +: + +### Inner boundary {#iso19115-3.2018-elem-gml-interior-3164a957fa955b24e183bc071bb38263} + +Name + +: + +> gml:interior + +Description + +: + +```{=html} +The inner boundary of a solid +``` +### Linear ring {#iso19115-3.2018-elem-gml-LinearRing-ced37e1154857d6ce3d664076659332c} + +Name + +: + +> gml:LinearRing + +Description + +: + +```{=html} +A gml:LinearRing is defined by four or more coordinate tuples, + with linear + interpolation between them; the first and last coordinates shall be + coincident. +``` +### Line {#iso19115-3.2018-elem-gml-LineString-600185f9928ea52861bb6db1d8faaaf9} + +Name + +: + +> gml:LineString + +Description + +: + +```{=html} +A gml:LineString is a special curve that consists of a single + segment with + linear interpolation. It is defined by two or more coordinate tuples, with + linear + interpolation between them. +``` +### Maximum value {#iso19115-3.2018-elem-gml-maximumValue-7f3fca69f6f90158c23b4b8ab4cea8d2} + +Name + +: + +> gml:maximumValue + +Description + +: + +### Metadata property {#iso19115-3.2018-elem-gml-metaDataProperty-d35cc559d1ea5955993b4b1f09eb07d8} + +Name + +: + +> gml:metaDataProperty + +Description + +: + +### Minimum value {#iso19115-3.2018-elem-gml-minimumValue-2b8ffd52e40a4035d7ac9df8ac3c0ff4} + +Name + +: + +> gml:minimumValue + +Description + +: + +### Name {#iso19115-3.2018-elem-gml-name-db4e6ae78001c92be5ac3e74d7ec8d77} + +Name + +: + +> gml:name + +Description + +: + +### Point {#iso19115-3.2018-elem-gml-Point-3d13098ff5d2b030481b094ab9d32184} + +Name + +: + +> gml:Point + +Description + +: + +```{=html} +A gml:Point is defined by a single coordinate tuple. +``` +### Point type {#iso19115-3.2018-elem-gml-PointType-060f62970e5ada17f74811359552d183} + +Name + +: + +> gml:PointType + +Description + +: + +### Polygon {#iso19115-3.2018-elem-gml-Polygon-be0aca51ddc0b4e76ab1f54444748cc0} + +Name + +: + +> gml:Polygon + +Description + +: + +```{=html} +A gml:Polygon is a special surface that is defined by a single + surface patch. + The boundary of this patch is coplanar and the polygon uses planar + interpolation in its + interior. +``` +### Pos {#iso19115-3.2018-elem-gml-pos-4fff453ab55389744543f2df6c5a0e0a} + +Name + +: + +> gml:pos + +Description + +: + +### Projected CRS {#iso19115-3.2018-elem-gml-ProjectedCRS-5d3ed9ff2ace3bd4dc4b6d4a68c24491} + +Name + +: + +> gml:ProjectedCRS + +Description + +: + +### Quantity type {#iso19115-3.2018-elem-gml-quantityType-49cf23ca6944dea5ec8fe2740bd8441e} + +Name + +: + +> gml:quantityType + +Description + +: + +### Quantity type reference {#iso19115-3.2018-elem-gml-quantityTypeReference-7d7da8f239d830b79402c17fbbd8bd34} + +Name + +: + +> gml:quantityTypeReference + +Description + +: + +### Range meaning {#iso19115-3.2018-elem-gml-rangeMeaning-02f759e960e187822ef303d11aaaaee5} + +Name + +: + +> gml:rangeMeaning + +Description + +: + +### Realization epoch {#iso19115-3.2018-elem-gml-realizationEpoch-c07141b4c3761224c67b8ad71596f617} + +Name + +: + +> gml:realizationEpoch + +Description + +: + +### Related time {#iso19115-3.2018-elem-gml-relatedTime-a4c0ec44ce9c5e9404b7a318ea456e82} + +Name + +: + +> gml:relatedTime + +Description + +: + +```{=html} +Defines the relation of a given time to the object. +``` +### Remarks {#iso19115-3.2018-elem-gml-remarks-aa7c5b619988014f875df4eb43f8fc20} + +Name + +: + +> gml:remarks + +Description + +: + +### Remote schema {#iso19115-3.2018-elem-gml-remoteSchema-e5c36c448e77fee875f1b4cbd87d5e37} + +Name + +: + +> gml:remoteSchema + +Description + +: + +### Scope {#iso19115-3.2018-elem-gml-scope-0030a4d6fa08ad7c1eb516c1bdf3377b} + +Name + +: + +> gml:scope + +Description + +: + +### Time edge {#iso19115-3.2018-elem-gml-TimeEdge-8de5f2633834b77940206332af02a3f3} + +Name + +: + +> gml:TimeEdge + +Description + +: + +### Time edge type {#iso19115-3.2018-elem-gml-TimeEdgeType-6f3c48eb82089951457a8b6e66376d72} + +Name + +: + +> gml:TimeEdgeType + +Description + +: + +### Time instant {#iso19115-3.2018-elem-gml-TimeInstant-9ed28d4003f6f01dcbb5c2a35eb1b868} + +Name + +: + +> gml:TimeInstant + +Description + +: + +### Time instant type {#iso19115-3.2018-elem-gml-TimeInstantType-3f5810bbca58aa889cce1be23cb8b296} + +Name + +: + +> gml:TimeInstantType + +Description + +: + +### Time interval {#iso19115-3.2018-elem-gml-timeInterval-1e58ea97b2d3c8d2ee8af8fba944525e} + +Name + +: + +> gml:timeInterval + +Description + +: + +```{=html} +conforms to ISO 11404 which is based on floating point values + for temporal length. + ISO 11404 syntax specifies the use of a positiveInteger together with + appropriate values for radix and factor. The resolution of the time + interval is to one radix ^(-factor) of the specified time unit. + The value of the unit is either selected from the units for time intervals + from ISO 31-1:1992, or is another suitable unit. The encoding is defined + for GML in gml:TimeUnitType. The second component of this union type + provides a method for indicating time units other than the six standard + units given in the enumeration. +``` +### Time node {#iso19115-3.2018-elem-gml-TimeNode-91dbe7a18704bd38bb78222821f700d4} + +Name + +: + +> gml:TimeNode + +Description + +: + +### Time node type {#iso19115-3.2018-elem-gml-TimeNodeType-8ad896bbeae74ddc6aeccb985219b0c8} + +Name + +: + +> gml:TimeNodeType + +Description + +: + +### Time period {#iso19115-3.2018-elem-gml-TimePeriod-d6dba552b799834fed47973fd4b7cd4f} + +Name + +: + +> gml:TimePeriod + +Description + +: + +### Time period type {#iso19115-3.2018-elem-gml-TimePeriodType-c1129dd5a4a5df9ca9aa3fcd4c8fb9b8} + +Name + +: + +> gml:TimePeriodType + +Description + +: + +### Time position {#iso19115-3.2018-elem-gml-timePosition-6857f16de011b9783e13a5d6d6273486} + +Name + +: + +> gml:timePosition + +Description + +: + +### Time position {#iso19115-3.2018-elem-gml-TimePosition-505d1e7bef8e83fa4766daf84513beff} + +Name + +: + +> gml:TimePosition + +Description + +: + +### Unit definition {#iso19115-3.2018-elem-gml-UnitDefinition-c407f907d054e79a4c4664b4c832b325} + +Name + +: + +> gml:UnitDefinition + +Description + +: + +### Units system {#iso19115-3.2018-elem-gml-unitsSystem-cc71d59e78af646f2d29be97dc8c2212} + +Name + +: + +> gml:unitsSystem + +Description + +: + +### Vertical CRS {#iso19115-3.2018-elem-gml-VerticalCRS-0499658a8cbf1588dc852d46a97208e2} + +Name + +: + +> gml:VerticalCRS + +Description + +: + +### Vertical CS {#iso19115-3.2018-elem-gml-verticalCS-da6818bd5029d419378e56a1452af0c8} + +Name + +: + +> gml:verticalCS + +Description + +: + +### Vertical CS {#iso19115-3.2018-elem-gml-VerticalCS-5b2ac8a91a1b1c96e534eac65bbacf38} + +Name + +: + +> gml:VerticalCS + +Description + +: + +### Vertical datum {#iso19115-3.2018-elem-gml-verticalDatum-b6eee3a14a8b0f1075ae043a034e1f40} + +Name + +: + +> gml:verticalDatum + +Description + +: + +### Vertical datum {#iso19115-3.2018-elem-gml-VerticalDatum-cebbc2196212fde90a395c3c216b36c6} + +Name + +: + +> gml:VerticalDatum + +Description + +: + +### Hidden Elements {#iso19115-3.2018-elem-hidden-elements-c22e8449aff98b154969567fdc5c04f0} + +Name + +: + +> hidden-elements + +Description + +: + +```{=html} +Child elements and attributes have been hidden because you do + no have access to view those elements +``` +### Identifier {#iso19115-3.2018-elem-id-2345f9dc93f577a30435e73a55c2e3c0} + +Name + +: + +> id + +Description + +: + +```{=html} +Unique identifier +``` +### Indeterminate position {#iso19115-3.2018-elem-indeterminatePosition-69ea8df41d40c0c9e8bb430d26bb0d49} + +Name + +: + +> indeterminatePosition + +Description + +: + +### Standard codelists Indeterminate position (indeterminatePosition) + +| code | label | +|---------|---------| +| after | After | +| before | Before | +| now | Now | +| unknown | Unknown | + +### Is infinite {#iso19115-3.2018-elem-isInfinite-f8b250954f378d7fed3f293b112e13c4} + +Name + +: + +> isInfinite + +Description + +: + +### Character encoding {#iso19115-3.2018-elem-lan-characterEncoding-2b6f0a1f954994506c54ac850f001f89} + +Name + +: + +> lan:characterEncoding + +Description + +: + +```{=html} +CharacterEncoding +``` +### Country {#iso19115-3.2018-elem-lan-country-da9f45a56a7e3bea3fad555ba7b0e8a6} + +Name + +: + +> lan:country + +Description + +: + +```{=html} +Designation of the specific country of the locale language +``` + +Condition + +: + +> optional + +### Country {#iso19115-3.2018-elem-lan-country-lan-PT_Locale-9ff105f1f19be3b26f3ab04cef7f90f2} + +Name + +: + +> lan:country + +Context + +: + +> lan:PT_Locale + +Description + +: + +```{=html} +Designation of the specific country of the locale language +``` + +Condition + +: + +> optional + +### Date {#iso19115-3.2018-elem-lan-date-lan-PT_LocaleContainer-132a4183d35d301254fb13df2d7d0338} + +Name + +: + +> lan:date + +Context + +: + +> lan:PT_LocaleContainer + +Description + +: + +```{=html} +Date of creation or revision of the locale + container +``` + +Condition + +: + +> mandatory + +### Description {#iso19115-3.2018-elem-lan-description-lan-PT_LocaleContainer-1f47795aecc317bde4c9afb79d853eb6} + +Name + +: + +> lan:description + +Context + +: + +> lan:PT_LocaleContainer + +Description + +: + +```{=html} +Designation of the locale language +``` + +Condition + +: + +> mandatory + +### Language {#iso19115-3.2018-elem-lan-language-8a2e23cada8f90f768153cd009dd1421} + +Name + +: + +> lan:language + +Description + +: + +```{=html} +Designation of the locale language +``` +### ISO Language code {#iso19115-3.2018-elem-lan-LanguageCode-dbfc1c90b859ca52a01a1f8bafbaf567} + +Name + +: + +> lan:LanguageCode + +Description + +: + +```{=html} +Language code +``` +### Locale {#iso19115-3.2018-elem-lan-locale-lan-PT_LocaleContainer-e7de1934cd262890bd1e025b68448154} + +Name + +: + +> lan:locale + +Context + +: + +> lan:PT_LocaleContainer + +Description + +: + +```{=html} +Locale in which the localised strings of the + container are expressed +``` + +Condition + +: + +> mandatory + +### Locale {#iso19115-3.2018-elem-lan-locale-lan-LocalisedCharacterString-89a38d8f8dd189b863a75f8a0f74f7ba} + +Name + +: + +> lan:locale + +Context + +: + +> lan:LocalisedCharacterString + +Description + +: + +```{=html} +defines the locale in which the value (sequence of + characters) of the localised character string is expressed +``` + +Condition + +: + +> mandatory + +### Localised character string {#iso19115-3.2018-elem-lan-LocalisedCharacterString-901dcad3602cb2b433174b51134a10d7} + +Name + +: + +> lan:LocalisedCharacterString + +Description + +: + +```{=html} +Expression of a free text in a given locale +``` +### Localised string {#iso19115-3.2018-elem-lan-localisedString-lan-PT_LocaleContainer-bf9b4b45e7257abd994d0abe61aa8e43} + +Name + +: + +> lan:localisedString + +Context + +: + +> lan:PT_LocaleContainer + +Description + +: + +```{=html} +Provides the list of localised character string + expressing the linguistic translation of a set of textual information in a + given locale +``` + +Condition + +: + +> mandatory + +### Character set code {#iso19115-3.2018-elem-lan-MD_CharacterSetCode-b9a04835e79ab3aca7ae89608dd5b3b4} + +Name + +: + +> lan:MD_CharacterSetCode + +Description + +: + +```{=html} +Use IANA Character Set register: + http://www.iana.org/assignments/character-sets. These are the official + names for character sets that may be used in the Internet and may be + referred to in Internet documentation. These names are expressed in + ANSI_X3.4-1968 which is commonly called US-ASCII or simply ASCII. +``` +### Standard codelists Character set code (lan:MD_CharacterSetCode) + +| code | label | description | +|------------|--------------|-----------------------------------------------------------------------------------------------------------------------------------| +| ucs2 | UCS2 | 16-bit fixed size Universal Character Set, based on ISO/IEC 10646 | +| ucs4 | UCS4 | 32-bit fixed size Universal Character Set, based on ISO/IEC 10646 | +| utf7 | UTF7 | 7-bit variable size UCS Transfer Format, based on ISO/IEC 10646 | +| utf8 | UTF8 | 8-bit variable size UCS Transfer Format, based on ISO/IEC 10646 | +| utf16 | UTF16 | 16-bit variable size UCS Transfer Format, based on ISO/IEC 10646 | +| 8859part1 | 8859 Part 1 | ISO/IEC 8859-1, Information technology - 8-bit single byte coded graphic character sets - Part 1 : Latin alphabet No.1 | +| 8859part2 | 8859 Part 2 | ISO/IEC 8859-2, Information technology - 8-bit single byte coded graphic character sets - Part 2 : Latin alphabet No.2 | +| 8859part3 | 8859 Part 3 | ISO/IEC 8859-3, Information technology - 8-bit single byte coded graphic character sets - Part 3 : Latin alphabet No.3 | +| 8859part4 | 8859 Part 4 | ISO/IEC 8859-4, Information technology - 8-bit single byte coded graphic character sets - Part 4 : Latin alphabet No.4 | +| 8859part5 | 8859 Part 5 | ISO/IEC 8859-5, Information technology - 8-bit single byte coded graphic character sets - Part 5 : Latin/Cyrillic alphabet | +| 8859part6 | 8859 Part 6 | ISO/IEC 8859-6, Information technology - 8-bit single byte coded graphic character sets - Part 6 : Latin/Arabic alphabet | +| 8859part7 | 8859 Part 7 | ISO/IEC 8859-7, Information technology - 8-bit single byte coded graphic character sets - Part 7 : Latin/Greek alphabet | +| 8859part8 | 8859 Part 8 | ISO/IEC 8859-8, Information technology - 8-bit single byte coded graphic character sets - Part 8 : Latin/Hebrew alphabet | +| 8859part9 | 8859 Part 9 | ISO/IEC 8859-9, Information technology - 8-bit single byte coded graphic character sets - Part 9 : Latin alphabet No.5 | +| 8859part10 | 8859 Part 10 | ISO/IEC 8859-10, Information technology - 8-bit single byte coded graphic character sets - Part 10 : Latin alphabet No.6 | +| 8859part11 | 8859 Part 11 | ISO/IEC 8859-11, Information technology - 8-bit single byte coded graphic character sets - Part 11 : Latin/Thai alphabet | +| 8859part13 | 8859 Part 13 | ISO/IEC 8859-13, Information technology - 8-bit single byte coded graphic character sets - Part 13 : Latin alphabet No.7 | +| 8859part14 | 8859 Part 14 | ISO/IEC 8859-14, Information technology - 8-bit single byte coded graphic character sets - Part 14 : Latin alphabet No.8 (Celtic) | +| 8859part15 | 8859 Part 15 | ISO/IEC 8859-15, Information technology - 8-bit single byte coded graphic character sets - Part 15 : Latin alphabet No.9 | +| 8859part16 | 8859 Part 16 | ISO/IEC 8859-16, Information technology - 8-bit single byte coded graphic character sets - Part 16 : Latin alphabet No.10 | +| jis | JIS | Japanese code set used for electronic transmission | +| shiftJIS | Shift JIS | Japanese code set used on MS-DOS machines | +| eucJP | EUC JP | Japanese code set used on UNIX based machines | +| usAscii | US ASCII | United States ASCII code set (ISO 646 US) | +| ebcdic | EBCDIC | IBM mainframe code set | +| eucKR | EUC KR | Korean code set | +| big5 | Big 5 | Traditional Chinese code set used in Taiwan, Hong Kong of China and other areas | +| GB2312 | GB2312 | Simplified Chinese code set | + +### Locale {#iso19115-3.2018-elem-lan-PT_Locale-c8a7a406cec8fd65657ae57ca0af6974} + +Name + +: + +> lan:PT_Locale + +Description + +: + +```{=html} +Locale +``` +### Container of localised character strings {#iso19115-3.2018-elem-lan-PT_LocaleContainer-117d7bd7272ea9abb9365a5aeb6e9bbc} + +Name + +: + +> lan:PT_LocaleContainer + +Description + +: + +```{=html} +Container of localised character strings. NOTE It provides a + means to isolate the localised strings related to a given locale. +``` +### Party responsible {#iso19115-3.2018-elem-lan-responsibleParty-lan-PT_LocaleContainer-0877d1ab157089bc69c5a6c64e7d8256} + +Name + +: + +> lan:responsibleParty + +Context + +: + +> lan:PT_LocaleContainer + +Description + +: + +```{=html} +Responsible parties of the locale container +``` + +Condition + +: + +> mandatory + +### Acquisition plan {#iso19115-3.2018-elem-mac-acquisitionPlan-4c8c1de47fbe550f3ccd431aa4a29724} + +Name + +: + +> mac:acquisitionPlan + +Description + +: + +### Acquisition requirement {#iso19115-3.2018-elem-mac-acquisitionRequirement-e37fc1c473395ccb539432ef3f950800} + +Name + +: + +> mac:acquisitionRequirement + +Description + +: + +### Author {#iso19115-3.2018-elem-mac-author-32773deaf9e82a5689b4e658e4bd0470} + +Name + +: + +> mac:author + +Description + +: + +### Air temperature average {#iso19115-3.2018-elem-mac-averageAirTemperature-d2e612416638d6ffbb455c9c9ab8cbbc} + +Name + +: + +> mac:averageAirTemperature + +Description + +: + +```{=html} +Average air temperature along the flight pass during the photo flight. +``` +### Child operation {#iso19115-3.2018-elem-mac-childOperation-ebec2a49b25229de0983dcc2e1235f3d} + +Name + +: + +> mac:childOperation + +Description + +: + +### Citation {#iso19115-3.2018-elem-mac-citation-9bf03298a3d41fa91feea2e4ccd51310} + +Name + +: + +> mac:citation + +Description + +: + +### Content {#iso19115-3.2018-elem-mac-content-f214d41a1c2135aaca4c17c657d771a0} + +Name + +: + +> mac:content + +Description + +: + +### Context {#iso19115-3.2018-elem-mac-context-7feab93bc0b7c188e27294530aeb9bf9} + +Name + +: + +> mac:context + +Description + +: + +```{=html} +Meaning of the event +``` +### Description {#iso19115-3.2018-elem-mac-description-3b10ebf848544f1783a7a05fa206e323} + +Name + +: + +> mac:description + +Description + +: + +### Environmental conditions {#iso19115-3.2018-elem-mac-environmentalConditions-b48e662a6b728e9481ee8de2f5f562be} + +Name + +: + +> mac:environmentalConditions + +Description + +: + +### Expected objective {#iso19115-3.2018-elem-mac-expectedObjective-1515a363116cec7e226709b5e3a29df5} + +Name + +: + +> mac:expectedObjective + +Description + +: + +### Expiry date {#iso19115-3.2018-elem-mac-expiryDate-67127493055f27d7a84c5d6c33dad0f3} + +Name + +: + +> mac:expiryDate + +Description + +: + +### Extent {#iso19115-3.2018-elem-mac-extent-32bca388546aa036836a0999d4a0985f} + +Name + +: + +> mac:extent + +Description + +: + +### Function {#iso19115-3.2018-elem-mac-function-43a516d7a5a9d330dfbca44dee9e7805} + +Name + +: + +> mac:function + +Description + +: + +### History {#iso19115-3.2018-elem-mac-history-2863203dec4254489da43424346c292a} + +Name + +: + +> mac:history + +Description + +: + +### Hosted {#iso19115-3.2018-elem-mac-hosted-a93658bd768bab76294623bdc03a7f46} + +Name + +: + +> mac:hosted + +Description + +: + +### Identifier {#iso19115-3.2018-elem-mac-identifier-81da0e180981d90216072a56b23a8aac} + +Name + +: + +> mac:identifier + +Description + +: + +### Instrument {#iso19115-3.2018-elem-mac-instrument-e2f3702c569b7cc4ec779f6747ddf617} + +Name + +: + +> mac:instrument + +Description + +: + +### Instrumentation event {#iso19115-3.2018-elem-mac-instrumentationEvent-4578f8e6e9f5bd9e5f143d95dcd6e551} + +Name + +: + +> mac:instrumentationEvent + +Description + +: + +```{=html} +An event related to a platform/instrument/sensor +``` +### Latest acceptable date {#iso19115-3.2018-elem-mac-latestAcceptableDate-4898adac6a40ba5ac94a923f11ee7df5} + +Name + +: + +> mac:latestAcceptableDate + +Description + +: + +### Language (locale) {#iso19115-3.2018-elem-mac-locale-1f9333f7305eb86aca37ce9b26daa454} + +Name + +: + +> mac:locale + +Description + +: + +### Maximum altitude {#iso19115-3.2018-elem-mac-maxAltitude-e09b6ad8e0fc72eece1045c524609e34} + +Name + +: + +> mac:maxAltitude + +Description + +: + +```{=html} +Maximum altitude during the photo flight. +``` +### Maximum of relative humidity {#iso19115-3.2018-elem-mac-maxRelativeHumidity-b6e9aa984f7a6d9c47d5f1ed397ff185} + +Name + +: + +> mac:maxRelativeHumidity + +Description + +: + +```{=html} +Maximum relative humidity along the flight pass during the photo flight. +``` +### Metadata constraints {#iso19115-3.2018-elem-mac-metadataConstraints-2b5dd2d8c580cbf6942d2aca1a24b252} + +Name + +: + +> mac:metadataConstraints + +Description + +: + +### Meterological conditions {#iso19115-3.2018-elem-mac-meterologicalConditions-d1a103da456e4ddb5ac84a6c34645147} + +Name + +: + +> mac:meterologicalConditions + +Description + +: + +```{=html} +Meteorological conditions in the photo flight area, in particular clouds, snow and wind. +``` +### Acquisition information {#iso19115-3.2018-elem-mac-MI_AcquisitionInformation-6dc340212b25f0c014271a29f5dd08ad} + +Name + +: + +> mac:MI_AcquisitionInformation + +Description + +: + +### Environmental record {#iso19115-3.2018-elem-mac-MI_EnvironmentalRecord-7f442841494df00f426bcc2b0851325f} + +Name + +: + +> mac:MI_EnvironmentalRecord + +Description + +: + +```{=html} +Information about the environmental conditions during the acquisition +``` +### Event {#iso19115-3.2018-elem-mac-MI_Event-ebe92cdc7725c63f0eff85b23d2f32c1} + +Name + +: + +> mac:MI_Event + +Description + +: + +```{=html} +Identification of a significant collection point within an operation +``` +### Instrument {#iso19115-3.2018-elem-mac-MI_Instrument-6eacc5914df11972c7d81a384ec2a3ce} + +Name + +: + +> mac:MI_Instrument + +Description + +: + +```{=html} +Characteristics of the measuring instrument +``` +### Instrumentation event {#iso19115-3.2018-elem-mac-MI_InstrumentationEvent-edc1ed671f48408d806ee8b24cba3472} + +Name + +: + +> mac:MI_InstrumentationEvent + +Description + +: + +### Instrumentation event list {#iso19115-3.2018-elem-mac-MI_InstrumentationEventList-ea0c6f932372328f403129acf99234e2} + +Name + +: + +> mac:MI_InstrumentationEventList + +Description + +: + +```{=html} +List of events related to platform/ instrument/sensor +``` +### Objective {#iso19115-3.2018-elem-mac-MI_Objective-26ac604605f8af66cb893cef57b01e4f} + +Name + +: + +> mac:MI_Objective + +Description + +: + +```{=html} +Describes the characteristics, spatial and temporal extent of the intended object to be observed +``` +### Operation {#iso19115-3.2018-elem-mac-MI_Operation-98933bc74bcfaf78c957c2b0a95acb1b} + +Name + +: + +> mac:MI_Operation + +Description + +: + +```{=html} +Designations for the operation used to acquire the dataset +``` +### Plan {#iso19115-3.2018-elem-mac-MI_Plan-ef5177b27b97b5ec45c6d82aebce6725} + +Name + +: + +> mac:MI_Plan + +Description + +: + +```{=html} +Designations for the planning information related to meeting the data acquisition requirements +``` +### Platform {#iso19115-3.2018-elem-mac-MI_Platform-7e4bdeefe1bc78a5f0dca2cb685eda26} + +Name + +: + +> mac:MI_Platform + +Description + +: + +```{=html} +Designations for the platform used to acquire the dataset +``` +### Platform pass {#iso19115-3.2018-elem-mac-MI_PlatformPass-4d1995d96efd13f5b1244545b89da350} + +Name + +: + +> mac:MI_PlatformPass + +Description + +: + +```{=html} +Identification of collection coverage. +``` +### Requested date {#iso19115-3.2018-elem-mac-MI_RequestedDate-9ad587a48505fdbd81772da036ccf318} + +Name + +: + +> mac:MI_RequestedDate + +Description + +: + +### Requirement {#iso19115-3.2018-elem-mac-MI_Requirement-3b49f0fe913e6addc285b9b9e670e5f3} + +Name + +: + +> mac:MI_Requirement + +Description + +: + +```{=html} +Requirement to be satisfied by the planned data acquisition +``` +### Revision {#iso19115-3.2018-elem-mac-MI_Revision-aa242ad86f140c920e8f3f10ce3873aa} + +Name + +: + +> mac:MI_Revision + +Description + +: + +```{=html} +History of the revision of an event +``` +### Sensor {#iso19115-3.2018-elem-mac-MI_Sensor-1213e290019529db22e20c83052b64db} + +Name + +: + +> mac:MI_Sensor + +Description + +: + +```{=html} +Specific type of instrument +``` +### Mounted on {#iso19115-3.2018-elem-mac-mountedOn-18c62cdc237e376b21d0e74d2c3b2391} + +Name + +: + +> mac:mountedOn + +Description + +: + +### Objective {#iso19115-3.2018-elem-mac-objective-f6969734c75afde5ff62a2397caef765} + +Name + +: + +> mac:objective + +Description + +: + +### Objective occurrence {#iso19115-3.2018-elem-mac-objectiveOccurence-a37834ed908ca4ee9d177d34dffff8c8} + +Name + +: + +> mac:objectiveOccurence + +Description + +: + +### Operation {#iso19115-3.2018-elem-mac-operation-33100585e6aa7f87c9f4adc93a740f1e} + +Name + +: + +> mac:operation + +Description + +: + +### Other property {#iso19115-3.2018-elem-mac-otherProperty-9c092131f6ca89ea73c6807fd14c2b31} + +Name + +: + +> mac:otherProperty + +Description + +: + +### Other property type {#iso19115-3.2018-elem-mac-otherPropertyType-f33fc4918fb4268f0073efc189ff4919} + +Name + +: + +> mac:otherPropertyType + +Description + +: + +### Parent operation {#iso19115-3.2018-elem-mac-parentOperation-c561a03420b95045a67c77bb7dd2af62} + +Name + +: + +> mac:parentOperation + +Description + +: + +### Pass {#iso19115-3.2018-elem-mac-pass-1f75aaf313f44ae7d58fe1b4f8c448e7} + +Name + +: + +> mac:pass + +Description + +: + +### Plan {#iso19115-3.2018-elem-mac-plan-9166bddcc181db05999aeedc97b54cda} + +Name + +: + +> mac:plan + +Description + +: + +### Platform {#iso19115-3.2018-elem-mac-platform-865e14036ff1d013e11fd2afd0108d6a} + +Name + +: + +> mac:platform + +Description + +: + +### Priority {#iso19115-3.2018-elem-mac-priority-52f9057ea4ae961125cb328b36d968db} + +Name + +: + +> mac:priority + +Description + +: + +```{=html} +Priority applied to the target +``` +### Recipient {#iso19115-3.2018-elem-mac-recipient-6b1a56cb60ca97365b1ececa8473c112} + +Name + +: + +> mac:recipient + +Description + +: + +### Related event {#iso19115-3.2018-elem-mac-relatedEvent-c343b731477ef2687d01751e388e8209} + +Name + +: + +> mac:relatedEvent + +Description + +: + +### Related pass {#iso19115-3.2018-elem-mac-relatedPass-913feab1c6f4fac31d46edf22de3eef7} + +Name + +: + +> mac:relatedPass + +Description + +: + +### Related sensor {#iso19115-3.2018-elem-mac-relatedSensor-b22fab77d761aa9e6046faa7581e68bb} + +Name + +: + +> mac:relatedSensor + +Description + +: + +### Requested date {#iso19115-3.2018-elem-mac-requestedDate-d38587d25a59a1a223f730353f102c82} + +Name + +: + +> mac:requestedDate + +Description + +: + +```{=html} +Range of date validity +``` +### Requested date of collection {#iso19115-3.2018-elem-mac-requestedDateOfCollection-76623dcb1fe75b01f587722ad3168472} + +Name + +: + +> mac:requestedDateOfCollection + +Description + +: + +### Requestor {#iso19115-3.2018-elem-mac-requestor-d769b574f6987630916fdd7c0995838c} + +Name + +: + +> mac:requestor + +Description + +: + +### Revision history {#iso19115-3.2018-elem-mac-revisionHistory-2e83384a42f16c9b91738b749272cfd1} + +Name + +: + +> mac:revisionHistory + +Description + +: + +### Satisfied requirement {#iso19115-3.2018-elem-mac-satisfiedRequirement-f9bf2f69059992413e902d634b40662d} + +Name + +: + +> mac:satisfiedRequirement + +Description + +: + +### Satisfied plan {#iso19115-3.2018-elem-mac-satisifiedPlan-fcbae74a0125ba3d459ccb25f56ee57c} + +Name + +: + +> mac:satisifiedPlan + +Description + +: + +### Scope {#iso19115-3.2018-elem-mac-scope-b02c43f01a8862e3af90a0e7ea66dcab} + +Name + +: + +> mac:scope + +Description + +: + +```{=html} +The specific data to which the acquisition information applies +``` +### Sensing instrument {#iso19115-3.2018-elem-mac-sensingInstrument-86ced1fab519e44c3fcd7325f491ed88} + +Name + +: + +> mac:sensingInstrument + +Description + +: + +### Sensor {#iso19115-3.2018-elem-mac-sensor-147aa2dffb67eddc2fa663e4c90b9f11} + +Name + +: + +> mac:sensor + +Description + +: + +### Sequence {#iso19115-3.2018-elem-mac-sequence-cacb52f654bf50348861ff06567e0bfd} + +Name + +: + +> mac:sequence + +Description + +: + +```{=html} +Relative time ordering of the event +``` +### Significant event {#iso19115-3.2018-elem-mac-significantEvent-290296da36d2627f560e1627fbfda7dc} + +Name + +: + +> mac:significantEvent + +Description + +: + +### Solar azimuth {#iso19115-3.2018-elem-mac-solarAzimuth-4bcda66fb83091bd3da326421c027203} + +Name + +: + +> mac:solarAzimuth + +Description + +: + +```{=html} +Clockwise angle in degrees from north to the centre of the sun’s disc. + Note: This angle is calculated from the nadir point of the sensor, not at the centre point of the image +``` +### Solar elevation {#iso19115-3.2018-elem-mac-solarElevation-af60e0eceb072b322b47c7d7a52421ba} + +Name + +: + +> mac:solarElevation + +Description + +: + +```{=html} +Angle between the horizon and the centre of the Sun’s disk +``` +### Sponsor {#iso19115-3.2018-elem-mac-sponsor-6bc390be3142f1f2b7ef936b3f677d2d} + +Name + +: + +> mac:sponsor + +Description + +: + +### Status {#iso19115-3.2018-elem-mac-status-32c22a9cae01134bd1520ed5116bc066} + +Name + +: + +> mac:status + +Description + +: + +### Time {#iso19115-3.2018-elem-mac-time-d7340d3c53dd6d1afac0240f87395978} + +Name + +: + +> mac:time + +Description + +: + +### Trigger {#iso19115-3.2018-elem-mac-trigger-622d8aa6e371df3f548306153c8ed493} + +Name + +: + +> mac:trigger + +Description + +: + +### Type {#iso19115-3.2018-elem-mac-type-2ac10a6cc42a333f605f86a2d5dd90c6} + +Name + +: + +> mac:type + +Description + +: + +### Constraint language {#iso19115-3.2018-elem-mas-constraintLanguage-6714589d416dbd712eacbe4f41b27057} + +Name + +: + +> mas:constraintLanguage + +Description + +: + +```{=html} +Formal language used in Application Schema +``` + +Condition + +: + +> mandatory + +### Graphics file {#iso19115-3.2018-elem-mas-graphicsFile-c3962cc9dc571ea941923664d931e386} + +Name + +: + +> mas:graphicsFile + +Description + +: + +```{=html} +Full application schema given as a graphics file +``` +### Application Schema Information {#iso19115-3.2018-elem-mas-MD_ApplicationSchemaInformation-239070d65d62849e45f86b052fc4b371} + +Name + +: + +> mas:MD_ApplicationSchemaInformation + +Description + +: + +```{=html} +Information about the application schema used to build the + dataset +``` +### Name {#iso19115-3.2018-elem-mas-name-mas-MD_ApplicationSchemaInformation-286a47b5c1b4cb4c26a6c502e81eab33} + +Name + +: + +> mas:name + +Context + +: + +> mas:MD_ApplicationSchemaInformation + +Description + +: + +```{=html} +Name of the application schema used +``` + +Condition + +: + +> mandatory + +### Schema ASCII {#iso19115-3.2018-elem-mas-schemaAscii-6a6918c5cca40db84b935a30a162f1fa} + +Name + +: + +> mas:schemaAscii + +Description + +: + +```{=html} +Full application schema given as an ASCII file +``` +### Schema language {#iso19115-3.2018-elem-mas-schemaLanguage-b9f9ab982f3e38f3100229b3919c7fe6} + +Name + +: + +> mas:schemaLanguage + +Description + +: + +```{=html} +Identification of the schema language used +``` + +Condition + +: + +> mandatory + +### Software development file {#iso19115-3.2018-elem-mas-softwareDevelopmentFile-9ba5d58b0408fa64717c4af73681252e} + +Name + +: + +> mas:softwareDevelopmentFile + +Description + +: + +```{=html} +Full application schema given as a software development file +``` +### Software development file format {#iso19115-3.2018-elem-mas-softwareDevelopmentFileFormat-921ba1f4eea12ce9cfb2f5a735b547a8} + +Name + +: + +> mas:softwareDevelopmentFileFormat + +Description + +: + +```{=html} +Software dependent format used for the application schema + software dependent + file +``` +### Attribute instances {#iso19115-3.2018-elem-mcc-attributeInstances-c2c72bc14be935621cb9c3906b18aa81} + +Name + +: + +> mcc:attributeInstances + +Description + +: + +```{=html} +Attribute instances to which the information applies +``` +### Attributes {#iso19115-3.2018-elem-mcc-attributes-1b6aa85965648de38efe03ea2375ae57} + +Name + +: + +> mcc:attributes + +Description + +: + +```{=html} +Attributes to which the information applies +``` +### Authority {#iso19115-3.2018-elem-mcc-authority-7e7bc76f9f5323599c8181b4bc336579} + +Name + +: + +> mcc:authority + +Description + +: + +```{=html} +Person or party responsible for maintenance of the namespace +``` +### Code {#iso19115-3.2018-elem-mcc-code-2dc2af7f022e459d364d671a8820be3f} + +Name + +: + +> mcc:code + +Description + +: + +```{=html} +Alphanumeric value identifying an instance in the namespace +``` +```{=html} +Alphanumeric value identifying an instance in the + namespace. NOTE Avoid characters that are not legal in URLs. EXAMPLE + EPSG::4326 +``` + +Condition + +: + +> mandatory + +### Codespace {#iso19115-3.2018-elem-mcc-codeSpace-1d595727b533966b906de29071e58024} + +Name + +: + +> mcc:codeSpace + +Description + +: + +```{=html} +Name or identifier of the person or organization responsible + for + namespace +``` +```{=html} +Identifier or namespace in which the code is valid +``` +Recommended values + +| code | label | +|------|-------| +| EPSG | EPSG | + +### Dataset {#iso19115-3.2018-elem-mcc-dataset-761bde17236898889de12474f6474d19} + +Name + +: + +> mcc:dataset + +Description + +: + +```{=html} +Dataset to which the information applies +``` +### Description {#iso19115-3.2018-elem-mcc-description-0a923100b3a1e6ae550b85f0a01ae8d7} + +Name + +: + +> mcc:description + +Description + +: + +```{=html} +natural language description of the meaning of the + code value. EXAMPLE For codeSpace = EPSG, code= 4326, description = + WGS-84. +``` +### Extent {#iso19115-3.2018-elem-mcc-extent-mcc-MD_Scope-9e1c7fbcc9cf379619506e011c40f92f} + +Name + +: + +> mcc:extent + +Context + +: + +> mcc:MD_Scope + +Description + +: + +```{=html} +Information about the horizontal, vertical and temporal extent + of the data specified by the scope +``` +### Feature instances {#iso19115-3.2018-elem-mcc-featureInstances-17bff6871ce84163c48f358d231b0856} + +Name + +: + +> mcc:featureInstances + +Description + +: + +```{=html} +Feature instances to which the information applies +``` +### Features {#iso19115-3.2018-elem-mcc-features-cd1d3790286adbd6dc53f82c201f23c1} + +Name + +: + +> mcc:features + +Description + +: + +```{=html} +Features to which the information applies +``` +### File description {#iso19115-3.2018-elem-mcc-fileDescription-b4c8b6a2ce9129eb824c8e8ed9463435} + +Name + +: + +> mcc:fileDescription + +Description + +: + +```{=html} +Text description of the illustration +``` +### File name {#iso19115-3.2018-elem-mcc-fileName-286b40df4c38bcadc32de27920d0ce50} + +Name + +: + +> mcc:fileName + +Description + +: + +```{=html} +Name of the file that contains a graphic that provides an + illustration of the + dataset. It could be a public image document URL. +``` + +Condition + +: + +> mandatory + +### File type {#iso19115-3.2018-elem-mcc-fileType-f47a2fb159012c382d43688a0c9cca21} + +Name + +: + +> mcc:fileType + +Description + +: + +```{=html} +Format in which the illustration is encoded +``` +```{=html} +Format in which the illustration is encoded Examples: EPS, GIF, JPEG, + PBM, PS, + TIFF, PDF +``` +Recommended values + +| code | label | +|------|-------| +| EPS | EPS | +| GIF | GIF | +| JPEG | JPEG | +| PNG | PNG | +| PBM | PBM | +| PS | PS | +| TIFF | TIFF | +| PDF | PDF | + +### Image constraints {#iso19115-3.2018-elem-mcc-imageConstraints-2d7c5a019e2366e90316111db4ab52dc} + +Name + +: + +> mcc:imageConstraints + +Description + +: + +```{=html} +restriction on access and/or use of browse graphic +``` +### Hierarchy level {#iso19115-3.2018-elem-mcc-level-7824a07e81fe2c038930823b13560140} + +Name + +: + +> mcc:level + +Description + +: + +```{=html} +Hierarchical level of the data specified by the scope +``` + +Condition + +: + +> mandatory + +### Level description {#iso19115-3.2018-elem-mcc-levelDescription-a3e2988d868514fc0ee95ad80a3c9cc0} + +Name + +: + +> mcc:levelDescription + +Description + +: + +```{=html} +Detailed description about the level of the data specified by + the + scope +``` +### Linkage {#iso19115-3.2018-elem-mcc-linkage-mcc-MD_BrowseGraphic-e51921d09bbc809d8d87caeaba6938f9} + +Name + +: + +> mcc:linkage + +Context + +: + +> mcc:MD_BrowseGraphic + +Description + +: + +```{=html} +link to browse graphic +``` +### Browse Graphic {#iso19115-3.2018-elem-mcc-MD_BrowseGraphic-5fedaf89e0cf7c798b88be661c7870a3} + +Name + +: + +> mcc:MD_BrowseGraphic + +Description + +: + +```{=html} +Graphic that provides an illustration of the dataset (should + include a legend for the graphic) +``` +```{=html} +Graphic that provides an illustration of a resource + NOTE Should include a legend for the graphic, if applicable. EXAMPLE A + dataset, an organisation logo, security constraint or citation graphic. +``` +### Identifier {#iso19115-3.2018-elem-mcc-MD_Identifier-f39fe5214b22e40dfa250c2d1c95eae0} + +Name + +: + +> mcc:MD_Identifier + +Description + +: + +```{=html} +Value uniquely identifying an object within a namespace +``` +### Status {#iso19115-3.2018-elem-mcc-MD_ProgressCode-27457369101e4cc3540e5d9cc6d5aa8f} + +Name + +: + +> mcc:MD_ProgressCode + +Description + +: + +### Standard codelists Status (mcc:MD_ProgressCode) + +| code | label | description | +|-------------------|--------------------|--------------------------------------------------------------------------------------| +| completed | Completed | Production of the data has been completed | +| historicalArchive | Historical archive | Data has been stored in an offline storage facility | +| obsolete | Obsolete | Data is no longer relevant | +| onGoing | On going | Data is continually being updated | +| planned | Planned | Fixed date has been established upon or by which the data will be created or updated | +| required | Required | Data needs to be generated or updated | +| underDevelopment | Under development | Data is currently in the process of being created | +| final | Final | Progress concluded and no changes will be accepted | +| pending | Pending | Committed to, but not yet addressed | +| retired | Retired | Item is no longer recommended for use. It has not been superseded by another item | +| superseded | Superseded | Replaced by new item | +| tentative | Tentative | Provisional changes likely before resource becomes final or complete | +| valid | Valid | Acceptable under specific conditions | +| accepted | Accepted | Agreed to by sponsor | +| notAccepted | Not Accepted | Rejected by sponsor | +| withdrawn | Withdrawn | Withdrawn | +| proposed | Proposed | Suggested that development needs to be undertaken | +| deprecated | Deprecated | Resource superseded and will become obsolete, use only for historical purposes | + +Those values are defined in the standard but hidden when editing. + +| code | label | description | +|-------------|--------------|-------------| +| notobsolete | Not obsolete | | + +``` xml + +``` + +### Scope {#iso19115-3.2018-elem-mcc-MD_Scope-3a2e1c3040c7203740b3178b8d9370b3} + +Name + +: + +> mcc:MD_Scope + +Description + +: + +```{=html} +Class of information about the target resource and + physical extent for which information is reported +``` +### Scope code {#iso19115-3.2018-elem-mcc-MD_ScopeCode-2f9ce057ea5e2205c2adee8624bac996} + +Name + +: + +> mcc:MD_ScopeCode + +Description + +: + +```{=html} +Class of information to which the referencing entity applies +``` +### Standard codelists Scope code (mcc:MD_ScopeCode) + +| code | label | description | +|----------------------|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| attribute | Attribute | Information applies to the attribute class | +| attributeType | Attribute type | Information applies to the characteristic of a feature | +| collectionHardware | Collection hardware | Information applies to the collection hardware class | +| collectionSession | Collection session | Information applies to the collection session | +| dataset | Dataset | Information applies to the dataset | +| series | Series | Information applies to the series | +| nonGeographicDataset | Non geographic dataset | Information applies to non-geographic data | +| dimensionGroup | Dimension group | Information applies to a dimension group | +| feature | Feature | Information applies to a feature | +| featureType | Feature type | Information applies to a feature type | +| propertyType | Property type | Information applies to a property type | +| fieldSession | Field session | Information applies to a field session | +| software | Software | Information applies to a computer program or routine | +| service | Service | Information applies to a capability which a service provider entity makes available to a service user entity through a set of interfaces that define a behaviour, such as a use case | +| model | Model | Information applies to a copy or imitation of an existing or hypothetical object | +| tile | Tile | Information applies to a tile, a spatial subset of geographic data | +| metadata | Metadata | Information applies to metadata | +| initiative | Initiative | Information applies to an initiative | +| sample | Sample | Information applies to a sample | +| document | Document | Information applies to a document | +| repository | Repository | Information applies to a repository | +| aggregate | Aggregate | Information applies to an aggregate resource | +| product | Product | Metadata describing an ISO 19131 data product specification | +| collection | Collection | Information applies to an unstructured set | +| coverage | Coverage | Information applies to a coverage | +| application | Application | Information resource hosted on a specific set of hardware and accessible over a network | + +Those values are defined in the standard but hidden when editing. + +| code | label | description | +|------------------------------|--------------------------------|-------------| +| map staticMap interactiveMap | Map Static map Interactive map | | + +### Scope description {#iso19115-3.2018-elem-mcc-MD_ScopeDescription-7995800501eaf72f941d8e81542f8e98} + +Name + +: + +> mcc:MD_ScopeDescription + +Description + +: + +```{=html} +Description of the class of information covered by the + information +``` + +Condition + +: + +> Either attributes, features, featureInstances, attributeInstnaces, dataset or other must be provided + +### Scope description {#iso19115-3.2018-elem-mcc-MD_ScopeDescription_Type-e5f6e8be7b7d7e196f4bbdfbb3c51a9c} + +Name + +: + +> mcc:MD_ScopeDescription_Type + +Description + +: + +```{=html} +Description of the class of information covered by the + information +``` + +Condition + +: + +> Either attributes, features, featureInstances, attributeInstnaces, dataset or other must be provided + +### Spatial Representation Type {#iso19115-3.2018-elem-mcc-MD_SpatialRepresentationTypeCode-31b02e6b3fa659af6d7f3bae53ccb6a2} + +Name + +: + +> mcc:MD_SpatialRepresentationTypeCode + +Description + +: + +### Standard codelists Spatial Representation Type (mcc:MD_SpatialRepresentationTypeCode) + +| code | label | description | +|-------------|--------------|----------------------------------------------------------------------------------------------------| +| vector | Vector | Vector data is used to represent geographic data | +| grid | Grid | Grid data is used to represent geographic data | +| textTable | Text, table | Textual or tabular data is used to represent geographic data | +| tin | TIN | Triangulated irregular network | +| stereoModel | Stereo model | Three-dimensional view formed by the intersecting homologous rays of an overlapping pair of images | +| video | Video | Scene from a video recording | + +``` xml + +``` + +### Other {#iso19115-3.2018-elem-mcc-other-0d4f5c50da1b8c13a103dc016e5c4255} + +Name + +: + +> mcc:other + +Description + +: + +```{=html} +Class of information that does not fall into the other + categories to which the + information applies +``` +### URI {#iso19115-3.2018-elem-mcc-URI-c4a96ada6291119a71dedb4fa821fe83} + +Name + +: + +> mcc:URI + +Description + +: + +### Version {#iso19115-3.2018-elem-mcc-version-mcc-MD_Identifier-e51f35d9b386584a92603051050142b7} + +Name + +: + +> mcc:version + +Context + +: + +> mcc:MD_Identifier + +Description + +: + +```{=html} +version identifier for the namespace +``` +### Access constraints {#iso19115-3.2018-elem-mco-accessConstraints-4434175ab3a8a6536daed140ccea3129} + +Name + +: + +> mco:accessConstraints + +Description + +: + +```{=html} +Access constraints applied to assure the protection of privacy + or intellectual + property, and any special restrictions or limitations on obtaining the + resource +``` +``` xml + + + +``` + +### Addressee {#iso19115-3.2018-elem-mco-addressee-mco-MD_Releasability-6b109e079fa7b6014b3d6746221d694b} + +Name + +: + +> mco:addressee + +Context + +: + +> mco:MD_Releasability + +Description + +: + +```{=html} +party to which the release statement applies +``` +### Classification {#iso19115-3.2018-elem-mco-classification-e17c62f61fd7efcb2183fbbb83922018} + +Name + +: + +> mco:classification + +Description + +: + +```{=html} +Name of the handling restrictions on the resource or metadata +``` + +Condition + +: + +> mandatory + +### Classification system {#iso19115-3.2018-elem-mco-classificationSystem-16a2730ef6db9ca4295ef332b221b3c4} + +Name + +: + +> mco:classificationSystem + +Description + +: + +```{=html} +Name of the classification system +``` +### Constraint application scope {#iso19115-3.2018-elem-mco-constraintApplicationScope-f10f04ce2d0209c0bab3f67d865cb084} + +Name + +: + +> mco:constraintApplicationScope + +Description + +: + +```{=html} +Spatial and/or temporal extent and or level of the application + of the constraint restrictions +``` +### Constraints of dissemination {#iso19115-3.2018-elem-mco-disseminationConstraints-mco-MD_Releasability-5c7a4a52cd05e52596ded12c6b653cb4} + +Name + +: + +> mco:disseminationConstraints + +Context + +: + +> mco:MD_Releasability + +Description + +: + +```{=html} +Component in determining releasability +``` +### Graphic {#iso19115-3.2018-elem-mco-graphic-787e1689b35d8928184c1b5bbd16ed01} + +Name + +: + +> mco:graphic + +Description + +: + +```{=html} +Graphic /symbol indicating the constraint +``` +### Handling description {#iso19115-3.2018-elem-mco-handlingDescription-7fba7a0ac032339d0c1b1886a1389060} + +Name + +: + +> mco:handlingDescription + +Description + +: + +```{=html} +Additional information about the restrictions on handling the + resource +``` +### Constraints {#iso19115-3.2018-elem-mco-MD_Constraints-33996fc2b6dc952cdf62806ef26202c2} + +Name + +: + +> mco:MD_Constraints + +Description + +: + +```{=html} +Restrictions on the access and use of a resource or metadata +``` +### Legal constraints {#iso19115-3.2018-elem-mco-MD_LegalConstraints-238a415897a1738a0d8b0e2e3c9bfd96} + +Name + +: + +> mco:MD_LegalConstraints + +Description + +: + +```{=html} +Restrictions and legal prerequisites for accessing and using + the resource or + metadata +``` +### Releasability {#iso19115-3.2018-elem-mco-MD_Releasability-88ac438bcff297d513b5fd666d45c824} + +Name + +: + +> mco:MD_Releasability + +Description + +: + +```{=html} +information about resource release constraints +``` +### Access constraints {#iso19115-3.2018-elem-mco-MD_RestrictionCode-mco-accessConstraints-060503bb481a7679abdc9347b485cd8a} + +Name + +: + +> mco:MD_RestrictionCode + +Context + +: + +> mco:accessConstraints + +Description + +: + +### Standard codelists Access constraints (mco:MD_RestrictionCode) + +| code | label | description | +|----------------------------|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| copyright | Copyright | Exclusive right to the publication, production, or sale of the rights to a literary, dramatic, musical, or artistic work, or to the use of a commercial print or label, granted by law for a specified period of time to an author, composer, artist, distributor | +| patent | Patent | Government has granted exclusive right to make, sell, use or license an invention or discovery | +| patentPending | Pending patent | Produced or sold information awaiting a patent | +| trademark | Trademark | A name, symbol, or other device identifying a product, officially registered and legally restricted to the use of the owner or manufacturer | +| license | License | Formal permission to do something | +| intellectualPropertyRights | Intellectual property rights | Rights to financial benefit from and control of distribution of non-tangible property that is a result of creativity | +| restricted | Restricted | Withheld from general circulation or disclosure | +| otherRestrictions | Other restrictions | Limitation not listed | +| unrestricted | Unrestricted | No constraints exist | +| licenceUnrestricted | Licence Unrestricted | formal permission not required to use the resource | +| licenceEndUser | Licence End User | Formal permission required for a person or an entity to use the resource and that may differ from the person that orders or purchases it | +| licenceDistributor | Licence Distributor | Formal permission required for a person or an entity to commercialize or distribute the resource | +| private | Private | Protects rights of individual or organisations from observation, intrusion, or attention of others | +| statutory | Statutory | Prescribed by law | +| confidential | Confidential | Not available to the public. NOTE: Contains information that could be prejudicial to a commercial, industrial, or national interest | +| SBU | Sensitive But Unclassified | Although unclassified, requires strict controls over its distribution | +| in-confidence | In-Confidence | With trust | + +### Security constraints {#iso19115-3.2018-elem-mco-MD_SecurityConstraints-efee55f2eb2d70f01eed428298e807ca} + +Name + +: + +> mco:MD_SecurityConstraints + +Description + +: + +```{=html} +Handling restrictions imposed on the resource or metadata for + national security + or similar security concerns +``` +### Other constraints {#iso19115-3.2018-elem-mco-otherConstraints-ee6f8fc54e0aa9767312008217583cec} + +Name + +: + +> mco:otherConstraints + +Description + +: + +```{=html} +Other restrictions and legal prerequisites for accessing and using the + resource +``` + +Condition + +: + +> conditional + +### Référence {#iso19115-3.2018-elem-mco-reference-be92d9dc3eac6458ea063c8b4e4d16e0} + +Name + +: + +> mco:reference + +Description + +: + +```{=html} +citation for the limitation or constraint EXAMPLE + Copyright statement,licence agreement, etc. +``` +### Releasability {#iso19115-3.2018-elem-mco-releasability-45662b1e4d3b7b93ffac2cacd9e20d8f} + +Name + +: + +> mco:releasability + +Description + +: + +```{=html} +information concerning the parties to whom the + resource can or cannot be released +``` +### Party responsible {#iso19115-3.2018-elem-mco-responsibleParty-47b9fb4016b7f424d783277a602b5819} + +Name + +: + +> mco:responsibleParty + +Description + +: + +```{=html} +Party responsible for the resource constraints +``` + +Condition + +: + +> mandatory + +### Statement {#iso19115-3.2018-elem-mco-statement-mco-MD_Releasability-7986cf3965f16774710c30022ed20228} + +Name + +: + +> mco:statement + +Context + +: + +> mco:MD_Releasability + +Description + +: + +```{=html} +Release statement +``` +### Use constraints {#iso19115-3.2018-elem-mco-useConstraints-a78891e6df6724f942e929e70f301fa3} + +Name + +: + +> mco:useConstraints + +Description + +: + +```{=html} +Constraints applied to assure the protection of privacy or + intellectual + property, and any special restrictions or limitations or warnings on using + the + resource +``` +``` xml + + + +``` + +### Use limitation {#iso19115-3.2018-elem-mco-useLimitation-40f33cf5aed3dcaded9c6b9b6893a17a} + +Name + +: + +> mco:useLimitation + +Description + +: + +```{=html} +Limitation affecting the fitness for use of the resource. Example, _not to be + used for navigation_ +``` +``` xml + + Conditions d'accès et d'utilisation + +``` + +### User note {#iso19115-3.2018-elem-mco-userNote-e0170adc40a3e38bc167e63c55773149} + +Name + +: + +> mco:userNote + +Description + +: + +```{=html} +Explanation of the application of the legal constraints or + other restrictions + and legal prerequisites for obtaining and using the resource or metadata +``` +### Acquisition information {#iso19115-3.2018-elem-mdb-acquisitionInformation-ce87174a305975fd6ab50c76fa062e87} + +Name + +: + +> mdb:acquisitionInformation + +Description + +: + +### Alternative metadata reference {#iso19115-3.2018-elem-mdb-alternativeMetadataReference-d658e4e78b4bb85f325070dac38656f2} + +Name + +: + +> mdb:alternativeMetadataReference + +Description + +: + +```{=html} +Reference to alternative metadata, e.g Dublin Core, + FGDC, or metadata in a non-ISO standard for the same resource +``` +### Application schema info {#iso19115-3.2018-elem-mdb-applicationSchemaInfo-6e29d5e06caa68d593c2abc867db859e} + +Name + +: + +> mdb:applicationSchemaInfo + +Description + +: + +```{=html} +Provides information about the conceptual schema of a dataset +``` +### Contact {#iso19115-3.2018-elem-mdb-contact-bd86ee4331a33e4a09966e9d3837b346} + +Name + +: + +> mdb:contact + +Description + +: + +```{=html} +Party responsible for the metadata information +``` + +Condition + +: + +> mandatory + +``` xml + + + + + + + + + Organisation + + + + + + + mail@organisation.org + + + + + + + + + +``` + +### Content Information {#iso19115-3.2018-elem-mdb-contentInfo-477f3b1af76890ee3158c66524002fd8} + +Name + +: + +> mdb:contentInfo + +Description + +: + +```{=html} +Provides information about the feature catalogue and describes + the coverage and + image data characteristics +``` +### Data quality info {#iso19115-3.2018-elem-mdb-dataQualityInfo-05c1cd27fb52b7bc5c361a03fb962e72} + +Name + +: + +> mdb:dataQualityInfo + +Description + +: + +```{=html} +Provides overall assessment of quality of a resource(s) +``` +``` xml + + + + + + + + + + + + + + + + + COMMISSION REGULATION (EU) No 1089/2010 of 23 November 2010 implementing Directive 2007/2/EC of the European Parliament and of the Council as regards interoperability of spatial data sets and services + + + + + 2010-12-08 + + + + + + + + + + Voir la spécification référencée + + + + + + + + +``` + +### Date info {#iso19115-3.2018-elem-mdb-dateInfo-74b8e273fbd6b264ff0c70ca542b6fa3} + +Name + +: + +> mdb:dateInfo + +Description + +: + +```{=html} +Date(s) associated with the metadata. NOTE Creation” + date must be provided, others can also be provided +``` +### Default locale {#iso19115-3.2018-elem-mdb-defaultLocale-dd848d0de1837131c70510c4ab1253b4} + +Name + +: + +> mdb:defaultLocale + +Description + +: + +```{=html} +Language and character set used for documenting + metadata +``` +``` xml + + + + + + + + + + +``` + +### Distribution Information {#iso19115-3.2018-elem-mdb-distributionInfo-26e7e205c5605edb7225b0aa5c3950f1} + +Name + +: + +> mdb:distributionInfo + +Description + +: + +```{=html} +Provides information about the distributor of and options for + obtaining the + resource(s) +``` +``` xml + + + + + + + + ESRI Shapefile + + + + 1.0 + + + + + + + + + + + https://geoservices.wallonie.be/inspire/atom/PS_Service.xml + + + atom:feed + + + Service de téléchargement ATOM Feed - Inspire + + + Ce service de téléchargement ATOM Feed permet de télécharger la série de couches de + données conforme au thème INSPIRE "Sites protégés". Cliquez sur le lien correspondant aux couches de + données Natura 2000 pour télécharger les informations relatives à ce mécanisme de désignation. + + + + + + + + + + +``` + +### Identification info {#iso19115-3.2018-elem-mdb-identificationInfo-7b3f7b7fbb8a986c92658058fe54f876} + +Name + +: + +> mdb:identificationInfo + +Description + +: + +```{=html} +Basic information about the resource(s) to which the metadata + applies +``` + +Condition + +: + +> mandatory + +``` xml + + + + + + INSPIRE - TG2 - Template + + + + + 2019-10-01 + + + + + + + + + + 48c6f2bb-4828-46eb-a2cc-d5bcb94340dc + + + https://registry.organisation.fr/datasets + + + + + + + Description du jeu de données + + + + + + + + + + + + + Organisation + + + + + + + mail@organisation.org + + + + + + + + + + + + + + + + + + 25000 + + + + + + + biota + + + environment + + + + + + + 2.78 + + + 6.41 + + + 49.46 + + + 50.85 + + + + + + + + + + + + + + + + Protected site + + + + + + + + GEMET - INSPIRE themes, version 1.0 + + + + + 2008-06-01 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GEMET themes + + + + + 2009-09-22 + + + + + + + + + + + + + + + + + + + + + Natura 2000 sites (Birds Directive) + + + + + + + + INSPIRE priority data set + + + + + 2018-04-24 + + + + + + + + + + + + + + + + + + + + + + + + No + limitations to public access + + + + + + + Conditions d'accès et d'utilisation + + + + + + Description des autres contraintes (eg. CGI, Licence) + + + + + + + + + + + + + + + +``` + +### Metadata {#iso19115-3.2018-elem-mdb-MD_Metadata-2a52ffbcceba76f90e734fdd465035a1} + +Name + +: + +> mdb:MD_Metadata + +Description + +: + +```{=html} +Root entity which defines metadata about a resource or + resources +``` +``` xml + + + + + 6d50311c-3ffd-4c09-aa0b-fe9ab1bb93fa + + + urn:uuid + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Organisation + + + + + + + mail@organisation.org + + + + + + + + + + + + + 2019-10-07T13:35:35 + + + + + + + + + + 2019-09-20T15:52:19 + + + creation + + + + + + + ISO 19115 + + + 2003/Cor 1:2006 + + + + + + + http://localhost:8080/geonetwork/srv/eng//metadata/6d50311c-3ffd-4c09-aa0b-fe9ab1bb93fa + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/3035 + + + + + + + + + + + INSPIRE - TG2 - Template + + + + + 2019-10-01 + + + + + + + + + + 48c6f2bb-4828-46eb-a2cc-d5bcb94340dc + + + https://registry.organisation.fr/datasets + + + + + + + Description du jeu de données + + + + + + + + + + + + + Organisation + + + + + + + mail@organisation.org + + + + + + + + + + + + + + + + + + 25000 + + + + + + + biota + + + environment + + + + + + + 2.78 + + + 6.41 + + + 49.46 + + + 50.85 + + + + + + + + + + + + + + + + Protected site + + + + + + + + GEMET - INSPIRE themes, version 1.0 + + + + + 2008-06-01 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GEMET themes + + + + + 2009-09-22 + + + + + + + + + + + + + + + + + + + + + Natura 2000 sites (Birds Directive) + + + + + + + + INSPIRE priority data set + + + + + 2018-04-24 + + + + + + + + + + + + + + + + + + + + + + + + No + limitations to public access + + + + + + + Conditions d'accès et d'utilisation + + + + + + Description des autres contraintes (eg. CGI, Licence) + + + + + + + + + + + + + + + + + + + + + + + ESRI Shapefile + + + + 1.0 + + + + + + + + + + + https://geoservices.wallonie.be/inspire/atom/PS_Service.xml + + + atom:feed + + + Service de téléchargement ATOM Feed - Inspire + + + Ce service de téléchargement ATOM Feed permet de télécharger la série de couches de + données conforme au thème INSPIRE "Sites protégés". Cliquez sur le lien correspondant aux couches de + données Natura 2000 pour télécharger les informations relatives à ce mécanisme de désignation. + + + + + + + + + + + + + + + + + + + + + + + + + + + COMMISSION REGULATION (EU) No 1089/2010 of 23 November 2010 implementing Directive 2007/2/EC of the European Parliament and of the Council as regards interoperability of spatial data sets and services + + + + + 2010-12-08 + + + + + + + + + + Voir la spécification référencée + + + + + + + + + + + + Généalogie du jeu de données + + + + + + + + + + + +``` + +### Hierarchy level {#iso19115-3.2018-elem-mdb-MD_MetadataScope-51fe8da3ee06d996c5cb057ea86d4341} + +Name + +: + +> mdb:MD_MetadataScope + +Description + +: + +```{=html} +Scope to which the metadata applies (see annex H for more + information about + metadata hierarchy levels) +``` +``` xml + + + + + +``` + +### Resource scope {#iso19115-3.2018-elem-mdb-MD_MetadataScoperd-a377c6e12454a013ffc0c05045d2ff20} + +Name + +: + +> mdb:MD_MetadataScoperd + +Description + +: + +```{=html} +Information about the scope of the resource. +``` +### Metadata constraints {#iso19115-3.2018-elem-mdb-metadataConstraints-cd13aab243e8cf8b0009f3c2cc6288a6} + +Name + +: + +> mdb:metadataConstraints + +Description + +: + +```{=html} +Provides restrictions on the access and use of metadata +``` +### Metadata Extension Information {#iso19115-3.2018-elem-mdb-metadataExtensionInfo-04e7d4f2e4caa82c3ee3957e01387b10} + +Name + +: + +> mdb:metadataExtensionInfo + +Description + +: + +```{=html} +Information describing metadata extensions +``` +### Metadata identifier {#iso19115-3.2018-elem-mdb-metadataIdentifier-a4b2a53a6ba91300cd824aaa32dced12} + +Name + +: + +> mdb:metadataIdentifier + +Description + +: + +```{=html} +Unique identifier for this metadata file +``` +``` xml + + + + 6d50311c-3ffd-4c09-aa0b-fe9ab1bb93fa + + + urn:uuid + + + +``` + +### Metadata linkage {#iso19115-3.2018-elem-mdb-metadataLinkage-582ff009f1d12392ca0be7e310ace58b} + +Name + +: + +> mdb:metadataLinkage + +Description + +: + +```{=html} +Online location where the metadata is available +``` +``` xml + + + + http://localhost:8080/geonetwork/srv/eng//metadata/6d50311c-3ffd-4c09-aa0b-fe9ab1bb93fa + + + + + + +``` + +### Metadata maintenance {#iso19115-3.2018-elem-mdb-metadataMaintenance-f31a9a9880a6a939b8125c2505a04439} + +Name + +: + +> mdb:metadataMaintenance + +Description + +: + +```{=html} +Provides information about the frequency of metadata updates, + and the scope of + those updates +``` +### Metadata profile {#iso19115-3.2018-elem-mdb-metadataProfile-92627fbcc80493116a75b90146bcf055} + +Name + +: + +> mdb:metadataProfile + +Description + +: + +### Type of resource {#iso19115-3.2018-elem-mdb-metadataScope-85ce83354003a98ad94f8f749af858f7} + +Name + +: + +> mdb:metadataScope + +Description + +: + +```{=html} +Type of resource for which metadata is provided +``` +``` xml + + + + + + + +``` + +### Metadata standard {#iso19115-3.2018-elem-mdb-metadataStandard-317906f5ed0893d367c6a78ab2d68812} + +Name + +: + +> mdb:metadataStandard + +Description + +: + +```{=html} +Citation for the standard to which the metadata + conforms. NOTE Metadata standard citations should include an identifier. +``` +``` xml + + + + ISO 19115 + + + 2003/Cor 1:2006 + + + +``` + +### Name {#iso19115-3.2018-elem-mdb-name-66f58b43b2635c779b3af02b3a9748e5} + +Name + +: + +> mdb:name + +Description + +: + +```{=html} +Description of the scope. +``` + +Condition + +: + +> optional + +### Other locale {#iso19115-3.2018-elem-mdb-otherLocale-f4f26265136a3b0812c2ce9d90c0c17f} + +Name + +: + +> mdb:otherLocale + +Description + +: + +```{=html} +Provides information about alternatively used + localised character strings +``` +### Parent metadata {#iso19115-3.2018-elem-mdb-parentMetadata-d82be96796ed0eaaa63a697cfec1287a} + +Name + +: + +> mdb:parentMetadata + +Description + +: + +```{=html} +Identification of the parent metadata record +``` +### Portrayal catalogue info {#iso19115-3.2018-elem-mdb-portrayalCatalogueInfo-f6c73fdd3d7c18f1e90d4a8853986230} + +Name + +: + +> mdb:portrayalCatalogueInfo + +Description + +: + +```{=html} +Provides information about the catalogue of rules defined for + the portrayal of + a resource(s) +``` +### Reference System Information {#iso19115-3.2018-elem-mdb-referenceSystemInfo-6e40de8cf9dbe75d0601aedf78756344} + +Name + +: + +> mdb:referenceSystemInfo + +Description + +: + +```{=html} +Description of the spatial and temporal reference systems used + in the + dataset +``` +``` xml + + + + + + http://www.opengis.net/def/crs/EPSG/0/3035 + + + + + +``` + +### Resource lineage {#iso19115-3.2018-elem-mdb-resourceLineage-b38f8fe2e0d2dee771b11f2dfcb77937} + +Name + +: + +> mdb:resourceLineage + +Description + +: + +```{=html} +Information about the provenance, source(s), and/or + the production process(es) applied to the resource +``` +``` xml + + + + Généalogie du jeu de données + + + + + + + + + + +``` + +### Resource scope {#iso19115-3.2018-elem-mdb-resourceScope-4c3f10bfb66b2ced01f50b3f1f71d4dc} + +Name + +: + +> mdb:resourceScope + +Description + +: + +```{=html} +Code for the scope. +``` + +Condition + +: + +> mandatory + +``` xml + + + +``` + +### Spatial representation info {#iso19115-3.2018-elem-mdb-spatialRepresentationInfo-fa98674c3f9afa7324634c07cda62b3b} + +Name + +: + +> mdb:spatialRepresentationInfo + +Description + +: + +```{=html} +Digital representation of spatial information in the dataset +``` +### Abstract {#iso19115-3.2018-elem-mdq-abstract-fca818cec40fe2f6148cf5424c4a90c6} + +Name + +: + +> mdq:abstract + +Description + +: + +### Date time {#iso19115-3.2018-elem-mdq-dateTime-e5096902a7314e76382ac0f08d866277} + +Name + +: + +> mdq:dateTime + +Description + +: + +### Deductive source {#iso19115-3.2018-elem-mdq-deductiveSource-5831020c420d98cef9262f352dbfcd50} + +Name + +: + +> mdq:deductiveSource + +Description + +: + +```{=html} +Information on which data are used as + sources in deductive evaluation method +``` +### Derived element {#iso19115-3.2018-elem-mdq-derivedElement-f4c2ee6a8acedce6cfb84f98ec17f06e} + +Name + +: + +> mdq:derivedElement + +Description + +: + +### Absolute external positional accuracy {#iso19115-3.2018-elem-mdq-DQ_AbsoluteExternalPositionalAccuracy-8bcd872552f871a19dce36d6bc7e8700} + +Name + +: + +> mdq:DQ_AbsoluteExternalPositionalAccuracy + +Description + +: + +```{=html} +Closeness of reported coordinate values to values accepted as + or being + true +``` +### Accuracy of time measurement {#iso19115-3.2018-elem-mdq-DQ_AccuracyOfATimeMeasurement-8d3752286366dd7dff87ad296ad7c413} + +Name + +: + +> mdq:DQ_AccuracyOfATimeMeasurement + +Description + +: + +```{=html} +Correctness of the temporal references of an item (reporting of + error in time + measurement) +``` +### Aggregation derivation {#iso19115-3.2018-elem-mdq-DQ_AggregationDerivation-ec544a1c126234ec85e6650ee644a702} + +Name + +: + +> mdq:DQ_AggregationDerivation + +Description + +: + +### Completeness commission {#iso19115-3.2018-elem-mdq-DQ_CompletenessCommission-0dd42a0ab10753452a3199c28fc5599c} + +Name + +: + +> mdq:DQ_CompletenessCommission + +Description + +: + +```{=html} +Excess data present in the dataset, as described by the scope +``` +### Completeness omission {#iso19115-3.2018-elem-mdq-DQ_CompletenessOmission-9f6df725bfe69d1f3664bdde5916ea83} + +Name + +: + +> mdq:DQ_CompletenessOmission + +Description + +: + +```{=html} +Data absent from the dataset, as described by the scope +``` +### Conceptual consistency {#iso19115-3.2018-elem-mdq-DQ_ConceptualConsistency-eb99a1efe55b65f59083813a036e4ecf} + +Name + +: + +> mdq:DQ_ConceptualConsistency + +Description + +: + +```{=html} +Adherence to rules of the conceptual schema +``` +### Metaquality / Confidence {#iso19115-3.2018-elem-mdq-DQ_Confidence-00d5fd5323b9dff53e6e4d6613946c29} + +Name + +: + +> mdq:DQ_Confidence + +Description + +: + +```{=html} +Trustworthiness of a data quality result. +``` +### Conformance result {#iso19115-3.2018-elem-mdq-DQ_ConformanceResult-070bb6852050a16c31715ecb6aa09f84} + +Name + +: + +> mdq:DQ_ConformanceResult + +Description + +: + +```{=html} +Information about the outcome of evaluating + the obtained value (or set of values) against a + specified acceptable conformance quality + level +``` +``` xml + + + + + COMMISSION REGULATION (EU) No 1089/2010 of 23 November 2010 implementing Directive 2007/2/EC of the European Parliament and of the Council as regards interoperability of spatial data sets and services + + + + + 2010-12-08 + + + + + + + + + + Voir la spécification référencée + + + +``` + +### Data inspection {#iso19115-3.2018-elem-mdq-DQ_DataInspection-f2e9ffb22ebdaddde326ffa11dac81ef} + +Name + +: + +> mdq:DQ_DataInspection + +Description + +: + +### Data quality {#iso19115-3.2018-elem-mdq-DQ_DataQuality-b969b0659a4303d9c1d35e4757ac62b3} + +Name + +: + +> mdq:DQ_DataQuality + +Description + +: + +```{=html} +Quality information for the data specified by a data quality + scope +``` +``` xml + + + + + + + + + + + + + + + + COMMISSION REGULATION (EU) No 1089/2010 of 23 November 2010 implementing Directive 2007/2/EC of the European Parliament and of the Council as regards interoperability of spatial data sets and services + + + + + 2010-12-08 + + + + + + + + + + Voir la spécification référencée + + + + + + + +``` + +### Descriptive result {#iso19115-3.2018-elem-mdq-DQ_DescriptiveResult-0191aad06a8d885f697f59296d80b017} + +Name + +: + +> mdq:DQ_DescriptiveResult + +Description + +: + +```{=html} +Data quality descriptive result +``` +### Domain consistency {#iso19115-3.2018-elem-mdq-DQ_DomainConsistency-c1ef69d6172610098aba6ed8e5b38a88} + +Name + +: + +> mdq:DQ_DomainConsistency + +Description + +: + +```{=html} +Adherence of values to the value domains +``` +``` xml + + + + + + + COMMISSION REGULATION (EU) No 1089/2010 of 23 November 2010 implementing Directive 2007/2/EC of the European Parliament and of the Council as regards interoperability of spatial data sets and services + + + + + 2010-12-08 + + + + + + + + + + Voir la spécification référencée + + + + + +``` + +### Evaluation method {#iso19115-3.2018-elem-mdq-DQ_EvaluationMethod-53191928f6b3e447e7e5200f6f9faf7b} + +Name + +: + +> mdq:DQ_EvaluationMethod + +Description + +: + +### Format consistency {#iso19115-3.2018-elem-mdq-DQ_FormatConsistency-8b5f34fa2b437f53829de2f084c0d3e8} + +Name + +: + +> mdq:DQ_FormatConsistency + +Description + +: + +```{=html} +Degree to which data is stored in accordance with the physical + structure of the + dataset, as described by the scope +``` +### Full inspection {#iso19115-3.2018-elem-mdq-DQ_FullInspection-de21b3a5be286e24d1fdec85ffb1b319} + +Name + +: + +> mdq:DQ_FullInspection + +Description + +: + +### Gridded data positional accuracy {#iso19115-3.2018-elem-mdq-DQ_GriddedDataPositionalAccuracy-6d18be23581ad90ef59f83b6bf5a4cf5} + +Name + +: + +> mdq:DQ_GriddedDataPositionalAccuracy + +Description + +: + +```{=html} +Closeness of gridded data position values to values accepted as + or being + true +``` +### Metaquality / Homogeneity {#iso19115-3.2018-elem-mdq-DQ_Homogeneity-180b944deee523419756c21b2194bb4d} + +Name + +: + +> mdq:DQ_Homogeneity + +Description + +: + +```{=html} +Expected or tested uniformity of the results obtained for a + data quality evaluation. +``` +### Indirect evaluation {#iso19115-3.2018-elem-mdq-DQ_IndirectEvaluation-e1a02547fc4a7b62e5408257b4a9a33d} + +Name + +: + +> mdq:DQ_IndirectEvaluation + +Description + +: + +### Measure reference {#iso19115-3.2018-elem-mdq-DQ_MeasureReference-b2f194226c538d01f7e1336f76fc0b24} + +Name + +: + +> mdq:DQ_MeasureReference + +Description + +: + +### Non quantitative attribute accuracy {#iso19115-3.2018-elem-mdq-DQ_NonQuantitativeAttributeAccuracy-a6eb7ec155510e83e271bb09695d3e4f} + +Name + +: + +> mdq:DQ_NonQuantitativeAttributeAccuracy + +Description + +: + +```{=html} +Correctness of non-quantitative attributes +``` +### Non quantitative attribute correctness {#iso19115-3.2018-elem-mdq-DQ_NonQuantitativeAttributeCorrectness-e1763f4a806bc415f75649d03e74e3bc} + +Name + +: + +> mdq:DQ_NonQuantitativeAttributeCorrectness + +Description + +: + +### Quantitative attribute accuracy {#iso19115-3.2018-elem-mdq-DQ_QuantitativeAttributeAccuracy-239216433c75c857c4138b0b58c352ab} + +Name + +: + +> mdq:DQ_QuantitativeAttributeAccuracy + +Description + +: + +```{=html} +Accuracy of quantitative attributes +``` +### Quantitative result {#iso19115-3.2018-elem-mdq-DQ_QuantitativeResult-e4aa4d6aa466082557a0e3ffcc2c9a57} + +Name + +: + +> mdq:DQ_QuantitativeResult + +Description + +: + +```{=html} +The values or information about the value(s) (or set of values) + obtained from + applying a data quality measure +``` +### Relative internal positional accuracy {#iso19115-3.2018-elem-mdq-DQ_RelativeInternalPositionalAccuracy-e4a653fe1414c1411957fc3952382400} + +Name + +: + +> mdq:DQ_RelativeInternalPositionalAccuracy + +Description + +: + +```{=html} +Closeness of the relative positions of features in the scope to + their + respective relative positions accepted as or being true +``` +### Metaquality / Representativity {#iso19115-3.2018-elem-mdq-DQ_Representativity-10240a1df9c53d02ddecae55fbafdbed} + +Name + +: + +> mdq:DQ_Representativity + +Description + +: + +```{=html} +Degree to which the sample used has produced a result which is + representative of the + data within the data quality scope +``` +### Sample based inspection {#iso19115-3.2018-elem-mdq-DQ_SampleBasedInspection-c33d13f764fa09dfb5a475d6e7195bdf} + +Name + +: + +> mdq:DQ_SampleBasedInspection + +Description + +: + +### Standalone quality report information {#iso19115-3.2018-elem-mdq-DQ_StandaloneQualityReportInformation-b121dac5f5592e3a9bb1a99b3a062d8d} + +Name + +: + +> mdq:DQ_StandaloneQualityReportInformation + +Description + +: + +### Temporal consistency {#iso19115-3.2018-elem-mdq-DQ_TemporalConsistency-0d4957b3d0b9c0dd8cca38734eb41fdf} + +Name + +: + +> mdq:DQ_TemporalConsistency + +Description + +: + +```{=html} +Correctness of ordered events or sequences, if reported +``` +### Temporal validity {#iso19115-3.2018-elem-mdq-DQ_TemporalValidity-99a32e6469000326870fa96cdada6a0d} + +Name + +: + +> mdq:DQ_TemporalValidity + +Description + +: + +```{=html} +Validity of data specified by the scope with respect to time +``` +### Thematic classification correctness {#iso19115-3.2018-elem-mdq-DQ_ThematicClassificationCorrectness-918c902da0e32c6f77178fcd97d60564} + +Name + +: + +> mdq:DQ_ThematicClassificationCorrectness + +Description + +: + +```{=html} +Comparison of the classes assigned to features or their + attributes to a + universe of discourse +``` +### Topological consistency {#iso19115-3.2018-elem-mdq-DQ_TopologicalConsistency-fa568b7fed7969dafdabfbcbdcfe0232} + +Name + +: + +> mdq:DQ_TopologicalConsistency + +Description + +: + +```{=html} +Correctness of the explicitly encoded topological + characteristics of the + dataset as described by the scope +``` +### Usability element {#iso19115-3.2018-elem-mdq-DQ_UsabilityElement-595e258aadfc90d614ad2b18937f035f} + +Name + +: + +> mdq:DQ_UsabilityElement + +Description + +: + +### Element report {#iso19115-3.2018-elem-mdq-elementReport-3cab2d79e4788afae28f563eb6f2be3a} + +Name + +: + +> mdq:elementReport + +Description + +: + +### Evaluation method {#iso19115-3.2018-elem-mdq-evaluationMethod-7861233af309ce32dbd0720123144e93} + +Name + +: + +> mdq:evaluationMethod + +Description + +: + +### Evaluation method description {#iso19115-3.2018-elem-mdq-evaluationMethodDescription-8d6e04e7fe7c9f9d3bce27ee81f522cf} + +Name + +: + +> mdq:evaluationMethodDescription + +Description + +: + +### Evaluation method type {#iso19115-3.2018-elem-mdq-evaluationMethodType-aedca134bbad262feabe9ace78c65b95} + +Name + +: + +> mdq:evaluationMethodType + +Description + +: + +### Evaluation procedure {#iso19115-3.2018-elem-mdq-evaluationProcedure-7e7c31ff40c9145381585833a674ca58} + +Name + +: + +> mdq:evaluationProcedure + +Description + +: + +### Explanation {#iso19115-3.2018-elem-mdq-explanation-cb1e2747d00884eed567257f6159357a} + +Name + +: + +> mdq:explanation + +Description + +: + +``` xml + + Voir la spécification référencée + +``` + +### File description {#iso19115-3.2018-elem-mdq-fileDescription-5d8d5370baa1113d804263b54d2a7068} + +Name + +: + +> mdq:fileDescription + +Description + +: + +### File format {#iso19115-3.2018-elem-mdq-fileFormat-9db9383f8fdb906cbec0c9aecc6283a3} + +Name + +: + +> mdq:fileFormat + +Description + +: + +### Result file name {#iso19115-3.2018-elem-mdq-fileName-a1158f7c0bf6be8f9584593a47af5977} + +Name + +: + +> mdq:fileName + +Description + +: + +### File type {#iso19115-3.2018-elem-mdq-fileType-c856d12e8ac8fd38d94e53cd6685a205} + +Name + +: + +> mdq:fileType + +Description + +: + +### Measure {#iso19115-3.2018-elem-mdq-measure-6de6f9f0d8d88ce71be56b93112a0ab7} + +Name + +: + +> mdq:measure + +Description + +: + +### Measure description {#iso19115-3.2018-elem-mdq-measureDescription-c54ad7c4f745a142d2f4a5a0569d174f} + +Name + +: + +> mdq:measureDescription + +Description + +: + +### Measure identification {#iso19115-3.2018-elem-mdq-measureIdentification-8a53966de7a9af0351fc36cc6563d9b8} + +Name + +: + +> mdq:measureIdentification + +Description + +: + +### Name of measure {#iso19115-3.2018-elem-mdq-nameOfMeasure-6d30a22ce349987e83351f36f006edeb} + +Name + +: + +> mdq:nameOfMeasure + +Description + +: + +### Pass {#iso19115-3.2018-elem-mdq-pass-81090ac8a72d22f1cb603c4d5d8c6a69} + +Name + +: + +> mdq:pass + +Description + +: + +``` xml + +``` + +### Coverage result {#iso19115-3.2018-elem-mdq-QE_CoverageResult-f8dae57f155420ec0fcaf24a2c89f826} + +Name + +: + +> mdq:QE_CoverageResult + +Description + +: + +```{=html} +Result of a data quality measure organising the measured values + as a coverage +``` +### Quality result file {#iso19115-3.2018-elem-mdq-QualityResultFile-f109f1bd9f2a7613c2240692764c6a67} + +Name + +: + +> mdq:QualityResultFile + +Description + +: + +### Reference doc {#iso19115-3.2018-elem-mdq-referenceDoc-0c442bf28823c9941c64476828a3aa8d} + +Name + +: + +> mdq:referenceDoc + +Description + +: + +### Related quality element {#iso19115-3.2018-elem-mdq-relatedElement-6cb5c2f116627d3ffebd1a44e60c6db6} + +Name + +: + +> mdq:relatedElement + +Description + +: + +### Report {#iso19115-3.2018-elem-mdq-report-3f560e7342c96a85b285df503914cd24} + +Name + +: + +> mdq:report + +Description + +: + +```{=html} +Quantitative quality information for the data specified by the + scope +``` + +Condition + +: + +> conditional + +``` xml + + + + + + + + COMMISSION REGULATION (EU) No 1089/2010 of 23 November 2010 implementing Directive 2007/2/EC of the European Parliament and of the Council as regards interoperability of spatial data sets and services + + + + + 2010-12-08 + + + + + + + + + + Voir la spécification référencée + + + + + + +``` + +### Report reference {#iso19115-3.2018-elem-mdq-reportReference-3fdd5c73d4c70e02ac95dcd1344fdc0c} + +Name + +: + +> mdq:reportReference + +Description + +: + +### Result {#iso19115-3.2018-elem-mdq-result-4b9abc04ab0aa92a7dfd24268ea92451} + +Name + +: + +> mdq:result + +Description + +: + +``` xml + + + + + + COMMISSION REGULATION (EU) No 1089/2010 of 23 November 2010 implementing Directive 2007/2/EC of the European Parliament and of the Council as regards interoperability of spatial data sets and services + + + + + 2010-12-08 + + + + + + + + + + Voir la spécification référencée + + + + +``` + +### Result content description {#iso19115-3.2018-elem-mdq-resultContentDescription-439741e7294de36459a0575d34b1e0d0} + +Name + +: + +> mdq:resultContentDescription + +Description + +: + +### Result file {#iso19115-3.2018-elem-mdq-resultFile-dd9d02421d1a1daac0ab8764cb9460ab} + +Name + +: + +> mdq:resultFile + +Description + +: + +### Result format {#iso19115-3.2018-elem-mdq-resultFormat-ddf9dccddc161522b101561d867e7416} + +Name + +: + +> mdq:resultFormat + +Description + +: + +### Result scope {#iso19115-3.2018-elem-mdq-resultScope-2d26c490e11930de1c49ad7e9dc5bab4} + +Name + +: + +> mdq:resultScope + +Description + +: + +### Result spatial representation {#iso19115-3.2018-elem-mdq-resultSpatialRepresentation-8bb7067999f2aa15977e1691d088afcc} + +Name + +: + +> mdq:resultSpatialRepresentation + +Description + +: + +### Scope {#iso19115-3.2018-elem-mdq-scope-a680ca4acf1fa0c4c2678a51709f9320} + +Name + +: + +> mdq:scope + +Description + +: + +```{=html} +The specific data to which the data quality information + applies +``` +``` xml + + + + + + + +``` + +### Spatial representation type {#iso19115-3.2018-elem-mdq-spatialRepresentationType-dc1790616f61278197b4dbd1cf1869bc} + +Name + +: + +> mdq:spatialRepresentationType + +Description + +: + +### Specification {#iso19115-3.2018-elem-mdq-specification-17ccfa051d8e7f1a633444b084c1ae5f} + +Name + +: + +> mdq:specification + +Description + +: + +``` xml + + + + COMMISSION REGULATION (EU) No 1089/2010 of 23 November 2010 implementing Directive 2007/2/EC of the European Parliament and of the Council as regards interoperability of spatial data sets and services + + + + + 2010-12-08 + + + + + + + + +``` + +### Standalone quality report {#iso19115-3.2018-elem-mdq-standaloneQualityReport-fd51848c91b175b598e66e34c0a7150c} + +Name + +: + +> mdq:standaloneQualityReport + +Description + +: + +### Standalone quality report details {#iso19115-3.2018-elem-mdq-standaloneQualityReportDetails-6a45bb0b8ba6ca15eda12e640cfa2a59} + +Name + +: + +> mdq:standaloneQualityReportDetails + +Description + +: + +### Statement {#iso19115-3.2018-elem-mdq-statement-66bfc04c451426e281bd6db312d7ff6a} + +Name + +: + +> mdq:statement + +Description + +: + +### Value {#iso19115-3.2018-elem-mdq-value-/mdb-MD_Metadata/mdb-dataQualityInfo/mdq-DQ_DataQuality/mdq-report/mdq-DQ_DomainConsistency/mdq-result/mdq-DQ_QuantitativeResult/mdq-value-dc03de6f70ba85162fea01c985e91d4e} + +Name + +: + +> mdq:value + +Context + +: + +> /mdb:MD_Metadata/mdb:dataQualityInfo/mdq:DQ_DataQuality/mdq:report/mdq:DQ_DomainConsistency/mdq:result/mdq:DQ_QuantitativeResult/mdq:value + +Description + +: + +```{=html} +Quantitative value or values, content determined by the evaluation procedure + used +``` + +Condition + +: + +> mandatory + +### Value {#iso19115-3.2018-elem-mdq-value-306d79adb03863fa4fe88c5160249035} + +Name + +: + +> mdq:value + +Description + +: + +### Value type {#iso19115-3.2018-elem-mdq-valueRecordType-39d1e11f86d5166ef7e04d464662590c} + +Name + +: + +> mdq:valueRecordType + +Description + +: + +```{=html} +Quantitative conformance quality level value or range of + values +``` +Recommended values + +| code | label | +|---------------------------------|---------------------------------| +| Boolean | Boolean | +| Real | Real | +| Integer | Integer | +| Ratio | Ratio | +| Percentage | Percentage | +| Measure(s) (value(s) + unit(s)) | Measure(s) (value(s) + unit(s)) | + +### Value unit {#iso19115-3.2018-elem-mdq-valueUnit-edcdbdc8d0e58c8764d5e6cd8088857e} + +Name + +: + +> mdq:valueUnit + +Description + +: + +```{=html} +Value unit for reporting a data quality result +``` + +Condition + +: + +> mandatory + +### Contact {#iso19115-3.2018-elem-mmi-contact-mmi-MD_MaintenanceInformation-67461bcb2fdc653d5dfe4b63a3cbdd5e} + +Name + +: + +> mmi:contact + +Context + +: + +> mmi:MD_MaintenanceInformation + +Description + +: + +```{=html} +Identification of, and means of communication with, person(s) + and + organization(s) with responsibility for maintaining the metadata +``` +### Maintenance and update frequency {#iso19115-3.2018-elem-mmi-maintenanceAndUpdateFrequency-a9f8c3b3ffff1868396b8be05b51b2ed} + +Name + +: + +> mmi:maintenanceAndUpdateFrequency + +Description + +: + +```{=html} +Frequency with which changes and additions are made to the + resource after the + initial resource is completed +``` + +Condition + +: + +> mandatory + +``` xml + + + +``` + +### Maintenance date {#iso19115-3.2018-elem-mmi-maintenanceDate-mmi-MD_MaintenanceInformation-f2d466937a8038b63f448b433b6b639a} + +Name + +: + +> mmi:maintenanceDate + +Context + +: + +> mmi:MD_MaintenanceInformation + +Description + +: + +```{=html} +Date information associated with maintenance of + resource +``` +### Maintenance note {#iso19115-3.2018-elem-mmi-maintenanceNote-c1095367f28dea87bbedf6ac07490607} + +Name + +: + +> mmi:maintenanceNote + +Description + +: + +```{=html} +Information regarding specific requirements for maintaining the + resource +``` +### Maintenance scopes {#iso19115-3.2018-elem-mmi-maintenanceScope-mmi-MD_MaintenanceInformation-41e944366902a5e666515d56d075014f} + +Name + +: + +> mmi:maintenanceScope + +Context + +: + +> mmi:MD_MaintenanceInformation + +Description + +: + +```{=html} +Type of resource and/or extent to which the + maintenance information applies +``` +### Maintenance Frequency {#iso19115-3.2018-elem-mmi-MD_MaintenanceFrequencyCode-2d1d3634943b4db7ca283424e745bc0e} + +Name + +: + +> mmi:MD_MaintenanceFrequencyCode + +Description + +: + +### Standard codelists Maintenance Frequency (mmi:MD_MaintenanceFrequencyCode) + +| code | label | description | +|-------------|--------------|----------------------------------------------------------| +| continual | Continual | Data is repeatedly and frequently updated | +| daily | Daily | Data is updated each day | +| weekly | Weekly | Data is updated on a weekly basis | +| fortnightly | Fortnightly | Data is updated every two weeks | +| monthly | Monthly | Data is updated each month | +| quarterly | Quarterly | Data is updated every three months | +| biannually | Biannually | Data is updated twice each year | +| annually | Annually | Data is updated every year | +| asNeeded | As needed | Data is updated as deemed necessary | +| irregular | Irregular | Data is updated in intervals that are uneven in duration | +| notPlanned | Not planned | There are no plans to update the data | +| unknown | Unknown | Frequency of maintenance for the data is not known | +| periodic | Periodic | Resource is updated at regular intervals | +| semimonthly | Semi-monthly | Resource updated twice monthly | +| biennially | Biennially | Resource is updated every 2 years | + +``` xml + +``` + +### Maintenance information {#iso19115-3.2018-elem-mmi-MD_MaintenanceInformation-98062b270bf3eb9ad460147bad01d2f7} + +Name + +: + +> mmi:MD_MaintenanceInformation + +Description + +: + +```{=html} +Information about the scope and frequency of updating +``` +``` xml + + + + + +``` + +### User defined maintenance frequency {#iso19115-3.2018-elem-mmi-userDefinedMaintenanceFrequency-cde10206b5d1414f49a995a98246b323} + +Name + +: + +> mmi:userDefinedMaintenanceFrequency + +Description + +: + +```{=html} +Maintenance period other than those defined +``` +### Portrayal catalogue reference {#iso19115-3.2018-elem-mpc-MD_PortrayalCatalogueReference-b60bb4ca1d31a379f47c40d06b9454d5} + +Name + +: + +> mpc:MD_PortrayalCatalogueReference + +Description + +: + +```{=html} +Information identifying the portrayal catalogue used +``` +### Portrayal catalogue citation {#iso19115-3.2018-elem-mpc-portrayalCatalogueCitation-d3ffb8ae720f87fb4ff0772f33219cfc} + +Name + +: + +> mpc:portrayalCatalogueCitation + +Description + +: + +```{=html} +Bibliographic reference to the portrayal catalogue cited +``` + +Condition + +: + +> mandatory + +### Attribute {#iso19115-3.2018-elem-mrc-attribute-dea7af5d2034cfa9e7a5a77fc87bf546} + +Name + +: + +> mrc:attribute + +Description + +: + +```{=html} +Information on an attribute of the resource +``` + +Condition + +: + +> optional + +### Attribute description {#iso19115-3.2018-elem-mrc-attributeDescription-37aaaca60c0cd43bf62d310ba147ef43} + +Name + +: + +> mrc:attributeDescription + +Description + +: + +```{=html} +Description of the attribute described by the measurement + value +``` + +Condition + +: + +> mandatory + +### Attribute group {#iso19115-3.2018-elem-mrc-attributeGroup-488906be5d4ea5fbfe94380ba5371d51} + +Name + +: + +> mrc:attributeGroup + +Description + +: + +```{=html} +Information on groups(s) of related attributes of + the resource with the same type +``` +### Bits per value {#iso19115-3.2018-elem-mrc-bitsPerValue-ea78a51caceb3feb5a8d573e937f1e26} + +Name + +: + +> mrc:bitsPerValue + +Description + +: + +```{=html} +Maximum number of significant bits in the uncompressed + representation for the + value in each band of each pixel +``` +### Bound max {#iso19115-3.2018-elem-mrc-boundMax-1016b54ba16d0ffde91fc11a1666047d} + +Name + +: + +> mrc:boundMax + +Description + +: + +```{=html} +Longest wavelength that the sensor is capable of + collecting within a designated band +``` + +Condition + +: + +> optional + +### Bound min {#iso19115-3.2018-elem-mrc-boundMin-2b69a646b72ab2f1d87f527fed1bcdde} + +Name + +: + +> mrc:boundMin + +Description + +: + +```{=html} +Shortest wavelength that the sensor is capable of + collecting within a designated band +``` + +Condition + +: + +> optional + +### Bound unit {#iso19115-3.2018-elem-mrc-boundUnits-4ad2b13f1b186a494053714d4cbc9886} + +Name + +: + +> mrc:boundUnits + +Description + +: + +```{=html} +Units in which sensor wavelengths are expressed +``` + +Condition + +: + +> optional + +### Camera calibration information availability {#iso19115-3.2018-elem-mrc-cameraCalibrationInformationAvailability-bbc9b002677f5c123fd1f9c935bd1d2c} + +Name + +: + +> mrc:cameraCalibrationInformationAvailability + +Description + +: + +```{=html} +Indication of whether or not constants are available which + allow for camera + calibration corrections +``` +### Cloud cover percentage {#iso19115-3.2018-elem-mrc-cloudCoverPercentage-703ebfc5d930f35ccecba7d9ba6d983a} + +Name + +: + +> mrc:cloudCoverPercentage + +Description + +: + +```{=html} +Area of the dataset obscured by clouds, expressed as a + percentage of the + spatial extent +``` +### Compliance code {#iso19115-3.2018-elem-mrc-complianceCode-085f3d1351953db360d964bb7bab6366} + +Name + +: + +> mrc:complianceCode + +Description + +: + +```{=html} +Indication of whether or not the cited feature catalogue + complies with ISO + 19110 +``` +### Content type {#iso19115-3.2018-elem-mrc-contentType-b3b7e695f74a74466893e19a20849596} + +Name + +: + +> mrc:contentType + +Description + +: + +```{=html} +Type of information represented by the cell value +``` + +Condition + +: + +> mandatory + +### Definition {#iso19115-3.2018-elem-mrc-definition-29b676d7a94fb93a2fa58282483a4692} + +Name + +: + +> mrc:definition + +Description + +: + +```{=html} +Designation associated with a set of range elements. eg. "Indicates the sample storage method used." +``` +### Description {#iso19115-3.2018-elem-mrc-description-74b8844c2a5832541e186bdf3a41a726} + +Name + +: + +> mrc:description + +Description + +: + +```{=html} +Description of the attribute +``` + +Condition + +: + +> optional + +### Feature catalogue {#iso19115-3.2018-elem-mrc-featureCatalogue-f1f508ee82724f13567d3975f1c70c3e} + +Name + +: + +> mrc:featureCatalogue + +Description + +: + +```{=html} +The catalogue of feature types, attribution, + operations, and relationships used by the resource +``` + +Condition + +: + +> mandatory + +### Feature catalogue citation {#iso19115-3.2018-elem-mrc-featureCatalogueCitation-beae05b407350c4ce10932b35a6947cc} + +Name + +: + +> mrc:featureCatalogueCitation + +Description + +: + +```{=html} +Complete bibliographic reference to one or more external feature catalogues +``` + +Condition + +: + +> mandatory + +### Feature instance count {#iso19115-3.2018-elem-mrc-featureInstanceCount-7b2fb0b426132c4080181e86e40321b5} + +Name + +: + +> mrc:featureInstanceCount + +Description + +: + +```{=html} +Number of occurrence of feature instances for this + feature type +``` + +Condition + +: + +> optional + +### Feature type name {#iso19115-3.2018-elem-mrc-featureTypeName-acf13aeabc8218359b85e1c5c16d32b9} + +Name + +: + +> mrc:featureTypeName + +Description + +: + +```{=html} +name of the feature type +``` + +Condition + +: + +> mandatory + +### Feature types {#iso19115-3.2018-elem-mrc-featureTypes-13f71555be371c5cc82c6cafa4e33211} + +Name + +: + +> mrc:featureTypes + +Description + +: + +```{=html} +Subset of feature types from cited feature catalogue occurring + in + data +``` +### Film distortion information availability {#iso19115-3.2018-elem-mrc-filmDistortionInformationAvailability-23e3979145822c8293c502656ce444de} + +Name + +: + +> mrc:filmDistortionInformationAvailability + +Description + +: + +```{=html} +Indication of whether or not Calibration Reseau information is + available +``` +### Illumination azimuth angle {#iso19115-3.2018-elem-mrc-illuminationAzimuthAngle-68703c8ec1b434991369ad110842f0d5} + +Name + +: + +> mrc:illuminationAzimuthAngle + +Description + +: + +```{=html} +Illumination azimuth measured in degrees clockwise from true + north at the time + the image is taken. For images from a scanning device, refer to the centre + pixel of the + image +``` +### Illumination elevation angle {#iso19115-3.2018-elem-mrc-illuminationElevationAngle-4942fcb50fa1ba386468663a170f4515} + +Name + +: + +> mrc:illuminationElevationAngle + +Description + +: + +```{=html} +Illumination elevation measured in degrees clockwise from the + target plane at + intersection of the optical line of sight with the Earth_s surface. For + images from a + scanning device, refer to the centre pixel of the image +``` +### Image quality code {#iso19115-3.2018-elem-mrc-imageQualityCode-d76c432bcf49e1705efa580424294b6d} + +Name + +: + +> mrc:imageQualityCode + +Description + +: + +```{=html} +Specifies the image quality +``` +```{=html} +specifies the image quality +``` +### Imaging condition {#iso19115-3.2018-elem-mrc-imagingCondition-138415b371cbe7c705db6c3858d9c19a} + +Name + +: + +> mrc:imagingCondition + +Description + +: + +```{=html} +Conditions affected the image +``` +### Included with dataset {#iso19115-3.2018-elem-mrc-includedWithDataset-406a9a329b292776ade8c8b32d3fdfd5} + +Name + +: + +> mrc:includedWithDataset + +Description + +: + +```{=html} +Indication of whether or not the feature catalogue + is included with the resource +``` +### Language {#iso19115-3.2018-elem-mrc-language-mrc-MD_FeatureCatalogueDescription-b823b546a702df52e72c3d763a33a1e0} + +Name + +: + +> mrc:language + +Context + +: + +> mrc:MD_FeatureCatalogueDescription + +Description + +: + +```{=html} +Language(s) used within the catalogue +``` +### Lens distortion information availability {#iso19115-3.2018-elem-mrc-lensDistortionInformationAvailability-b4bcaa5a49e2e331bce3130b001528ba} + +Name + +: + +> mrc:lensDistortionInformationAvailability + +Description + +: + +```{=html} +Indication of whether or not lens aberration correction + information is + available +``` +### Other language {#iso19115-3.2018-elem-mrc-locale-d66cfb23e274f1b932595edae8291687} + +Name + +: + +> mrc:locale + +Description + +: + +```{=html} +Use this section to define other metadata language + (multilingual metadata). +``` +### Maximum value {#iso19115-3.2018-elem-mrc-maxValue-f4d6b07e0627d3dad6327a88e0fb7645} + +Name + +: + +> mrc:maxValue + +Description + +: + +```{=html} +Longest wavelength that the sensor is capable of collecting + within a designated + band +``` +### Attribute group {#iso19115-3.2018-elem-mrc-MD_AttributeGroup-fde4af4efe67a27c7eb38f18e55a7bfa} + +Name + +: + +> mrc:MD_AttributeGroup + +Description + +: + +```{=html} +Class of information about contentType for groups of + attributes for a specific MD_RangeDimension +``` +### Band {#iso19115-3.2018-elem-mrc-MD_Band-b11f77f7425007bf07d4fa479295fc57} + +Name + +: + +> mrc:MD_Band + +Description + +: + +```{=html} +Range of wavelengths in the electromagnetic spectrum +``` +```{=html} +range of wavelengths in the electromagnetic spectrum +``` +### Coverage content {#iso19115-3.2018-elem-mrc-MD_CoverageContentTypeCode-b7fd2aef2e8871ea509a92f553d14c52} + +Name + +: + +> mrc:MD_CoverageContentTypeCode + +Description + +: + +### Standard codelists Coverage content (mrc:MD_CoverageContentTypeCode) + +| code | label | description | +|------------------------|-------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| image | Image | Meaningful numerical representation of a physical parameter that is not the actual value of the physical parameter | +| thematicClassification | Thematic classification | Code value with no quantitative meaning, used to represent a physical quantity | +| physicalMeasurement | Physical measurement | Value in physical units of the quantity being measured | +| auxillaryInformation | Auxillary Information | Data, usually a physical measurement, used to support the calculation of the primary physicalMeasurement coverages in the dataset. EXAMPLE: Grid of aerosol optical thickness used in the calculation of a sea surface temperature product | +| qualityInformation | Quality Information | Data used to characterize the quality of the physicalMeasurement coverages in the dataset. NOTE: Typically included in a gmi:QE_CoverageResult | +| referenceInformation | Reference Information | Data used to characterize the quality of the physicalMeasurement coverages in the dataset. NOTE: Typically included in a gmi:QE_CoverageResult | +| modelResult | Model Result | Resources with values that are calculated using a model rather than being observed or calculated from observations | +| coordinate | Coordinate | Data used to provide coordinate axis values | + +### Coverage description {#iso19115-3.2018-elem-mrc-MD_CoverageDescription-20da3d15d7d2d5b9fe25c271bf685b2f} + +Name + +: + +> mrc:MD_CoverageDescription + +Description + +: + +```{=html} +Information about the content of a grid data cell +``` +### Feature catalogue {#iso19115-3.2018-elem-mrc-MD_FeatureCatalogue-bbbf11cbc612ed2caa46922976d76c6e} + +Name + +: + +> mrc:MD_FeatureCatalogue + +Description + +: + +```{=html} +A catalogue of feature types +``` +### Feature catalogue description {#iso19115-3.2018-elem-mrc-MD_FeatureCatalogueDescription-25544385dc037d9d72c849835f4600d9} + +Name + +: + +> mrc:MD_FeatureCatalogueDescription + +Description + +: + +```{=html} +Information identifying the feature catalogue or the conceptual + schema +``` +### Feature type info {#iso19115-3.2018-elem-mrc-MD_FeatureTypeInfo-62a86318a6a5fa1493616ea4e0703f1b} + +Name + +: + +> mrc:MD_FeatureTypeInfo + +Description + +: + +```{=html} +Information about the occurring feature type +``` +### Image description {#iso19115-3.2018-elem-mrc-MD_ImageDescription-593f7c8841d10f6d890cb7c653b68304} + +Name + +: + +> mrc:MD_ImageDescription + +Description + +: + +```{=html} +Information about an image's suitability for use +``` +### Range dimension {#iso19115-3.2018-elem-mrc-MD_RangeDimension-5d6ee7c06f95d6a0873f9d3e73f9f806} + +Name + +: + +> mrc:MD_RangeDimension + +Description + +: + +```{=html} +Information on the range of each dimension of a cell + measurement + value +``` +### Sample dimension {#iso19115-3.2018-elem-mrc-MD_SampleDimension-d144bfef885aeb0a9646d264f6bac3a4} + +Name + +: + +> mrc:MD_SampleDimension + +Description + +: + +```{=html} +Class of information about characteristics of each + dimension (layer) included in the resource +``` +### Mean value {#iso19115-3.2018-elem-mrc-meanValue-dca986b28aac66bb498a06cc8bd63de2} + +Name + +: + +> mrc:meanValue + +Description + +: + +```{=html} +Mean value of data values in each dimension included + in the resource +``` + +Condition + +: + +> optional + +### Coverage description (with range elements) {#iso19115-3.2018-elem-mrc-MI_CoverageDescription-f1c665c83cb4c58187c8267e58693137} + +Name + +: + +> mrc:MI_CoverageDescription + +Description + +: + +```{=html} +information about the content of a coverage, including the description of specific range elements +``` +### Range element description {#iso19115-3.2018-elem-mrc-MI_RangeElementDescription-3ea08f39e0b95158ed36f0a1d95f32b2} + +Name + +: + +> mrc:MI_RangeElementDescription + +Description + +: + +```{=html} +eg. storage_meth +``` +### Minimum value {#iso19115-3.2018-elem-mrc-minValue-6c115fdd9335853f2ed4d501c55d0cd3} + +Name + +: + +> mrc:minValue + +Description + +: + +```{=html} +Shortest wavelength that the sensor is capable of collecting + within a + designated band +``` +### Name {#iso19115-3.2018-elem-mrc-name-b10ecd5c969f4405e4432a10ce4c987a} + +Name + +: + +> mrc:name + +Description + +: + +```{=html} +Identifiers for each attribute included in the resource. NOTE + These identifiers can be used to provide names for the attribute from a + standard set of names. +``` +### Number of values {#iso19115-3.2018-elem-mrc-numberOfValues-7523788807eb16fb4c28f3cc87695fea} + +Name + +: + +> mrc:numberOfValues + +Description + +: + +```{=html} +The number of values used in a + thematic-Classification resource. Example The number of classes in a Land + Cover Type coverage or the number of cells with data in other types of + coverages. +``` + +Condition + +: + +> optional + +### Offset {#iso19115-3.2018-elem-mrc-offset-cbfe08793cf284c302b1a3ff5279fd2b} + +Name + +: + +> mrc:offset + +Description + +: + +```{=html} +The physical value corresponding to a cell value of zero +``` +### Other property {#iso19115-3.2018-elem-mrc-otherProperty-2b07e124713e224f44f3f16c558d07a4} + +Name + +: + +> mrc:otherProperty + +Description + +: + +```{=html} +Instance of otherAttributeType that defines + attributes not explicitly included in MD_CoverageType +``` + +Condition + +: + +> optional + +### Other property type {#iso19115-3.2018-elem-mrc-otherPropertyType-3c86efa51e730535417cf07c9d0e46b7} + +Name + +: + +> mrc:otherPropertyType + +Description + +: + +```{=html} +Type of other attribute description (i.e. + netcdf/variable in ncml.xsd) +``` + +Condition + +: + +> optional + +### Peak response {#iso19115-3.2018-elem-mrc-peakResponse-3de9d3d87866575d11d2843ecfaf3f14} + +Name + +: + +> mrc:peakResponse + +Description + +: + +```{=html} +Wavelength at which the response is the highest +``` +### Processing level code {#iso19115-3.2018-elem-mrc-processingLevelCode-6b9cbec9c2e7653417fe4085fa2f518e} + +Name + +: + +> mrc:processingLevelCode + +Description + +: + +```{=html} +Image distributor_s code that identifies the level of + radiometric and geometric + processing that has been applied +``` +### Radiometric calibration data availability {#iso19115-3.2018-elem-mrc-radiometricCalibrationDataAvailability-cd03f7e1aa8805ed7f2629c4d71f9ab0} + +Name + +: + +> mrc:radiometricCalibrationDataAvailability + +Description + +: + +```{=html} +Indication of whether or not the radiometric calibration + information for + generating the radiometrically calibrated standard data product is + available +``` +### Range element {#iso19115-3.2018-elem-mrc-rangeElement-c2ca16217781d20936083b76e758a5b6} + +Name + +: + +> mrc:rangeElement + +Description + +: + +```{=html} +Specific range elements, i.e. range elements associated with a name and their definition. eg. "frozen: Samples are kept frozen.", "room temperature, dry: Samples are kept at room temperature, unsealed." +``` +### Range element description {#iso19115-3.2018-elem-mrc-rangeElementDescription-0d1cc78e663f1eccce73c39c905e8606} + +Name + +: + +> mrc:rangeElementDescription + +Description + +: + +### Scale factor {#iso19115-3.2018-elem-mrc-scaleFactor-d0c127708af77d60471931d015e154da} + +Name + +: + +> mrc:scaleFactor + +Description + +: + +```{=html} +Scale factor which has been applied to the cell value +``` +### Sequence identifier {#iso19115-3.2018-elem-mrc-sequenceIdentifier-9985f58f70c92c442461a95ff7a2387e} + +Name + +: + +> mrc:sequenceIdentifier + +Description + +: + +```{=html} +Number that uniquely identifies instances of bands of + wavelengths on which a + sensor operates +``` +### Standard deviation {#iso19115-3.2018-elem-mrc-standardDeviation-46d51bf39f4256ce781ba724ce7a4678} + +Name + +: + +> mrc:standardDeviation + +Description + +: + +```{=html} +Standard deviation of data values in each dimension + included in the resource +``` + +Condition + +: + +> optional + +### Tone gradation {#iso19115-3.2018-elem-mrc-toneGradation-00522b18a25c437874134ff1507233ee} + +Name + +: + +> mrc:toneGradation + +Description + +: + +```{=html} +Number of discrete numerical values in the grid data +``` +### Triangulation indicator {#iso19115-3.2018-elem-mrc-triangulationIndicator-766a13c1a0f5c40aeeea98ea964584ac} + +Name + +: + +> mrc:triangulationIndicator + +Description + +: + +```{=html} +Indication of whether or not triangulation has been performed + upon the + image +``` +### Value unit {#iso19115-3.2018-elem-mrc-units-beb1f3c6a128f74d575f87e6e7ea46b4} + +Name + +: + +> mrc:units + +Description + +: + +```{=html} +Units in which sensor wavelengths are expressed +``` +### Amendment number {#iso19115-3.2018-elem-mrd-amendmentNumber-6f1c8cb20613ad2e309e5bb98c2cbdc6} + +Name + +: + +> mrd:amendmentNumber + +Description + +: + +```{=html} +Amendment number of the format version +``` +### Density {#iso19115-3.2018-elem-mrd-density-1dd26b1967b18ff25f8427f5ded195b0} + +Name + +: + +> mrd:density + +Description + +: + +```{=html} +Density at which the data is recorded +``` +### Density units {#iso19115-3.2018-elem-mrd-densityUnits-e82aa4195b9434d3a68263bcffdba896} + +Name + +: + +> mrd:densityUnits + +Description + +: + +```{=html} +Units of measure for the recording density +``` + +Condition + +: + +> conditional + +### Description {#iso19115-3.2018-elem-mrd-description-mrd-MD_Distribution-4776d7962b0a05ccef02ea6322033b31} + +Name + +: + +> mrd:description + +Context + +: + +> mrd:MD_Distribution + +Description + +: + +```{=html} +Brief description of a set of distribution options +``` + +Condition + +: + +> optional + +### Distribution format {#iso19115-3.2018-elem-mrd-distributionFormat-ab2a7aa7307b337b55fd0813ee4164be} + +Name + +: + +> mrd:distributionFormat + +Description + +: + +```{=html} +Provides a description of the format of the data to be + distributed +``` + +Condition + +: + +> mandatory + +``` xml + + + + + + ESRI Shapefile + + + + 1.0 + + + + + +``` + +### Distribution / Order Process {#iso19115-3.2018-elem-mrd-distributionOrderProcess-9d9c84da23cda2ebdfd2df84ed8c8238} + +Name + +: + +> mrd:distributionOrderProcess + +Description + +: + +```{=html} +Provides information about how the resource may be obtained, + and related + instructions and fee information +``` +### Distributor {#iso19115-3.2018-elem-mrd-distributor-ded9d0279d2a2b1d04058bcfe0cdadd3} + +Name + +: + +> mrd:distributor + +Description + +: + +```{=html} +Provides information about the distributor +``` +### Distributor contact {#iso19115-3.2018-elem-mrd-distributorContact-c291667f416ad3edb6e9ba3c7ce6e6d2} + +Name + +: + +> mrd:distributorContact + +Description + +: + +```{=html} +Party from whom the resource may be obtained. This list need + not be + exhaustive +``` + +Condition + +: + +> mandatory + +### Distributor format {#iso19115-3.2018-elem-mrd-distributorFormat-385b3a3cdc414ef818b29eead21ed7e6} + +Name + +: + +> mrd:distributorFormat + +Description + +: + +```{=html} +Provides information about the format used by the distributor +``` + +Condition + +: + +> conditional + +### Distributor transfer options {#iso19115-3.2018-elem-mrd-distributorTransferOptions-fed28aa32a0ff7ee645473414c10fd93} + +Name + +: + +> mrd:distributorTransferOptions + +Description + +: + +```{=html} +Provides information about the technical means and media used + by the + distributor +``` +### Fees {#iso19115-3.2018-elem-mrd-fees-a89d56e0d6fad26e33792138077cf724} + +Name + +: + +> mrd:fees + +Description + +: + +```{=html} +Fees and terms for retrieving the resource. Include monetary + units (as + specified in ISO 4217) +``` +### File decompression technique {#iso19115-3.2018-elem-mrd-fileDecompressionTechnique-79a96bbb2fc4a7cfacb6cb50f79ac39a} + +Name + +: + +> mrd:fileDecompressionTechnique + +Description + +: + +```{=html} +Recommendations of algorithms or processes that can be applied + to read or + expand resources to which compression techniques have been applied +``` +### Format distributor {#iso19115-3.2018-elem-mrd-formatDistributor-76fa4371c29fb34aeaa312f75b331eb0} + +Name + +: + +> mrd:formatDistributor + +Description + +: + +```{=html} +Provides information about the distributor’s format +``` +### Format specification citation {#iso19115-3.2018-elem-mrd-formatSpecificationCitation-8857c3b7bb4601e89bcc1459881dce96} + +Name + +: + +> mrd:formatSpecificationCitation + +Description + +: + +```{=html} +citation/URL of the specification for the format +``` + +Condition + +: + +> mandatory + +``` xml + + + + ESRI Shapefile + + + + 1.0 + + + +``` + +### Identifier {#iso19115-3.2018-elem-mrd-identifier-mrd-MD_Medium-b4ad5d7dfbc8331c8b46a58b5e2074f4} + +Name + +: + +> mrd:identifier + +Context + +: + +> mrd:MD_Medium + +Description + +: + +```{=html} +Unique identifier for an instance of the MD_Medium +``` + +Condition + +: + +> optional + +### Digital transfer options {#iso19115-3.2018-elem-mrd-MD_DigitalTransferOptions-c26594fe5b1a54f2778851719f742143} + +Name + +: + +> mrd:MD_DigitalTransferOptions + +Description + +: + +```{=html} +Technical means and media by which a resource is obtained from + the + distributor +``` +``` xml + + + + + https://geoservices.wallonie.be/inspire/atom/PS_Service.xml + + + atom:feed + + + Service de téléchargement ATOM Feed - Inspire + + + Ce service de téléchargement ATOM Feed permet de télécharger la série de couches de + données conforme au thème INSPIRE "Sites protégés". Cliquez sur le lien correspondant aux couches de + données Natura 2000 pour télécharger les informations relatives à ce mécanisme de désignation. + + + + + + + +``` + +### Distribution {#iso19115-3.2018-elem-mrd-MD_Distribution-0aca2560647689db7ebf415baf443815} + +Name + +: + +> mrd:MD_Distribution + +Description + +: + +```{=html} +Information about the distributor of and options for obtaining + the + resource +``` +``` xml + + + + + + + ESRI Shapefile + + + + 1.0 + + + + + + + + + + + https://geoservices.wallonie.be/inspire/atom/PS_Service.xml + + + atom:feed + + + Service de téléchargement ATOM Feed - Inspire + + + Ce service de téléchargement ATOM Feed permet de télécharger la série de couches de + données conforme au thème INSPIRE "Sites protégés". Cliquez sur le lien correspondant aux couches de + données Natura 2000 pour télécharger les informations relatives à ce mécanisme de désignation. + + + + + + + + + +``` + +### Distributor {#iso19115-3.2018-elem-mrd-MD_Distributor-d38062afe33f6acc7dd0874610344056} + +Name + +: + +> mrd:MD_Distributor + +Description + +: + +```{=html} +Information about the distributor +``` +### Format {#iso19115-3.2018-elem-mrd-MD_Format-cf79bdb2251ece19f8f9a2efa0080e17} + +Name + +: + +> mrd:MD_Format + +Description + +: + +```{=html} +Description of the computer language construct that specifies + the + representation of data objects in a record, file, message, storage device + or + transmission channel +``` +``` xml + + + + + ESRI Shapefile + + + + 1.0 + + + + +``` + +### Medium {#iso19115-3.2018-elem-mrd-MD_Medium-47c4ae7fb9c00a03bc19f6684356ccd3} + +Name + +: + +> mrd:MD_Medium + +Description + +: + +```{=html} +Information about the media on which the resource can be + distributed +``` +### Standard order process {#iso19115-3.2018-elem-mrd-MD_StandardOrderProcess-bbf8a6d49b7ccfe336ae772581224a5c} + +Name + +: + +> mrd:MD_StandardOrderProcess + +Description + +: + +```{=html} +Common ways in which the resource may be obtained or received, + and related + instructions and fee information +``` +### Medium {#iso19115-3.2018-elem-mrd-medium-2da5ffeab982f345f690536effef17c3} + +Name + +: + +> mrd:medium + +Description + +: + +```{=html} +Medium used by the format +``` +### Medium format {#iso19115-3.2018-elem-mrd-mediumFormat-ead4f2e742d591857767ef2599762f33} + +Name + +: + +> mrd:mediumFormat + +Description + +: + +```{=html} +Method used to write to the medium +``` +### Medium note {#iso19115-3.2018-elem-mrd-mediumNote-18fe569d2e175e458cdba96d642973ed} + +Name + +: + +> mrd:mediumNote + +Description + +: + +```{=html} +Description of other limitations or requirements for using the + medium +``` +### Name {#iso19115-3.2018-elem-mrd-name-mrd-MD_Medium-6b32246dbc4ce932f20d5faa5622c8cb} + +Name + +: + +> mrd:name + +Context + +: + +> mrd:MD_Medium + +Description + +: + +```{=html} +Name of the medium on which the resource can be received +``` + +Condition + +: + +> optional + +### Offline {#iso19115-3.2018-elem-mrd-offLine-48c66fab18ef14981a5e4fae104c6f97} + +Name + +: + +> mrd:offLine + +Description + +: + +```{=html} +Information about offline media on which the resource can be + obtained +``` +### OnLine resource {#iso19115-3.2018-elem-mrd-onLine-b258f26a552d7bdb353a9ed8602955f9} + +Name + +: + +> mrd:onLine + +Description + +: + +```{=html} +Information about online sources from which the resource can be + obtained +``` +``` xml + + + + https://geoservices.wallonie.be/inspire/atom/PS_Service.xml + + + atom:feed + + + Service de téléchargement ATOM Feed - Inspire + + + Ce service de téléchargement ATOM Feed permet de télécharger la série de couches de + données conforme au thème INSPIRE "Sites protégés". Cliquez sur le lien correspondant aux couches de + données Natura 2000 pour télécharger les informations relatives à ce mécanisme de désignation. + + + + + + +``` + +### Ordering instructions {#iso19115-3.2018-elem-mrd-orderingInstructions-697dea5f51a3bc14b9261c199646b2e5} + +Name + +: + +> mrd:orderingInstructions + +Description + +: + +```{=html} +General instructions, terms and services provided by the + distributor +``` +### Request/Purchase choices {#iso19115-3.2018-elem-mrd-orderOptions-77c57136b3bbf368b7ce40dc320e0f10} + +Name + +: + +> mrd:orderOptions + +Description + +: + +### Order options type {#iso19115-3.2018-elem-mrd-orderOptionsType-3fa15edfa3acc92ebf7095a49192991f} + +Name + +: + +> mrd:orderOptionsType + +Description + +: + +```{=html} +Description of the order options record +``` +### Planned available datetime {#iso19115-3.2018-elem-mrd-plannedAvailableDateTime-58431a14cc32a4038ddbce9871023820} + +Name + +: + +> mrd:plannedAvailableDateTime + +Description + +: + +```{=html} +Date and time when the dataset will be available + (CCYY-MM-DDThh:mm:ss) +``` +### Transfer frequency {#iso19115-3.2018-elem-mrd-transferFrequency-734c97eb43b31196d37e306d4a55c64f} + +Name + +: + +> mrd:transferFrequency + +Description + +: + +```{=html} +Rate of occurrence of distribution +``` +### Transfer options {#iso19115-3.2018-elem-mrd-transferOptions-406dce14c80f3ab2bab25cbcb045148b} + +Name + +: + +> mrd:transferOptions + +Description + +: + +```{=html} +Provides information about technical means and media by which a + resource is + obtained from the distributor +``` +``` xml + + + + + + https://geoservices.wallonie.be/inspire/atom/PS_Service.xml + + + atom:feed + + + Service de téléchargement ATOM Feed - Inspire + + + Ce service de téléchargement ATOM Feed permet de télécharger la série de couches de + données conforme au thème INSPIRE "Sites protégés". Cliquez sur le lien correspondant aux couches de + données Natura 2000 pour télécharger les informations relatives à ce mécanisme de désignation. + + + + + + + + +``` + +### Transfer size {#iso19115-3.2018-elem-mrd-transferSize-18c1e66604b41b220a25872a4e4392b3} + +Name + +: + +> mrd:transferSize + +Description + +: + +```{=html} +Estimated size of a unit in the specified transfer format, + expressed in + megabytes. The transfer size is > 0.0 +``` +### Turnaround {#iso19115-3.2018-elem-mrd-turnaround-428b1bfcefbc1a5350d5e910d0a49941} + +Name + +: + +> mrd:turnaround + +Description + +: + +```{=html} +Typical turnaround time for the filling of an order +``` +### Units of distribution {#iso19115-3.2018-elem-mrd-unitsOfDistribution-bfd51096d182fdfed936fe30f646b048} + +Name + +: + +> mrd:unitsOfDistribution + +Description + +: + +```{=html} +Tiles, layers, geographic areas, etc., in which data is + available +``` +### Volumes {#iso19115-3.2018-elem-mrd-volumes-8fbc4cdb71c04f0d9d7a81fd69811a6f} + +Name + +: + +> mrd:volumes + +Description + +: + +```{=html} +Number of items in the media identified +``` +### Abstract {#iso19115-3.2018-elem-mri-abstract-b1bed9a6d2c9c70eb6b29dc5f23b5b99} + +Name + +: + +> mri:abstract + +Description + +: + +```{=html} +Brief narrative summary of the content of the resource(s) +``` + +Condition + +: + +> mandatory + +``` xml + + Description du jeu de données + +``` + +### Additional documentation {#iso19115-3.2018-elem-mri-additionalDocumentation-085f02b75f646444bac3a4e64e1902ab} + +Name + +: + +> mri:additionalDocumentation + +Description + +: + +```{=html} +Publications that describe usage of data +``` +### Address {#iso19115-3.2018-elem-mri-address-mri-CI_ResponsibleParty-cdfa0ffe58b9f168d74204ba97e5c255} + +Name + +: + +> mri:address + +Context + +: + +> mri:CI_ResponsibleParty + +Description + +: + +```{=html} +Address of the responsible party +``` +### Aggregate Datasetindentifier {#iso19115-3.2018-elem-mri-aggregateDataSetIdentifier-80a8130a9c7c9d5c351a30f6d3b19922} + +Name + +: + +> mri:aggregateDataSetIdentifier + +Description + +: + +```{=html} +Identification information about aggregate dataset +``` +### Aggregate Datasetname {#iso19115-3.2018-elem-mri-aggregateDataSetName-008e770be965e057181c9ba67f7744aa} + +Name + +: + +> mri:aggregateDataSetName + +Description + +: + +```{=html} +Citation information about the aggregate dataset +``` +### Aggregation Information {#iso19115-3.2018-elem-mri-aggregationInfo-05a21c978da37347b2374194e023b8c3} + +Name + +: + +> mri:aggregationInfo + +Description + +: + +```{=html} +Provides aggregate dataset information +``` +### Angular sampling measure {#iso19115-3.2018-elem-mri-angularDistance-ca774f3cfa2db619366fd4746b5feb0b} + +Name + +: + +> mri:angularDistance + +Description + +: + +```{=html} +Angular sampling measure +``` +### Associated resource {#iso19115-3.2018-elem-mri-associatedResource-4687e155ff36c1fced9bb0a5a55a34fa} + +Name + +: + +> mri:associatedResource + +Description + +: + +```{=html} +Associated resource information +``` +### Association Type {#iso19115-3.2018-elem-mri-associationType-50002af61552cfafa00e8158d1e86dd4} + +Name + +: + +> mri:associationType + +Description + +: + +```{=html} +Association type of the aggregate dataset +``` + +Condition + +: + +> mandatory + +### Axis Dimensions Properties {#iso19115-3.2018-elem-mri-axisDimensionProperties-843437604cfe1e16ceda396764927b8c} + +Name + +: + +> mri:axisDimensionProperties + +Description + +: + +```{=html} +Information about spatial-temporal axis properties +``` +### Cell geometry {#iso19115-3.2018-elem-mri-cellGeometry-f970f9e6a0c45f74441de613b704305e} + +Name + +: + +> mri:cellGeometry + +Description + +: + +```{=html} +Identification of grid data as point or cell +``` + +Condition + +: + +> mandatory + +### Center point {#iso19115-3.2018-elem-mri-centerPoint-cb30d24a90d23a1948cd9db74bfe6149} + +Name + +: + +> mri:centerPoint + +Description + +: + +```{=html} +Earth location in the coordinate system defined by the Spatial + Reference System + and the grid coordinate of the cell halfway between opposite ends of the + grid in the + spatial dimensions +``` +### Character set {#iso19115-3.2018-elem-mri-characterSet-mri-MD_Metadata-fbb8af54487af62f6d4dd9bbcbd5e4ab} + +Name + +: + +> mri:characterSet + +Context + +: + +> mri:MD_Metadata + +Description + +: + +```{=html} +Full name of the character coding standard used for the + metadata + set +``` + +Condition + +: + +> conditional + +### Character set {#iso19115-3.2018-elem-mri-characterSet-mri-MD_DataIdentification-670c14eea2290ec02febe561bb9dc317} + +Name + +: + +> mri:characterSet + +Context + +: + +> mri:MD_DataIdentification + +Description + +: + +```{=html} +Full name of the character coding standard used for the + dataset +``` +### Character set {#iso19115-3.2018-elem-mri-characterSet-e5dcdb278033ab3d5b29b1d3adffbeeb} + +Name + +: + +> mri:characterSet + +Description + +: + +```{=html} +Full name of the character coding standard used for the + metadata + set +``` + +Condition + +: + +> conditional + +### Checkpoint Availability {#iso19115-3.2018-elem-mri-checkPointAvailability-0d6de599f9bd32d29175051a4ae24928} + +Name + +: + +> mri:checkPointAvailability + +Description + +: + +```{=html} +Indication of whether or not geographic position points are + available to test + the accuracy of the georeferenced grid data +``` + +Condition + +: + +> mandatory + +### Checkpoint Description {#iso19115-3.2018-elem-mri-checkPointDescription-555aba53a5c04b8cb05befe68bcf8524} + +Name + +: + +> mri:checkPointDescription + +Description + +: + +```{=html} +Description of geographic position points used to test the + accuracy of the + georeferenced grid data +``` + +Condition + +: + +> conditional + +### Responsible party {#iso19115-3.2018-elem-mri-CI_ResponsibleParty-dc40d258bd15a7fb52433fbb269d409e} + +Name + +: + +> mri:CI_ResponsibleParty + +Description + +: + +```{=html} +Identification of, and means of communication with, person(s) + and organizations + associated with the dataset +``` +### Role code {#iso19115-3.2018-elem-mri-CI_RoleCode-831e2b39ab9b602c6becdbf79b4f0443} + +Name + +: + +> mri:CI_RoleCode + +Description + +: + +### Series {#iso19115-3.2018-elem-mri-CI_Series-6a7b9c3a3ef0733a8f9b4180070cef1f} + +Name + +: + +> mri:CI_Series + +Description + +: + +```{=html} +Information about the series, or aggregate dataset, to which a + dataset + belongs +``` +### Citation {#iso19115-3.2018-elem-mri-citation-mri-MD_Identification-a2fcf35af33b9a01b7c462115da464dd} + +Name + +: + +> mri:citation + +Context + +: + +> mri:MD_Identification + +Description + +: + +```{=html} +Citation data for the resource(s) +``` +``` xml + + + + INSPIRE - TG2 - Template + + + + + 2019-10-01 + + + + + + + + + + 48c6f2bb-4828-46eb-a2cc-d5bcb94340dc + + + https://registry.organisation.fr/datasets + + + + + +``` + +### Citation {#iso19115-3.2018-elem-mri-citation-mri-MD_Authority-eaa69cd35eb9afb1096bad7358353672} + +Name + +: + +> mri:citation + +Context + +: + +> mri:MD_Authority + +Description + +: + +```{=html} +Citation which belongs to the authority +``` +``` xml + + + + INSPIRE - TG2 - Template + + + + + 2019-10-01 + + + + + + + + + + 48c6f2bb-4828-46eb-a2cc-d5bcb94340dc + + + https://registry.organisation.fr/datasets + + + + + +``` + +### Citation {#iso19115-3.2018-elem-mri-citation-mri-MD_Thesaurus-b6bb9eeb1a510d12d52677ed2bc11d8f} + +Name + +: + +> mri:citation + +Context + +: + +> mri:MD_Thesaurus + +Description + +: + +```{=html} +Citation of the thesaurus +``` +``` xml + + + + INSPIRE - TG2 - Template + + + + + 2019-10-01 + + + + + + + + + + 48c6f2bb-4828-46eb-a2cc-d5bcb94340dc + + + https://registry.organisation.fr/datasets + + + + + +``` + +### Citation {#iso19115-3.2018-elem-mri-citation-c0c64fab562a266e6c2ed433b3aa4648} + +Name + +: + +> mri:citation + +Description + +: + +```{=html} +Citation data for the resource(s) +``` +``` xml + + + + INSPIRE - TG2 - Template + + + + + 2019-10-01 + + + + + + + + + + 48c6f2bb-4828-46eb-a2cc-d5bcb94340dc + + + https://registry.organisation.fr/datasets + + + + + +``` + +### Class name {#iso19115-3.2018-elem-mri-className-04b5dd0e3097cde916ca0c5a4cfa35e1} + +Name + +: + +> mri:className + +Description + +: + +```{=html} +Character string to label the keyword category in natural + language +``` +### Unique resource identifier {#iso19115-3.2018-elem-mri-code-mri-RS_Identifier-c455cad07e7765deb05b6635b4fd9690} + +Name + +: + +> mri:code + +Context + +: + +> mri:RS_Identifier + +Description + +: + +```{=html} +Alphanumeric value identifying an instance in the namespace +``` + +Condition + +: + +> mandatory + +### Code {#iso19115-3.2018-elem-mri-code-mri-MD_CodeValue-28d6cd273cf6fbf5bb1aacf1d1a4baa9} + +Name + +: + +> mri:code + +Context + +: + +> mri:MD_CodeValue + +Description + +: + +```{=html} +Value code +``` +```{=html} +Value code (i.e. numeric) +``` +### Collective title {#iso19115-3.2018-elem-mri-collectiveTitle-f256578a9a2233009afc61772d6a7f33} + +Name + +: + +> mri:collectiveTitle + +Description + +: + +```{=html} +Common title with holdings note. NOTE title identifies elements + of a series + collectively, combined with information about what volumes are available + at the source + cited +``` +```{=html} +This field is used to name the Basic Geodata as defined in the GeoIV + Annex I, as it is possible that there are more than 1 "physical" datasets + assigned to 1 legal entry. E.g.: Entry no. 47 "Geophysikalisches + Kartenwerk" consists of 3 datasets "Geophysikalische Karten 1:500000", + "Geophysikalische Spezialkarten" and "Gravimetrischer Atlas 1:100000" +``` +### ComposedOf {#iso19115-3.2018-elem-mri-composedOf-f92227eb3a814aba43b51e3d34cd42e5} + +Name + +: + +> mri:composedOf + +Description + +: + +```{=html} +ComposedOf +``` +### Compression generation quantity {#iso19115-3.2018-elem-mri-compressionGenerationQuantity-d160638acebb019ed7a920807bdbf1ab} + +Name + +: + +> mri:compressionGenerationQuantity + +Description + +: + +```{=html} +Count of the number of lossy compression cycles + performed on the + image +``` +### Concept Identifier {#iso19115-3.2018-elem-mri-conceptIdentifier-b98afc41c1dfd685b2c144a974df26f9} + +Name + +: + +> mri:conceptIdentifier + +Description + +: + +```{=html} +URI of concept in the ontology specified by the next + element (ontology) and labelled by the previous element (className) +``` +### Condition {#iso19115-3.2018-elem-mri-condition-d09f5c29e8fc98d775e2441859741fcd} + +Name + +: + +> mri:condition + +Description + +: + +```{=html} +Condition under which the extended element is mandatory +``` +### Metadata author {#iso19115-3.2018-elem-mri-contact-bacc2742e5169472e4f906ecdbe619aa} + +Name + +: + +> mri:contact + +Description + +: + +```{=html} +Party responsible for the metadata information +``` + +Condition + +: + +> mandatory + +### Controlpoint Availability {#iso19115-3.2018-elem-mri-controlPointAvailability-c8b4921fc9ebea36af87be3c0bf06a4b} + +Name + +: + +> mri:controlPointAvailability + +Description + +: + +```{=html} +Indication of whether or not control point(s) exists +``` + +Condition + +: + +> mandatory + +### Corner points {#iso19115-3.2018-elem-mri-cornerPoints-32f0d2d110abed4a81576c25d2428903} + +Name + +: + +> mri:cornerPoints + +Description + +: + +```{=html} +Earth location in the coordinate system defined by the Spatial + Reference System + and the grid coordinate of the cells at opposite ends of grid coverage + along two + diagonals in the grid spatial dimensions. There are four corner points in + a georectified + grid; at least two corner points along one diagonal are required +``` + +Condition + +: + +> mandatory + +### Country {#iso19115-3.2018-elem-mri-country-mri-MD_Legislation-3b41c7104c5243085e9a8075d454b1a6} + +Name + +: + +> mri:country + +Context + +: + +> mri:MD_Legislation + +Description + +: + +```{=html} +Country in which the law was issued +``` +### Country {#iso19115-3.2018-elem-mri-country-PT_Group-5cc39a3f362fc6adbbb8ca2cc466b38b} + +Name + +: + +> mri:country + +Context + +: + +> PT_Group + +Description + +: + +```{=html} +Country of language used for documenting a plain text +``` +### Credit {#iso19115-3.2018-elem-mri-credit-f6c38ebd90277f0c08097e3db4cd7334} + +Name + +: + +> mri:credit + +Description + +: + +```{=html} +Recognition of those who contributed to the resource(s) +``` +### Dataset URI {#iso19115-3.2018-elem-mri-dataSetURI-3094b958d87ee68d3f1eb876b6645c15} + +Name + +: + +> mri:dataSetURI + +Description + +: + +```{=html} +Uniformed Resource Identifier (URI) of the dataset to which the + metadata + applies +``` +```{=html} +Uniformed Resource Identifier (URI) of the dataset to which the + metadata applies. This + link refers direct to the machine-readable dataset. +``` +### Data type {#iso19115-3.2018-elem-mri-dataType-04da587951dce6d554e42c1695bdd525} + +Name + +: + +> mri:dataType + +Description + +: + +```{=html} +Code which identifies the kind of valueprovidedeprovided in the + extended + element +``` + +Condition + +: + +> mandatory + +### Date {#iso19115-3.2018-elem-mri-date-6a55cc1dfd056e73aa1b4c012ce4574f} + +Name + +: + +> mri:date + +Description + +: + +```{=html} +Reference date for the cited resource (YYYY-MM-DD) +``` + +Condition + +: + +> mandatory + +### Date of last update {#iso19115-3.2018-elem-mri-date-mri-MD_Revision-729c81a65123dc90b3a9e9e306ac0694} + +Name + +: + +> mri:date + +Context + +: + +> mri:MD_Revision + +Description + +: + +```{=html} +Date of last update +``` +### Date of next update {#iso19115-3.2018-elem-mri-date-mri-MD_MaintenanceInformation-30e9e24621af992aa138556c1736c8a1} + +Name + +: + +> mri:date + +Context + +: + +> mri:MD_MaintenanceInformation + +Description + +: + +```{=html} +Scheduled revision date for resource +``` +### Date of next update {#iso19115-3.2018-elem-mri-dateOfNextUpdate-22828f5e6b6f62144cf28bca8e708bb0} + +Name + +: + +> mri:dateOfNextUpdate + +Description + +: + +```{=html} +Scheduled revision date for resource (YYYY-MM-DD) +``` +### Date stamp {#iso19115-3.2018-elem-mri-dateStamp-daf76a0c4f3ff93e20644dd6ab31181c} + +Name + +: + +> mri:dateStamp + +Description + +: + +```{=html} +Date that the metadata was created (YYYY-MM-DDThh:mm:ss) +``` + +Condition + +: + +> mandatory + +### Date / Time {#iso19115-3.2018-elem-mri-dateTime-d2271d115f2a482a92c2e1a1dd3459eb} + +Name + +: + +> mri:dateTime + +Description + +: + +```{=html} +Date and time or range of date and time on or over which the + process step + occurred (YYYY-MM-DDThh:mm:ss) +``` +### Date / Time {#iso19115-3.2018-elem-mri-dateTime-LI_ProcessStep-3ad03f294b10052ffc357100eaa260ae} + +Name + +: + +> mri:dateTime + +Context + +: + +> LI_ProcessStep + +Description + +: + +```{=html} +Date and time or range of date and time on or over which the + process step + occurred (YYYY-MM-DDThh:mm:ss) +``` +### Date / Time {#iso19115-3.2018-elem-mri-dateTime-mri-DQ_Element-ff109aefe881cf309cad57b5773e87a8} + +Name + +: + +> mri:dateTime + +Context + +: + +> mri:DQ_Element + +Description + +: + +```{=html} +Date or range of dates on which a data quality measure was + applied +``` +### Default locale {#iso19115-3.2018-elem-mri-defaultLocale-354b26c7ab4ca62c4ea66a28a2d85ba7} + +Name + +: + +> mri:defaultLocale + +Description + +: + +```{=html} +Language and character set used within the + resource +``` +``` xml + + + + + + + + + + +``` + +### Definition {#iso19115-3.2018-elem-mri-definition-bf5edfffdd3034ef755376dafcfb4726} + +Name + +: + +> mri:definition + +Description + +: + +```{=html} +Definition of the extended element +``` + +Condition + +: + +> mandatory + +### Denominator {#iso19115-3.2018-elem-mri-denominator-edd990de0c40bd27204fea0f87cb2c83} + +Name + +: + +> mri:denominator + +Description + +: + +```{=html} +The number below the line in a vulgar fraction +``` + +Condition + +: + +> add either a denominator or a distance + +Recommended values + +| code | label | +|---------|-------------| +| 5000 | 1:5´000 | +| 10000 | 1:10´000 | +| 25000 | 1:25´000 | +| 50000 | 1:50´000 | +| 100000 | 1:100´000 | +| 200000 | 1:200´000 | +| 300000 | 1:300´000 | +| 500000 | 1:500´000 | +| 1000000 | 1:1´000´000 | + +``` xml + + 25000 + +``` + +### Describes {#iso19115-3.2018-elem-mri-describes-47ece431d0767368e0126222741e51e3} + +Name + +: + +> mri:describes + +Description + +: + +```{=html} +Describes +``` +### Description {#iso19115-3.2018-elem-mri-description-dae99f8d3d2cea097c94167ab45d1141} + +Name + +: + +> mri:description + +Description + +: + +```{=html} +Description of the event, including related parameters or + tolerances +``` +### Description {#iso19115-3.2018-elem-mri-description-mri-MD_AbstractClass-4257d154e3ae528bdad656f043f167b3} + +Name + +: + +> mri:description + +Context + +: + +> mri:MD_AbstractClass + +Description + +: + +```{=html} +Description +``` +### Description {#iso19115-3.2018-elem-mri-description-LI_ProcessStep-3e394cb8d22507d6341ba875fff94ad5} + +Name + +: + +> mri:description + +Context + +: + +> LI_ProcessStep + +Description + +: + +```{=html} +Description of the event, including related parameters or + tolerances +``` + +Condition + +: + +> mandatory + +### Description {#iso19115-3.2018-elem-mri-description-mri-MD_CodeDomain-a073652c24dc830d64f1a571e5a5d398} + +Name + +: + +> mri:description + +Context + +: + +> mri:MD_CodeDomain + +Description + +: + +```{=html} +Description of the code domain +``` +### Value description {#iso19115-3.2018-elem-mri-description-mri-MD_CodeValue-c4f9744373b4f7ee492f3e74deec4e90} + +Name + +: + +> mri:description + +Context + +: + +> mri:MD_CodeValue + +Description + +: + +```{=html} +Description of the value +``` +### Description {#iso19115-3.2018-elem-mri-description-mri-MD_Attribute-0cf58a01b569955380601f5c96a58d6f} + +Name + +: + +> mri:description + +Context + +: + +> mri:MD_Attribute + +Description + +: + +```{=html} +Attribute description +``` +### Description {#iso19115-3.2018-elem-mri-description-mri-MD_Role-0424c25c947e4c293301c06364d797c2} + +Name + +: + +> mri:description + +Context + +: + +> mri:MD_Role + +Description + +: + +```{=html} +Role description +``` +### Descriptive keywords {#iso19115-3.2018-elem-mri-descriptiveKeywords-3bbdaa8489a36cab45781306bdf7418c} + +Name + +: + +> mri:descriptiveKeywords + +Description + +: + +```{=html} +Provides category keywords, their type, and reference source +``` +### Descriptor {#iso19115-3.2018-elem-mri-descriptor-d03fecc7145f034b0e41d44613397ed4} + +Name + +: + +> mri:descriptor + +Description + +: + +```{=html} +Description of the range of a cell measurement value +``` +### Dimension {#iso19115-3.2018-elem-mri-dimension-53c837bdd73cb3e453d4bd6f3e1055f3} + +Name + +: + +> mri:dimension + +Description + +: + +```{=html} +Information on the dimensions of the cell measurement value +``` +### Dimension name {#iso19115-3.2018-elem-mri-dimensionName-3b4bcb3ee8f0f2a3f0a32e19e7932bcc} + +Name + +: + +> mri:dimensionName + +Description + +: + +```{=html} +Name of the axis +``` + +Condition + +: + +> mandatory + +### Dimension size {#iso19115-3.2018-elem-mri-dimensionSize-56ea1ddf2c206136a267554acc5d1c0e} + +Name + +: + +> mri:dimensionSize + +Description + +: + +```{=html} +Number of elements along the axis +``` + +Condition + +: + +> mandatory + +### Spatial resolution {#iso19115-3.2018-elem-mri-distance-3928324dc7cf53182407dbe43a21ccfd} + +Name + +: + +> mri:distance + +Description + +: + +```{=html} +Ground sample distance +``` + +Condition + +: + +> Provide a distance if no equivalent Scale is documented + +Recommended values + +| code | label | +|------|-------| +| 0.10 | 10 cm | +| 0.25 | 25 cm | +| 0.50 | 50 cm | +| 1 | 1 m | +| 30 | 30 m | +| 100 | 100 m | + +### Domain code {#iso19115-3.2018-elem-mri-domainCode-04aff018af98f2c97ba5e4889daea229} + +Name + +: + +> mri:domainCode + +Description + +: + +```{=html} +Three digit code assigned to the extended element +``` +### Domain of validity {#iso19115-3.2018-elem-mri-domainOfValidity-51dfb463c5bc44fb8ed66fa8bc54c46e} + +Name + +: + +> mri:domainOfValidity + +Description + +: + +```{=html} +Range which is valid for the referencesystem +``` +### Domain value {#iso19115-3.2018-elem-mri-domainValue-05bccd10b5fc9843957e6c93022f8e1d} + +Name + +: + +> mri:domainValue + +Description + +: + +```{=html} +Valid values that can be assigned to the extended element +``` +### Conformance result {#iso19115-3.2018-elem-mri-DQ_ConformanceResult-6fa2196468e3afbaa5831ce5af398ae6} + +Name + +: + +> mri:DQ_ConformanceResult + +Description + +: + +```{=html} +Information about the outcome of evaluating the obtained value + (or set of + values) against a specified acceptable conformance quality level +``` +### Scope {#iso19115-3.2018-elem-mri-DQ_Scope-5db3160e69e03b2221e538d816192372} + +Name + +: + +> mri:DQ_Scope + +Description + +: + +```{=html} +Description of the data specified by the scope +``` +```{=html} +extent of characteristic(s) of the data for which quality information + is + reported +``` +### DS_Association {#iso19115-3.2018-elem-mri-DS_Association-625caa34f37621855b1adc979fdf5ecf} + +Name + +: + +> mri:DS_Association + +Description + +: + +```{=html} +DS_Association +``` +### DS_DataSet {#iso19115-3.2018-elem-mri-DS_DataSet-b5e6c1fc90906663f44d86998594b001} + +Name + +: + +> mri:DS_DataSet + +Description + +: + +```{=html} +DS_DataSet +``` +### DS_Initiative {#iso19115-3.2018-elem-mri-DS_Initiative-f5b135d1832358421374540b97006ef2} + +Name + +: + +> mri:DS_Initiative + +Description + +: + +```{=html} +DS_Initiative +``` +### DS_OtherAggregate {#iso19115-3.2018-elem-mri-DS_OtherAggregate-2d9d8e81109c16a488a15dea67edbe24} + +Name + +: + +> mri:DS_OtherAggregate + +Description + +: + +```{=html} +DS_OtherAggregate +``` +### DS_Platform {#iso19115-3.2018-elem-mri-DS_Platform-395f7c4d1717e416dcf564d4062adefe} + +Name + +: + +> mri:DS_Platform + +Description + +: + +```{=html} +DS_Platform +``` +### DS_ProductionSeries {#iso19115-3.2018-elem-mri-DS_ProductionSeries-5921b13217f1a54a7fe5be17bb100ba3} + +Name + +: + +> mri:DS_ProductionSeries + +Description + +: + +```{=html} +DS_ProductionSeries +``` +### DS_Sensor {#iso19115-3.2018-elem-mri-DS_Sensor-c627d0348b2116c3948d2028e1d7dbe5} + +Name + +: + +> mri:DS_Sensor + +Description + +: + +```{=html} +DS_Sensor +``` +### DS_Series {#iso19115-3.2018-elem-mri-DS_Series-c84ca9870459bc2c905b3625036ced17} + +Name + +: + +> mri:DS_Series + +Description + +: + +```{=html} +DS_Series +``` +### DS_StereoMate {#iso19115-3.2018-elem-mri-DS_StereoMate-8fc4ee2a9b8c90412129e6a8f0e94931} + +Name + +: + +> mri:DS_StereoMate + +Description + +: + +```{=html} +DS_StereoMate +``` +### East bound {#iso19115-3.2018-elem-mri-eastBoundLongitude-1b0c554db3391725ff40fd4b3f7d4d4d} + +Name + +: + +> mri:eastBoundLongitude + +Description + +: + +```{=html} +Eastern-most coordinate of the limit of the dataset extent, + expressed in + longitude in decimal degrees (positive east) +``` + +Condition + +: + +> mandatory + +### Environment description {#iso19115-3.2018-elem-mri-environmentDescription-ac2adb30f1402078f5b6f707c3d9c2f1} + +Name + +: + +> mri:environmentDescription + +Description + +: + +```{=html} +Description of the dataset in the producer_s processing + environment, including + items such as the software, the computer operating system, file name, and + the dataset + size +``` +### Equivalent scale {#iso19115-3.2018-elem-mri-equivalentScale-2fd017e8c8cd6e6663fe128196d0be07} + +Name + +: + +> mri:equivalentScale + +Description + +: + +```{=html} +Level of detail expressed as the scale of a comparable hardcopy + map or + chart +``` +``` xml + + + + 25000 + + + +``` + +### Error statistic {#iso19115-3.2018-elem-mri-errorStatistic-df112e02728fdfa199b3c136c6ff11fd} + +Name + +: + +> mri:errorStatistic + +Description + +: + +```{=html} +Statistical method used to determine the value +``` +### Evaluation method description {#iso19115-3.2018-elem-mri-evaluationMethodDescription-ee3bd83356c3eafce1900c161d09c14a} + +Name + +: + +> mri:evaluationMethodDescription + +Description + +: + +```{=html} +Description of the evaluation method +``` +### Evaluation Method {#iso19115-3.2018-elem-mri-evaluationMethodType-ad6e089dfe9c39eaa2e5f6cf3e7dbf9c} + +Name + +: + +> mri:evaluationMethodType + +Description + +: + +```{=html} +Type of method used to evaluate quality of the dataset +``` +### Evaluation procedure {#iso19115-3.2018-elem-mri-evaluationProcedure-dd1d15f51eea1fc725ba6dc3dca04024} + +Name + +: + +> mri:evaluationProcedure + +Description + +: + +```{=html} +Reference to the procedure information +``` +### Explanation {#iso19115-3.2018-elem-mri-explanation-4a7325eb479000c4bf97ced8d8f40d22} + +Name + +: + +> mri:explanation + +Description + +: + +```{=html} +Explanation of the meaning of conformance for this result +``` + +Condition + +: + +> mandatory + +### Extended element information {#iso19115-3.2018-elem-mri-extendedElementInformation-41146f06b4994ea88616e35991861c17} + +Name + +: + +> mri:extendedElementInformation + +Description + +: + +```{=html} +Provides information about a new metadata element, not found in + ISO 19115, which is required to describe geographic data +``` +### Extension Online resource {#iso19115-3.2018-elem-mri-extensionOnLineResource-7c1d5fd25b64912f01f87f3b3575b621} + +Name + +: + +> mri:extensionOnLineResource + +Description + +: + +```{=html} +Information about on-line sources containing the community + profile name and the extended metadata elements. Information for all new metadata elements +``` +### Extent {#iso19115-3.2018-elem-mri-extent-2265c394538ef47049b9d39e1431a5b1} + +Name + +: + +> mri:extent + +Description + +: + +```{=html} +Extent information including the bounding polygon, vertical, + and temporal extent of the dataset +``` +``` xml + + + + + + 2.78 + + + 6.41 + + + 49.46 + + + 50.85 + + + + + +``` + +### Facsimile {#iso19115-3.2018-elem-mri-facsimile-ed44306eda27fbc251eb4cb8d042c12e} + +Name + +: + +> mri:facsimile + +Description + +: + +```{=html} +Telephone number of a facsimile machine for the responsible organization or individual +``` +### Feature attribute {#iso19115-3.2018-elem-mri-featureAttribute-c9379b1b5ddea9c2098fb5eb5d473c07} + +Name + +: + +> mri:featureAttribute + +Description + +: + +### Feature type {#iso19115-3.2018-elem-mri-featureType-affc938534ba82ccfad753e3de66f4dc} + +Name + +: + +> mri:featureType + +Description + +: + +```{=html} +Subset of feature types from cited feature catalogue occurring + in + data +``` +### Geometric object count {#iso19115-3.2018-elem-mri-geometricObjectCount-3db26814a8c8452828933028c75dc10b} + +Name + +: + +> mri:geometricObjectCount + +Description + +: + +```{=html} +Total number of the point or vector object type occurring in + the + dataset +``` +### Geometric objects {#iso19115-3.2018-elem-mri-geometricObjects-29d1b872c8bcf5d90e3e3ea7155c59b3} + +Name + +: + +> mri:geometricObjects + +Description + +: + +```{=html} +Information about the geometric objects used in the dataset +``` +### Geometric object type {#iso19115-3.2018-elem-mri-geometricObjectType-13b5366ea59d71264a65d4238c788e41} + +Name + +: + +> mri:geometricObjectType + +Description + +: + +```{=html} +Name of point and vector spatial objects used to locate zero-, + one-, and + two-dimensional spatial locations in the dataset +``` + +Condition + +: + +> mandatory + +### GeoreferencedParameters {#iso19115-3.2018-elem-mri-georeferencedParameters-028b4f1108628c33bb915234d2324ab5} + +Name + +: + +> mri:georeferencedParameters + +Description + +: + +```{=html} +GeoreferencedParameters +``` +### Graphic overview {#iso19115-3.2018-elem-mri-graphicOverview-8640aa6248a384d60f83fa2c32942577} + +Name + +: + +> mri:graphicOverview + +Description + +: + +```{=html} +Provides a graphic that illustrates the resource(s) (should + include a legend + for the graphic) +``` +### Has {#iso19115-3.2018-elem-mri-has-a62a70d8d758396c952ad3c7a7090571} + +Name + +: + +> mri:has + +Description + +: + +```{=html} +Has +``` +### Hierarchy level {#iso19115-3.2018-elem-mri-hierarchyLevel-1ba3e3235eedebc22f7ff178c66f25c6} + +Name + +: + +> mri:hierarchyLevel + +Description + +: + +```{=html} +Scope to which the metadata applies (see annex H for more + information about + metadata hierarchy levels) +``` +### Hierarchy level name {#iso19115-3.2018-elem-mri-hierarchyLevelName-55cf15d0f210413ac816ec9e8abce9ac} + +Name + +: + +> mri:hierarchyLevelName + +Description + +: + +```{=html} +Name of the hierarchy levels for which the metadata is + provided +``` +### Identified issues {#iso19115-3.2018-elem-mri-identifiedIssues-ee073e37cce74aaabfd1c7d230c349ab} + +Name + +: + +> mri:identifiedIssues + +Description + +: + +```{=html} +Citation of a description of known issues associated + with the resource along with proposed solutions if available +``` +### Identifier {#iso19115-3.2018-elem-mri-identifier-a2ed8fa00e68521846e3c515084cb9f9} + +Name + +: + +> mri:identifier + +Description + +: + +```{=html} +Unique identifier for the resource. EXAMPLE: Universal Product + Code (UPC), + National Stock Number (NSN) +``` +### Identifier {#iso19115-3.2018-elem-mri-identifier-mri-MD_Authority-14f0abc5b645685e06a83445d163dfae} + +Name + +: + +> mri:identifier + +Context + +: + +> mri:MD_Authority + +Description + +: + +```{=html} +Identifier which belongs to the authority +``` +### Included with dataset {#iso19115-3.2018-elem-mri-includedWithDataset-5f9bc1136b461cdfc172fc42fc0419be} + +Name + +: + +> mri:includedWithDataset + +Description + +: + +```{=html} +Indication of whether or not the feature catalogue is included + with the + dataset +``` + +Condition + +: + +> mandatory + +### Initiative Type {#iso19115-3.2018-elem-mri-initiativeType-1004a8e07ee24afe674aeaa8e59e230e} + +Name + +: + +> mri:initiativeType + +Description + +: + +```{=html} +Type of initiative under which the aggregate dataset was + produced +``` +### Keyword {#iso19115-3.2018-elem-mri-keyword-71c3570eaf518f78a536bb606c93f359} + +Name + +: + +> mri:keyword + +Description + +: + +```{=html} +Commonly used word(s) or formalised word(s) or phrase(s) used + to describe the + subject +``` +### Keyword class {#iso19115-3.2018-elem-mri-keywordClass-8bcc88fad14d5de58ebe26e47303657a} + +Name + +: + +> mri:keywordClass + +Description + +: + +```{=html} +association of a MD_Keywords instance with a + MD_KeywordClass to provide user-defined categorization of groups of + keywords that extend or are orthogonal to the standardized + KeywordTypeCodes and are associated with an ontology that allows + additional semantic query processing NOTE The thesaurus citation specifies + a collection of instances from some ontology, but is not an ontology. It + might be a list of places that include rivers, mountains, counties and + cities. There might be a Laconte county, the city of Laconte, the Laconte + River, and Mt. Laconte; when searching it is useful for the user to be + able to restrict the search to only rivers. +``` +### Metadata language {#iso19115-3.2018-elem-mri-language-mri-MD_Metadata-35e24f579bcdd8eb6b3a4afd1fb07d75} + +Name + +: + +> mri:language + +Context + +: + +> mri:MD_Metadata + +Description + +: + +```{=html} +Language used for documenting metadata +``` + +Condition + +: + +> conditional + +### Language {#iso19115-3.2018-elem-mri-language-mri-MD_DataIdentification-1a91b7a90b04ad15f6d973265b70dc48} + +Name + +: + +> mri:language + +Context + +: + +> mri:MD_DataIdentification + +Description + +: + +```{=html} +Language(s) used within the dataset +``` +```{=html} +language(s) used within the dataset +``` +### Language {#iso19115-3.2018-elem-mri-languageCode-305fbc461b78dd7b5659ea8a28a96cdf} + +Name + +: + +> mri:languageCode + +Description + +: + +```{=html} +Language code +``` +### ISO Language code {#iso19115-3.2018-elem-mri-LanguageCode-440e7030d461f7a681b67af921c79bfb} + +Name + +: + +> mri:LanguageCode + +Description + +: + +```{=html} +Language code +``` +### Level of detail {#iso19115-3.2018-elem-mri-levelOfDetail-401a945f53a61c9289d6a8e0d372cf99} + +Name + +: + +> mri:levelOfDetail + +Description + +: + +```{=html} +Brief textual description of the spatial resolution of the + resource +``` +### Process step {#iso19115-3.2018-elem-mri-LI_ProcessStep-2e909c9f21434501914535cfcaf75997} + +Name + +: + +> mri:LI_ProcessStep + +Description + +: + +```{=html} +Information about an event in the creation process for the data + specified by + the scope +``` +```{=html} +information about an event or transformation in the life of a dataset + including the + process used to maintain the dataset +``` +### Source {#iso19115-3.2018-elem-mri-LI_Source-5cd1e641a7cfe7cc97c848bce1a49475} + +Name + +: + +> mri:LI_Source + +Description + +: + +```{=html} +Information about the source data used in creating the data + specified by the + scope +``` +### Lineage {#iso19115-3.2018-elem-mri-lineage-4a5e3f33503eddf336b5c8fb9a0dec13} + +Name + +: + +> mri:lineage + +Description + +: + +```{=html} +Non-quantitative quality information about the lineage of the + data specified by + the scope +``` +### Maximum occurrence {#iso19115-3.2018-elem-mri-maximumOccurrence-08133a89b21a5fea01ca6a8f80fa0386} + +Name + +: + +> mri:maximumOccurrence + +Description + +: + +```{=html} +Maximum occurrence of the extended element +``` +### Aggregate Information {#iso19115-3.2018-elem-mri-MD_AggregateInformation-140ed169bbe03a66caa26f1a81cc4dc5} + +Name + +: + +> mri:MD_AggregateInformation + +Description + +: + +```{=html} +Aggregate dataset information +``` +### Associated resource {#iso19115-3.2018-elem-mri-MD_AssociatedResource-4741c31756de110640d3751ef259b610} + +Name + +: + +> mri:MD_AssociatedResource + +Description + +: + +```{=html} +Associated resource information +``` +### Data identification {#iso19115-3.2018-elem-mri-MD_DataIdentification-45539414c34262f719bd1a9cb65d5c34} + +Name + +: + +> mri:MD_DataIdentification + +Description + +: + +```{=html} +Information required to identify a dataset +``` +``` xml + + + + + INSPIRE - TG2 - Template + + + + + 2019-10-01 + + + + + + + + + + 48c6f2bb-4828-46eb-a2cc-d5bcb94340dc + + + https://registry.organisation.fr/datasets + + + + + + + Description du jeu de données + + + + + + + + + + + + + Organisation + + + + + + + mail@organisation.org + + + + + + + + + + + + + + + + + + 25000 + + + + + + + biota + + + environment + + + + + + + 2.78 + + + 6.41 + + + 49.46 + + + 50.85 + + + + + + + + + + + + + + + + Protected site + + + + + + + + GEMET - INSPIRE themes, version 1.0 + + + + + 2008-06-01 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GEMET themes + + + + + 2009-09-22 + + + + + + + + + + + + + + + + + + + + + Natura 2000 sites (Birds Directive) + + + + + + + + INSPIRE priority data set + + + + + 2018-04-24 + + + + + + + + + + + + + + + + + + + + + + + + No + limitations to public access + + + + + + + Conditions d'accès et d'utilisation + + + + + + Description des autres contraintes (eg. CGI, Licence) + + + + + + + + + + + + + + +``` + +### Dimension {#iso19115-3.2018-elem-mri-MD_Dimension-4247609a5b17f0635f0771ccf8f1d7c6} + +Name + +: + +> mri:MD_Dimension + +Description + +: + +```{=html} +Axis properties +``` +### Extended Element Information {#iso19115-3.2018-elem-mri-MD_ExtendedElementInformation-b44873eaadd8ccde9aedba5fb0f6378d} + +Name + +: + +> mri:MD_ExtendedElementInformation + +Description + +: + +```{=html} +New metadata element, not found in ISO 19115, which is required + to describe + geographic data +``` +### Geometric objects {#iso19115-3.2018-elem-mri-MD_GeometricObjects-701be4ade2337a169cdd7437341bdfd8} + +Name + +: + +> mri:MD_GeometricObjects + +Description + +: + +```{=html} +Number of objects, listed by geometric object type, used in the + dataset +``` +### Georectified {#iso19115-3.2018-elem-mri-MD_Georectified-9cd3df419c9405e05aa22437fd8f44b8} + +Name + +: + +> mri:MD_Georectified + +Description + +: + +```{=html} +Grid whose cells are regularly spaced in a geographic (i.e., + lat / long) or map + coordinate system defined in the Spatial Referencing System (SRS) so that + any cell in + the grid can be geolocated given its grid coordinate and the grid origin, + cell spacing, + and orientation +``` +### Georeferenceable {#iso19115-3.2018-elem-mri-MD_Georeferenceable-6f861dc9dcd05001b271619beb2a0b02} + +Name + +: + +> mri:MD_Georeferenceable + +Description + +: + +```{=html} +Grid with cells irregularly spaced in any given geographic/map + projection + coordinate system, whose individual cells can be geolocated using + geolocation + information supplied with the data but cannot be geolocated from the grid + properties + alone +``` +### Grid spatial representation {#iso19115-3.2018-elem-mri-MD_GridSpatialRepresentation-704f579a18d1e383740b32a1c40f4025} + +Name + +: + +> mri:MD_GridSpatialRepresentation + +Description + +: + +```{=html} +Information about grid spatial objects in the dataset +``` +### Keyword class {#iso19115-3.2018-elem-mri-MD_KeywordClass-e8da816d8a2be293339b5591c5b31709} + +Name + +: + +> mri:MD_KeywordClass + +Description + +: + +```{=html} +Specification of a class to categorize keywords in a + domain-specific vocabulary that has a binding to a formal ontology +``` +### Keywords {#iso19115-3.2018-elem-mri-MD_Keywords-c8844255cb6b1346e604a53d830e6697} + +Name + +: + +> mri:MD_Keywords + +Description + +: + +```{=html} +Keywords, their type and reference source +``` +### Metadata Extension Information {#iso19115-3.2018-elem-mri-MD_MetadataExtensionInformation-0d852a81587a640b13d910e246bda49f} + +Name + +: + +> mri:MD_MetadataExtensionInformation + +Description + +: + +```{=html} +Information describing metadata extensions +``` +### Obligation code {#iso19115-3.2018-elem-mri-MD_ObligationCode-0457c04f99f950848fce2bed3f4ef83b} + +Name + +: + +> mri:MD_ObligationCode + +Description + +: + +```{=html} +Obligation of the element or entity +``` +### Representative fraction {#iso19115-3.2018-elem-mri-MD_RepresentativeFraction-af8f6be9f23e0d14630082d51a310384} + +Name + +: + +> mri:MD_RepresentativeFraction + +Description + +: + +```{=html} +Derived from Scale where MD_RepresentativeFraction.denominator + = 1 / + Scale.measure And Scale.targetUnits = Scale.sourceUnits +``` +``` xml + + + 25000 + + +``` + +### Resolution {#iso19115-3.2018-elem-mri-MD_Resolution-e0b4cae62a188c5bc322edb64b2d26b0} + +Name + +: + +> mri:MD_Resolution + +Description + +: + +```{=html} +Level of detail expressed as a scale factor or a ground + distance +``` +``` xml + + + + + 25000 + + + + +``` + +### Resolution type {#iso19115-3.2018-elem-mri-MD_Resolution_Type-de6a074ca31faa71c5dc3549bb2ade22} + +Name + +: + +> mri:MD_Resolution_Type + +Description + +: + +### Scope code {#iso19115-3.2018-elem-mri-MD_ScopeCode-836acd6fc05e96ec03dca7f9e6cef9e9} + +Name + +: + +> mri:MD_ScopeCode + +Description + +: + +```{=html} +Class of information to which the referencing entity applies +``` +### Service Identification {#iso19115-3.2018-elem-mri-MD_ServiceIdentification-ae78ae27b9261dcfde913c0f1780d1fe} + +Name + +: + +> mri:MD_ServiceIdentification + +Description + +: + +```{=html} +Identification of capabilities which a service provider makes + available to a + service user through a set of interfaces that define a behaviour - See ISO + 19119 - + Services for further information +``` +### Topic category code {#iso19115-3.2018-elem-mri-MD_TopicCategoryCode-809913fe5286f1b06f3cef490e3eb204} + +Name + +: + +> mri:MD_TopicCategoryCode + +Description + +: + +```{=html} +High-level geographic data thematic classification to assist in + the grouping + and search of available geographic data sets. Can be used to group + keywords as well. + Listed examples are not exhaustive. NOTE It is understood there are + overlaps between + general categories and the user is encouraged to select the one most + appropriate. +``` +### Standard codelists Topic category code (mri:MD_TopicCategoryCode) + +| code | label | description | +|----------------------------------|--------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| farming | Farming | Rearing of animals and/or cultivation of plants. Examples: agriculture, irrigation, aquaculture, plantations, herding, pests and diseases affecting crops and livestock | +| biota | Biota | Flora and/or fauna in natural environment. Examples: wildlife, vegetation, biological sciences, ecology, wilderness, sealife, wetlands, habitat | +| boundaries | Boundaries | Legal land descriptions. Examples: political and administrative boundaries | +| climatologyMeteorologyAtmosphere | Climatology, meteorology, atmosphere | Processes and phenomena of the atmosphere. Examples: cloud cover, weather, climate, atmospheric conditions, climate change, precipitation | +| economy | Economy | Economic activities, conditions and employment. Examples: production, labour, revenue, commerce, industry, tourism and ecotourism, forestry, fisheries, commercial or subsistence hunting, exploration and exploitation of resources such as minerals, oil and gas | +| elevation | Elevation | Height above or below sea level. Examples: altitude, bathymetry, digital elevation models, slope, derived products | +| environment | Environment | Environmental resources, protection and conservation. Examples: environmental pollution, waste storage and treatment, environmental impact assessment, monitoring environmental risk, nature reserves, landscape | +| geoscientificInformation | Geoscientific information | Information pertaining to earth sciences. Examples: geophysical features and processes, geology, minerals, sciences dealing with the composition, structure and origin of the earth s rocks, risks of earthquakes, volcanic activity, landslides, gravity information, soils, permafrost, hydrogeology, erosion | +| health | Health | Health, health services, human ecology, and safety. Examples: disease and illness, factors affecting health, hygiene, substance abuse, mental and physical health, health services | +| imageryBaseMapsEarthCover | Imagery base maps earth cover | Base maps. Examples: land cover, topographic maps, imagery, unclassified images, annotations | +| intelligenceMilitary | Intelligence military | Military bases, structures, activities. Examples: barracks, training grounds, military transportation, information collection | +| inlandWaters | Inland waters | Inland water features, drainage systems and their characteristics. Examples: rivers and glaciers, salt lakes, water utilization plans, dams, currents, floods, water quality, hydrographic charts | +| location | Location | Positional information and services. Examples: addresses, geodetic networks, control points, postal zones and services, place names | +| oceans | Oceans | Features and characteristics of salt water bodies (excluding inland waters). Examples: tides, tidal waves, coastal information, reefs | +| planningCadastre | Planning cadastre | Information used for appropriate actions for future use of the land. Examples: land use maps, zoning maps, cadastral surveys, land ownership | +| society | Society | Characteristics of society and cultures. Examples: settlements, anthropology, archaeology, education, traditional beliefs, manners and customs, demographic data, recreational areas and activities, social impact assessments, crime and justice, census information | +| structure | Structure | Man-made construction. Examples: buildings, museums, churches, factories, housing, monuments, shops, towers | +| transportation | Transportation | Means and aids for conveying persons and/or goods. Examples: roads, airports/airstrips, shipping routes, tunnels, nautical charts, vehicle or vessel location, aeronautical charts, railways | +| utilitiesCommunication | Utilities communication | Energy, water and waste systems and communications infrastructure andservices. Examples: hydroelectricity, geothermal, solar and nuclear sources of energy, water purification and distribution, sewage collection and disposal, electricity and gas distribution, data communication, telecommunication, radio, communication networks | +| extraTerrestrial | Extra Terrestrial | Region more than 100 km above the surface of the Earth | +| disaster | Disaster | Information related to disasters EXAMPLES: Site of the disaster, evacuation zone, disaster-prevention facility, disaster relief activities | + +### Usage {#iso19115-3.2018-elem-mri-MD_Usage-28b7ff49f2495cc919db1dfdb5504d4a} + +Name + +: + +> mri:MD_Usage + +Description + +: + +```{=html} +Brief description of ways in which the resource(s) is/are + currently + used +``` +### Vector spatial representation {#iso19115-3.2018-elem-mri-MD_VectorSpatialRepresentation-1fa2cede09489f2fe243fa7e91a26c94} + +Name + +: + +> mri:MD_VectorSpatialRepresentation + +Description + +: + +```{=html} +Information about the vector spatial objects in the dataset +``` +### Measure description {#iso19115-3.2018-elem-mri-measureDescription-20a5a3fe84e0b24da0dc627dde2ba323} + +Name + +: + +> mri:measureDescription + +Description + +: + +```{=html} +Description of the measure being determined +``` +### Measure identification {#iso19115-3.2018-elem-mri-measureIdentification-5d7fb93ef9082c314e8c8f7245a54d93} + +Name + +: + +> mri:measureIdentification + +Description + +: + +```{=html} +Code identifying a registered standard procedure +``` +### Metadata Reference {#iso19115-3.2018-elem-mri-metadataReference-10650eae9154c3c351793de92fffaf31} + +Name + +: + +> mri:metadataReference + +Description + +: + +```{=html} +Reference to the metadata of the associated + resource +``` +### Metadata standard name {#iso19115-3.2018-elem-mri-metadataStandardName-f03bf900f90b2510635c8fe4b33a13d2} + +Name + +: + +> mri:metadataStandardName + +Description + +: + +```{=html} +Name of the metadata standard (including profile name) used +``` +### Metadata standard version {#iso19115-3.2018-elem-mri-metadataStandardVersion-d38c2f3d2a6d13013d6ea511e584b610} + +Name + +: + +> mri:metadataStandardVersion + +Description + +: + +```{=html} +Version (profile) of the metadata standard used +``` +### Name {#iso19115-3.2018-elem-mri-name-mri-MD_AbstractClass-9877241cc220793ccba8ca14dcc1b384} + +Name + +: + +> mri:name + +Context + +: + +> mri:MD_AbstractClass + +Description + +: + +```{=html} +Name +``` +### Name {#iso19115-3.2018-elem-mri-name-mri-RS_ReferenceSystem-c677cc018d021b59efd4d4877cc8b127} + +Name + +: + +> mri:name + +Context + +: + +> mri:RS_ReferenceSystem + +Description + +: + +```{=html} +Name of reference system used +``` + +Condition + +: + +> mandatory + +### Name {#iso19115-3.2018-elem-mri-name-mri-MD_Format-8ba2d3536f54f8f338f96ee1c631fb7a} + +Name + +: + +> mri:name + +Context + +: + +> mri:MD_Format + +Description + +: + +```{=html} +Name of the data transfer format(s) +``` +```{=html} +name of the data transfer format(s) +``` + +Condition + +: + +> mandatory + +### Name {#iso19115-3.2018-elem-mri-name-mri-MD_ExtendedElementInformation-71da9b45b9a805e89bdb4ebb0e589286} + +Name + +: + +> mri:name + +Context + +: + +> mri:MD_ExtendedElementInformation + +Description + +: + +```{=html} +Name of the extended metadata element +``` + +Condition + +: + +> mandatory + +### Name {#iso19115-3.2018-elem-mri-name-mri-MD_AssociatedResource-592c1a294a5f5e20abb8a2eb4ff9fd5d} + +Name + +: + +> mri:name + +Context + +: + +> mri:MD_AssociatedResource + +Description + +: + +```{=html} +To be provided if no metadata reference provided +``` +### Name {#iso19115-3.2018-elem-mri-name-4ced2246372284fb55369904f44d6a96} + +Name + +: + +> mri:name + +Description + +: + +### Name {#iso19115-3.2018-elem-mri-name-mri-MD_CodeDomain-7e463975608cc25196e1a6e9331330b6} + +Name + +: + +> mri:name + +Context + +: + +> mri:MD_CodeDomain + +Description + +: + +```{=html} +Name of the code domain +``` +### Name {#iso19115-3.2018-elem-mri-name-mri-MD_CodeValue-2e8d7c21f7913f12492cecdfdafd9f87} + +Name + +: + +> mri:name + +Context + +: + +> mri:MD_CodeValue + +Description + +: + +```{=html} +Value name +``` +### Name {#iso19115-3.2018-elem-mri-name-mri-MD_Attribute-34776ed0db644231645dbea5da7a6d41} + +Name + +: + +> mri:name + +Context + +: + +> mri:MD_Attribute + +Description + +: + +```{=html} +Attribute name +``` +### Name {#iso19115-3.2018-elem-mri-name-mri-MD_Role-dbac7d81940bece1b2bd05ee942e0f1a} + +Name + +: + +> mri:name + +Context + +: + +> mri:MD_Role + +Description + +: + +```{=html} +Role name +``` +### Name of measure {#iso19115-3.2018-elem-mri-nameOfMeasure-339a7390bc51c94a8cd698950f14e00a} + +Name + +: + +> mri:nameOfMeasure + +Description + +: + +```{=html} +Name of the test applied to the data +``` +Recommended values + +| code | label | +|-----------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------| +| | -- Completeness -- | +| Excess item | Excess item | +| Number of excess items | Number of excess items | +| Rate of excess items | Rate of excess items | +| Number of duplicate feature instances | Number of duplicate feature instances | +| Missing item | Missing item | +| Number of missing items | Number of missing items | +| Rate of missing items | Rate of missing items -- Logical consistency / Conceptual consistency -- | +| Conceptual schema noncompliance | Conceptual schema noncompliance | +| Conceptual schema compliance | Conceptual schema compliance | +| Number of items noncompliant to the rules of the conceptual schema | Number of items noncompliant to the rules of the conceptual schema | +| Number of invalid overlaps of surfaces | Number of invalid overlaps of surfaces | +| Non-compliance rate with respect to the rules of the conceptual schema | Non-compliance rate with respect to the rules of the conceptual schema | +| Compliance rate with the rules of the conceptual schema | Compliance rate with the rules of the conceptual schema -- Logical consistency / Domain consistency -- | +| Value domain non-conformance | Value domain non-conformance | +| Value domain conformance | Value domain conformance | +| Number of items not in conformance with their value domain | Number of items not in conformance with their value domain | +| Value domain conformance rate | Value domain conformance rate | +| Value domain non-conformance rate | Value domain non-conformance rate | +| Physical structure conflicts | Physical structure conflicts | +| Physical structure conflict rate | Physical structure conflict rate -- Logical consistency / Topological consistency -- | +| Number of faulty point-curve connections | Number of faulty point-curve connections | +| Rate of faulty point-curve connections | Rate of faulty point-curve connections | +| Number of missing connection due to undershoots | Number of missing connection due to undershoots | +| Number of missing connections due to overshoots | Number of missing connections due to overshoots | +| Number of invalid slivers | Number of invalid slivers | +| Number of invalid self intersect errors | Number of invalid self intersect errors | +| Number of invalid self overlap errors | Number of invalid self overlap errors -- Positional accuracy / Absolute or external accuracy / General measures -- | +| Mean value of positional uncertainties | Mean value of positional uncertainties | +| Mean value of positional uncertainties excluding outliers | Mean value of positional uncertainties excluding outliers | +| Number of positional uncertainties above a given threshold | Number of positional uncertainties above a given threshold | +| Rate of positional errors above a given threshold | Rate of positional errors above a given threshold | +| Covariance matrix | Covariance matrix -- Positional accuracy / Absolute or external accuracy / Vertical -- | +| Linear error probable | Linear error probable | +| Standard linear error | Standard linear error | +| Linear map accuracy at 90% significance level | Linear map accuracy at 90% significance level | +| Linear map accuracy at 95% significance level | Linear map accuracy at 95% significance level | +| Linear map accuracy at 99% significance level | Linear map accuracy at 99% significance level | +| Near certainty linear error | Near certainty linear error | +| Root mean square error | Root mean square error | +| Absolute linear error at 90% significance level of biased vertical data (Alternative 1) | Absolute linear error at 90% significance level of biased vertical data (Alternative 1) | +| Absolute linear error at 90% significance level of biased vertical data | Absolute linear error at 90% significance level of biased vertical data -- Positional accuracy / Absolute or external accuracy / Horizontal -- | +| Circular standard deviation | Circular standard deviation | +| Circular error probable | Circular error probable | +| Circular map accuracy standard | Circular map accuracy standard | +| Circular error at 95% significance level | Circular error at 95% significance level | +| Circular near certainty error | Circular near certainty error | +| Root mean square error of planimetry | Root mean square error of planimetry | +| Absolute circular error at 90% significance level of biased data (Alternative 2) | Absolute circular error at 90% significance level of biased data (Alternative 2) | +| Absolute circular error at 90% significance level of biased data | Absolute circular error at 90% significance level of biased data | +| Uncertainty ellipse | Uncertainty ellipse | +| Confidence ellipse | Confidence ellipse -- Positional accuracy / Relative or internal accuracy -- | +| Relative vertical error | Relative vertical error | +| Relative horizontal error | Relative horizontal error -- Temporal accuracy / Accuracy of a time measurement -- | +| Time accuracy at 68.3% significance level | Time accuracy at 68.3% significance level | +| Time accuracy at 50% significance level | Time accuracy at 50% significance level | +| Time accuracy at 90% significance level | Time accuracy at 90% significance level | +| Time accuracy at 95% significance level | Time accuracy at 95% significance level | +| Time accuracy at 99% significance level | Time accuracy at 99% significance level | +| Time accuracy at 99.8% significance level | Time accuracy at 99.8% significance level -- Thematic accuracy / Classification correctness -- | +| Number of incorrectly classified features | Number of incorrectly classified features | +| Misclassification rate | Misclassification rate | +| Misclassification matrix | Misclassification matrix | +| Relative misclassification matrix | Relative misclassification matrix | +| Kappa coefficient | Kappa coefficient -- Thematic accuracy / Non-quantitative attribute correctness -- | +| Number of incorrect attribute values | Number of incorrect attribute values | +| Rate of correct attribute values | Rate of correct attribute values | +| Rate of incorrect attribute values | Rate of incorrect attribute values -- Thematic accuracy / Quantitative attribute accuracy -- | +| Attribute value uncertainty at 68.3% significance level | Attribute value uncertainty at 68.3% significance level | +| Attribute value uncertainty at 50% significance level | Attribute value uncertainty at 50% significance level | +| Attribute value uncertainty at 90% significance level | Attribute value uncertainty at 90% significance level | +| Attribute value uncertainty at 95% significance level | Attribute value uncertainty at 95% significance level | +| Attribute value uncertainty at 99% significance level | Attribute value uncertainty at 99% significance level | +| Attribute value uncertainty at 99.8% significance level | Attribute value uncertainty at 99.8% significance level | + +### North bound {#iso19115-3.2018-elem-mri-northBoundLatitude-e07339e2d468c1051d7560ef6225ef2e} + +Name + +: + +> mri:northBoundLatitude + +Description + +: + +```{=html} +Northern-most, coordinate of the limit of the dataset extent + expressed in + latitude in decimal degrees (positive north) +``` + +Condition + +: + +> mandatory + +### Number of dimensions {#iso19115-3.2018-elem-mri-numberOfDimensions-cf4fa5a9e3934a3c2c4d4a6b08321edb} + +Name + +: + +> mri:numberOfDimensions + +Description + +: + +```{=html} +Number of independent spatial-temporal axes +``` + +Condition + +: + +> mandatory + +### Obligation {#iso19115-3.2018-elem-mri-obligation-b03e941988d111c06fc0a685a14b79fb} + +Name + +: + +> mri:obligation + +Description + +: + +```{=html} +Obligation of the extended element +``` +### Ontology {#iso19115-3.2018-elem-mri-ontology-413f6aac4db11311fc78f9a029912c9a} + +Name + +: + +> mri:ontology + +Description + +: + +```{=html} +Reference that binds the keyword class to a formal + conceptualization of a knowledge domain for use in semantic processing + NOTE Keywords in the associated MD_Keywords keyword list must be within + the scope of this ontology. +``` +### Orientation parameter availability {#iso19115-3.2018-elem-mri-orientationParameterAvailability-1d8cbe1a4b5d406ef7721d68bbcec95d} + +Name + +: + +> mri:orientationParameterAvailability + +Description + +: + +```{=html} +Indication of whether or not orientation parameters are + available +``` + +Condition + +: + +> mandatory + +### Orientation parameter description {#iso19115-3.2018-elem-mri-orientationParameterDescription-fbbc85950d68d2de1919b38ba893120f} + +Name + +: + +> mri:orientationParameterDescription + +Description + +: + +```{=html} +Description of parameters used to describe sensor orientation +``` +### Other locale {#iso19115-3.2018-elem-mri-otherLocale-bfdf11aeefc7ffb0ac1f8ae02ae7d875} + +Name + +: + +> mri:otherLocale + +Description + +: + +```{=html} +Alternate localised language(s) and character set + (s) used within the resource +``` +### Parameter citation {#iso19115-3.2018-elem-mri-parameterCitation-9ef2b2fc7df47c492bb9a19fce4ba6e8} + +Name + +: + +> mri:parameterCitation + +Description + +: + +```{=html} +Reference providing description of the parameters +``` +### Parent entity {#iso19115-3.2018-elem-mri-parentEntity-0b202b298ce60d1717e5d04b88c83e4e} + +Name + +: + +> mri:parentEntity + +Description + +: + +```{=html} +Name of the metadata entity(s) under which this extended + metadata element may + appear. The name(s) may be standard metadata element(s) or other extended + metadata + element(s). +``` + +Condition + +: + +> mandatory + +### Parent identifier {#iso19115-3.2018-elem-mri-parentIdentifier-5f0e8c7441e5779b27d133eba76fbbad} + +Name + +: + +> mri:parentIdentifier + +Description + +: + +```{=html} +File identifier of the metadata to which this metadata is a + subset + (child) +``` +### PartOf {#iso19115-3.2018-elem-mri-partOf-1567d8c5a5040af4fb70a2a728ec3d00} + +Name + +: + +> mri:partOf + +Description + +: + +```{=html} +PartOf +``` +### Pass {#iso19115-3.2018-elem-mri-pass-80f8d49ddc3e9855c783a6eca671a20d} + +Name + +: + +> mri:pass + +Description + +: + +```{=html} +Indication of the conformance result where 0 = fail and 1 = + pass +``` + +Condition + +: + +> mandatory + +### Phone {#iso19115-3.2018-elem-mri-phone-60b8622d9cf4ed86cab44b6ec6dda2a5} + +Name + +: + +> mri:phone + +Description + +: + +```{=html} +Telephone numbers at which the organization or individual may + be + contacted +``` +### Point in Pixel {#iso19115-3.2018-elem-mri-pointInPixel-2c8b52f284ca32d399381131e41a4305} + +Name + +: + +> mri:pointInPixel + +Description + +: + +```{=html} +Point in a pixel corresponding to the Earth location of the + pixel +``` + +Condition + +: + +> mandatory + +### Point of contact {#iso19115-3.2018-elem-mri-pointOfContact-0a191d0435894206a844cde68a5bc873} + +Name + +: + +> mri:pointOfContact + +Description + +: + +```{=html} +Identification of, and means of communication with, person(s) + and + organizations(s) associated with the resource(s) +``` +``` xml + + + + + + + + + Organisation + + + + + + + mail@organisation.org + + + + + + + + + +``` + +### Presentation form {#iso19115-3.2018-elem-mri-presentationForm-c60bbfde21396f943e6032fca7b69550} + +Name + +: + +> mri:presentationForm + +Description + +: + +```{=html} +Mode in which the resource is represented +``` +### Processing level {#iso19115-3.2018-elem-mri-processingLevel-92beb3a40f398b02520cb6da80890df9} + +Name + +: + +> mri:processingLevel + +Description + +: + +```{=html} +Code that identifies the level of processing in the + producers coding system of a resource. Example NOAA level 1B. +``` +### PropertyType {#iso19115-3.2018-elem-mri-propertyType-e9212239d95c65d827b824b048de51a6} + +Name + +: + +> mri:propertyType + +Description + +: + +```{=html} +PropertyType +``` +### Free text {#iso19115-3.2018-elem-mri-PT_FreeText-6219dda1e26c4d314689c8bc49ddfb63} + +Name + +: + +> mri:PT_FreeText + +Description + +: + +```{=html} +Description of a multi-language free text metadata element +``` +### Purpose {#iso19115-3.2018-elem-mri-purpose-f010699f7244e7c9797817d3a9a78c8d} + +Name + +: + +> mri:purpose + +Description + +: + +```{=html} +Summary of the intentions with which the resource(s) was + developed +``` +### Rationale {#iso19115-3.2018-elem-mri-rationale-mri-MD_ExtendedElementInformation-b1f26013fe0ce1e4f6018873aa1f0e5b} + +Name + +: + +> mri:rationale + +Context + +: + +> mri:MD_ExtendedElementInformation + +Description + +: + +```{=html} +Reason for creating the extended element +``` +### Resource constraints {#iso19115-3.2018-elem-mri-resourceConstraints-22849b1b8ec64c231cd8eda0547a553a} + +Name + +: + +> mri:resourceConstraints + +Description + +: + +```{=html} +Provides information about constraints which apply to the + resource(s) +``` +### Resource format {#iso19115-3.2018-elem-mri-resourceFormat-713c10529cd9a1b05d0e0d70cf37fa08} + +Name + +: + +> mri:resourceFormat + +Description + +: + +```{=html} +Provides a description of the format of the resource(s) +``` +### Resource maintenance {#iso19115-3.2018-elem-mri-resourceMaintenance-9aabbe5ce70e511c06bf7decde6ba3ac} + +Name + +: + +> mri:resourceMaintenance + +Description + +: + +```{=html} +Provides information about the frequency of resource updates, + and the scope of + those updates +``` +``` xml + + + + + + + +``` + +### Resource specific usage {#iso19115-3.2018-elem-mri-resourceSpecificUsage-16894db96c1cd1836b2b8838b3a7ad30} + +Name + +: + +> mri:resourceSpecificUsage + +Description + +: + +```{=html} +Provides basic information about specific application(s) for + which the + resource(s) has/have been or is being used by different users +``` +### Response {#iso19115-3.2018-elem-mri-response-5c7415e8bb679a4645e53f1bca4888c1} + +Name + +: + +> mri:response + +Description + +: + +```{=html} +Response to the user-determined limitations. Example + “This has been fixed in version x.” +``` +### Result {#iso19115-3.2018-elem-mri-result-cf813985cacbefc1455b60255c9aacd0} + +Name + +: + +> mri:result + +Description + +: + +```{=html} +Value (or set of values) obtained from applying a data quality + measure or the + out come of evaluating the obtained value (or set of values) against a + specified + acceptable conformance quality level +``` + +Condition + +: + +> mandatory + +### Identifier {#iso19115-3.2018-elem-mri-RS_Identifier-0ff1b8f7f7961d3b04637810bc4bbc95} + +Name + +: + +> mri:RS_Identifier + +Description + +: + +```{=html} +Identifier used for reference systems +``` +### Rule {#iso19115-3.2018-elem-mri-rule-4724b8d466dc221ef079c5a9c07ad554} + +Name + +: + +> mri:rule + +Description + +: + +```{=html} +Specifies how the extended element relates to other existing + elements and + entities +``` + +Condition + +: + +> mandatory + +### Scale Denominator {#iso19115-3.2018-elem-mri-scaleDenominator-dac4fe9262fc158c1184fa0969bef7ae} + +Name + +: + +> mri:scaleDenominator + +Description + +: + +```{=html} +Denominator of the representative fraction on a source map +``` +### Series {#iso19115-3.2018-elem-mri-series-00c09e9ddd3edc0274c60cf72e66966b} + +Name + +: + +> mri:series + +Description + +: + +```{=html} +Information about the series, or aggregate dataset, of which + the dataset is a + part +``` +### SeriesMetadata {#iso19115-3.2018-elem-mri-seriesMetadata-983451ad1bc581791b639c841965fc41} + +Name + +: + +> mri:seriesMetadata + +Description + +: + +```{=html} +SeriesMetadata +``` +### Short name {#iso19115-3.2018-elem-mri-shortName-d6f9ddc078149cfd4ae0fff6efe14041} + +Name + +: + +> mri:shortName + +Description + +: + +```{=html} +Short form suitable for use in an implementation method such as + XML or SGML. + NOTE other methods may be used +``` +### Source {#iso19115-3.2018-elem-mri-source-mri-MD_ExtendedElementInformation-69dc34a4ad2af38b82c4651fed59231c} + +Name + +: + +> mri:source + +Context + +: + +> mri:MD_ExtendedElementInformation + +Description + +: + +```{=html} +Name of the person or organization creating the extended + element +``` + +Condition + +: + +> mandatory + +### Source extent {#iso19115-3.2018-elem-mri-sourceExtent-3c6ed438e292db496d6517c3534f17a7} + +Name + +: + +> mri:sourceExtent + +Description + +: + +```{=html} +Information about the spatial, vertical and temporal extent of + the source + data +``` + +Condition + +: + +> conditional + +### South bound {#iso19115-3.2018-elem-mri-southBoundLatitude-4ddecaaf6237fcc1c5d40358875edf7c} + +Name + +: + +> mri:southBoundLatitude + +Description + +: + +```{=html} +Southern-most coordinate of the limit of the dataset extent, + expressed in + latitude in decimal degrees (positive north) +``` + +Condition + +: + +> mandatory + +### Spatial representation type {#iso19115-3.2018-elem-mri-spatialRepresentationType-e3208e8cd1381b9fc68b3aeea9b717bc} + +Name + +: + +> mri:spatialRepresentationType + +Description + +: + +```{=html} +Method used to spatially represent geographic information +``` +``` xml + + + +``` + +### Spatial resolution {#iso19115-3.2018-elem-mri-spatialResolution-21e177ffd817c0d4ab98dbb85f2023f4} + +Name + +: + +> mri:spatialResolution + +Description + +: + +```{=html} +Factor which provides a general understanding of the density of + spatial data in + the dataset +``` +``` xml + + + + + + 25000 + + + + + +``` + +### Specification {#iso19115-3.2018-elem-mri-specification-mri-DQ_ConformanceResult-b7cc00be1811025bfd6d444339699780} + +Name + +: + +> mri:specification + +Context + +: + +> mri:DQ_ConformanceResult + +Description + +: + +```{=html} +Citation of product specification or user requirement against + which data is + being evaluated +``` + +Condition + +: + +> mandatory + +### Specification {#iso19115-3.2018-elem-mri-specification-mri-MD_Format-7df5c14f28cb23cf5b04ecb8bc52a50d} + +Name + +: + +> mri:specification + +Context + +: + +> mri:MD_Format + +Description + +: + +```{=html} +Name of a subset, profile, or product specification of the + format +``` +### Specification {#iso19115-3.2018-elem-mri-specification-da131cbaabfe65e6342437511b16716f} + +Name + +: + +> mri:specification + +Description + +: + +### Specific usage {#iso19115-3.2018-elem-mri-specificUsage-e10bbb146f9122f24b86bd27cd582a0b} + +Name + +: + +> mri:specificUsage + +Description + +: + +```{=html} +Brief description of the resource and/or resource series + usage +``` + +Condition + +: + +> mandatory + +### Status {#iso19115-3.2018-elem-mri-status-cc6f58a635c230364c21dcd8822e7ebd} + +Name + +: + +> mri:status + +Description + +: + +```{=html} +Status of the resource(s) +``` +``` xml + + + +``` + +### Subset {#iso19115-3.2018-elem-mri-subset-e094e68292e2fa9500f0d6380981f185} + +Name + +: + +> mri:subset + +Description + +: + +```{=html} +Subset +``` +### Superset {#iso19115-3.2018-elem-mri-superset-786873bc68f8c3a000a3fd54ece6fb6f} + +Name + +: + +> mri:superset + +Description + +: + +```{=html} +Superset +``` +### Supplemental Information {#iso19115-3.2018-elem-mri-supplementalInformation-84665de001cb75c50eb593b3a9366f70} + +Name + +: + +> mri:supplementalInformation + +Description + +: + +```{=html} +Any other descriptive information about the dataset +``` +### Temporal resolution {#iso19115-3.2018-elem-mri-temporalResolution-50d263b81d8636c123eea3bcb704872d} + +Name + +: + +> mri:temporalResolution + +Description + +: + +```{=html} +Smallest resolvable temporal period in a resource +``` +### TextGroup {#iso19115-3.2018-elem-mri-textGroup-f5fee81a35f938add5c2959da2e0944a} + +Name + +: + +> mri:textGroup + +Description + +: + +```{=html} +TextGroup +``` +### Thesaurus name {#iso19115-3.2018-elem-mri-thesaurusName-fdfd987e5e74c33c17af7d710026a114} + +Name + +: + +> mri:thesaurusName + +Description + +: + +```{=html} +Name of the formally registered thesaurus or a similar + authoritative source of + keywords +``` +### Title {#iso19115-3.2018-elem-mri-title-mri-MD_Legislation-87bbb0dc3d29b30cec5bdf043159fec3} + +Name + +: + +> mri:title + +Context + +: + +> mri:MD_Legislation + +Description + +: + +```{=html} +Reference to legal title +``` +### Topic category {#iso19115-3.2018-elem-mri-topicCategory-3384f3f2b46b6851db1e3c2ac2404477} + +Name + +: + +> mri:topicCategory + +Description + +: + +```{=html} +Main theme(s) of the dataset +``` + +Condition + +: + +> mandatory + +### Topology level {#iso19115-3.2018-elem-mri-topologyLevel-c192e149d637dd11a6735e4ab2793cce} + +Name + +: + +> mri:topologyLevel + +Description + +: + +```{=html} +Code which identifies the degree of complexity of the spatial + relationships +``` +### Transformation dimension description {#iso19115-3.2018-elem-mri-transformationDimensionDescription-7817f43a4aedff49f2770b81155bd879} + +Name + +: + +> mri:transformationDimensionDescription + +Description + +: + +```{=html} +Description of the information about which grid dimensions are + the spatial + dimensions +``` +### Transformation dimension mapping {#iso19115-3.2018-elem-mri-transformationDimensionMapping-af6c96c0b976aae72d391badb572d556} + +Name + +: + +> mri:transformationDimensionMapping + +Description + +: + +```{=html} +Information about which grid dimensions are the spatial + dimensions +``` +### Transformation parameter availability {#iso19115-3.2018-elem-mri-transformationParameterAvailability-00ae4b9f58a82c8747c05290206e073c} + +Name + +: + +> mri:transformationParameterAvailability + +Description + +: + +```{=html} +Indication of whether or not parameters for transformation + between image + coordinates and geographic or map coordinates exist (are available) +``` + +Condition + +: + +> mandatory + +### Type {#iso19115-3.2018-elem-mri-type-c713af5b3e37409f862f317150418a43} + +Name + +: + +> mri:type + +Description + +: + +```{=html} +Subject matter used to group similar keywords +``` +### Type {#iso19115-3.2018-elem-mri-type-mri-MD_CodeDomain-f36524bc9b2bcff08dc13b26a6f1c412} + +Name + +: + +> mri:type + +Context + +: + +> mri:MD_CodeDomain + +Description + +: + +```{=html} +Datatype of the code domain +``` +### Type definition {#iso19115-3.2018-elem-mri-type-mri-MD_Type-509a3b36cee46d21f76032143452c3df} + +Name + +: + +> mri:type + +Context + +: + +> mri:MD_Type + +Description + +: + +```{=html} +Data type definition +``` +```{=html} +Data type definition, formal of informal (i.e. Text12, Line) +``` +### Update scope {#iso19115-3.2018-elem-mri-updateScope-2f6505dc9e21679f55889d5d3dab55f0} + +Name + +: + +> mri:updateScope + +Description + +: + +```{=html} +Scope of data to which maintenance is applied +``` +### Update scope description {#iso19115-3.2018-elem-mri-updateScopeDescription-4ed2c444d7ad67f7d337a115667d00f4} + +Name + +: + +> mri:updateScopeDescription + +Description + +: + +```{=html} +Additional information about the range or extent of the + resource +``` +### URL {#iso19115-3.2018-elem-mri-URL-ade84020707f315475cd2242c01dd25a} + +Name + +: + +> mri:URL + +Description + +: + +```{=html} +URL +``` +### Usage datetime {#iso19115-3.2018-elem-mri-usageDateTime-cb7d2c81941c09afc3a52bfc79bf71fb} + +Name + +: + +> mri:usageDateTime + +Description + +: + +```{=html} +Date and time of the first use or range of uses of the resource + and/or resource + series (YYYY-MM-DDThh:mm:ss) +``` +### User contact info {#iso19115-3.2018-elem-mri-userContactInfo-a2ba616281c1660c5480ee85e959ee52} + +Name + +: + +> mri:userContactInfo + +Description + +: + +```{=html} +Identification of and means of communicating with person(s) and + organization(s) + using the resource(s) +``` + +Condition + +: + +> mandatory + +### User determined limitations {#iso19115-3.2018-elem-mri-userDeterminedLimitations-cbd92baf556f2b19980a621ce6c02254} + +Name + +: + +> mri:userDeterminedLimitations + +Description + +: + +```{=html} +Applications, determined by the user for which the resource + and/or resource + series is not suitable +``` +### Version {#iso19115-3.2018-elem-mri-version-mri-RS_Identifier-21131c5f6a0db9532cc8ee120d605769} + +Name + +: + +> mri:version + +Context + +: + +> mri:RS_Identifier + +Description + +: + +```{=html} +Version identifier for the namespace +``` +### Version {#iso19115-3.2018-elem-mri-version-37b307063b9e962d1848882bb4e6cfbd} + +Name + +: + +> mri:version + +Description + +: + +```{=html} +Version of the format (date, number, etc.) +``` + +Condition + +: + +> mandatory + +### Vertical sampling distance {#iso19115-3.2018-elem-mri-vertical-43bcad35797e8b97a17410d5045328f0} + +Name + +: + +> mri:vertical + +Description + +: + +```{=html} +Vertical sampling distance +``` +### Voice {#iso19115-3.2018-elem-mri-voice-8b6d31c838c1369223d55ee98798ca8f} + +Name + +: + +> mri:voice + +Description + +: + +```{=html} +Telephone number by which individuals can speak to the + responsible organization + or individual +``` +### West bound {#iso19115-3.2018-elem-mri-westBoundLongitude-ce82ae6636f5b594044aada5c51913ac} + +Name + +: + +> mri:westBoundLongitude + +Description + +: + +```{=html} +Western-most coordinate of the limit of the dataset extent, + expressed in + longitude in decimal degrees (positive east) +``` + +Condition + +: + +> mandatory + +### Additional doc. {#iso19115-3.2018-elem-mrl-additionalDocumentation-f113e2c0288a07cf4fe6882d11069fad} + +Name + +: + +> mrl:additionalDocumentation + +Description + +: + +### Description {#iso19115-3.2018-elem-mrl-description-a45016f67dc027509d26734d33ba598c} + +Name + +: + +> mrl:description + +Description + +: + +### Description {#iso19115-3.2018-elem-mrl-description-mrl-LI_Source-3f37e9df548dbad7ccfc5a97b569f6bb} + +Name + +: + +> mrl:description + +Context + +: + +> mrl:LI_Source + +Description + +: + +```{=html} +Detailed description of the level of the source data +``` +### File type {#iso19115-3.2018-elem-mrl-fileType-34ce7f3d07796298fa2fd3be3ca9f725} + +Name + +: + +> mrl:fileType + +Description + +: + +### Process step {#iso19115-3.2018-elem-mrl-LE_ProcessStep-34c17a1d181ee4939772d7207becf6ee} + +Name + +: + +> mrl:LE_ProcessStep + +Description + +: + +### Process step report {#iso19115-3.2018-elem-mrl-LE_ProcessStepReport-7f36ac19621de69c869f50fffa5888f6} + +Name + +: + +> mrl:LE_ProcessStepReport + +Description + +: + +### Source (imagery) {#iso19115-3.2018-elem-mrl-LE_Source-966e475433745f44485a80b7d3d67a5b} + +Name + +: + +> mrl:LE_Source + +Description + +: + +### Lineage {#iso19115-3.2018-elem-mrl-LI_Lineage-f498f5aafe17748455864fd3fb332568} + +Name + +: + +> mrl:LI_Lineage + +Description + +: + +```{=html} +Information about the events or source data used in + constructing the data + specified by the scope or lack of knowledge about lineage +``` +``` xml + + + Généalogie du jeu de données + + + + + + + + + +``` + +### Process step (imagery) {#iso19115-3.2018-elem-mrl-LI_ProcessStep-523fb797e15543dcd78820cf7da6a353} + +Name + +: + +> mrl:LI_ProcessStep + +Description + +: + +### Source {#iso19115-3.2018-elem-mrl-LI_Source-516cbe9c5aee24a2298148e192b1b430} + +Name + +: + +> mrl:LI_Source + +Description + +: + +### Name {#iso19115-3.2018-elem-mrl-name-c3ddefc350a7df82d699cd21db3265bb} + +Name + +: + +> mrl:name + +Description + +: + +### Output {#iso19115-3.2018-elem-mrl-output-7b92f6eed5c27bf127bcd1b00ba02bd2} + +Name + +: + +> mrl:output + +Description + +: + +### Processed level {#iso19115-3.2018-elem-mrl-processedLevel-a16a0921791d25b12c661d6b523823fd} + +Name + +: + +> mrl:processedLevel + +Description + +: + +### Information sur le processus {#iso19115-3.2018-elem-mrl-processingInformation-43dcf9a95a6b46ecd38081b26ad4405c} + +Name + +: + +> mrl:processingInformation + +Description + +: + +### Processor {#iso19115-3.2018-elem-mrl-processor-d25f51596af7f766fb5e2e2d235b8d38} + +Name + +: + +> mrl:processor + +Description + +: + +```{=html} +Identification of, and means of communication with, person(s) + and + organization(s) associated with the process step +``` +### Process step {#iso19115-3.2018-elem-mrl-processStep-b30816d20fac90a8f4714473ce039ab6} + +Name + +: + +> mrl:processStep + +Description + +: + +```{=html} +Information about an event in the creation process for the data + specified by + the scope +``` + +Condition + +: + +> conditional + +### Rationale {#iso19115-3.2018-elem-mrl-rationale-80f6a85b661cb0e1343a18c85fef1c6a} + +Name + +: + +> mrl:rationale + +Description + +: + +```{=html} +Requirement or purpose for the process step +``` +### Reference {#iso19115-3.2018-elem-mrl-reference-f0e0b120539f104664b10ed341d78e1c} + +Name + +: + +> mrl:reference + +Description + +: + +### Report {#iso19115-3.2018-elem-mrl-report-a6ace6224eaf1048b4fa5a64e3ed3c8d} + +Name + +: + +> mrl:report + +Description + +: + +### Resolution {#iso19115-3.2018-elem-mrl-resolution-4a197894c21de3f79a1db7fd8cdef215} + +Name + +: + +> mrl:resolution + +Description + +: + +```{=html} +Degree of detail in the grid dataset +``` +### Scope {#iso19115-3.2018-elem-mrl-scope-6d6d5c1accac2c5584b8d24677b8e466} + +Name + +: + +> mrl:scope + +Description + +: + +```{=html} +Type of resource and/or extent to which the lineage + information applies +``` +``` xml + + + + + + + +``` + +### Source {#iso19115-3.2018-elem-mrl-source-f9e07e326a4d78299bfa20d20350d4e5} + +Name + +: + +> mrl:source + +Description + +: + +```{=html} +Information about the source data used in creating the data + specified by the + scope +``` + +Condition + +: + +> mandatory + +### Source citation {#iso19115-3.2018-elem-mrl-sourceCitation-493609aa2a1f745385660e829fa9dfb4} + +Name + +: + +> mrl:sourceCitation + +Description + +: + +```{=html} +Recommended reference to be used for the source data +``` +### Source Metadata {#iso19115-3.2018-elem-mrl-sourceMetadata-e2c32177f459ed654ad740ae7a82c89a} + +Name + +: + +> mrl:sourceMetadata + +Description + +: + +```{=html} +Reference to metadata for the source +``` + +Condition + +: + +> optional + +### Source reference system {#iso19115-3.2018-elem-mrl-sourceReferenceSystem-1037d7bf6f0b485f262e4322cb9e37cf} + +Name + +: + +> mrl:sourceReferenceSystem + +Description + +: + +```{=html} +Spatial reference system used by the source data +``` +### Source spatial resolution {#iso19115-3.2018-elem-mrl-sourceSpatialResolution-cf018c59a91f5566c1b1783f2acbd27d} + +Name + +: + +> mrl:sourceSpatialResolution + +Description + +: + +```{=html} +spatial resolution expressed as a scale factor, a distance, an + angle or a level of detail +``` + +Condition + +: + +> optional + +### Source step {#iso19115-3.2018-elem-mrl-sourceStep-mrl-LI_Source-df0d740b9f8a72af86d6f0c7adee8c72} + +Name + +: + +> mrl:sourceStep + +Context + +: + +> mrl:LI_Source + +Description + +: + +```{=html} +Information about a process step in which this source was + used +``` + +Condition + +: + +> optional + +### Source step {#iso19115-3.2018-elem-mrl-sourceStep-7a3ac763c9a58974ba992b5b15f42c8e} + +Name + +: + +> mrl:sourceStep + +Description + +: + +```{=html} +Information about an event in the creation process for the + source + data +``` +### Statement {#iso19115-3.2018-elem-mrl-statement-889c16bd4aae51af718de1e5d417231b} + +Name + +: + +> mrl:statement + +Description + +: + +```{=html} +General explanation of the data producer_s knowledge about the + lineage of a + dataset +``` + +Condition + +: + +> conditional + +``` xml + + Généalogie du jeu de données + +``` + +### Step date time {#iso19115-3.2018-elem-mrl-stepDateTime-ff4d18ce2643f44151f2edb998f6d42d} + +Name + +: + +> mrl:stepDateTime + +Description + +: + +### Reference system {#iso19115-3.2018-elem-mrs-MD_ReferenceSystem-75f781a6e44f220db44fb9f797143583} + +Name + +: + +> mrs:MD_ReferenceSystem + +Description + +: + +```{=html} +Information about the reference system. +``` +```{=html} +information about the reference system +``` +``` xml + + + + + http://www.opengis.net/def/crs/EPSG/0/3035 + + + + +``` + +### Reference system identifier {#iso19115-3.2018-elem-mrs-referenceSystemIdentifier-c940c3e9ba051b44e2041d768ac777c8} + +Name + +: + +> mrs:referenceSystemIdentifier + +Description + +: + +```{=html} +Name of reference system +``` + +Condition + +: + +> conditional + +``` xml + + + + http://www.opengis.net/def/crs/EPSG/0/3035 + + + +``` + +### Reference system type {#iso19115-3.2018-elem-mrs-referenceSystemType-9165956812eecd1c7858dd599ce31ca8} + +Name + +: + +> mrs:referenceSystemType + +Description + +: + +```{=html} +Type of reference system used Example + compoundGeographic2DParametric +``` +### Axis dimension properties {#iso19115-3.2018-elem-msr-axisDimensionProperties-073ec35418d10c4f0c137378a6134493} + +Name + +: + +> msr:axisDimensionProperties + +Description + +: + +```{=html} +Information about spatial-temporal axis properties +``` + +Condition + +: + +> mandatory + +### Cell geometry {#iso19115-3.2018-elem-msr-cellGeometry-3a6cc41f54ba7d4c75eee03be5598318} + +Name + +: + +> msr:cellGeometry + +Description + +: + +```{=html} +Identification of grid data as point or cell +``` + +Condition + +: + +> mandatory + +### Point central {#iso19115-3.2018-elem-msr-centrePoint-f92f835c824050de5f3fbf6f008870a8} + +Name + +: + +> msr:centrePoint + +Description + +: + +```{=html} +Position terrestre dans le système de coordonnées + définie par le système de références spatiales et la coordonnée dans la + grille de la cellule située à mi-chemin entre les extrémités opposées de + la grille selon les dimensions spatiales. +``` + +Condition + +: + +> optional + +### Check point availability {#iso19115-3.2018-elem-msr-checkPointAvailability-eede9501cd9cc8710550fe01f8fe1cee} + +Name + +: + +> msr:checkPointAvailability + +Description + +: + +```{=html} +Indication of whether or not geographic position + points are available to test the accuracy of the georeferenced grid data +``` + +Condition + +: + +> mandatory + +### Check point description {#iso19115-3.2018-elem-msr-checkPointDescription-226168985a0798a955267fbc21aacab4} + +Name + +: + +> msr:checkPointDescription + +Description + +: + +```{=html} +Description of geographic position points used to + test the accuracy of the georeferenced grid data +``` +### Compliance code {#iso19115-3.2018-elem-msr-complianceCode-f13f2f65f47a827bb9bbea5e092edad1} + +Name + +: + +> msr:complianceCode + +Description + +: + +```{=html} +Indication of whether or not the cited feature + catalogue complies with ISO 191109110 +``` + +Condition + +: + +> optional + +### Control point availability {#iso19115-3.2018-elem-msr-controlPointAvailability-c7d5efb26ca7e4ef90f8ad058e99ae88} + +Name + +: + +> msr:controlPointAvailability + +Description + +: + +```{=html} +Indication of whether or not control point(s) + existse existent +``` + +Condition + +: + +> mandatory + +### Corner points {#iso19115-3.2018-elem-msr-cornerPoints-3c2edbd5ef81dec63afd53ca43db0765} + +Name + +: + +> msr:cornerPoints + +Description + +: + +```{=html} +Earth location in the coordinate system defined by + the Spatial Reference System and the grid coordinate of the cells at + opposite ends of grid coverage along two diagonals in the grid spatial + dimensions NOTE There are four corner points in a georectified grid; at + least two corner points along one diagonal are required. The first corner + point corresponds to the origin of the grid.. +``` + +Condition + +: + +> optional + +### Dimension description {#iso19115-3.2018-elem-msr-dimensionDescription-069e485d9f5957e96240c0b98bc04124} + +Name + +: + +> msr:dimensionDescription + +Description + +: + +```{=html} +Description of the axis +``` + +Condition + +: + +> optional + +### Dimension name {#iso19115-3.2018-elem-msr-dimensionName-c36a4acbeab1e6196344534c31664de1} + +Name + +: + +> msr:dimensionName + +Description + +: + +```{=html} +Name of the axis +``` + +Condition + +: + +> mandatory + +### Dimension size {#iso19115-3.2018-elem-msr-dimensionSize-9f8a6d21785fddccf25ed28f463ff82c} + +Name + +: + +> msr:dimensionSize + +Description + +: + +```{=html} +Number of elements along the axis +``` + +Condition + +: + +> mandatory + +### Dimension title {#iso19115-3.2018-elem-msr-dimensionTitle-cfbbd35244998db6fedc70383d0b1a4f} + +Name + +: + +> msr:dimensionTitle + +Description + +: + +```{=html} +enhancement/modifier of the dimension name. EXAMPLE + dimensionName = “column” dimensionTitle = “Longitude” +``` + +Condition + +: + +> optional + +### Feature catalogue citation {#iso19115-3.2018-elem-msr-featureCatalogueCitation-86dcf88571deb3bc83ffd96f17063b0c} + +Name + +: + +> msr:featureCatalogueCitation + +Description + +: + +```{=html} +complete bibliographic reference to one or more + external feature catalogues +``` +### Feature types {#iso19115-3.2018-elem-msr-featureTypes-4eff89188c1d3db76667047f6cf6badc} + +Name + +: + +> msr:featureTypes + +Description + +: + +```{=html} +Subset of feature types from cited feature catalogue + occurring in resource and count of feature instances +``` + +Condition + +: + +> optional + +### Geometric object count {#iso19115-3.2018-elem-msr-geometricObjectCount-c1286bf556b766a23d0f4f8dc8876b1b} + +Name + +: + +> msr:geometricObjectCount + +Description + +: + +```{=html} +Total number of the point or vector object type + occurring in the dataset +``` + +Condition + +: + +> optional + +### Geometric objects {#iso19115-3.2018-elem-msr-geometricObjects-a372c8a09516b77dbe0b8670c1022008} + +Name + +: + +> msr:geometricObjects + +Description + +: + +```{=html} +Information about the geometric objects used in the + resource +``` + +Condition + +: + +> optional + +### Geometric object type {#iso19115-3.2018-elem-msr-geometricObjectType-c9165f96bf9fa94f81beca9336981531} + +Name + +: + +> msr:geometricObjectType + +Description + +: + +```{=html} +Name of point or vector objects used to locate + zero-, one-, two-, or three-dimensional spatial locations in the resource +``` + +Condition + +: + +> mandatory + +### Georeferenced parameters {#iso19115-3.2018-elem-msr-georeferencedParameters-c9d8550ed978763e23072bb01554fefa} + +Name + +: + +> msr:georeferencedParameters + +Description + +: + +```{=html} +Terms which support grid data georeferencing +``` + +Condition + +: + +> mandatory + +### Included with dataset {#iso19115-3.2018-elem-msr-includedWithDataset-595a7c08cab2d676de4bdce06cbac54e} + +Name + +: + +> msr:includedWithDataset + +Description + +: + +```{=html} +Indication of whether or not the feature catalogue + is included with the resource +``` + +Condition + +: + +> optional + +### Locale {#iso19115-3.2018-elem-msr-locale-f20a8851d10c4ed34e8953c641b28abd} + +Name + +: + +> msr:locale + +Description + +: + +```{=html} +Language(s) and character set(s) used within the + catalogue +``` + +Condition + +: + +> optional + +### ContentInformation {#iso19115-3.2018-elem-msr-MD_ContentInformation-dc1f6d0dc9b01792c811602b6b31fd6d} + +Name + +: + +> msr:MD_ContentInformation + +Description + +: + +```{=html} +description of the content of a resource +``` +### Dimension {#iso19115-3.2018-elem-msr-MD_Dimension-87ab48f712228b93b6951a4260df02c6} + +Name + +: + +> msr:MD_Dimension + +Description + +: + +```{=html} +Axis properties +``` +### Name {#iso19115-3.2018-elem-msr-MD_DimensionNameTypeCode-37d039177e852fd253d6c21c02fe5ae7} + +Name + +: + +> msr:MD_DimensionNameTypeCode + +Description + +: + +### Standard codelists Name (msr:MD_DimensionNameTypeCode) + +| code | label | description | +|------------|-------------|------------------------------------------------------------| +| row | Row | Ordinate (y) axis | +| column | Column | Abscissa (x) axis | +| vertical | Vertical | Vertical (z) axis | +| track | Track | Along the direction of motion of the scan point | +| crossTrack | Cross track | Perpendicular to the direction of motion of the scan point | +| line | Line | Scan line of a sensor | +| sample | Sample | Element along a scan line | +| time | Time | Duration | + +### Feature catalogue description {#iso19115-3.2018-elem-msr-MD_FeatureCatalogueDescription-19307415e31a221cf4c2a6153a0eb8b8} + +Name + +: + +> msr:MD_FeatureCatalogueDescription + +Description + +: + +```{=html} +Information identifying the feature catalogue or the + conceptual schema +``` +### Geometric objects {#iso19115-3.2018-elem-msr-MD_GeometricObjects-75921e796523b0c5e9e75e059ce2373d} + +Name + +: + +> msr:MD_GeometricObjects + +Description + +: + +```{=html} +Number of objects, listed by geometric object type, + used in the resource +``` +### Georectified {#iso19115-3.2018-elem-msr-MD_Georectified-cb54f6a4733d966162a4d43f454cd92b} + +Name + +: + +> msr:MD_Georectified + +Description + +: + +```{=html} +Grid whose cells are regularly spaced in a + geographic (i.e., lat / long) or map coordinate system defined in the + Spatial Referencing System (SRS) so that any cell in the grid can be + geolocated given its grid coordinate and the grid origin, cell spacing, + and orientation +``` +### Georeferenceable {#iso19115-3.2018-elem-msr-MD_Georeferenceable-858db82597d26c7495c70c557fae1a4a} + +Name + +: + +> msr:MD_Georeferenceable + +Description + +: + +```{=html} +Grid with cells irregularly spaced in any given + geographic/map projection coordinate system, whose individual cells can be + eolocated using geolocation information supplied with the data but cannot + be geolocated from the grid properties alone +``` +### Grid spatial representation {#iso19115-3.2018-elem-msr-MD_GridSpatialRepresentation-a05d8ac70cdbde9496a5c63a5dc94f3d} + +Name + +: + +> msr:MD_GridSpatialRepresentation + +Description + +: + +```{=html} +Information about grid spatial objects in the + resource +``` +### Pixel orientation code {#iso19115-3.2018-elem-msr-MD_PixelOrientationCode-70d12e70676ab7a22eaf4b94d24fdc11} + +Name + +: + +> msr:MD_PixelOrientationCode + +Description + +: + +```{=html} +Point in a pixel corresponding to the Earth location of the + pixel +``` +### Standard codelists Pixel orientation code (msr:MD_PixelOrientationCode) + +| code | label | description | +|------------|-------------|----------------------------------------------------------------------------------------------------------------------------------------------| +| center | Center | Point halfway between the lower left and the upper right of the pixel | +| lowerLeft | Lower left | The corner in the pixel closest to the origin of the SRS; if two are at the same distance from the origin, the one with the smallest x-value | +| lowerRight | Lower right | Next corner counterclockwise from the lower left | +| upperRight | Upper right | Next corner counterclockwise from the lower right | +| upperLeft | Upper left | Next corner counterclockwise from the upper right | + +### Reference system {#iso19115-3.2018-elem-msr-MD_ReferenceSystem-050bc2ad30ca0aa0877ac3c39ead49a6} + +Name + +: + +> msr:MD_ReferenceSystem + +Description + +: + +```{=html} +Information about the reference system +``` +### Vector spatial sepresentation {#iso19115-3.2018-elem-msr-MD_VectorSpatialRepresentation-995972e18071d37f9476492d224d6186} + +Name + +: + +> msr:MD_VectorSpatialRepresentation + +Description + +: + +```{=html} +Information about the vector spatial objects in the + resource +``` +### Number of dimensions {#iso19115-3.2018-elem-msr-numberOfDimensions-e13eac032aba12c4d1306effd633cd91} + +Name + +: + +> msr:numberOfDimensions + +Description + +: + +```{=html} +Number of independent spatial-temporal axes +``` + +Condition + +: + +> mandatory + +### Orientation parameter availability {#iso19115-3.2018-elem-msr-orientationParameterAvailability-69856b25d667d8d93e60b54298dc7321} + +Name + +: + +> msr:orientationParameterAvailability + +Description + +: + +```{=html} +Indication of whether or not orientation parameters + are available +``` + +Condition + +: + +> mandatory + +### Orientation parameter description {#iso19115-3.2018-elem-msr-orientationParameterDescription-73c93e809e439a9e74b59660193a9e5b} + +Name + +: + +> msr:orientationParameterDescription + +Description + +: + +```{=html} +Description of parameters used to describe sensor + orientation +``` + +Condition + +: + +> optional + +### Parameter citation {#iso19115-3.2018-elem-msr-parameterCitation-f73ae3a2b90e81efc9580944ce22b2ac} + +Name + +: + +> msr:parameterCitation + +Description + +: + +```{=html} +reference providing description of the parameters +``` + +Condition + +: + +> optional + +### Point in pixel {#iso19115-3.2018-elem-msr-pointInPixel-0af6deb11128e3f4a2ff8b0977992bfa} + +Name + +: + +> msr:pointInPixel + +Description + +: + +```{=html} +earth location in the coordinate system defined by + the Spatial Reference System and the grid coordinate of the cell halfway + between opposite ends of the grid in the spatial dimensions +``` + +Condition + +: + +> mandatory + +### Reference system identifier {#iso19115-3.2018-elem-msr-referenceSystemIdentifier-09e68463a6d485661dea8c8ee60f200c} + +Name + +: + +> msr:referenceSystemIdentifier + +Description + +: + +```{=html} +identifier and codespace for reference system.: NOTE + Refer to SC_CRS in ISO 19111 and ISO 19111-2 when coordinate reference + system information is not given through reference system identifier. + EXAMPLE EPSG::4326 +``` + +Condition + +: + +> optional + +### Reference system type {#iso19115-3.2018-elem-msr-referenceSystemType-ceb046628f892e9275b16576075da590} + +Name + +: + +> msr:referenceSystemType + +Description + +: + +```{=html} +Type of reference system used. EXAMPLE + compoundGeographic2DParametric +``` + +Condition + +: + +> optional + +### Resolution {#iso19115-3.2018-elem-msr-resolution-8c31d92119d27e90a500ba143ebba523} + +Name + +: + +> msr:resolution + +Description + +: + +```{=html} +Degree of detail in the grid dataset +``` + +Condition + +: + +> optional + +Recommended values + +| code | label | +|------|---------| +| 1 | seconds | +| 1 | minutes | +| 1 | hours | +| 1 | days | +| 1 | months | +| 1 | years | + +### Scope {#iso19115-3.2018-elem-msr-scope-09241cd1dbd4fe44de5bfc2286fbf809} + +Name + +: + +> msr:scope + +Description + +: + +### Topology level {#iso19115-3.2018-elem-msr-topologyLevel-be67871bdfef340e4c64d23ce720309f} + +Name + +: + +> msr:topologyLevel + +Description + +: + +```{=html} +Code which identifies the degree of complexity of + the spatial relationships +``` + +Condition + +: + +> optional + +### Transformation dimension description {#iso19115-3.2018-elem-msr-transformationDimensionDescription-d8267d48e06a28d23995f4d15632df06} + +Name + +: + +> msr:transformationDimensionDescription + +Description + +: + +```{=html} +General description of the transformation +``` + +Condition + +: + +> optional + +### Transformation dimension mapping {#iso19115-3.2018-elem-msr-transformationDimensionMapping-096dd7aa9d987551a7fc05916ab175e5} + +Name + +: + +> msr:transformationDimensionMapping + +Description + +: + +```{=html} +information about which grid axes are the spatial + (map) axes +``` + +Condition + +: + +> optional + +### Transformation parameter availability {#iso19115-3.2018-elem-msr-transformationParameterAvailability-6b1938c019c8c19dfd766adb28ac8ad2} + +Name + +: + +> msr:transformationParameterAvailability + +Description + +: + +```{=html} +Indication of whether or not parameters for + transformation between image coordinates and geographic or map coordinates + exist (are available) +``` + +Condition + +: + +> mandatory + +### Owns {#iso19115-3.2018-elem-owns-07532653d8de43dc6b0895600811d193} + +Name + +: + +> owns + +Description + +: + +### Radix {#iso19115-3.2018-elem-radix-d838eab62c3144df803ddaa55d6095bc} + +Name + +: + +> radix + +Description + +: + +### Amendment Type {#iso19115-3.2018-elem-reg-RE_AmendmentType-bc6ddbef5ca2d044bee06fd1e05fb752} + +Name + +: + +> reg:RE_AmendmentType + +Description + +: + +### Standard codelists Amendment Type (reg:RE_AmendmentType) + +| code | label | description | +|-------------------------|-------------------------|-------------| +| supersession retirement | Supersession Retirement | | + +### Decision status {#iso19115-3.2018-elem-reg-RE_DecisionStatus-66fa1c01ac218aa9877e8385d9191958} + +Name + +: + +> reg:RE_DecisionStatus + +Description + +: + +### Standard codelists Decision status (reg:RE_DecisionStatus) + +| code | label | description | +|-------------------------|-------------------------|-------------| +| pending tentative final | Pending Tentative Final | | + +### Disposition {#iso19115-3.2018-elem-reg-RE_Disposition-a0b74f296840fca012ef83c90e5652f1} + +Name + +: + +> reg:RE_Disposition + +Description + +: + +### Standard codelists Disposition (reg:RE_Disposition) + +| code | label | description | +|--------------------------------|---------------------------------|-------------| +| withdrawn accepted notAccepted | Withdrawn Accepted Not Accepted | | + +### Item status {#iso19115-3.2018-elem-reg-RE_ItemStatus-89ad94dd47ec1c6aee8e600828b872d9} + +Name + +: + +> reg:RE_ItemStatus + +Description + +: + +### Standard codelists Item status (reg:RE_ItemStatus) + +| code | label | description | +|-----------------------------------|------------------------------------|-------------| +| notValid valid superseded retired | Not Valid Valid Superseded Retired | | + +### Relative position {#iso19115-3.2018-elem-relativePosition-9b7022d59a1a04be5c97e5183ed0dad1} + +Name + +: + +> relativePosition + +Description + +: + +### Source URL {#iso19115-3.2018-elem-src-3f3e4b17ba622503c28a6c57e4bf00ed} + +Name + +: + +> src + +Description + +: + +```{=html} +URL of the document. +``` +### Access Properties {#iso19115-3.2018-elem-srv-accessProperties-1dcd3beb74b9676cd785381643761876} + +Name + +: + +> srv:accessProperties + +Description + +: + +```{=html} +Information about the availability of the service eg. fees, + availability, + oredering instructions +``` +### Connect Point {#iso19115-3.2018-elem-srv-connectPoint-7c5cf627952a324e2bfe7d4b61a8ad43} + +Name + +: + +> srv:connectPoint + +Description + +: + +```{=html} +Handle for accessing the service interface +``` +### Contains chain {#iso19115-3.2018-elem-srv-containsChain-27a1d0df5e650777f8e743e2f2467942} + +Name + +: + +> srv:containsChain + +Description + +: + +```{=html} +Provide information about the chain applied by the service +``` +### Contains Operations {#iso19115-3.2018-elem-srv-containsOperations-2eecc0ef056aa77980cf2310cbbf0c61} + +Name + +: + +> srv:containsOperations + +Description + +: + +```{=html} +Provides information about the operations that comprise the + service +``` +### Coupled Resource {#iso19115-3.2018-elem-srv-coupledResource-100ccf0b66cb2f607621adb7e3fc9faa} + +Name + +: + +> srv:coupledResource + +Description + +: + +```{=html} +Details of services coupled with this one +``` +### Coupling Type {#iso19115-3.2018-elem-srv-couplingType-d0122b98967eda4ad7f6dc04f2696288} + +Name + +: + +> srv:couplingType + +Description + +: + +```{=html} +Type of Coupling +``` +### Distributed Computing Platforms {#iso19115-3.2018-elem-srv-DCP-998f113aa8f9c2233a5eaabf47816383} + +Name + +: + +> srv:DCP + +Description + +: + +```{=html} +Distributed computing platforms on which the operation has been + implemented +``` +### Distributed Computing Platforms list {#iso19115-3.2018-elem-srv-DCPList-c62e5d011b03b39b745537e308630f03} + +Name + +: + +> srv:DCPList + +Description + +: + +### Standard codelists Distributed Computing Platforms list (srv:DCPList) + ++-------------+-------------+--------------------+ +| code | label | description | ++=============+=============+====================+ +| XML | XML | DCP is XML | ++-------------+-------------+--------------------+ +| CORBA | CORBA | DCP is CORBA | ++-------------+-------------+--------------------+ +| JAVA | JAVA | DCP is JAVA | ++-------------+-------------+--------------------+ +| COM | COM | DCP is COM | ++-------------+-------------+--------------------+ +| SQL | DCP is SQL | > SQL | ++-------------+-------------+--------------------+ +| SOAP | SOAP | DCP is SOAP | ++-------------+-------------+--------------------+ +| Z3950 | Z3950 | DCP is Z3950 | ++-------------+-------------+--------------------+ +| HTTP | HTTP | DCP is HTTP | ++-------------+-------------+--------------------+ +| FTP | FTP | DCP is FTP | ++-------------+-------------+--------------------+ +| WebServices | WebServices | DCP is WebServices | ++-------------+-------------+--------------------+ + +### Depends On {#iso19115-3.2018-elem-srv-dependsOn-1332fa3f646ce374f71ce340e90a89c8} + +Name + +: + +> srv:dependsOn + +Description + +: + +```{=html} +List of operations that must be completed immediately before + current operation + is invoked, structured as a list for capturing alternate predecessor paths + and sets for + capturing parallel predecessor paths +``` +### Description {#iso19115-3.2018-elem-srv-description-89c6b5fc52f0f104cffb29ff89a72125} + +Name + +: + +> srv:description + +Description + +: + +```{=html} +Narrative explanation of the services in the chain and + resulting output or role + of the parameter +``` +### Direction {#iso19115-3.2018-elem-srv-direction-56def65b903590f672385be14b20d5fd} + +Name + +: + +> srv:direction + +Description + +: + +### Distributed computing platform (DCP) {#iso19115-3.2018-elem-srv-distributedComputingPlatform-2d5874d202fafb73f06538a78607a586} + +Name + +: + +> srv:distributedComputingPlatform + +Description + +: + +```{=html} +DCP on which the operation has been implemented +``` +### Identifier {#iso19115-3.2018-elem-srv-identifier-cb2268470326162da9519dae784ee639} + +Name + +: + +> srv:identifier + +Description + +: + +```{=html} +Identifier of resource to which the operation applies +``` +### Invocation Name {#iso19115-3.2018-elem-srv-invocationName-f632c6f1011da90346f900f7839a33a8} + +Name + +: + +> srv:invocationName + +Description + +: + +```{=html} +The name used to invoke this interface within the context of + the DCP. The name + is identical for all DCPs +``` +### Keywords {#iso19115-3.2018-elem-srv-keywords-cb9fb095a7a8472109439348ed146d7f} + +Name + +: + +> srv:keywords + +Description + +: + +```{=html} +Keywords describing service +``` +### Name {#iso19115-3.2018-elem-srv-name-8213033a4a5d36c4b7a7a21e51058844} + +Name + +: + +> srv:name + +Description + +: + +```{=html} +The name, as used by the service for this chain or parameter +``` +### Operated dataset {#iso19115-3.2018-elem-srv-operatedDataset-feeb6f24e1ef2b2c5f23d1aaaa1ac0d1} + +Name + +: + +> srv:operatedDataset + +Description + +: + +```{=html} +Provides a reference to the resource on which the service operates. Note: For one resource either operated dataset or operates on may be used (not both). +``` +### Operates On {#iso19115-3.2018-elem-srv-operatesOn-2690cd62eaa299d9d24d44103a7c6f1d} + +Name + +: + +> srv:operatesOn + +Description + +: + +```{=html} +Provides information on the datasets that the service operates + on +``` +### Operation Description {#iso19115-3.2018-elem-srv-operationDescription-4bf280cc494e9e2d0ccbbcc1e6213185} + +Name + +: + +> srv:operationDescription + +Description + +: + +```{=html} +Free text description of the intent of the operation and the + results of the + operation +``` +### Operation Name {#iso19115-3.2018-elem-srv-operationName-ae64b692aa02e2fccc8081aae5d6fd08} + +Name + +: + +> srv:operationName + +Description + +: + +```{=html} +A unique identifier for this interface +``` +### Optionality {#iso19115-3.2018-elem-srv-optionality-62aca8e868833c95f16a1c5d9fc41ce8} + +Name + +: + +> srv:optionality + +Description + +: + +```{=html} +Indication if the parameter is required +``` +### Parameter {#iso19115-3.2018-elem-srv-parameter-efeaa89fa390b7c869522baf94cb3421} + +Name + +: + +> srv:parameter + +Description + +: + +### Parameters {#iso19115-3.2018-elem-srv-parameters-2b38d36e3a0bef6c49fff8b983deb47e} + +Name + +: + +> srv:parameters + +Description + +: + +```{=html} +The parameters that are required for this interface +``` +### Profile {#iso19115-3.2018-elem-srv-profile-8a095529da8795ed9becd1b15d1cdb6d} + +Name + +: + +> srv:profile + +Description + +: + +```{=html} +Profile to which the service adheres +``` +### Provider Name {#iso19115-3.2018-elem-srv-providerName-30341d7e33c9b0622f5fe1c7e33bf449} + +Name + +: + +> srv:providerName + +Description + +: + +```{=html} +A unique identifier for this organization +``` +### Repeatability {#iso19115-3.2018-elem-srv-repeatability-88dc3b9d192faab07e37d1aaf1b98440} + +Name + +: + +> srv:repeatability + +Description + +: + +```{=html} +Indication if more than one value of the parameter may be + provided +``` +### Restrictions {#iso19115-3.2018-elem-srv-restrictions-640e586d60c54c786ca65fa870eb7e46} + +Name + +: + +> srv:restrictions + +Description + +: + +```{=html} +Legal and security constraints on accessing the service and + distributing data + generated by the service +``` +### Service Contact {#iso19115-3.2018-elem-srv-serviceContact-ec85c67af1aecbd4739b76567523edb1} + +Name + +: + +> srv:serviceContact + +Description + +: + +```{=html} +Information for contacting the service provider +``` +### Service standard {#iso19115-3.2018-elem-srv-serviceStandard-97e92f2223295fea76badfd3355952c9} + +Name + +: + +> srv:serviceStandard + +Description + +: + +```{=html} +Standard to which the service adheres +``` +### Service Type {#iso19115-3.2018-elem-srv-serviceType-2234736c4656254dd3186e40b24d9acf} + +Name + +: + +> srv:serviceType + +Description + +: + +```{=html} +Service type name from a registry of services. For example, the + values of the + nameSpace and name attributes of GeneralName may be 'OGC' and 'catalogue' +``` +Recommended values + +| code | label | +|-----------|----------------------------| +| OGC:WMS | OGC Web Map Service | +| OGC:WMTS | OGC Web Map Tile Service | +| OGC:WFS | OGC Web Feature Service | +| OGC:WCS | OGC Web Coverage Service | +| OGC:WPS | OGC Web Processing Service | +| atom:feed | ATOM feed | + +### Service Version {#iso19115-3.2018-elem-srv-serviceTypeVersion-d13d77b6c3c1085c84121099f3e977b9} + +Name + +: + +> srv:serviceTypeVersion + +Description + +: + +```{=html} +Provides for searching based on the version of serviceType. For + example, we may + only be interested in OGC Catalogue V1.1 services. If version is + maintained as a + separate attribute, users can easily search for all services of a type + regardless of the + version +``` +### Coupled Resource {#iso19115-3.2018-elem-srv-SV_CoupledResource-58b1bb08fb2ff8e0c70e6ee5f9b5a151} + +Name + +: + +> srv:SV_CoupledResource + +Description + +: + +```{=html} +Details of services coupled with this one +``` +### Operation {#iso19115-3.2018-elem-srv-SV_OperationMetadata-3267aa3513feb299599031dd1cf78c96} + +Name + +: + +> srv:SV_OperationMetadata + +Description + +: + +```{=html} +Operation Metadata +``` +### Parameter {#iso19115-3.2018-elem-srv-SV_Parameter-6f238c83d2a447d7ff4fc3f2e7af0e88} + +Name + +: + +> srv:SV_Parameter + +Description + +: + +```{=html} +The parameters that are required for this interface +``` +### Parameter direction {#iso19115-3.2018-elem-srv-SV_ParameterDirection-7bd1f85c0b44fa0fee670d93cc089089} + +Name + +: + +> srv:SV_ParameterDirection + +Description + +: + +### Standard codelists Parameter direction (srv:SV_ParameterDirection) + +| code | label | description | +|--------|--------------|-----------------------------------------------------------------------------| +| in | Input | The parameter is an input parameter to the service instance | +| out | Output | The parameter is an output parameter to the service instance | +| in/out | Input/output | The parameter is both an input and output parameter to the service instance | + +### Service Identification {#iso19115-3.2018-elem-srv-SV_ServiceIdentification-fc7ece2ea3d136f031fb0392e774dee6} + +Name + +: + +> srv:SV_ServiceIdentification + +Description + +: + +```{=html} +Service identification section +``` +### Value type {#iso19115-3.2018-elem-srv-valueType-e15acf0ffbb059ee6c8bd9516d8d4b0c} + +Name + +: + +> srv:valueType + +Description + +: + +### Unit {#iso19115-3.2018-elem-unit-272387d5556a648743e54ae5e2dba3af} + +Name + +: + +> unit + +Description + +: + +### Units of measure {#iso19115-3.2018-elem-uom-e10669ccd649478676b9c5fafba3f843} + +Name + +: + +> uom + +Description + +: + +Recommended values + +| code | label | +|------|--------| +| m | meters | + +### Metadata uuid {#iso19115-3.2018-elem-uuidref-11480fcd74a341f26892dff0229f85c3} + +Name + +: + +> uuidref + +Description + +: + +```{=html} +Unique identifier +``` +### Link href {#iso19115-3.2018-elem-xlink-href-3546192ce8d22ae0019a3b6c851328e5} + +Name + +: + +> xlink:href + +Description + +: + +```{=html} +Supplies the data that allows an XLink application to find a + remote resource (or resource fragment) [W3C XLINK] +``` +### Type of link {#iso19115-3.2018-elem-xlink-type-bb34ecc5adb016fbd170f488e20511ca} + +Name + +: + +> xlink:type + +Description + +: + +### Nil {#iso19115-3.2018-elem-xsi-nil-6e33165974e6ce03896d82c4465e9a29} + +Name + +: + +> xsi:nil + +Description + +: + +```{=html} +Indicates that a certain element does not have a value or that the value is unknown. +``` +## Standard codelists + +List of all codelists available in the standard. + +### Standard codelists (cit:CI_TelephoneTypeCode) {#iso19115-3.2018-cl-cit-CI_TelephoneTypeCode} + +| code | label | description | +|------------|-----------|--------------------------------------| +| voice | Voice | Telephone provides voice service | +| facsimilie | Facsimile | Telephone provides facsimile service | +| sms | SMS | Telephone provides sms service | + +### Standard codelists (cit:CI_DateTypeCode) {#iso19115-3.2018-cl-cit-CI_DateTypeCode} + +| code | label | description | +|-----------------|------------------|---------------------------------------------------------------------------------------| +| creation | Creation | Date identifies when the resource was brought into existence | +| publication | Publication | Date identifies when the resource was issued | +| revision | Revision | Date identifies when the resource was examined or re-examined and improved or amended | +| expiry | Expiry | Date identifies when the resource expires | +| lastUpdate | Last Update | Date identifies when the resource was last updated | +| lastRevision | Last Revision | Date identifies when the resource was last reviewed | +| nextUpdate | Next Update | Date identifies when the resource will be next updated | +| unavailable | Unavailable | Date identifies when the resource became not available or obtainable | +| inForce | In Force | Date identifies when the resource became in force | +| adopted | Adopted | Date identifies when the resource was adopted | +| deprecated | Deprecated | Date identifies when the resource was deprecated | +| superseded | Superseded | Date identifies when the resource was superseded or replaced by another resource | +| validityBegins | Validity Begins | Date identifies when the resource is considered to be valid | +| validityExpires | Validity Expires | Date identifies when the resource is no longer considered to be valid | +| released | Released | Date identifies when the resource shall be released for public access | +| distribution | Distribution | Date identifies when an instance of the resource was distributed | + +### Standard codelists (cit:CI_OnLineFunctionCode) {#iso19115-3.2018-cl-cit-CI_OnLineFunctionCode} + +| code | label | description | +|----------------------|---------------------------------------------------|----------------------------------------------------------------------------------------| +| download | Download | Online instructions for transferring data from one storage device or system to another | +| information | Information | Online information about the resource | +| offlineAccess | Offline access | Online instructions for requesting the resource from the provider | +| order | Order | Online order process for obtening the resource | +| search | Search | Online search interface for seeking out information about the resource | +| completeMetadata doi | Complete Metadata Digital Object Identifier (DOI) | Complete metadata provided | +| browseGraphic | Browse Graphic | Browse Graphic provided | +| upload | Upload | Upload service provided | +| emailService | Email Service | Email service provided | +| browsing | Browsing | Online browsing provided | +| fileAccess | Access File | Online file access provided | + +### Standard codelists (cit:CI_PresentationFormCode) {#iso19115-3.2018-cl-cit-CI_PresentationFormCode} + +| code | label | description | +|--------------------|---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| documentDigital | Digital document | Digital representation of a primarily textual item (can contain illustrations also) | +| imageDigital | Digital image | Likeness of natural or man-made features, objects, and activities acquired through the sensing of visual or any other segment of the electromagnetic spectrum by sensors, such as thermal infrared, and high resolution radar and stored in digital format | +| documentHardcopy | Hardcopy document | Representation of a primarily textual item (can contain illustrations also) on paper, photographic material, or other media | +| imageHardcopy | Hardcopy image | Likeness of natural or man-made features, objects, and activities acquired through the sensing of visual or any other segment of the electromagnetic spectrum by sensors, such as thermal infrared, and high resolution radar and reproduced on paper, photographic material, or other media for use directly by the human user | +| mapDigital | Digital map | Map represented in raster or vector form | +| mapHardcopy | Hardcopy map | Map printed on paper, photographic material, or other media for use directly by the human user | +| modelDigital | Digital model | Multi-dimensional digital representation of a feature, process, etc. | +| modelHardcopy | Hardcopy model | 3-dimensional, physical model | +| profileDigital | Digital profile | Vertical cross-section in digital form | +| profileHardcopy | Hardcopy profile | Vertical cross-section printed on paper, etc. | +| tableDigital | Digital table | Digital representation of facts or figures systematically displayed, especially in columns | +| tableHardcopy | Hardcopy table | Representation of facts or figures systematically displayed, especially in columns, printed onpapers, photographic material, or other media | +| videoDigital | Digital video | Digital video recording | +| videoHardcopy | Hardcopy video | Video recording on film | +| audioDigital | Digital audio | Digital audio recording | +| audioHardcopy | Hardcopy audio | Audio recording delivered by analog media, such as magnetic tape | +| multimediaDigital | Multimedia digital | Information representation using simultaneously various digital modes for text, sound and image | +| multimediaHardcopy | Multimedia hardcopy | Information representation using simultaneously various analog modes for text, sound and image | +| physicalObject | Physical object | A physical object eg. rock or mineral sample, microscope slide | +| diagramDigital | Digital diagram | Information represented graphically by charts such as pie chart, bar chart and other type of diagrams and recorded in digital format | +| diagramHardcopy | Hardcopy diagram | Information represented graphically by charts such as pie chart, bar chart and other type of diagrams and printed on paper, photographic material, or other media | + +### Standard codelists Role code (cit:CI_RoleCode) {#iso19115-3.2018-cl-cit-CI_RoleCode} + +| code | label | description | +|-----------------------|------------------------|--------------------------------------------------------------------------------------------------------------------------------| +| resourceProvider | Resource provider | Party that supplies the resource | +| custodian | Custodian | Party that accepts accountability and responsibility for the data and ensures appropriate care and maintenance of the resource | +| owner | Owner | Party that owns the resource | +| user | User | Party who uses the resource | +| distributor | Distributor | Party who distributes the resource | +| originator | Originator | Party who created the resource | +| pointOfContact | Point of contact | Party who can be contacted for acquiring knowledge about or acquisition of the resource | +| principalInvestigator | Principal investigator | Key party responsible for gathering information and conducting research | +| processor | Processor | Party that has processed the data in a manner such that the resource has been modified | +| publisher | Publisher | Party who published the resource | +| author | Author | Party who authored the resource | +| sponsor | Sponsor | Party who speaks for the resource | +| coAuthor | Co-author | Party who jointly authors the resource | +| collaborator | Collaborator | Party who assists with the generation of the resource other than the principal investigator | +| editor | Editor | Party who reviewed or modified the resource to improve the content | +| mediator | Mediator | A class of entity that mediates access to the resource and for whom the resource is intended or useful | +| rightsHolder | Rights holder | Party owning or managing rights over the resource | +| contributor | Contributor | Party contributing to the resource | +| funder | Funder | Party providing monetary support for the resource | +| stakeholder | Stakeholder | Party who has an interest in the resource or the use of the resource | + +### Standard codelists (mdq:DQ_EvaluationMethodTypeCode) {#iso19115-3.2018-cl-mdq-DQ_EvaluationMethodTypeCode} + +| code | label | description | +|----------------|-----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| directInternal | Direct internal | Method of evaluating the quality of a dataset based on inspection of items within the dataset, where all data required is internal to the dataset being evaluated | +| directExternal | Direct external | Method of evaluating the quality of a dataset based on inspection of items within the dataset, where reference data external to the dataset being evaluated is required | +| indirect | Indirect | Method of evaluating the quality of a dataset based on external knowledge | + +### Standard codelists (mri:DS_AssociationTypeCode) {#iso19115-3.2018-cl-mri-DS_AssociationTypeCode} + +| code | label | description | +|------------------------|---------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| crossReference | Cross reference | Reference from one dataset to another | +| largerWorkCitation | Larger work citation | Reference to a master dataset of which this one is a part | +| partOfSeamlessDatabase | Part of seamless database | Part of the same structured set of data held in a computer | +| stereoMate | Stereo mate | Part of a set of imagery that when used together, provides three-dimensional images | +| isComposedOf | Is composed of | Reference to resources that are parts of this resource | +| collectiveTitle | Collective Title | Common title for a collection of resources. NOTE Title identifies elements of a series collectively, combined with information about what volumes are available at the source cite | +| series | Series | Associated through a common heritage such as produced to a common product specification | +| dependency | Dependency | Associated through a dependency | +| revisionOf | Revision Of | Resource is a revision of associated resource | + +### Standard codelists (mri:DS_InitiativeTypeCode) {#iso19115-3.2018-cl-mri-DS_InitiativeTypeCode} + +| code | label | description | +|---------------|---------------|-------------------------------------------------------------| +| campaign | Campaign | Series of organized planned actions | +| collection | Collection | Accumulation of datasets assembled for a specific purpose | +| exercise | Exercise | Specific performance of a function or group of functions | +| experiment | Experiment | Process designed to find if something is effective or valid | +| investigation | Investigation | Search or systematic inquiry | +| mission | Mission | Specific operation of a data collection system | +| sensor | Sensor | Device or piece of equipment which detects or records | +| operation | Operation | Action that is part of a series of actions | +| platform | Platform | Vehicle or other support base that holds a sensor | +| process | Process | Method of doing something involving a number of steps | +| program | Program | Specific planned activity | +| project | Project | Organized undertaking, research, or development | +| study | Study | Examination or investigation | +| task | Task | Piece of work | +| trial | Trial | Process of testing to discover or demonstrate something | + +### Standard codelists Role type (gfc:FC_RoleType) {#iso19115-3.2018-cl-gfc-FC_RoleType} + +| code | label | description | +|-------------|-------------|------------------------------------------| +| ordinary | Ordinary | Indicates an ordinary association. | +| aggregation | Aggregation | Indicates a UML aggregation (part role). | +| composition | Composition | Indicates a UML composition (part role). | + +### Standard codelists (mco:MD_ClassificationCode) {#iso19115-3.2018-cl-mco-MD_ClassificationCode} + +| code | label | description | +|---------------------|----------------------------|-----------------------------------------------------------------------------------------------------------| +| unclassified | Unclassified | Available for general disclosure | +| restricted | Restricted | Not for general disclosure | +| confidential | Confidential | Available for someone who can be entrusted with information | +| secret | Secret | Kept or meant to be kept private, unknown, or hidden from all but a select group of people | +| topSecret | Top secret | Of the highest secrecy | +| SBU | Sensitive But Unclassified | Although unclassified, requires strict controls over its distribution | +| forOfficialUseOnly | For Official Use Only | Unclassified information that is to be used only for official purposes determined by the designating body | +| protected | Protected | Compromise of the information could cause damage | +| limitedDistribution | Limited Distribution | Dissemination limited by designating body | + +### Standard codelists Coverage content (mrc:MD_CoverageContentTypeCode) {#iso19115-3.2018-cl-mrc-MD_CoverageContentTypeCode} + +| code | label | description | +|------------------------|-------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| image | Image | Meaningful numerical representation of a physical parameter that is not the actual value of the physical parameter | +| thematicClassification | Thematic classification | Code value with no quantitative meaning, used to represent a physical quantity | +| physicalMeasurement | Physical measurement | Value in physical units of the quantity being measured | +| auxillaryInformation | Auxillary Information | Data, usually a physical measurement, used to support the calculation of the primary physicalMeasurement coverages in the dataset. EXAMPLE: Grid of aerosol optical thickness used in the calculation of a sea surface temperature product | +| qualityInformation | Quality Information | Data used to characterize the quality of the physicalMeasurement coverages in the dataset. NOTE: Typically included in a gmi:QE_CoverageResult | +| referenceInformation | Reference Information | Data used to characterize the quality of the physicalMeasurement coverages in the dataset. NOTE: Typically included in a gmi:QE_CoverageResult | +| modelResult | Model Result | Resources with values that are calculated using a model rather than being observed or calculated from observations | +| coordinate | Coordinate | Data used to provide coordinate axis values | + +### Standard codelists (mex:MD_DatatypeCode) {#iso19115-3.2018-cl-mex-MD_DatatypeCode} + +| code | label | description | +|-----------------|------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| class | Class | Descriptor of a set of objects that share the same attributes, operations, methods, relationships, and behavior | +| codelist | Codelist | Descriptor of a set of objects that share the same attributes, operations, methods, relationships, and behavior | +| enumeration | Enumeration | Data type whose instances form a list of named literal values, not extendable | +| codelistElement | Codelist element | Permissible value for a codelist or enumeration | +| abstractClass | Abstract class | Class that cannot be directly instantiated | +| aggregateClass | Aggregate class | Class that is composed of classes it is connected to by an aggregate relationship | +| specifiedClass | Specified class | Subclass that may be substituted for its superclass | +| datatypeClass | Datatype class | Class with few or no operations whose primary purpose is to hold the abstract state of another class for transmittal, storage, encoding or persistent storage | +| interfaceClass | Interface class | Named set of operations that characterize the behavior of an element | +| unionClass | Union class | Class describing a selection of one of the specified types | +| metaClass | Meta class | Class whose instances are classes | +| typeClass | Type class | Class used for specification of a domain of instances (objects), together with the operations applicable to the objects. A type may have attributes and associations | +| characterString | Character string | Free text field | +| integer | Integer | Numerical field | +| association | Association | Semantic relationship between two classes that involves connections among their instances | + +### Standard codelists Name (msr:MD_DimensionNameTypeCode) {#iso19115-3.2018-cl-msr-MD_DimensionNameTypeCode} + +| code | label | description | +|------------|-------------|------------------------------------------------------------| +| row | Row | Ordinate (y) axis | +| column | Column | Abscissa (x) axis | +| vertical | Vertical | Vertical (z) axis | +| track | Track | Along the direction of motion of the scan point | +| crossTrack | Cross track | Perpendicular to the direction of motion of the scan point | +| line | Line | Scan line of a sensor | +| sample | Sample | Element along a scan line | +| time | Time | Duration | + +### Standard codelists (msr:MD_GeometricObjectTypeCode) {#iso19115-3.2018-cl-msr-MD_GeometricObjectTypeCode} + +| code | label | description | +|-----------|-----------|----------------------------------------------------------------------------------------------------------------| +| complex | Complex | Set of geometric primitives such that their boundaries can be represented as an union of other primitives | +| composite | Composite | Connected set of curves, solids or surfaces | +| curve | Curve | Bounded, 1-dimensional geometric primitive, representing the continuous image of a line | +| point | Point | Zero-dimensional geometric primitive, representing a position but not having an extent | +| solid | Solid | Bounded, connected 3-dimensional geometric primitive, representing the continuous image of a region of space | +| surface | Surface | Bounded, connected 2-dimensional geometric primitive, representing the continuous image of a region of a plane | + +### Standard codelists (mrc:MD_ImagingConditionCode) {#iso19115-3.2018-cl-mrc-MD_ImagingConditionCode} + +| code | label | description | +|--------------------|---------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| blurredImage | Blurred image | Portion of the image is blurred | +| cloud | Cloud | Portion of the image is partially obscured by cloud cover | +| degradingObliquity | Degrading obliquity | Acute angle between the plane of the ecliptic (the plane of the Earth s orbit) and the plane of the celestial equator | +| fog | Fog | Portion of the image is partially obscured by fog | +| heavySmokeOrDust | Heavy smoke or dust | Portion of the image is partially obscured by heavy smoke or dust | +| night | Night | Image was taken at night | +| rain | Rain | Image was taken during rainfall | +| semiDarkness | Semi darkness | Image was taken during semi-dark conditions -- twilight conditions | +| shadow | Shadow | Portion of the image is obscured by shadow | +| snow | Snow | Portion of the image is obscured by snow | +| terrainMasking | Terrain masking | The absence of collection data of a given point or area caused by the relative location of topographic features which obstruct the collection path between the collector(s) and the subject(s) of interest | + +### Standard codelists (mri:MD_KeywordTypeCode) {#iso19115-3.2018-cl-mri-MD_KeywordTypeCode} + +| code | label | description | +|------------------|--------------------|-----------------------------------------------------------------------------------------------------------------| +| discipline | Discipline | Keyword identifies a branch of instruction or specialized learning | +| place | Place | Keyword identifies a location | +| stratum | Stratum | Keyword identifies the layer(s) of any deposited substance | +| temporal | Temporal | Keyword identifies a time period related to the dataset | +| theme | Theme | Keyword identifies a particular subject or topic | +| dataCentre | Data centre | Keyword identifies a repository or archive that manages and distributes data | +| featureType | Feature type | Keyword identifies a resource containing or about a collection of feature instances with common characteristics | +| instrument | Instrument | Keyword identifies a device used to measure or compare physical properties | +| platform | Platform | Keyword identifies a structure upon which an instrument is mounted | +| process | Process | Keyword identifies a series of actions or natural occurrences | +| project | Project | Keyword identifies an endeavour undertaken to create or modify a product or service | +| service | Service | Keyword identifies an activity carried out by one party for the benefit of another | +| product | Product | Keyword identifies a type of product | +| subTopicCategory | Sub-Topic Category | Refinement of a topic category for the purpose of geographic data classification | +| taxon | Taxon | Keyword identifies a taxonomy of the resource | + +### Standard codelists Maintenance Frequency (mmi:MD_MaintenanceFrequencyCode) {#iso19115-3.2018-cl-mmi-MD_MaintenanceFrequencyCode} + +| code | label | description | +|-------------|--------------|----------------------------------------------------------| +| continual | Continual | Data is repeatedly and frequently updated | +| daily | Daily | Data is updated each day | +| weekly | Weekly | Data is updated on a weekly basis | +| fortnightly | Fortnightly | Data is updated every two weeks | +| monthly | Monthly | Data is updated each month | +| quarterly | Quarterly | Data is updated every three months | +| biannually | Biannually | Data is updated twice each year | +| annually | Annually | Data is updated every year | +| asNeeded | As needed | Data is updated as deemed necessary | +| irregular | Irregular | Data is updated in intervals that are uneven in duration | +| notPlanned | Not planned | There are no plans to update the data | +| unknown | Unknown | Frequency of maintenance for the data is not known | +| periodic | Periodic | Resource is updated at regular intervals | +| semimonthly | Semi-monthly | Resource updated twice monthly | +| biennially | Biennially | Resource is updated every 2 years | + +### Standard codelists (mrd:MD_MediumFormatCode) {#iso19115-3.2018-cl-mrd-MD_MediumFormatCode} + +| code | label | description | +|------------------|--------------------|------------------------------------------------------------| +| cpio | CPIO | CoPy In / Out (UNIX file format and command) | +| tar | TAR | Tape ARchive | +| highSierra | High sierra | High sierra file system | +| iso9660 | ISO9660 | Information processing volume and file structure of CD-ROM | +| iso9660RockRidge | ISO9660 Rock Ridge | Rock ridge interchange protocol (UNIX) | +| iso9660AppleHFS | ISO9660 Apple HFS | Hierarchical file system (Macintosh) | +| udf | UDF | Universal Disk Format | + +### Standard codelists (mex:MD_ObligationCode) {#iso19115-3.2018-cl-mex-MD_ObligationCode} + +| code | label | description | +|-------------|-------------|------------------------------------------------------| +| mandatory | Mandatory | Element is always required | +| optional | Optional | Element is not required | +| conditional | Conditional | Element is required when a specific condition is met | + +### Standard codelists Pixel orientation code (msr:MD_PixelOrientationCode) {#iso19115-3.2018-cl-msr-MD_PixelOrientationCode} + +| code | label | description | +|------------|-------------|----------------------------------------------------------------------------------------------------------------------------------------------| +| center | Center | Point halfway between the lower left and the upper right of the pixel | +| lowerLeft | Lower left | The corner in the pixel closest to the origin of the SRS; if two are at the same distance from the origin, the one with the smallest x-value | +| lowerRight | Lower right | Next corner counterclockwise from the lower left | +| upperRight | Upper right | Next corner counterclockwise from the lower right | +| upperLeft | Upper left | Next corner counterclockwise from the upper right | + +### Standard codelists Status (mcc:MD_ProgressCode) {#iso19115-3.2018-cl-mcc-MD_ProgressCode} + +| code | label | description | +|-------------------|--------------------|--------------------------------------------------------------------------------------| +| completed | Completed | Production of the data has been completed | +| historicalArchive | Historical archive | Data has been stored in an offline storage facility | +| obsolete | Obsolete | Data is no longer relevant | +| onGoing | On going | Data is continually being updated | +| planned | Planned | Fixed date has been established upon or by which the data will be created or updated | +| required | Required | Data needs to be generated or updated | +| underDevelopment | Under development | Data is currently in the process of being created | +| final | Final | Progress concluded and no changes will be accepted | +| pending | Pending | Committed to, but not yet addressed | +| retired | Retired | Item is no longer recommended for use. It has not been superseded by another item | +| superseded | Superseded | Replaced by new item | +| tentative | Tentative | Provisional changes likely before resource becomes final or complete | +| valid | Valid | Acceptable under specific conditions | +| accepted | Accepted | Agreed to by sponsor | +| notAccepted | Not Accepted | Rejected by sponsor | +| withdrawn | Withdrawn | Withdrawn | +| proposed | Proposed | Suggested that development needs to be undertaken | +| deprecated | Deprecated | Resource superseded and will become obsolete, use only for historical purposes | + +Those values are defined in the standard but hidden when editing. + +| code | label | description | +|-------------|--------------|-------------| +| notobsolete | Not obsolete | | + +### Standard codelists Access constraints (mco:MD_RestrictionCode) {#iso19115-3.2018-cl-mco-MD_RestrictionCode} + +| code | label | description | +|----------------------------|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| copyright | Copyright | Exclusive right to the publication, production, or sale of the rights to a literary, dramatic, musical, or artistic work, or to the use of a commercial print or label, granted by law for a specified period of time to an author, composer, artist, distributor | +| patent | Patent | Government has granted exclusive right to make, sell, use or license an invention or discovery | +| patentPending | Pending patent | Produced or sold information awaiting a patent | +| trademark | Trademark | A name, symbol, or other device identifying a product, officially registered and legally restricted to the use of the owner or manufacturer | +| license | License | Formal permission to do something | +| intellectualPropertyRights | Intellectual property rights | Rights to financial benefit from and control of distribution of non-tangible property that is a result of creativity | +| restricted | Restricted | Withheld from general circulation or disclosure | +| otherRestrictions | Other restrictions | Limitation not listed | +| unrestricted | Unrestricted | No constraints exist | +| licenceUnrestricted | Licence Unrestricted | formal permission not required to use the resource | +| licenceEndUser | Licence End User | Formal permission required for a person or an entity to use the resource and that may differ from the person that orders or purchases it | +| licenceDistributor | Licence Distributor | Formal permission required for a person or an entity to commercialize or distribute the resource | +| private | Private | Protects rights of individual or organisations from observation, intrusion, or attention of others | +| statutory | Statutory | Prescribed by law | +| confidential | Confidential | Not available to the public. NOTE: Contains information that could be prejudicial to a commercial, industrial, or national interest | +| SBU | Sensitive But Unclassified | Although unclassified, requires strict controls over its distribution | +| in-confidence | In-Confidence | With trust | + +### Standard codelists Scope code (mcc:MD_ScopeCode) {#iso19115-3.2018-cl-mcc-MD_ScopeCode} + +| code | label | description | +|----------------------|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| attribute | Attribute | Information applies to the attribute class | +| attributeType | Attribute type | Information applies to the characteristic of a feature | +| collectionHardware | Collection hardware | Information applies to the collection hardware class | +| collectionSession | Collection session | Information applies to the collection session | +| dataset | Dataset | Information applies to the dataset | +| series | Series | Information applies to the series | +| nonGeographicDataset | Non geographic dataset | Information applies to non-geographic data | +| dimensionGroup | Dimension group | Information applies to a dimension group | +| feature | Feature | Information applies to a feature | +| featureType | Feature type | Information applies to a feature type | +| propertyType | Property type | Information applies to a property type | +| fieldSession | Field session | Information applies to a field session | +| software | Software | Information applies to a computer program or routine | +| service | Service | Information applies to a capability which a service provider entity makes available to a service user entity through a set of interfaces that define a behaviour, such as a use case | +| model | Model | Information applies to a copy or imitation of an existing or hypothetical object | +| tile | Tile | Information applies to a tile, a spatial subset of geographic data | +| metadata | Metadata | Information applies to metadata | +| initiative | Initiative | Information applies to an initiative | +| sample | Sample | Information applies to a sample | +| document | Document | Information applies to a document | +| repository | Repository | Information applies to a repository | +| aggregate | Aggregate | Information applies to an aggregate resource | +| product | Product | Metadata describing an ISO 19131 data product specification | +| collection | Collection | Information applies to an unstructured set | +| coverage | Coverage | Information applies to a coverage | +| application | Application | Information resource hosted on a specific set of hardware and accessible over a network | + +Those values are defined in the standard but hidden when editing. + +| code | label | description | +|------------------------------|--------------------------------|-------------| +| map staticMap interactiveMap | Map Static map Interactive map | | + +### Standard codelists Spatial Representation Type (mcc:MD_SpatialRepresentationTypeCode) {#iso19115-3.2018-cl-mcc-MD_SpatialRepresentationTypeCode} + +| code | label | description | +|-------------|--------------|----------------------------------------------------------------------------------------------------| +| vector | Vector | Vector data is used to represent geographic data | +| grid | Grid | Grid data is used to represent geographic data | +| textTable | Text, table | Textual or tabular data is used to represent geographic data | +| tin | TIN | Triangulated irregular network | +| stereoModel | Stereo model | Three-dimensional view formed by the intersecting homologous rays of an overlapping pair of images | +| video | Video | Scene from a video recording | + +### Standard codelists Topic category code (mri:MD_TopicCategoryCode) {#iso19115-3.2018-cl-mri-MD_TopicCategoryCode} + +| code | label | description | +|----------------------------------|--------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| farming | Farming | Rearing of animals and/or cultivation of plants. Examples: agriculture, irrigation, aquaculture, plantations, herding, pests and diseases affecting crops and livestock | +| biota | Biota | Flora and/or fauna in natural environment. Examples: wildlife, vegetation, biological sciences, ecology, wilderness, sealife, wetlands, habitat | +| boundaries | Boundaries | Legal land descriptions. Examples: political and administrative boundaries | +| climatologyMeteorologyAtmosphere | Climatology, meteorology, atmosphere | Processes and phenomena of the atmosphere. Examples: cloud cover, weather, climate, atmospheric conditions, climate change, precipitation | +| economy | Economy | Economic activities, conditions and employment. Examples: production, labour, revenue, commerce, industry, tourism and ecotourism, forestry, fisheries, commercial or subsistence hunting, exploration and exploitation of resources such as minerals, oil and gas | +| elevation | Elevation | Height above or below sea level. Examples: altitude, bathymetry, digital elevation models, slope, derived products | +| environment | Environment | Environmental resources, protection and conservation. Examples: environmental pollution, waste storage and treatment, environmental impact assessment, monitoring environmental risk, nature reserves, landscape | +| geoscientificInformation | Geoscientific information | Information pertaining to earth sciences. Examples: geophysical features and processes, geology, minerals, sciences dealing with the composition, structure and origin of the earth s rocks, risks of earthquakes, volcanic activity, landslides, gravity information, soils, permafrost, hydrogeology, erosion | +| health | Health | Health, health services, human ecology, and safety. Examples: disease and illness, factors affecting health, hygiene, substance abuse, mental and physical health, health services | +| imageryBaseMapsEarthCover | Imagery base maps earth cover | Base maps. Examples: land cover, topographic maps, imagery, unclassified images, annotations | +| intelligenceMilitary | Intelligence military | Military bases, structures, activities. Examples: barracks, training grounds, military transportation, information collection | +| inlandWaters | Inland waters | Inland water features, drainage systems and their characteristics. Examples: rivers and glaciers, salt lakes, water utilization plans, dams, currents, floods, water quality, hydrographic charts | +| location | Location | Positional information and services. Examples: addresses, geodetic networks, control points, postal zones and services, place names | +| oceans | Oceans | Features and characteristics of salt water bodies (excluding inland waters). Examples: tides, tidal waves, coastal information, reefs | +| planningCadastre | Planning cadastre | Information used for appropriate actions for future use of the land. Examples: land use maps, zoning maps, cadastral surveys, land ownership | +| society | Society | Characteristics of society and cultures. Examples: settlements, anthropology, archaeology, education, traditional beliefs, manners and customs, demographic data, recreational areas and activities, social impact assessments, crime and justice, census information | +| structure | Structure | Man-made construction. Examples: buildings, museums, churches, factories, housing, monuments, shops, towers | +| transportation | Transportation | Means and aids for conveying persons and/or goods. Examples: roads, airports/airstrips, shipping routes, tunnels, nautical charts, vehicle or vessel location, aeronautical charts, railways | +| utilitiesCommunication | Utilities communication | Energy, water and waste systems and communications infrastructure andservices. Examples: hydroelectricity, geothermal, solar and nuclear sources of energy, water purification and distribution, sewage collection and disposal, electricity and gas distribution, data communication, telecommunication, radio, communication networks | +| extraTerrestrial | Extra Terrestrial | Region more than 100 km above the surface of the Earth | +| disaster | Disaster | Information related to disasters EXAMPLES: Site of the disaster, evacuation zone, disaster-prevention facility, disaster relief activities | + +### Standard codelists (msr:MD_TopologyLevelCode) {#iso19115-3.2018-cl-msr-MD_TopologyLevelCode} + +| code | label | description | +|------------------|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| geometryOnly | Geometry only | Geometry objects without any additional structure which describes topology | +| topology1D | Topology 1D | 1-dimensional topological complex -- commonly called chain-node topology | +| planarGraph | Planar graph | 1-dimensional topological complex that is planar. (A planar graph is a graph that can be drawn in a plane in such a way that no two edges intersect except at a vertex.) | +| fullPlanarGraph | Full planar graph | 2-dimensional topological complex that is planar. (A 2-dimensional topological complex is commonly called full topology in a cartographic 2D environment.) | +| surfaceGraph | Surface graph | 1-dimensional topological complex that is isomorphic to a subset of a surface. (A geometric complex is isomorphic to a topological complex if their elements are in a one-to-one, dimensional-and boundry-preserving correspondence to one another.) | +| fullSurfaceGraph | Full surface graph | 2-dimensional topological complex that is isomorphic to a subset of a surface | +| topology3D | Topology 3D | 3-dimensional topological complex. (A topological complex is a collection of topological primitives that are closed under the boundary operations.) | +| fullTopology3D | Full topology 3D | Complete coverage of a 3D Euclidean coordinate space | +| abstract | Abstract | Topological complex without any specified geometric realisation | + +### Standard codelists (mrc:MI_BandDefinition) {#iso19115-3.2018-cl-mrc-MI_BandDefinition} + +| code | label | description | +|-----------------|------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------| +| 3db | 3db | TBD | +| halfMaximum | Half Maximum | Description: width of a distribution equal to the distance between the outer two points on the distribution having power level half of that at the peak | +| fiftyPercent | Fifty Percent | Description: wavelength difference between the upper and lower bounds at the 50% (-3db) points of the sensor spectral response | +| oneOverE | One Over E | TBD | +| equivalentWidth | Equivalent Width | TBD | + +### Standard codelists (mac:MI_ContextCode) {#iso19115-3.2018-cl-mac-MI_ContextCode} + +| code | label | description | +|-------------|-------------|----------------------------------------| +| acquisition | Acquisition | Event related to a specific collection | +| pass | Pass | Event related to general collection | +| wayPoint | Way Point | Event related to general collection | + +### Standard codelists (mac:MI_GeometryTypeCode) {#iso19115-3.2018-cl-mac-MI_GeometryTypeCode} + +| code | label | description | +|--------------------|--------------------|-----------------------------------------------------------------| +| areal | Areal | Collection of a geographic area defined by a polygon (coverage) | +| strip linear point | Strip Linear Point | Series of linear collections grouped by way points | + +### Standard codelists (mac:MI_ObjectiveTypeCode) {#iso19115-3.2018-cl-mac-MI_ObjectiveTypeCode} + +| code | label | description | +|-------------------------|--------------------------|----------------------------------| +| instantaneousCollection | Instantaneous Collection | Single instance of collection | +| persistentView | Persistent View | Multiple instances of collection | +| survey | Survey | Comparative collection | + +### Standard codelists (mac:MI_OperationTypeCode) {#iso19115-3.2018-cl-mac-MI_OperationTypeCode} + +| code | label | description | +|--------------------------|--------------------------|-------------| +| real simulated synthetic | Real Simulated Synthetic | | + +### Standard codelists (mrc:MI_PolarisationOrientationCode) {#iso19115-3.2018-cl-mrc-MI_PolarisationOrientationCode} + +| code | label | description | +|----------------------------------------------------------|------------------------------------------------------------|-------------| +| horizontal vertical leftCircular rightCircular theta phi | Horizontal Vertical Left Circular Right Circular Theta Phi | | + +### Standard codelists (mac:MI_PriorityCode) {#iso19115-3.2018-cl-mac-MI_PriorityCode} + +| code | label | description | +|-------------------------|--------------------------|----------------------------------------------| +| critical | Critical | Decisive importance | +| highImportance | High Importance | Requires resources to be made available | +| mediumImportance | Medium Importance | Normal operation priority | +| lowImportance theta phi | Low Importance theta phi | To be completed when resources are available | + +### Standard codelists (mac:MI_SequenceCode) {#iso19115-3.2018-cl-mac-MI_SequenceCode} + +| code | label | description | +|---------------|---------------|-------------------------------------------| +| start | Start | Beginning of a collection | +| end | End | End of a collection | +| instantaneous | Instantaneous | Collection without a significant duration | + +### Standard codelists (mrc:MI_TransferFunctionTypeCode) {#iso19115-3.2018-cl-mrc-MI_TransferFunctionTypeCode} + +| code | label | description | +|--------------------------------|--------------------------------|-------------| +| linear logarithmic exponential | Linear Logarithmic Exponential | | + +### Standard codelists (mac:MI_TriggerCode) {#iso19115-3.2018-cl-mac-MI_TriggerCode} + +| code | label | description | +|---------------|---------------|-------------------------------------| +| automatic | Automatic | Event due to external stimuli | +| manual | Manual | Event manually instigated | +| preProgrammed | PreProgrammed | Event instigated by planned stimuli | + +### Standard codelists Amendment Type (reg:RE_AmendmentType) {#iso19115-3.2018-cl-reg-RE_AmendmentType} + +| code | label | description | +|-------------------------|-------------------------|-------------| +| supersession retirement | Supersession Retirement | | + +### Standard codelists Decision status (reg:RE_DecisionStatus) {#iso19115-3.2018-cl-reg-RE_DecisionStatus} + +| code | label | description | +|-------------------------|-------------------------|-------------| +| pending tentative final | Pending Tentative Final | | + +### Standard codelists Disposition (reg:RE_Disposition) {#iso19115-3.2018-cl-reg-RE_Disposition} + +| code | label | description | +|--------------------------------|---------------------------------|-------------| +| withdrawn accepted notAccepted | Withdrawn Accepted Not Accepted | | + +### Standard codelists Item status (reg:RE_ItemStatus) {#iso19115-3.2018-cl-reg-RE_ItemStatus} + +| code | label | description | +|-----------------------------------|------------------------------------|-------------| +| notValid valid superseded retired | Not Valid Valid Superseded Retired | | + +### Standard codelists Parameter direction (srv:SV_ParameterDirection) {#iso19115-3.2018-cl-srv-SV_ParameterDirection} + +| code | label | description | +|--------|--------------|-----------------------------------------------------------------------------| +| in | Input | The parameter is an input parameter to the service instance | +| out | Output | The parameter is an output parameter to the service instance | +| in/out | Input/output | The parameter is both an input and output parameter to the service instance | + +### Standard codelists (mrs:MD_ReferenceSystemTypeCode) {#iso19115-3.2018-cl-mrs-MD_ReferenceSystemTypeCode} + +| code | label | description | +|----------------------------------------|--------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| compoundEngineeringParametric | Compound Engineering Parametric | Compound spatio-parametric coordinate reference system containing an engineering coordinate reference system and a parametric reference system EXAMPLE: [local] x, y, pressure | +| compoundEngineeringParametricTemporal | Compound Engineering Parametric Temporal | Compound spatio-parametric-temporal coordinate reference system containing an engineering, a parametric, and a temporal coordinate reference system EXAMPLE: [local] x, y, pressure, time | +| compoundEngineeringTemporal | Compound Engineering Temporal | Compound spatio-temporal coordinate reference system containing an engineering and a temporal coordinate reference system EXAMPLE: [local] x, y, time | +| compoundEngineeringVertical | Compound Engineering Vertical | Compound spatial reference system containing a horizontal engineering coordinate reference system and a vertical coordinate reference system EXAMPLE: [local] x, y, height | +| compoundEngineeringVerticalTemporal | Compound Engineering Vertical Temporal | Compound spatio-temporal coordinate reference system containing an engineering, a vertical, and a temporal coordinate reference system EXAMPLE: [local] x, y, height, time | +| compoundGeographic2DParametric | Compound Geographic 2D Parametric | Compound spatio-parametric coordinate reference system containing a 2 dimensional geographic horizontal coordinate reference system and a parametric reference system EXAMPLE: latitude, longitude, pressure | +| compoundGeographic2DParametricTemporal | Compound Geographic 2D Parametric Temporal | Compound spatio-parametric-temporal coordinate reference system containing a 2 dimensional geographic horizontal, a parametric and a temporal coordinate reference system EXAMPLE: latitude, longitude, pressure, time | +| compoundGeographic2DTemporal | Compound Geographic 2D Temporal | Compound spatio-temporal coordinate reference system containing a 2 dimensional geographic horizontal coordinate reference system and a temporal reference system EXAMPLE: latitude, longitude, time | +| compoundGeographic2DVertical | Compound Geographic 2D Vertical | Compound coordinate reference system in which one constituent coordinate reference system is a horizontal geodetic coordinate reference system and one is a vertical coordinate reference system EXAMPLE: latitude, longitude, [gravity-related] height or depth | +| compoundGeographic2DVerticalTemporal | Compound Geographic 2D Vertical Temporal | Compound spatio-temporal coordinate reference system containing a 2 dimensional geographic horizontal, a vertical, and a temporal coordinate reference system EXAMPLE: latitude, longitude, height, time | +| compoundGeographic3DTemporal | Compound Geographic 3D Temporal | Compound spatio-temporal coordinate reference system containing a 3 dimensional geographic and a temporal coordinate reference system EXAMPLE latitude, longitude, ellipsoidal height, time | +| compoundProjected2DParametric | Compound Projected 2D Parametric | Compound spatio-parametric coordinate reference system containing a projected horizontal coordinate reference system and a parametric reference system EXAMPLE: easting, northing, density | +| compoundProjected2DParametricTemporal | Compound Projected 2D Parametric Temporal | Compound spatio-parametric-temporal coordinate reference system containing a projected horizontal, a parametric, and a temporal coordinate reference system EXAMPLE: easting, northing, density, time | +| compoundProjectedTemporal | Compound Projected Temporal | Compound spatio-temporal coordinate reference system containing a projected horizontal and a temporal coordinate reference system EXAMPLE: easting, northing, time | +| compoundProjectedVertical | Compound Projected Vertical | Compound spatial reference system containing a horizontal projected coordinate reference system and a vertical coordinate reference system EXAMPLE easting, northing, [gravity-related] height or depth | +| compoundProjectedVerticalTemporal | Compound Projected Vertical Temporal | Compound spatio-temporal coordinate reference system containing a projected horizontal, a vertical, and a temporal coordinate reference system EXAMPLE: easting, northing, height, time | +| engineering | Engineering | Coordinate reference system based on an engineering datum (datum describing the relationship of a coordinate system to a local reference) EXAMPLE: [local] x,y | +| engineeringDesign | Engineering Design | Engineering coordinate reference system in which the base representation of a moving object is specified EXAMPLE: [local] x,y | +| engineeringImage | Engineering Image | Coordinate reference system based on an image datum (engineering datum which defines the relationship of a coordinate system to an image) EXAMPLE: row, column | +| geodeticGeocentric | Geodetic Geocentric | Geodetic CRS having a Cartesian 3D coordinate system EXAMPLE: [geocentric] X,Y,Z | +| geodeticGeographic2D | Geodetic Geographic 2D | Geodetic CRS having an ellipsoidal 2D coordinate system EXAMPLE: latitude, longitude | +| geodeticGeographic3D | Geodetic Geographic 3D | Geodetic CRS having an ellipsoidal 3D coordinate system EXAMPLE: latitude, longitude, ellipsoidal height | +| geographicIdentifier | Geographic Identifier | Spatial reference in the form of a label or code that identifies a location EXAMPLE: post code | +| linear | Linear | Reference system that identifies a location by reference to a segment of a linear geographic feature and distance along that segment from a given point EXAMPLE: x km along road | +| parametric | Parametric | Coordinate reference system based on a parametric datum (datum describing the relationship of a parametric coordinate system to an object) EXAMPLE: pressure | +| projected | Projected | Coordinate reference system derived from a two-dimensional geodetic coordinate reference system by applying a map projection EXAMPLE: easting, northing | +| temporal | Temporal | Reference system against which time is measured EXAMPLE: time | +| vertical | Vertical | One-dimensional coordinate reference system based on a vertical datum (datum describing the relation of gravity-related heights or depths to the Earth) EXAMPLE: [gravity-related] height or depth | + +### Standard codelists (msr:MD_CellGeometryCode) {#iso19115-3.2018-cl-msr-MD_CellGeometryCode} + +| code | label | description | +|---------|---------|--------------------------------------------------------------------------------------------| +| point | Point | Each cell represents a point | +| area | Area | Each cell represents an area | +| voxel | Voxel | Each cell represents a volumetric measurement on a regular grid in three dimensional space | +| stratum | Stratum | Height range for a single point vertical profile | + +### Standard codelists Character set code (lan:MD_CharacterSetCode) {#iso19115-3.2018-cl-lan-MD_CharacterSetCode} + +| code | label | description | +|------------|--------------|-----------------------------------------------------------------------------------------------------------------------------------| +| ucs2 | UCS2 | 16-bit fixed size Universal Character Set, based on ISO/IEC 10646 | +| ucs4 | UCS4 | 32-bit fixed size Universal Character Set, based on ISO/IEC 10646 | +| utf7 | UTF7 | 7-bit variable size UCS Transfer Format, based on ISO/IEC 10646 | +| utf8 | UTF8 | 8-bit variable size UCS Transfer Format, based on ISO/IEC 10646 | +| utf16 | UTF16 | 16-bit variable size UCS Transfer Format, based on ISO/IEC 10646 | +| 8859part1 | 8859 Part 1 | ISO/IEC 8859-1, Information technology - 8-bit single byte coded graphic character sets - Part 1 : Latin alphabet No.1 | +| 8859part2 | 8859 Part 2 | ISO/IEC 8859-2, Information technology - 8-bit single byte coded graphic character sets - Part 2 : Latin alphabet No.2 | +| 8859part3 | 8859 Part 3 | ISO/IEC 8859-3, Information technology - 8-bit single byte coded graphic character sets - Part 3 : Latin alphabet No.3 | +| 8859part4 | 8859 Part 4 | ISO/IEC 8859-4, Information technology - 8-bit single byte coded graphic character sets - Part 4 : Latin alphabet No.4 | +| 8859part5 | 8859 Part 5 | ISO/IEC 8859-5, Information technology - 8-bit single byte coded graphic character sets - Part 5 : Latin/Cyrillic alphabet | +| 8859part6 | 8859 Part 6 | ISO/IEC 8859-6, Information technology - 8-bit single byte coded graphic character sets - Part 6 : Latin/Arabic alphabet | +| 8859part7 | 8859 Part 7 | ISO/IEC 8859-7, Information technology - 8-bit single byte coded graphic character sets - Part 7 : Latin/Greek alphabet | +| 8859part8 | 8859 Part 8 | ISO/IEC 8859-8, Information technology - 8-bit single byte coded graphic character sets - Part 8 : Latin/Hebrew alphabet | +| 8859part9 | 8859 Part 9 | ISO/IEC 8859-9, Information technology - 8-bit single byte coded graphic character sets - Part 9 : Latin alphabet No.5 | +| 8859part10 | 8859 Part 10 | ISO/IEC 8859-10, Information technology - 8-bit single byte coded graphic character sets - Part 10 : Latin alphabet No.6 | +| 8859part11 | 8859 Part 11 | ISO/IEC 8859-11, Information technology - 8-bit single byte coded graphic character sets - Part 11 : Latin/Thai alphabet | +| 8859part13 | 8859 Part 13 | ISO/IEC 8859-13, Information technology - 8-bit single byte coded graphic character sets - Part 13 : Latin alphabet No.7 | +| 8859part14 | 8859 Part 14 | ISO/IEC 8859-14, Information technology - 8-bit single byte coded graphic character sets - Part 14 : Latin alphabet No.8 (Celtic) | +| 8859part15 | 8859 Part 15 | ISO/IEC 8859-15, Information technology - 8-bit single byte coded graphic character sets - Part 15 : Latin alphabet No.9 | +| 8859part16 | 8859 Part 16 | ISO/IEC 8859-16, Information technology - 8-bit single byte coded graphic character sets - Part 16 : Latin alphabet No.10 | +| jis | JIS | Japanese code set used for electronic transmission | +| shiftJIS | Shift JIS | Japanese code set used on MS-DOS machines | +| eucJP | EUC JP | Japanese code set used on UNIX based machines | +| usAscii | US ASCII | United States ASCII code set (ISO 646 US) | +| ebcdic | EBCDIC | IBM mainframe code set | +| eucKR | EUC KR | Korean code set | +| big5 | Big 5 | Traditional Chinese code set used in Taiwan, Hong Kong of China and other areas | +| GB2312 | GB2312 | Simplified Chinese code set | + +### Standard codelists (mrd:MD_MediumNameCode) {#iso19115-3.2018-cl-mrd-MD_MediumNameCode} + +| code | label | description | +|---------------------------|-------------------------------|----------------------------------------------------| +| cdRom | CDROM | Read-only optical disk | +| dvd | DVD | Digital versatile disk | +| dvdRom | DVDROM | Digital versatile disk, read only | +| 3halfInchFloppy | 3 Half Inch Floppy | 3,5 inch magnetic disk | +| 5quarterInchFloppy | 5 Quarter Inch Floppy | 5,25 inch magnetic disk | +| 7trackTape | 7 Track tape | 7 track magnetic tape | +| 9trackTape | 9 track tape | 9 track magnetic tape | +| 3480Cartridge | 3480 Cartridge | 3480 cartridge tape drive | +| 3490Cartridge | 3490 Cartridge | 3490 cartridge tape drive | +| 3580Cartridge | 3580 Cartridge | 3580 cartridge tape drive | +| 4mmCartridgeTape | 4 mm Cartridge tape | 4 millimetre magnetic tape | +| 8mmCartridgeTape | 8 mm Cartridge tape | 8 millimetre magnetic tape | +| 1quarterInchCartridgeTape | 1 Quarter inch cartridge tape | 0,25 inch magnetic tape | +| digitalLinearTap | Digital linear tape | Half inch cartridge streaming tape drive | +| onLine | Online | Direct computer linkage | +| satellite | Satellite | Linkage through a satellite communication system | +| telephoneLink | Telephone link | Communication through a telephone network | +| hardcopy | Hardcopy | Pamphlet or leaflet giving descriptive information | + +### Standard codelists Distributed Computing Platforms list (srv:DCPList) {#iso19115-3.2018-cl-srv-DCPList} + ++-------------+-------------+--------------------+ +| code | label | description | ++=============+=============+====================+ +| XML | XML | DCP is XML | ++-------------+-------------+--------------------+ +| CORBA | CORBA | DCP is CORBA | ++-------------+-------------+--------------------+ +| JAVA | JAVA | DCP is JAVA | ++-------------+-------------+--------------------+ +| COM | COM | DCP is COM | ++-------------+-------------+--------------------+ +| SQL | DCP is SQL | > SQL | ++-------------+-------------+--------------------+ +| SOAP | SOAP | DCP is SOAP | ++-------------+-------------+--------------------+ +| Z3950 | Z3950 | DCP is Z3950 | ++-------------+-------------+--------------------+ +| HTTP | HTTP | DCP is HTTP | ++-------------+-------------+--------------------+ +| FTP | FTP | DCP is FTP | ++-------------+-------------+--------------------+ +| WebServices | WebServices | DCP is WebServices | ++-------------+-------------+--------------------+ + +### Standard codelists (srv:SV_CouplingType) {#iso19115-3.2018-cl-srv-SV_CouplingType} + +| code | label | description | +|-------|-------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| loose | Loose | service instance is loosely coupled with a data instance, i.e. no MD_DataIdentification class has to be described | +| mixed | Mixed | Service instance is mixed coupled with a data instance, i.e. MD_DataIdentification describes the associated data instance and additionally the service instance might work with other external data instances | +| tight | Tight | Service instance is tightly coupled with a data instance, i.e. MD_DataIdentification class MUST be described | + +### Standard codelists Indeterminate position (indeterminatePosition) {#iso19115-3.2018-cl-indeterminatePosition} + +| code | label | +|---------|---------| +| after | After | +| before | Before | +| now | Now | +| unknown | Unknown | diff --git a/docs/manual/docs/annexes/standards/iso19139.md b/docs/manual/docs/annexes/standards/iso19139.md new file mode 100644 index 00000000000..ceb1ef656c9 --- /dev/null +++ b/docs/manual/docs/annexes/standards/iso19139.md @@ -0,0 +1,17594 @@ +# Geographic information -- Metadata (iso19139:2007) (iso19139) {#iso19139} + +ISO 19115 defines the schema required for describing geographic information and services by means of metadata. It provides information about the identification, the extent, the quality, the spatial and temporal aspects, the content, the spatial reference, the portrayal, distribution, and other properties of digital geographic data and services. + +ISO 19115 is applicable to: + +- the cataloguing of all types of resources, clearinghouse activities, and the full description of datasets and services; +- geographic services, geographic datasets, dataset series, and individual geographic features and feature properties. + +ISO 19115 defines: + +- mandatory and conditional metadata sections, metadata entities, and metadata elements; +- the minimum set of metadata required to serve most metadata applications (data discovery, determining data fitness for use, data access, data transfer, and use of digital data and services); +- optional metadata elements to allow for a more extensive standard description of resources, if required; +- a method for extending metadata to fit specialized needs. + +Though ISO 19115 is applicable to digital data and services, its principles can be extended to many other types of resources such as maps, charts, and textual documents as well as non-geographic data. Certain conditional metadata elements might not apply to these other forms of data. + +More details: + +## Metadata editor + +This standard can be encoded using 4 view(s). + +- [View: INSPIRE (inspire)](iso19139.md#iso19139-view-inspire) +- [View: Simple (default)](iso19139.md#iso19139-view-default) +- [View: Full (advanced)](iso19139.md#iso19139-view-advanced) +- [View: XML (xml)](iso19139.md#iso19139-view-xml) + +### View: INSPIRE (inspire) {#iso19139-view-inspire} + +This view is composed of2tab(s). + +- [Tab: INSPIRE (inspire)](iso19139.md#iso19139-tab-inspire) +- [Tab: SDS (inspire_sds)](iso19139.md#iso19139-tab-inspire_sds) + +This view also allows to add the following element even if not in the current record: + +- Contains Operations (srv:containsOperations) +- Operation (srv:SV_OperationMetadata) +- Parameters (srv:parameters) + +#### Tab: INSPIRE (inspire) {#iso19139-tab-inspire} + +![](img/iso19139-tab-inspire.png) + +This tab display elements from the XML metadata record. + +##### Section: Identification + +##### File identifier + +```{=html} +Unique identifier for this metadata file +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:fileIdentifier + +See [File identifier](iso19139.md#iso19139-elem-gmd-fileIdentifier-353be7794d17e5435ce2fe57d91966ba) + +##### Title + +```{=html} +Name by which the cited resource is known +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/*/gmd:citation/gmd:CI_Citation/gmd:title + +See [Title](iso19139.md#iso19139-elem-gmd-title-cc3002a2d81bcdbc5bf4c8735faf6980) + +##### Abstract + +```{=html} +Brief narrative summary of the content of the resource(s) +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/gmd:MD_DataIdentification/gmd:abstract + +See [Abstract](iso19139.md#iso19139-elem-gmd-abstract-cacfcd3bd6bbd44733f828dd2903ecd8) + +##### Abstract + +```{=html} +Brief narrative summary of the content of the resource(s) +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:abstract + +See [Abstract](iso19139.md#iso19139-elem-gmd-abstract-cacfcd3bd6bbd44733f828dd2903ecd8) + +##### Hierarchy level + +```{=html} +Scope to which the metadata applies (see annex H for more information about metadata hierarchy levels) +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:hierarchyLevel + +See [Hierarchy level](iso19139.md#iso19139-elem-gmd-hierarchyLevel-2b6d53b433d8f9c0cc58606d27eecc17) + +Name + +: + +> Hierarchy level + +Name + +: + +> Hierarchy level + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification) = 0 + +``` xml + + + +``` + +Name + +: + +> Hierarchy level + +Name + +: + +> Hierarchy level + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification) > 0 + +``` xml + + + +``` + +##### Online resource + +##### OnLine resource + +```{=html} +Information about online sources from which the resource can be obtained +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:distributionInfo/gmd:MD_Distribution/gmd:transferOptions /gmd:MD_DigitalTransferOptions/gmd:onLine + +See [OnLine resource](iso19139.md#iso19139-elem-gmd-onLine-c0b191c96e7e4d7dfc2a4ba2fd8946f4) + +Name + +: + +> Online resource + +Name + +: + +> Online resource + +Type + +: + +> add + +``` xml + + + + + + + + + + +``` + +##### Resource identifier + +##### Citation identifier + +```{=html} +Identifier of the citation +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/gmd:MD_DataIdentification/gmd:citation/gmd:CI_Citation/gmd:identifier + +See [Identifier](iso19139.md#iso19139-elem-gmd-identifier-c4f31fd808ee0eaa1e5525c5ff0edd23) + +Name + +: + +> Resource identifier + +Name + +: + +> Resource identifier + +Type + +: + +> add + +``` xml + + + + + + + +``` + +Type + +: + +> process + +Displayed only if + +: + +> (count(gmd:MD_Metadata/gmd:identificationInfo/gmd:MD_DataIdentification) + count(gmd:MD_Metadata/gmd:identificationInfo/gmd:MD_DataIdentification/gmd:citation/gmd:CI_Citation/ gmd:identifier[ends-with(gmd:MD_Identifier/gmd:code/gco:CharacterString, //gmd:MD_Metadata/gmd:fileIdentifier/gco:CharacterString)])) = 1 + +##### Language + +```{=html} +Language(s) used within the dataset +``` +```{=html} +language(s) used within the dataset +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/gmd:MD_DataIdentification/gmd:language + +See [Metadata language](iso19139.md#iso19139-elem-gmd-language-98a1fec5ea30c100ef63f1ca4bd6dbdb) + +##### Spatial representation type + +```{=html} +Method used to spatially represent geographic information +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/gmd:MD_DataIdentification/gmd:spatialRepresentationType + +See [Spatial representation type](iso19139.md#iso19139-elem-gmd-spatialRepresentationType-1617a07231ac2246d0844778962d4ca0) + +Name + +: + +> Spatial representation type + +Name + +: + +> Spatial representation type + +Type + +: + +> add + +``` xml + + + +``` + +##### Encoding + +##### Distribution format + +```{=html} +Provides a description of the format of the data to be distributed +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:distributionInfo/gmd:MD_Distribution/gmd:distributionFormat + +See [Distribution format](iso19139.md#iso19139-elem-gmd-distributionFormat-5cad81c9a7af3991db918a5e8fc0c596) + +Name + +: + +> Encoding + +Name + +: + +> Encoding + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification) = 0 + +``` xml + + + + + + + + + + + + + +``` + +##### Projection + +##### Reference system identifier + +```{=html} +Name of reference system +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:referenceSystemInfo/gmd:MD_ReferenceSystem/gmd:referenceSystemIdentifier + +See [Reference system identifier](iso19139.md#iso19139-elem-gmd-referenceSystemIdentifier-5393a29789a4b6def1795d5a9e70f665) + +Name + +: + +> Projection + +Name + +: + +> Ref. system + +Type + +: + +> add + +``` xml + + + + + + http://www.opengis.net/def/crs/EPSG/0/4936 + + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/4937 + + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/4258 + + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/3035 + + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/3034 + + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/3038 + + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/3039 + + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/3040 + + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/3041 + + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/3042 + + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/3043 + + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/3044 + + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/3045 + + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/3046 + + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/3047 + + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/3048 + + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/3049 + + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/3050 + + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/3051 + + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/5730 + + + + + + + + + + + + + http://www.opengis.net/def/crs/EPSG/0/7409 + + + + + +``` + +##### Section: Classification of data and services + +##### Topic category + +```{=html} +Main theme(s) of the dataset +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/gmd:MD_DataIdentification/gmd:topicCategory + +See [Topic category](iso19139.md#iso19139-elem-gmd-topicCategory-beb19f9aa38425d24bc8c438657fff74) + +Name + +: + +> Topic category code + +Name + +: + +> Topic category code + +Type + +: + +> add + +``` xml + + + +``` + +##### Section: Classification of data and services + +##### Service Type + +```{=html} +Service type name from a registry of services. For example, the values of the nameSpace and name attributes of GeneralName may be 'OGC' and 'catalogue' +``` +Recommended values + +| code | label | +|-------------------|-------------------------------------------------| +| OGC:WMS | OGC Web Map Service (OGC:WMS) | +| OGC:WFS | OGC Web Feature Service (OGC:WFS) | +| OGC:WCS | OGC Web Coverage Service (OGC:WCS) | +| W3C:HTML:DOWNLOAD | Download (W3C:HTML:DOWNLOAD) | +| W3C:HTML:LINK | Information (W3C:HTML:LINK) | +| discovery | INSPIRE Discovery Service (discovery) | +| view | INSPIRE View Service (view) | +| download | INSPIRE Download Service (download) | +| transformation | INSPIRE Transformation Service (transformation) | +| other | INSPIRE Other Services (other) | + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/srv:serviceType + +See [Service Type](iso19139.md#iso19139-elem-srv-serviceType-31230933e2a7436c80955195b74bc0a0) + +##### Coupling Type + +```{=html} +Type of Coupling +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/srv:couplingType + +See [Coupling Type](iso19139.md#iso19139-elem-srv-couplingType-bc1606dff717a83807e97a1a3789e30a) + +##### Section: Coupled resource + +##### Coupled resource + +##### Operates On + +```{=html} +Provides information on the datasets that the service operates on +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/srv:operatesOn + +See [Operates On](iso19139.md#iso19139-elem-srv-operatesOn-fc0165e60dcb452c05c9f1d95416b89a) + +Name + +: + +> Coupled resource + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification) > 0 + +``` xml + +``` + +##### Section: Coupled resource + +##### Coupled resource + +##### Operates On + +```{=html} +Provides information on the datasets that the service operates on +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/srv:operatesOn + +See [Operates On](iso19139.md#iso19139-elem-srv-operatesOn-fc0165e60dcb452c05c9f1d95416b89a) + +Name + +: + +> Coupled resource + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification) > 0 + +``` xml + +``` + +##### Section: Classification of data and services + +##### Service Type + +```{=html} +Service type name from a registry of services. For example, the values of the nameSpace and name attributes of GeneralName may be 'OGC' and 'catalogue' +``` +Recommended values + +| code | label | +|-------------------|-------------------------------------------------| +| OGC:WMS | OGC Web Map Service (OGC:WMS) | +| OGC:WFS | OGC Web Feature Service (OGC:WFS) | +| OGC:WCS | OGC Web Coverage Service (OGC:WCS) | +| W3C:HTML:DOWNLOAD | Download (W3C:HTML:DOWNLOAD) | +| W3C:HTML:LINK | Information (W3C:HTML:LINK) | +| discovery | INSPIRE Discovery Service (discovery) | +| view | INSPIRE View Service (view) | +| download | INSPIRE Download Service (download) | +| transformation | INSPIRE Transformation Service (transformation) | +| other | INSPIRE Other Services (other) | + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/srv:serviceType + +See [Service Type](iso19139.md#iso19139-elem-srv-serviceType-31230933e2a7436c80955195b74bc0a0) + +##### Coupling Type + +```{=html} +Type of Coupling +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/srv:couplingType + +See [Coupling Type](iso19139.md#iso19139-elem-srv-couplingType-bc1606dff717a83807e97a1a3789e30a) + +##### Section: Coupled resource + +##### Coupled resource + +##### Operates On + +```{=html} +Provides information on the datasets that the service operates on +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/srv:operatesOn + +See [Operates On](iso19139.md#iso19139-elem-srv-operatesOn-fc0165e60dcb452c05c9f1d95416b89a) + +Name + +: + +> Coupled resource + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification) > 0 + +``` xml + +``` + +##### Section: Coupled resource + +##### Coupled resource + +##### Operates On + +```{=html} +Provides information on the datasets that the service operates on +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/srv:operatesOn + +See [Operates On](iso19139.md#iso19139-elem-srv-operatesOn-fc0165e60dcb452c05c9f1d95416b89a) + +Name + +: + +> Coupled resource + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification) > 0 + +``` xml + +``` + +##### Section: Keywords + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/ gmd:descriptiveKeywords [gmd:MD_Keywords/gmd:thesaurusName/gmd:CI_Citation/gmd:title/gco:CharacterString = 'INSPIRE Service taxonomy'] + +See [Descriptive keywords](iso19139.md#iso19139-elem-gmd-descriptiveKeywords-d9044aa0856cf55d016da575dc037fa3) + +Name + +: + +> INSPIRE Service Taxonomy + +Name + +: + +> INSPIRE Service Taxonomy + +Type + +: + +> add + +Displayed only if + +: + +> (count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/ gmd:descriptiveKeywords[ contains(gmd:MD_Keywords/gmd:thesaurusName/ gmd:CI_Citation/gmd:title/gco:CharacterString, 'INSPIRE Service taxonomy')]) + count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification)) = 1 + +``` xml + + + + + + + + + + + + INSPIRE Service taxonomy + + + + + 2010-04-22 + + + + + + + + + + + geonetwork.thesaurus.external.theme.inspire-service-taxonomy + + + + + + + +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/*/ gmd:descriptiveKeywords [contains(gmd:MD_Keywords/gmd:thesaurusName/gmd:CI_Citation/gmd:title/*[name() = 'gco:CharacterString' or name() = 'gmx:Anchor']/text(), 'INSPIRE themes')] + +See [Descriptive keywords](iso19139.md#iso19139-elem-gmd-descriptiveKeywords-d9044aa0856cf55d016da575dc037fa3) + +Name + +: + +> INSPIRE themes + +Name + +: + +> INSPIRE themes + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/*/ gmd:descriptiveKeywords[ contains(gmd:MD_Keywords/gmd:thesaurusName/ gmd:CI_Citation/gmd:title/*[name() = 'gco:CharacterString' or name() = 'gmx:Anchor']/text(), 'INSPIRE themes')]) = 0 + +``` xml + + + + + + + + + + + + GEMET - INSPIRE themes, version 1.0 + + + + + 2008-06-01 + + + + + + + + + + + geonetwork.thesaurus.external.theme.httpinspireeceuropaeutheme-theme + + + + + + + + +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/*/ gmd:descriptiveKeywords [count(gmd:MD_Keywords/gmd:thesaurusName) > 0 and not(contains(gmd:MD_Keywords/gmd:thesaurusName/gmd:CI_Citation/gmd:title/*[name() = 'gco:CharacterString' or name() = 'gmx:Anchor']/text(), 'INSPIRE themes'))] + +See [Descriptive keywords](iso19139.md#iso19139-elem-gmd-descriptiveKeywords-d9044aa0856cf55d016da575dc037fa3) + +##### Section: Other keywords + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/ gmd:descriptiveKeywords[not(gmd:MD_Keywords/gmd:thesaurusName)] + +See [Descriptive keywords](iso19139.md#iso19139-elem-gmd-descriptiveKeywords-d9044aa0856cf55d016da575dc037fa3) + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/gmd:MD_DataIdentification/ gmd:descriptiveKeywords[not(gmd:MD_Keywords/gmd:thesaurusName)] + +See [Descriptive keywords](iso19139.md#iso19139-elem-gmd-descriptiveKeywords-d9044aa0856cf55d016da575dc037fa3) + +##### Section: Other keywords + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/ gmd:descriptiveKeywords[not(gmd:MD_Keywords/gmd:thesaurusName)] + +See [Descriptive keywords](iso19139.md#iso19139-elem-gmd-descriptiveKeywords-d9044aa0856cf55d016da575dc037fa3) + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/gmd:MD_DataIdentification/ gmd:descriptiveKeywords[not(gmd:MD_Keywords/gmd:thesaurusName)] + +See [Descriptive keywords](iso19139.md#iso19139-elem-gmd-descriptiveKeywords-d9044aa0856cf55d016da575dc037fa3) + +##### Section: Geographic coverage + +##### Geographic bounding box + +```{=html} +Geographic position of the dataset +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/ srv:extent/gmd:EX_Extent/gmd:geographicElement/gmd:EX_GeographicBoundingBox + +See [Geographic bounding box](iso19139.md#iso19139-elem-gmd-EX_GeographicBoundingBox-317fd5425b55f40c235ada8a89ee0519) + +##### Geographic bounding box + +```{=html} +Geographic position of the dataset +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/gmd:MD_DataIdentification/ gmd:extent/gmd:EX_Extent/gmd:geographicElement/gmd:EX_GeographicBoundingBox + +See [Geographic bounding box](iso19139.md#iso19139-elem-gmd-EX_GeographicBoundingBox-317fd5425b55f40c235ada8a89ee0519) + +Name + +: + +> Geographic bounding box + +Name + +: + +> Geographic bounding box + +Type + +: + +> add + +``` xml + + + + + + + + + + + + + + + + + + + + +``` + +Name + +: + +> Geographic bounding box + +Name + +: + +> Geographic bounding box + +Type + +: + +> add + +``` xml + + + + + + + + + + + + + + + + + + + + +``` + +##### Section: Temporal reference + +##### Temporal extent + +##### Temporal element + +```{=html} +Provides temporal component of the extent of the referring object +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/gmd:MD_DataIdentification/gmd:extent/gmd:EX_Extent/gmd:temporalElement + +See [Temporal element](iso19139.md#iso19139-elem-gmd-temporalElement-98c13f1732cd7f7c06320d907eec27ce) + +Name + +: + +> Geographic bounding box + +Name + +: + +> Temporal extent + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/gmd:MD_DataIdentification/gmd:extent/gmd:EX_Extent/gmd:temporalElement) = 0 + +``` xml + + + + + + + + + + + + + + +``` + +##### Temporal extent + +##### Temporal element + +```{=html} +Provides temporal component of the extent of the referring object +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/srv:extent/gmd:EX_Extent/gmd:temporalElement + +See [Temporal element](iso19139.md#iso19139-elem-gmd-temporalElement-98c13f1732cd7f7c06320d907eec27ce) + +Name + +: + +> Geographic bounding box + +Name + +: + +> Temporal extent + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/srv:extent/gmd:EX_Extent/gmd:temporalElement) = 0 + +``` xml + + + + + + + + + + + + + + +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/*/gmd:citation/gmd:CI_Citation/ gmd:date + +See [Date](iso19139.md#iso19139-elem-gmd-date-ebb509445b6cf496cbf813a8b01a2362) + +Name + +: + +> Temporal information + +Name + +: + +> Temporal information + +Type + +: + +> add + +``` xml + + + + + + + + + + +``` + +##### Section: Quality and validity + +##### Lineage + +##### Statement + +```{=html} +General explanation of the data producer_s knowledge about the lineage of a dataset +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:dataQualityInfo/gmd:DQ_DataQuality/gmd:lineage/gmd:LI_Lineage/gmd:statement + +See [Statement](iso19139.md#iso19139-elem-gmd-statement-593ac58687a7831e3112879ec00a306e) + +Name + +: + +> Lineage + +Name + +: + +> Lineage + +Type + +: + +> add + +``` xml + + + +``` + +Name + +: + +> Lineage + +Name + +: + +> Lineage + +Type + +: + +> add + +``` xml + + + + + + + +``` + +##### Denominator + +```{=html} +The number below the line in a vulgar fraction +``` +Recommended values + +| code | label | +|---------|-------------| +| 5000 | 1:5´000 | +| 10000 | 1:10´000 | +| 25000 | 1:25´000 | +| 50000 | 1:50´000 | +| 100000 | 1:100´000 | +| 200000 | 1:200´000 | +| 300000 | 1:300´000 | +| 500000 | 1:500´000 | +| 1000000 | 1:1´000´000 | + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/ */gmd:spatialResolution/ */gmd:equivalentScale/*/gmd:denominator + +See [Denominator](iso19139.md#iso19139-elem-gmd-denominator-e807028ba183b3decd6aa631d0ca1ca3) + +Name + +: + +> Spatial resolution (scale) + +Type + +: + +> add + +``` xml + + + + + + + + + + + +``` + +##### Distance + +```{=html} +Ground sample distance +``` +Recommended values + +| code | label | +|------|-------| +| 0.10 | 10 cm | +| 0.25 | 25 cm | +| 0.50 | 50 cm | +| 1 | 1 m | +| 30 | 30 m | +| 100 | 100 m | + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/ */gmd:spatialResolution/*/gmd:distance + +See [Distance](iso19139.md#iso19139-elem-gmd-distance-7b7fc9e19c5ebb9644dc51880d95a12d) + +Name + +: + +> Spatial resolution (distance) + +Type + +: + +> add + +``` xml + + + + + + + +``` + +##### Section: Conformity + +##### Conformity + +##### Result + +```{=html} +Value (or set of values) obtained from applying a data quality measure or the out come of evaluating the obtained value (or set of values) against a specified acceptable conformance quality level +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:dataQualityInfo/gmd:DQ_DataQuality/ gmd:report/gmd:DQ_DomainConsistency/gmd:result[count(gmd:DQ_ConformanceResult/gmd:specification/ gmd:CI_Citation/gmd:title/gmx:Anchor) > 0] + +See [Result](iso19139.md#iso19139-elem-gmd-result-83539788e54d2fc7d166ac779dc43f0b) + +##### Conformity + +##### Result + +```{=html} +Value (or set of values) obtained from applying a data quality measure or the out come of evaluating the obtained value (or set of values) against a specified acceptable conformance quality level +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:dataQualityInfo/gmd:DQ_DataQuality/ gmd:report/gmd:DQ_DomainConsistency/gmd:result[count(gmd:DQ_ConformanceResult/gmd:specification/ gmd:CI_Citation/gmd:title/gco:CharacterString) > 0] + +See [Result](iso19139.md#iso19139-elem-gmd-result-83539788e54d2fc7d166ac779dc43f0b) + +Name + +: + +> Conformity + +Name + +: + +> Conformity + +Type + +: + +> add + +``` xml + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + +``` + +##### Section: Conformity + +##### Conformity + +##### Result + +```{=html} +Value (or set of values) obtained from applying a data quality measure or the out come of evaluating the obtained value (or set of values) against a specified acceptable conformance quality level +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:dataQualityInfo/gmd:DQ_DataQuality/ gmd:report/gmd:DQ_DomainConsistency/gmd:result[count(gmd:DQ_ConformanceResult/gmd:specification/ gmd:CI_Citation/gmd:title/gmx:Anchor) > 0] + +See [Result](iso19139.md#iso19139-elem-gmd-result-83539788e54d2fc7d166ac779dc43f0b) + +##### Conformity + +##### Result + +```{=html} +Value (or set of values) obtained from applying a data quality measure or the out come of evaluating the obtained value (or set of values) against a specified acceptable conformance quality level +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:dataQualityInfo/gmd:DQ_DataQuality/ gmd:report/gmd:DQ_DomainConsistency/gmd:result[count(gmd:DQ_ConformanceResult/gmd:specification/ gmd:CI_Citation/gmd:title/gco:CharacterString) > 0] + +See [Result](iso19139.md#iso19139-elem-gmd-result-83539788e54d2fc7d166ac779dc43f0b) + +Name + +: + +> Conformity + +Name + +: + +> Conformity + +Type + +: + +> add + +``` xml + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + +``` + +##### Section: Restrictions on access and use + +##### Use limitation + +```{=html} +Limitation affecting the fitness for use of the resource. Example, _not to be used for navigation_ +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/gmd:MD_DataIdentification/ gmd:resourceConstraints/gmd:MD_Constraints/gmd:useLimitation + +See [Use limitation](iso19139.md#iso19139-elem-gmd-useLimitation-07252e81be8d86aea4553aa3df807d8b) + +Name + +: + +> Use limitation + +Name + +: + +> Use limitation + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/gmd:MD_DataIdentification) > 0 + +``` xml + + + + + + + +``` + +##### Access constraints + +##### Other constraints + +```{=html} +Other restrictions and legal prerequisites for accessing and using the resource +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/gmd:MD_DataIdentification/ gmd:resourceConstraints/gmd:MD_LegalConstraints/gmd:otherConstraints + +See [Other constraints](iso19139.md#iso19139-elem-gmd-otherConstraints-696de5ef421a230cf560f7566a3c5028) + +Name + +: + +> Access constraints + +Name + +: + +> Access constraints + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/gmd:MD_DataIdentification) > 0 + +``` xml + + + + + + + + + + + +``` + +##### Section: Restrictions on access and use + +##### Use limitation + +```{=html} +Limitation affecting the fitness for use of the resource. Example, _not to be used for navigation_ +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/ gmd:resourceConstraints/gmd:MD_Constraints/gmd:useLimitation + +See [Use limitation](iso19139.md#iso19139-elem-gmd-useLimitation-07252e81be8d86aea4553aa3df807d8b) + +Name + +: + +> Use limitation + +Name + +: + +> Use limitation + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification) > 0 + +``` xml + + + + + + + +``` + +##### Access constraints + +##### Other constraints + +```{=html} +Other restrictions and legal prerequisites for accessing and using the resource +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/ gmd:resourceConstraints/gmd:MD_LegalConstraints/gmd:otherConstraints + +See [Other constraints](iso19139.md#iso19139-elem-gmd-otherConstraints-696de5ef421a230cf560f7566a3c5028) + +Name + +: + +> Other constraints + +Name + +: + +> Access constraints + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification) > 0 + +``` xml + + + + + + + + + + + +``` + +##### Section: Responsible organization (s) + +##### Contact for the resource + +##### Point of contact + +```{=html} +Identification of, and means of communication with, person(s) and organizations(s) associated with the resource(s) +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/*/gmd:pointOfContact + +See [Point of contact](iso19139.md#iso19139-elem-gmd-pointOfContact-2a38035f4c8b63a35a4e6c44e6f4b624) + +Name + +: + +> Contact for the resource + +Type + +: + +> add + +``` xml + + + + + + + + + + + + + + + + + + + + + +``` + +##### Section: Responsible organization (s) + +##### Contact for the resource + +##### Point of contact + +```{=html} +Identification of, and means of communication with, person(s) and organizations(s) associated with the resource(s) +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/*/gmd:pointOfContact + +See [Point of contact](iso19139.md#iso19139-elem-gmd-pointOfContact-2a38035f4c8b63a35a4e6c44e6f4b624) + +Name + +: + +> Contact for the resource + +Type + +: + +> add + +``` xml + + + + + + + + + + + + + + + + + + + + + +``` + +##### Section: Metadata information + +##### Contact for the metadata + +##### Contact + +```{=html} +Party responsible for the metadata information +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:contact + +See [Metadata author](iso19139.md#iso19139-elem-gmd-contact-1a17bee429a4ae3c87f4026bd2da8005) + +Name + +: + +> Contact for the metadata + +Type + +: + +> add + +``` xml + + + + + + + + + + + + + + + + + + + + + +``` + +##### Date stamp + +```{=html} +Date that the metadata was created (YYYY-MM-DDThh:mm:ss) +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:dateStamp + +See [Date stamp](iso19139.md#iso19139-elem-gmd-dateStamp-ee89eb65741d89aef14d153887f60948) + +##### Metadata language + +```{=html} +Language used for documenting metadata +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:language + +See [Metadata language](iso19139.md#iso19139-elem-gmd-language-98a1fec5ea30c100ef63f1ca4bd6dbdb) + +Name + +: + +> Metadata language + +Name + +: + +Type + +: + +> add + +``` xml + + + +``` + +##### Character set + +```{=html} +Full name of the character coding standard used for the dataset +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/gmd:MD_DataIdentification/gmd:characterSet + +See [Character set](iso19139.md#iso19139-elem-gmd-characterSet-351330c9787387f916fed1143727215b) + +#### Tab: SDS (inspire_sds) {#iso19139-tab-inspire_sds} + +This tab display elements from the XML metadata record. + +##### Section: Conformance class 1: invocable + +Type + +: + +> process + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:dataQualityInfo/gmd:DQ_DataQuality[gmd:scope/gmd:DQ_Scope/gmd:level/gmd:='service'])=0 + +Type + +: + +> process + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:dataQualityInfo/gmd:DQ_DataQuality[gmd:scope/gmd:DQ_Scope/gmd:level/gmd:='service']/gmd:report/gmd:DQ_DomainConsistency/gmd:result/gmd:DQ_ConformanceResult/gmd:specification/gmd:CI_Citation/gmd:title/gco:CharacterString)>0 + +##### Category + +##### Data quality + +```{=html} +Quality information for the data specified by a data quality scope +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:dataQualityInfo/gmd:DQ_DataQuality[gmd:scope/gmd:DQ_Scope/gmd:level/gmd:='service']/gmd:report/gmd:DQ_DomainConsistency/gmd:result/gmd:DQ_ConformanceResult/gmd:specification/gmd:CI_Citation/gmd:title + +See [Data quality](iso19139.md#iso19139-elem-gmd-DQ_DataQuality-16d17a37284f157b42d492a5960b5171) + +##### Data quality + +```{=html} +Quality information for the data specified by a data quality scope +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:dataQualityInfo/gmd:DQ_DataQuality[gmd:scope/gmd:DQ_Scope/gmd:level/gmd:='service']/gmd:report/gmd:DQ_DomainConsistency/gmd:result/gmd:DQ_ConformanceResult/gmd:pass + +See [Data quality](iso19139.md#iso19139-elem-gmd-DQ_DataQuality-16d17a37284f157b42d492a5960b5171) + +Name + +: + +> Add pass element + +Type + +: + +> add + +``` xml + + true + +``` + +##### Access Point URL + +##### OnLine resource + +```{=html} +Information about online sources from which the resource can be obtained +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:distributionInfo/gmd:MD_Distribution//gmd:transferOptions/gmd:MD_DigitalTransferOptions/gmd:onLine[gmd:CI_OnlineResource/gmd:description/gmx:Anchor/text() = 'accessPoint'] + +See [OnLine resource](iso19139.md#iso19139-elem-gmd-onLine-c0b191c96e7e4d7dfc2a4ba2fd8946f4) + +Name + +: + +> Add Access Point + +Type + +: + +> add + +``` xml + + + + http://accesspoint.url + + + + accessPoint + + + + + + + +``` + +##### Endpoint URL + +##### OnLine resource + +```{=html} +Information about online sources from which the resource can be obtained +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:distributionInfo/gmd:MD_Distribution//gmd:transferOptions/gmd:MD_DigitalTransferOptions/gmd:onLine[gmd:CI_OnlineResource/gmd:description/gmx:Anchor/text() = 'endPoint'] + +See [OnLine resource](iso19139.md#iso19139-elem-gmd-onLine-c0b191c96e7e4d7dfc2a4ba2fd8946f4) + +Name + +: + +> Add Endpoint + +Type + +: + +> add + +``` xml + + + + http://endpoint.url + + + + endPoint + + + + + + + +``` + +##### Technical specification + +##### Data quality + +```{=html} +Quality information for the data specified by a data quality scope +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:dataQualityInfo/gmd:DQ_DataQuality[gmd:scope/gmd:DQ_Scope/gmd:level/gmd:='service']/gmd:report/gmd:DQ_DomainConsistency/gmd:result + +See [Data quality](iso19139.md#iso19139-elem-gmd-DQ_DataQuality-16d17a37284f157b42d492a5960b5171) + +Name + +: + +> Add a technical specification + +Type + +: + +> add + +``` xml + + + + + + + + + Description of technical specification + + + + + + 2014-12-11 + + + + + + + + + + Conformant to the cited specifications. + + + + true + + + + + +``` + +##### Section: Conformance class 2: interoperable + +##### Section: Coordinate reference system + +##### Anchor + +```{=html} +Supports hyper-linking capabilities and ensures a web-like implementation of CharacterStrings +``` + +XPath + +: + +> gmd:MD_Metadata/gmd:referenceSystemInfo/gmd:MD_ReferenceSystem/gmd:referenceSystemIdentifier/gmd:RS_Identifier/gmd:code/gmx:Anchor + +See [Anchor](iso19139.md#iso19139-elem-gmx-Anchor-d0ccf7ef89bd129a31fe766fae38f1df) + +Name + +: + +> Projection + +Type + +: + +> add + +``` xml + + + + + + {{code}} + + + + + + +``` + +##### Section: Quality of Service + +Type + +: + +> process + +Displayed only if + +: + +> (count(gmd:MD_Metadata/gmd:dataQualityInfo/gmd:DQ_DataQuality[gmd:scope/gmd:DQ_Scope/gmd:level/gmd:='service'])>0 and (count(gmd:MD_Metadata/gmd:dataQualityInfo/gmd:DQ_DataQuality[gmd:scope/gmd:DQ_Scope/gmd:level/gmd:='service']/gmd:report/gmd:DQ_ConceptualConsistency/gmd:nameOfMeasure/gmx:Anchor[text()='availability'])=0 or count(gmd:MD_Metadata/gmd:dataQualityInfo/gmd:DQ_DataQuality[gmd:scope/gmd:DQ_Scope/gmd:level/gmd:='service']/gmd:report/gmd:DQ_ConceptualConsistency/gmd:nameOfMeasure/gmx:Anchor[text()='performance'])=0 or count(gmd:MD_Metadata/gmd:dataQualityInfo/gmd:DQ_DataQuality[gmd:scope/gmd:DQ_Scope/gmd:level/gmd:='service']/gmd:report/gmd:DQ_ConceptualConsistency/gmd:nameOfMeasure/gmx:Anchor[text()='capacity'])=0 )) + +##### Conceptual consistency + +```{=html} +Adherence to rules of the conceptual schema +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:dataQualityInfo/gmd:DQ_DataQuality/gmd:report/gmd:DQ_ConceptualConsistency + +See [Conceptual consistency](iso19139.md#iso19139-elem-gmd-DQ_ConceptualConsistency-d42ad4a3a30578c7431606e8c1df4df8) + +##### Section: Access constraints + +##### Resource constraints + +```{=html} +Provides information about constraints which apply to the resource(s) +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:resourceConstraints[gmd:MD_LegalConstraints[gmd:accessConstraints]/gmd:otherConstraints/gmx:Anchor] + +See [Resource constraints](iso19139.md#iso19139-elem-gmd-resourceConstraints-3ce815f506c31e6b5ef8e4e7022eefad) + +##### Limitation + +##### Resource constraints + +```{=html} +Provides information about constraints which apply to the resource(s) +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:resourceConstraints[gmd:MD_LegalConstraints[gmd:accessConstraints]/gmd:otherConstraints[gco:CharacterString]] + +See [Resource constraints](iso19139.md#iso19139-elem-gmd-resourceConstraints-3ce815f506c31e6b5ef8e4e7022eefad) + +Name + +: + +> No Limitation + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:resourceConstraints/gmd:MD_LegalConstraints[gmd:accessConstraints]) = 0 + +``` xml + + + + + + + + No Conditions Apply + + + + +``` + +Name + +: + +> Unknown Limitation + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:resourceConstraints/gmd:MD_LegalConstraints[gmd:accessConstraints]) = 0 + +``` xml + + + + + + + + Conditions Unknown + + + + +``` + +Name + +: + +> Customizable constraints + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:resourceConstraints/gmd:MD_LegalConstraints[gmd:accessConstraints]) = 0 + +``` xml + + + + + + + + + + +``` + +##### Section: Use constraints + +##### Resource constraints + +```{=html} +Provides information about constraints which apply to the resource(s) +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:resourceConstraints[gmd:MD_LegalConstraints[gmd:useConstraints]/gmd:otherConstraints/gmx:Anchor] + +See [Resource constraints](iso19139.md#iso19139-elem-gmd-resourceConstraints-3ce815f506c31e6b5ef8e4e7022eefad) + +##### Limitation + +##### Resource constraints + +```{=html} +Provides information about constraints which apply to the resource(s) +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:resourceConstraints[gmd:MD_LegalConstraints[gmd:useConstraints]/gmd:otherConstraints[gco:CharacterString]] + +See [Resource constraints](iso19139.md#iso19139-elem-gmd-resourceConstraints-3ce815f506c31e6b5ef8e4e7022eefad) + +Name + +: + +> No Limitation + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:resourceConstraints/gmd:MD_LegalConstraints[gmd:useConstraints]) = 0 + +``` xml + + + + + + + + No Conditions Apply + + + + +``` + +Name + +: + +> Unknown Limitation + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:resourceConstraints/gmd:MD_LegalConstraints[gmd:useConstraints]) = 0 + +``` xml + + + + + + + + Conditions Unknown + + + + +``` + +Name + +: + +> Customizable constraints + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:resourceConstraints/gmd:MD_LegalConstraints[gmd:useConstraints]) = 0 + +``` xml + + + + + + + + + + +``` + +##### Section: Responsible custodian + +##### Contact for the resource + +##### Point of contact + +```{=html} +Identification of, and means of communication with, person(s) and organizations(s) associated with the resource(s) +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:pointOfContact[gmd:CI_ResponsibleParty/gmd:role/gmd:='custodian'] + +See [Point of contact](iso19139.md#iso19139-elem-gmd-pointOfContact-2a38035f4c8b63a35a4e6c44e6f4b624) + +Name + +: + +> Contact for the resource + +Type + +: + +> add + +##### Section: Coordinate reference system + +##### Anchor + +```{=html} +Supports hyper-linking capabilities and ensures a web-like implementation of CharacterStrings +``` + +XPath + +: + +> gmd:MD_Metadata/gmd:referenceSystemInfo/gmd:MD_ReferenceSystem/gmd:referenceSystemIdentifier/gmd:RS_Identifier/gmd:code/gmx:Anchor + +See [Anchor](iso19139.md#iso19139-elem-gmx-Anchor-d0ccf7ef89bd129a31fe766fae38f1df) + +Name + +: + +> Projection + +Type + +: + +> add + +``` xml + + + + + + {{code}} + + + + + + +``` + +##### Section: Quality of Service + +Type + +: + +> process + +Displayed only if + +: + +> (count(gmd:MD_Metadata/gmd:dataQualityInfo/gmd:DQ_DataQuality[gmd:scope/gmd:DQ_Scope/gmd:level/gmd:='service'])>0 and (count(gmd:MD_Metadata/gmd:dataQualityInfo/gmd:DQ_DataQuality[gmd:scope/gmd:DQ_Scope/gmd:level/gmd:='service']/gmd:report/gmd:DQ_ConceptualConsistency/gmd:nameOfMeasure/gmx:Anchor[text()='availability'])=0 or count(gmd:MD_Metadata/gmd:dataQualityInfo/gmd:DQ_DataQuality[gmd:scope/gmd:DQ_Scope/gmd:level/gmd:='service']/gmd:report/gmd:DQ_ConceptualConsistency/gmd:nameOfMeasure/gmx:Anchor[text()='performance'])=0 or count(gmd:MD_Metadata/gmd:dataQualityInfo/gmd:DQ_DataQuality[gmd:scope/gmd:DQ_Scope/gmd:level/gmd:='service']/gmd:report/gmd:DQ_ConceptualConsistency/gmd:nameOfMeasure/gmx:Anchor[text()='capacity'])=0 )) + +##### Conceptual consistency + +```{=html} +Adherence to rules of the conceptual schema +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:dataQualityInfo/gmd:DQ_DataQuality/gmd:report/gmd:DQ_ConceptualConsistency + +See [Conceptual consistency](iso19139.md#iso19139-elem-gmd-DQ_ConceptualConsistency-d42ad4a3a30578c7431606e8c1df4df8) + +##### Section: Access constraints + +##### Resource constraints + +```{=html} +Provides information about constraints which apply to the resource(s) +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:resourceConstraints[gmd:MD_LegalConstraints[gmd:accessConstraints]/gmd:otherConstraints/gmx:Anchor] + +See [Resource constraints](iso19139.md#iso19139-elem-gmd-resourceConstraints-3ce815f506c31e6b5ef8e4e7022eefad) + +##### Limitation + +##### Resource constraints + +```{=html} +Provides information about constraints which apply to the resource(s) +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:resourceConstraints[gmd:MD_LegalConstraints[gmd:accessConstraints]/gmd:otherConstraints[gco:CharacterString]] + +See [Resource constraints](iso19139.md#iso19139-elem-gmd-resourceConstraints-3ce815f506c31e6b5ef8e4e7022eefad) + +Name + +: + +> No Limitation + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:resourceConstraints/gmd:MD_LegalConstraints[gmd:accessConstraints]) = 0 + +``` xml + + + + + + + + No Conditions Apply + + + + +``` + +Name + +: + +> Unknown Limitation + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:resourceConstraints/gmd:MD_LegalConstraints[gmd:accessConstraints]) = 0 + +``` xml + + + + + + + + Conditions Unknown + + + + +``` + +Name + +: + +> Customizable constraints + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:resourceConstraints/gmd:MD_LegalConstraints[gmd:accessConstraints]) = 0 + +``` xml + + + + + + + + + + +``` + +##### Section: Use constraints + +##### Resource constraints + +```{=html} +Provides information about constraints which apply to the resource(s) +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:resourceConstraints[gmd:MD_LegalConstraints[gmd:useConstraints]/gmd:otherConstraints/gmx:Anchor] + +See [Resource constraints](iso19139.md#iso19139-elem-gmd-resourceConstraints-3ce815f506c31e6b5ef8e4e7022eefad) + +##### Limitation + +##### Resource constraints + +```{=html} +Provides information about constraints which apply to the resource(s) +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:resourceConstraints[gmd:MD_LegalConstraints[gmd:useConstraints]/gmd:otherConstraints[gco:CharacterString]] + +See [Resource constraints](iso19139.md#iso19139-elem-gmd-resourceConstraints-3ce815f506c31e6b5ef8e4e7022eefad) + +Name + +: + +> No Limitation + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:resourceConstraints/gmd:MD_LegalConstraints[gmd:useConstraints]) = 0 + +``` xml + + + + + + + + No Conditions Apply + + + + +``` + +Name + +: + +> Unknown Limitation + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:resourceConstraints/gmd:MD_LegalConstraints[gmd:useConstraints]) = 0 + +``` xml + + + + + + + + Conditions Unknown + + + + +``` + +Name + +: + +> Customizable constraints + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:resourceConstraints/gmd:MD_LegalConstraints[gmd:useConstraints]) = 0 + +``` xml + + + + + + + + + + +``` + +##### Section: Responsible custodian + +##### Contact for the resource + +##### Point of contact + +```{=html} +Identification of, and means of communication with, person(s) and organizations(s) associated with the resource(s) +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/gmd:pointOfContact[gmd:CI_ResponsibleParty/gmd:role/gmd:='custodian'] + +See [Point of contact](iso19139.md#iso19139-elem-gmd-pointOfContact-2a38035f4c8b63a35a4e6c44e6f4b624) + +Name + +: + +> Contact for the resource + +Type + +: + +> add + +##### Section: Conformance class 3: harmonized + +##### Contains Operations + +```{=html} +Provides information about the operations that comprise the service +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification/srv:containsOperations + +See [Contains Operations](iso19139.md#iso19139-elem-srv-containsOperations-5765a967aadd33b5ba92cde03c9ce30e) + +Name + +: + +> Add Operation + +Type + +: + +> add + +Displayed only if + +: + +> count(gmd:MD_Metadata/gmd:identificationInfo/srv:SV_ServiceIdentification) > 0 + +``` xml + + + + + + + Web services + + + + + + http:// + + + + + +``` + +### View: Simple (default) {#iso19139-view-default} + +This view is composed of1tab(s). + +- [Tab: Simple (default)](iso19139.md#iso19139-tab-default) + +This view also allows to add the following element even if not in the current record: + +- Descriptive keywords (gmd:descriptiveKeywords) +- Keyword (gmd:keyword) +- Name (gmd:name) +- Spatial resolution (gmd:spatialResolution) +- Point of contact (gmd:pointOfContact) +- Distributor (gmd:distributor) +- Distribution format (gmd:distributionFormat) +- Contact (gmd:contact) +- Processor (gmd:processor) +- Topic category (gmd:topicCategory) +- Parameters (srv:parameters) + +#### Tab: Simple (default) {#iso19139-tab-default} + +![](img/iso19139-tab-default.png) + +This tab display elements from the XML metadata record. + +Instruction + +: + +##### Linkage + +```{=html} +Location (address) for on-line access using a Uniform Resource Locator address or similar addressing scheme such as http://www.statkart.no/isotc211 +``` + +XPath + +: + +> */gmd:linkage + +See [Linkage](iso19139.md#iso19139-elem-gmd-linkage-ddec55285da8318007d8ba8df6febcb5) + +##### Name + +XPath + +: + +> */gmd:name + +See [Name](iso19139.md#iso19139-elem-gmd-name-9796db4d1cab411f64fa97871fd1dd7e) + +Instruction + +: + +##### Linkage + +```{=html} +Location (address) for on-line access using a Uniform Resource Locator address or similar addressing scheme such as http://www.statkart.no/isotc211 +``` + +XPath + +: + +> */gmd:linkage + +See [Linkage](iso19139.md#iso19139-elem-gmd-linkage-ddec55285da8318007d8ba8df6febcb5) + +##### Name + +XPath + +: + +> */gmd:name + +See [Name](iso19139.md#iso19139-elem-gmd-name-9796db4d1cab411f64fa97871fd1dd7e) + +##### Section: Content Information + +```{=html} +Provides information about the feature catalogue and describes the coverage and image data characteristics +``` +See [Content Information](iso19139.md#iso19139-elem-gmd-contentInfo-da18cd6a5e91bae67187adc15ff47622) + +##### Included with dataset + +```{=html} +Indication of whether or not the feature catalogue is included with the dataset +``` + +XPath + +: + +> gmd:MD_FeatureCatalogueDescription/gmd:includedWithDataset + +See [Included with dataset](iso19139.md#iso19139-elem-gmd-includedWithDataset-0148507e25f25653e843ec66cf6cb878) + +##### Feature catalogue citation + +```{=html} +Complete bibliographic reference to one or more external feature catalogues +``` +See [Feature catalogue citation](iso19139.md#iso19139-elem-gmd-featureCatalogueCitation-0d490aca236a02c867c265dc0656143b) + +XPath + +: + +> . + +##### Feature catalogue citation + +```{=html} +Complete bibliographic reference to one or more external feature catalogues +``` +See [Feature catalogue citation](iso19139.md#iso19139-elem-gmd-featureCatalogueCitation-0d490aca236a02c867c265dc0656143b) + +XPath + +: + +> . + +Name + +: + +Type + +: + +> add + +``` xml + + + + true + + + + +``` + +### View: Full (advanced) {#iso19139-view-advanced} + +This view is composed of11tab(s). + +- [Tab: Identification (identificationInfo)](iso19139.md#iso19139-tab-identificationInfo) +- [Tab: Distribution (distributionInfo)](iso19139.md#iso19139-tab-distributionInfo) +- [Tab: Quality (dataQualityInfo)](iso19139.md#iso19139-tab-dataQualityInfo) +- [Tab: Spatial rep. (spatialRepresentationInfo)](iso19139.md#iso19139-tab-spatialRepresentationInfo) +- [Tab: Ref. system (referenceSystemInfo)](iso19139.md#iso19139-tab-referenceSystemInfo) +- [Tab: Content (contentInfo)](iso19139.md#iso19139-tab-contentInfo) +- [Tab: Portrayal (portrayalCatalogueInfo)](iso19139.md#iso19139-tab-portrayalCatalogueInfo) +- [Tab: Metadata (metadata)](iso19139.md#iso19139-tab-metadata) +- [Tab: Md. constraints (metadataConstraints)](iso19139.md#iso19139-tab-metadataConstraints) +- [Tab: Md. maintenance (metadataMaintenance)](iso19139.md#iso19139-tab-metadataMaintenance) +- [Tab: Schema info (applicationSchemaInfo)](iso19139.md#iso19139-tab-applicationSchemaInfo) + +#### Tab: Identification (identificationInfo) {#iso19139-tab-identificationInfo} + +![](img/iso19139-tab-identificationInfo.png) + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Identification info + +```{=html} +Basic information about the resource(s) to which the metadata applies +``` +See [Identification info](iso19139.md#iso19139-elem-gmd-identificationInfo-4fe68a205ff13feeccf0b58e08f39472) + +#### Tab: Distribution (distributionInfo) {#iso19139-tab-distributionInfo} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Distribution Information + +```{=html} +Provides information about the distributor of and options for obtaining the resource(s) +``` +See [Distribution Information](iso19139.md#iso19139-elem-gmd-distributionInfo-3bddab6fda29c9ebd6f0ece68843fcff) + +#### Tab: Quality (dataQualityInfo) {#iso19139-tab-dataQualityInfo} + +![](img/iso19139-tab-dataQualityInfo.png) + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Data quality info + +```{=html} +Provides overall assessment of quality of a resource(s) +``` +See [Data quality info](iso19139.md#iso19139-elem-gmd-dataQualityInfo-9a53c25e2dacf5a7ab0aa1d155efc3dc) + +#### Tab: Spatial rep. (spatialRepresentationInfo) {#iso19139-tab-spatialRepresentationInfo} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Spatial representation info + +```{=html} +Digital representation of spatial information in the dataset +``` +See [Spatial representation info](iso19139.md#iso19139-elem-gmd-spatialRepresentationInfo-f93705d4877ccd4c41819cc79677d6f2) + +#### Tab: Ref. system (referenceSystemInfo) {#iso19139-tab-referenceSystemInfo} + +![](img/iso19139-tab-referenceSystemInfo.png) + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Reference System Information + +```{=html} +Description of the spatial and temporal reference systems used in the dataset +``` +See [Reference System Information](iso19139.md#iso19139-elem-gmd-referenceSystemInfo-c7702a2e8ac03097e306ab3a02406765) + +#### Tab: Content (contentInfo) {#iso19139-tab-contentInfo} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Content Information + +```{=html} +Provides information about the feature catalogue and describes the coverage and image data characteristics +``` +See [Content Information](iso19139.md#iso19139-elem-gmd-contentInfo-da18cd6a5e91bae67187adc15ff47622) + +#### Tab: Portrayal (portrayalCatalogueInfo) {#iso19139-tab-portrayalCatalogueInfo} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Portrayal catalogue info + +```{=html} +Provides information about the catalogue of rules defined for the portrayal of a resource(s) +``` +See [Portrayal catalogue info](iso19139.md#iso19139-elem-gmd-portrayalCatalogueInfo-0a09defe8c7ca8431460b5690da9a52d) + +#### Tab: Metadata (metadata) {#iso19139-tab-metadata} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Metadata + +##### File identifier + +```{=html} +Unique identifier for this metadata file +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:fileIdentifier + +See [File identifier](iso19139.md#iso19139-elem-gmd-fileIdentifier-353be7794d17e5435ce2fe57d91966ba) + +##### Metadata language + +```{=html} +Language used for documenting metadata +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:language + +See [Metadata language](iso19139.md#iso19139-elem-gmd-language-98a1fec5ea30c100ef63f1ca4bd6dbdb) + +##### Other language + +```{=html} +Use this section to define other metadata language (multilingual metadata). +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:locale + +See [Other language](iso19139.md#iso19139-elem-gmd-locale-826113f1d130f65f95c78f6b16227c4b) + +##### Character set + +```{=html} +Full name of the character coding standard used for the metadata set +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:characterSet + +See [Character set](iso19139.md#iso19139-elem-gmd-characterSet-351330c9787387f916fed1143727215b) + +##### Parent identifier + +```{=html} +File identifier of the metadata to which this metadata is a subset (child) +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:parentIdentifier + +See [Parent identifier](iso19139.md#iso19139-elem-gmd-parentIdentifier-e660d48fcd79782e330d99a6eee272bc) + +##### Hierarchy level + +```{=html} +Scope to which the metadata applies (see annex H for more information about metadata hierarchy levels) +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:hierarchyLevel + +See [Hierarchy level](iso19139.md#iso19139-elem-gmd-hierarchyLevel-2b6d53b433d8f9c0cc58606d27eecc17) + +##### Hierarchy level name + +```{=html} +Name of the hierarchy levels for which the metadata is provided +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:hierarchyLevelName + +See [Hierarchy level name](iso19139.md#iso19139-elem-gmd-hierarchyLevelName-1c79276b0501d07055d7480b292899f0) + +##### Date stamp + +```{=html} +Date that the metadata was created (YYYY-MM-DDThh:mm:ss) +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:dateStamp + +See [Date stamp](iso19139.md#iso19139-elem-gmd-dateStamp-ee89eb65741d89aef14d153887f60948) + +##### Metadata standard name + +```{=html} +Name of the metadata standard (including profile name) used +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:metadataStandardName + +See [Metadata standard name](iso19139.md#iso19139-elem-gmd-metadataStandardName-1e8d324f913f2da08b656d26e73e994d) + +##### Metadata standard version + +```{=html} +Version (profile) of the metadata standard used +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:metadataStandardVersion + +See [Metadata standard version](iso19139.md#iso19139-elem-gmd-metadataStandardVersion-ab0dd515a6ca9c890bc32d3615cd427f) + +##### Contact + +```{=html} +Party responsible for the metadata information +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:contact + +See [Metadata author](iso19139.md#iso19139-elem-gmd-contact-1a17bee429a4ae3c87f4026bd2da8005) + +##### Dataset URI + +```{=html} +Uniformed Resource Identifier (URI) of the dataset to which the metadata applies +``` +```{=html} +Uniformed Resource Identifier (URI) of the dataset to which the metadata applies. This link refers direct to the machine-readable dataset. +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:dataSetURI + +See [Dataset URI](iso19139.md#iso19139-elem-gmd-dataSetURI-8e14b3e6d98f92a9356ba2f3ba1ee982) + +##### Series + +```{=html} +Information about the series, or aggregate dataset, of which the dataset is a part +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:series + +See [Series](iso19139.md#iso19139-elem-gmd-series-98524248b047e1a31966f4fc05c765fb) + +##### Describes + +```{=html} +Describes +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:describes + +See [Describes](iso19139.md#iso19139-elem-gmd-describes-ea7ef755fceda2ec8b1bf4486f5572bf) + +##### PropertyType + +```{=html} +PropertyType +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:propertyType + +See [PropertyType](iso19139.md#iso19139-elem-gmd-propertyType-12fff0b8b43529f0300c32a5e13c9f89) + +##### Feature type + +```{=html} +Subset of feature types from cited feature catalogue occurring in data +``` + +XPath + +: + +> /gmd:MD_Metadata/gmd:featureType + +See [Feature type](iso19139.md#iso19139-elem-gmd-featureType-1a7ddaf6d70b2bca513bbb097769f7a5) + +##### Feature attribute + +XPath + +: + +> /gmd:MD_Metadata/gmd:featureAttribute + +See [Feature attribute](iso19139.md#iso19139-elem-gmd-featureAttribute-ed65880b0d966b5862d0d434b26fd36b) + +#### Tab: Md. constraints (metadataConstraints) {#iso19139-tab-metadataConstraints} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Metadata constraints + +```{=html} +Provides restrictions on the access and use of metadata +``` +See [Metadata constraints](iso19139.md#iso19139-elem-gmd-metadataConstraints-0547cb4265a8d2f9663d558a9ac72d43) + +#### Tab: Md. maintenance (metadataMaintenance) {#iso19139-tab-metadataMaintenance} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Metadata maintenance + +```{=html} +Provides information about the frequency of metadata updates, and the scope of those updates +``` +See [Metadata maintenance](iso19139.md#iso19139-elem-gmd-metadataMaintenance-2af9bf1fc8f71819e7361e5d6987358c) + +#### Tab: Schema info (applicationSchemaInfo) {#iso19139-tab-applicationSchemaInfo} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +##### Section: Application schema info + +```{=html} +Provides information about the conceptual schema of a dataset +``` +See [Application schema info](iso19139.md#iso19139-elem-gmd-applicationSchemaInfo-45e55618bc13cc73f4ede49af591b9cb) + +### View: XML (xml) {#iso19139-view-xml} + +This view is composed of1tab(s). + +- [Tab: XML (xml)](iso19139.md#iso19139-tab-xml) + +#### Tab: XML (xml) {#iso19139-tab-xml} + +This tab display elements from the XML metadata record and also provide controls to add all elements defined in the schema (XSD). + +## Schema technical details + +Standard identifier + +: + +> iso19139 + +Version + +: + +> 1.0 + +Schema location + +: + +> + +Schema namespaces + +: + +- +- +- +- +- + +Schema detection mode + +: + +> elements (root) + +Schema detection elements + +: + +- gmd:CI_ResponsibleParty +- gmd:DQ_DomainConsistency +- gmd:EX_Extent +- gmd:MD_Format +- gmd:MD_Metadata + +## Standard elements + +List of all elements available in the standard. + +### Name of the calendar era {#iso19139-elem-calendarEraName-f6992f57e0b42d0d298ceab6163baa24} + +Name + +: + +> calendarEraName + +Description + +: + +### Code {#iso19139-elem-code-gmd-MD_Identifier-b9e23155977b220811ee241a27dec71c} + +Name + +: + +> code + +Context + +: + +> gmd:MD_Identifier + +Description + +: + +```{=html} +Alphanumeric value identifying an instance in the namespace +``` +```{=html} +alphanumeric value identifying an instance in the namespace +``` +### System code {#iso19139-elem-code-34002ba7723581d2ef06d2611cab31af} + +Name + +: + +> code + +Description + +: + +```{=html} +Code. i.e. EPSG code. +``` +### Code {#iso19139-elem-code-gmd-MD_CodeValue-1315454a3efd07503687cfc5628f2cf1} + +Name + +: + +> code + +Context + +: + +> gmd:MD_CodeValue + +Description + +: + +```{=html} +Value code +``` +```{=html} +Value code (i.e. numeric) +``` +### Reference Authority {#iso19139-elem-codeSpace-0e8f09aab4d7c2a27305e0cc2a489acc} + +Name + +: + +> codeSpace + +Description + +: + +```{=html} +Authority responsible for codification. i.e. EPSG +``` +### Direct projection system (for geographical resources) {#iso19139-elem-DirectReferenceSystem-d28cd37e0c2b9a86305c20c194bf5f79} + +Name + +: + +> DirectReferenceSystem + +Description + +: + +```{=html} +ReferenceSystem derived / specify that it is a direct + reference +``` +### Factor {#iso19139-elem-factor-7e34666ca11658e04e31d3a614685b15} + +Name + +: + +> factor + +Description + +: + +### Frame {#iso19139-elem-frame-4aefbf304b03d93af57daba6b7c1fa8d} + +Name + +: + +> frame + +Description + +: + +```{=html} +Frame attribute provides a URI reference that identifies a description of the + reference system +``` +### Name {#iso19139-elem-gco-aName-39d38a0515ba733c328d5bd1c57e7e5e} + +Name + +: + +> gco:aName + +Description + +: + +### Type name {#iso19139-elem-gco-aName-gco-TypeName-b5751c296623f4c8529273aaf3caa587} + +Name + +: + +> gco:aName + +Context + +: + +> gco:TypeName + +Description + +: + +Recommended values + +| code | label | +|-----------|-----------| +| BOOLEAN | BOOLEAN | +| BYTE | BYTE | +| CHARACTER | CHARACTER | +| DATE | DATE | +| DATETIME | DATETIME | +| DOUBLE | DOUBLE | +| FLOAT | FLOAT | +| INTEGER | INTEGER | +| NUMERIC | NUMERIC | +| REAL | REAL | +| SERIAL | SERIAL | +| VARCHAR | VARCHAR | +| TEXT | TEXT | + +### Angle {#iso19139-elem-gco-Angle-3593960aae71b8b1bdfe5ebf0f35d2c9} + +Name + +: + +> gco:Angle + +Description + +: + +### Attribute type {#iso19139-elem-gco-attributeType-0b903ede9f187704365df4f997921127} + +Name + +: + +> gco:attributeType + +Description + +: + +### Binary {#iso19139-elem-gco-Binary-a22b5d55570c2130700e110981a19fc0} + +Name + +: + +> gco:Binary + +Description + +: + +### Text {#iso19139-elem-gco-CharacterString-3c4a83cea72b8088a49c2cdafdcaf1c1} + +Name + +: + +> gco:CharacterString + +Description + +: + +### Edition Date {#iso19139-elem-gco-Date-gmd-CI_Citation-ca5259e4b2838d1c0558671de588f0df} + +Name + +: + +> gco:Date + +Context + +: + +> gmd:CI_Citation + +Description + +: + +```{=html} +Date of the edition +``` +### Date {#iso19139-elem-gco-Date-c5ab2c208539dd2f12e12861e602dc91} + +Name + +: + +> gco:Date + +Description + +: + +```{=html} +Formatted as 2007-09-12 (YYYY-MM-DD) +``` +```{=html} +reference date and event used to describe it +``` +### Usage Date / Time {#iso19139-elem-gco-DateTime-gmd-MD_Usage-5932999d2f9d3461e5820eade7175b5b} + +Name + +: + +> gco:DateTime + +Context + +: + +> gmd:MD_Usage + +Description + +: + +```{=html} +Formatted as 2007-09-12T15:00:00 (YYYY-MM-DDTHH:mm:ss) +``` +```{=html} +date and time of the first use or range of uses of the resource and/or resource + series +``` +``` xml +2016-01-15T16:57:35 +``` + +### Planned Available Date / Time {#iso19139-elem-gco-DateTime-gmd-MD_StandardOrderProcess-c7c418ca6afb419b0c0f7978f0f70bd5} + +Name + +: + +> gco:DateTime + +Context + +: + +> gmd:MD_StandardOrderProcess + +Description + +: + +```{=html} +Formatted as 2007-09-12T15:00:00 (YYYY-MM-DDTHH:mm:ss) +``` +```{=html} +date and time when theresource will be available +``` +``` xml +2016-01-15T16:57:35 +``` + +### Date and time {#iso19139-elem-gco-DateTime-32c0a3056194945a06e26342a31c4abe} + +Name + +: + +> gco:DateTime + +Description + +: + +```{=html} +Date and time or range of date and time on or over which the process step occurred + (YYYY-MM-DDThh:mm:ss) +``` +``` xml +2016-01-15T16:57:35 +``` + +### Distance {#iso19139-elem-gco-Distance-97e7c5e41f65464cfde4bdcbd0987611} + +Name + +: + +> gco:Distance + +Description + +: + +``` xml +100 +``` + +### Length {#iso19139-elem-gco-Length-caf3c113efd04589ae6f255714b3cfb5} + +Name + +: + +> gco:Length + +Description + +: + +### Name {#iso19139-elem-gco-localName-d5d8fd10758516aba7e3e61dca6a3d06} + +Name + +: + +> gco:localName + +Description + +: + +### Local name {#iso19139-elem-gco-LocalName-eab12ae644d752a8b1eff54b0477039a} + +Name + +: + +> gco:LocalName + +Description + +: + +### Lower cardinality {#iso19139-elem-gco-lower-2cae58bb16663bb430a5756705195313} + +Name + +: + +> gco:lower + +Description + +: + +```{=html} +Lower cardinality +``` +### Name of Measure {#iso19139-elem-gco-Measure-gmd-DQ_Element-6560606f315eea7246848f93ddc3d967} + +Name + +: + +> gco:Measure + +Context + +: + +> gmd:DQ_Element + +Description + +: + +```{=html} +Name of the test applied to the data +``` +### Unit of Measure {#iso19139-elem-gco-Measure-gmd-EX_VerticalExtent-89983ecdbd1cba38f291e34bee6c223f} + +Name + +: + +> gco:Measure + +Context + +: + +> gmd:EX_VerticalExtent + +Description + +: + +```{=html} +Vertical units used for vertical extent information Examples: metres, feet, + millimetres, hectopascals +``` +### Measure {#iso19139-elem-gco-Measure-462aeec614da812d758659486be00b47} + +Name + +: + +> gco:Measure + +Description + +: + +### Member name {#iso19139-elem-gco-MemberName-b60b50f5b87b148b6615393b823e6a3b} + +Name + +: + +> gco:MemberName + +Description + +: + +### Nil reason {#iso19139-elem-gco-nilReason-fab8a57f0e69d3ca1699fa818c483698} + +Name + +: + +> gco:nilReason + +Description + +: + +### Standard codelists Nil reason (gco:nilReason) + +| code | label | +|--------------|--------------| +| missing | Missing | +| inapplicable | Inapplicable | +| template | Template | +| unknown | Unknown | +| withheld | Withheld | + +### Record {#iso19139-elem-gco-Record-6d9e28990789e830931b4d2ba9766597} + +Name + +: + +> gco:Record + +Description + +: + +### Scale {#iso19139-elem-gco-Scale-be644ab22ff8340a59eb1ea346d70bae} + +Name + +: + +> gco:Scale + +Description + +: + +### Scoped name {#iso19139-elem-gco-ScopedName-fa518f7fd322d0dc580364a3bdd0d0ba} + +Name + +: + +> gco:ScopedName + +Description + +: + +### Type name {#iso19139-elem-gco-TypeName-ca6ce43198031eafc2870fd56a3cca80} + +Name + +: + +> gco:TypeName + +Description + +: + +### Upper cardinality {#iso19139-elem-gco-upper-bb37e0d692d0d0dd4557b3b31c16d35c} + +Name + +: + +> gco:upper + +Description + +: + +```{=html} +Upper cardinality +``` +### Abstract {#iso19139-elem-gmd-abstract-cacfcd3bd6bbd44733f828dd2903ecd8} + +Name + +: + +> gmd:abstract + +Description + +: + +```{=html} +Brief narrative summary of the content of the resource(s) +``` + +Condition + +: + +> mandatory + +``` xml + + The data set combines the Corine based MAES (Mapping and Assessment of + Ecosystems and their Services) ecosystem classes with the non-spatial EUNIS habitat + classification (LEVEL 1) for a better biological characterization of ecosystems across + Europe (EEA-39). As such it represents probabilities of EUNIS habitat presence for each + MAES ecosystem type. + + The data set aims to combine spatially explicit land cover information with non-spatially + referenced habitat information to improve our knowledge about ecosystems and their + distribution across Europe. The work supports the MAES process, Target 2 Action 5 of the + implementation of the EU Biodiversity Strategy to 2020, established to achieve the Aichi + targets of the Convention of Biological Diversity (CBD). + + The objective of the ecosystem data set produced by EEA and its Topic Centre ETC/SIA was + to improve the biological description of land cover based ecosystem types. It represents + probabilities of EUNIS habitat presence in ecosystem types at European level. Since it is + not based on spatial explicit mapping the spatial and thematic accuracy is not of same + quality as delineated maps. + + The MAES ecosystem typology differentiates three levels: whereas the level 2 of the MAES + proposal follows closely the EUNIS level 1, the third level of the MAES typology + corresponds to the EUNIS level 2. This level will be the base for the mapping approach. + + +``` + +### Access constraints {#iso19139-elem-gmd-accessConstraints-37a2c49e23691aae70811fa8493a9501} + +Name + +: + +> gmd:accessConstraints + +Description + +: + +```{=html} +Access constraints applied to assure the protection of privacy or intellectual + property, and any special restrictions or limitations on obtaining the + resource +``` +``` xml + + + +``` + +### Address {#iso19139-elem-gmd-address-gmd-CI_ResponsibleParty-f03654d869b99fc91ee4abcff33fd45a} + +Name + +: + +> gmd:address + +Context + +: + +> gmd:CI_ResponsibleParty + +Description + +: + +```{=html} +Address of the responsible party +``` +### Address {#iso19139-elem-gmd-address-7526bc750039dec29eb9d0d886b5b895} + +Name + +: + +> gmd:address + +Description + +: + +```{=html} +Physical and email address at which the organization or individual may be + contacted +``` +### Administrative area {#iso19139-elem-gmd-administrativeArea-7e04a671c8b9220833d4bf8cbdc92040} + +Name + +: + +> gmd:administrativeArea + +Description + +: + +```{=html} +State, province of the location +``` +### Aggregate Datasetindentifier {#iso19139-elem-gmd-aggregateDataSetIdentifier-f9f0932f51fb5f976d14dc7a9b9d27eb} + +Name + +: + +> gmd:aggregateDataSetIdentifier + +Description + +: + +```{=html} +Identification information about aggregate dataset +``` +### Aggregate Datasetname {#iso19139-elem-gmd-aggregateDataSetName-59f3c71bb683851f84e8495e4cbf6753} + +Name + +: + +> gmd:aggregateDataSetName + +Description + +: + +```{=html} +Citation information about the aggregate dataset +``` +### Aggregation Information {#iso19139-elem-gmd-aggregationInfo-5f7895f7021de881e9a8eeb5f3cf954f} + +Name + +: + +> gmd:aggregationInfo + +Description + +: + +```{=html} +Provides aggregate dataset information +``` +### Alternate title {#iso19139-elem-gmd-alternateTitle-a6ad7cbd770ba390dd40d40adc3767f7} + +Name + +: + +> gmd:alternateTitle + +Description + +: + +```{=html} +Short name or other language name by which the cited information is known. + Example: "DCW" as an alternative title for "Digital Chart of the World +``` +### Amendment number {#iso19139-elem-gmd-amendmentNumber-9baa9c155f39c7359de9d01c15841366} + +Name + +: + +> gmd:amendmentNumber + +Description + +: + +```{=html} +Amendment number of the format version +``` +### Application profile {#iso19139-elem-gmd-applicationProfile-5705b47df6b8e82c11958958b15914a1} + +Name + +: + +> gmd:applicationProfile + +Description + +: + +```{=html} +Name of an application profile that can be used with the online + resource +``` +### Application schema info {#iso19139-elem-gmd-applicationSchemaInfo-45e55618bc13cc73f4ede49af591b9cb} + +Name + +: + +> gmd:applicationSchemaInfo + +Description + +: + +```{=html} +Provides information about the conceptual schema of a dataset +``` +### Association Type {#iso19139-elem-gmd-associationType-e943c0b17dfbb55713da9617c4b8f82d} + +Name + +: + +> gmd:associationType + +Description + +: + +```{=html} +Association type of the aggregate dataset +``` + +Condition + +: + +> mandatory + +### Attribute description {#iso19139-elem-gmd-attributeDescription-00769a0e138b43e364425bc2024f59a7} + +Name + +: + +> gmd:attributeDescription + +Description + +: + +```{=html} +Description of the attribute described by the measurement value +``` + +Condition + +: + +> mandatory + +### Attribute instances {#iso19139-elem-gmd-attributeInstances-d2471a047af6b59087ff645bd19192cf} + +Name + +: + +> gmd:attributeInstances + +Description + +: + +```{=html} +Attribute instances to which the information applies +``` +### Attributes {#iso19139-elem-gmd-attributes-649c8af5decae1033a93a033cc949221} + +Name + +: + +> gmd:attributes + +Description + +: + +```{=html} +Attributes to which the information applies +``` +### Authority {#iso19139-elem-gmd-authority-8906bfad81e05c31f72e1ea5fc426c79} + +Name + +: + +> gmd:authority + +Description + +: + +```{=html} +Person or party responsible for maintenance of the namespace +``` +### Axis Dimensions Properties {#iso19139-elem-gmd-axisDimensionProperties-0bb4895a894113bc668ea60ab4d65b7b} + +Name + +: + +> gmd:axisDimensionProperties + +Description + +: + +```{=html} +Information about spatial-temporal axis properties +``` +### Bits per value {#iso19139-elem-gmd-bitsPerValue-c821e4cbb21edf31325b2502030f1b4a} + +Name + +: + +> gmd:bitsPerValue + +Description + +: + +```{=html} +Maximum number of significant bits in the uncompressed representation for the + value in each band of each pixel +``` +### Camera calibration information availability {#iso19139-elem-gmd-cameraCalibrationInformationAvailability-a7b5dfec3c788d338536cb889d5a9aea} + +Name + +: + +> gmd:cameraCalibrationInformationAvailability + +Description + +: + +```{=html} +Indication of whether or not constants are available which allow for camera + calibration corrections +``` +### Cell geometry {#iso19139-elem-gmd-cellGeometry-890a25e7df81597ba59f0485b15e434f} + +Name + +: + +> gmd:cellGeometry + +Description + +: + +```{=html} +Identification of grid data as point or cell +``` + +Condition + +: + +> mandatory + +### Center point {#iso19139-elem-gmd-centerPoint-c69510c5e9aaea576a6ec9a4d2216a1d} + +Name + +: + +> gmd:centerPoint + +Description + +: + +```{=html} +Earth location in the coordinate system defined by the Spatial Reference System + and the grid coordinate of the cell halfway between opposite ends of the grid in the + spatial dimensions +``` +### Character encoding {#iso19139-elem-gmd-characterEncoding-7c26199d236a428b73baf1a730615e56} + +Name + +: + +> gmd:characterEncoding + +Description + +: + +```{=html} +CharacterEncoding +``` +### Character set {#iso19139-elem-gmd-characterSet-gmd-MD_Metadata-754de1196395a6e9833e813ecf4adaa3} + +Name + +: + +> gmd:characterSet + +Context + +: + +> gmd:MD_Metadata + +Description + +: + +```{=html} +Full name of the character coding standard used for the metadata + set +``` + +Condition + +: + +> conditional + +``` xml + + + +``` + +### Character set {#iso19139-elem-gmd-characterSet-gmd-MD_DataIdentification-bcb6931cff8dcf767968cfa67fd83a88} + +Name + +: + +> gmd:characterSet + +Context + +: + +> gmd:MD_DataIdentification + +Description + +: + +```{=html} +Full name of the character coding standard used for the dataset +``` +``` xml + + + +``` + +### Character set {#iso19139-elem-gmd-characterSet-351330c9787387f916fed1143727215b} + +Name + +: + +> gmd:characterSet + +Description + +: + +```{=html} +Full name of the character coding standard used for the metadata + set +``` + +Condition + +: + +> conditional + +``` xml + + + +``` + +### Checkpoint Availability {#iso19139-elem-gmd-checkPointAvailability-72ce5f12e30b81e5dc63f0585a98bd8a} + +Name + +: + +> gmd:checkPointAvailability + +Description + +: + +```{=html} +Indication of whether or not geographic position points are available to test + the accuracy of the georeferenced grid data +``` + +Condition + +: + +> mandatory + +### Checkpoint Description {#iso19139-elem-gmd-checkPointDescription-cdfe4f08433f7ba8c78498f65aec1099} + +Name + +: + +> gmd:checkPointDescription + +Description + +: + +```{=html} +Description of geographic position points used to test the accuracy of the + georeferenced grid data +``` + +Condition + +: + +> conditional + +### Address {#iso19139-elem-gmd-CI_Address-1d6106250b28fc5d97a0cf1a34c00ef8} + +Name + +: + +> gmd:CI_Address + +Description + +: + +```{=html} +Location of the responsible individual or organization +``` +### Citation {#iso19139-elem-gmd-CI_Citation-1b27899fdd70634298035b26812c0e67} + +Name + +: + +> gmd:CI_Citation + +Description + +: + +```{=html} +Standardised resource reference +``` +### Contact {#iso19139-elem-gmd-CI_Contact-087be944cc5050234e102c0d8eb3cc3d} + +Name + +: + +> gmd:CI_Contact + +Description + +: + +```{=html} +Information required to enable contact with the responsible person and/or + organization +``` +### Date {#iso19139-elem-gmd-CI_Date-7703f686b3d66a527500403e9e888c5d} + +Name + +: + +> gmd:CI_Date + +Description + +: + +```{=html} +Reference date and event used to describe it (YYYY-MM-DD) +``` +### Date type code {#iso19139-elem-gmd-CI_DateTypeCode-beb19798d5fb72e1e08905a0196a7d1a} + +Name + +: + +> gmd:CI_DateTypeCode + +Description + +: + +### Standard codelists Date type code (gmd:CI_DateTypeCode) + +| code | label | description | +|-------------|-------------|---------------------------------------------------------------------------------------| +| creation | Creation | Date identifies when the resource was brought into existence | +| publication | Publication | Date identifies when the resource was issued | +| revision | Revision | Date identifies when the resource was examined or re-examined and improved or amended | + +### OnLine function code {#iso19139-elem-gmd-CI_OnLineFunctionCode-6fe7732b8773444ae385d33f3e3e7ce0} + +Name + +: + +> gmd:CI_OnLineFunctionCode + +Description + +: + +### Standard codelists OnLine function code (gmd:CI_OnLineFunctionCode) + +| code | label | description | +|---------------|----------------|----------------------------------------------------------------------------------------| +| download | Download | Online instructions for transferring data from one storage device or system to another | +| information | Information | Online information about the resource | +| offlineAccess | Offline access | Online instructions for requesting the resource from the provider | +| order | Order | Online order process for obtening the resource | +| search | Search | Online search interface for seeking out information about the resource | + +### OnLine resource {#iso19139-elem-gmd-CI_OnlineResource-213bee17108ab0feab5f62eb0cb7d7ae} + +Name + +: + +> gmd:CI_OnlineResource + +Description + +: + +```{=html} +Information about on-line sources from which the dataset, specification, or + community profile name and extended metadata elements can be obtained +``` +### Presentatiewijze code {#iso19139-elem-gmd-CI_PresentationFormCode-65627a7048d5ce0c224f1836c65ea95f} + +Name + +: + +> gmd:CI_PresentationFormCode + +Description + +: + +### Standard codelists Presentatiewijze code (gmd:CI_PresentationFormCode) + +| code | label | description | +|------------------|-------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| documentDigital | Digital document | Digital representation of a primarily textual item (can contain illustrations also) | +| imageDigital | Digital image | Likeness of natural or man-made features, objects, and activities acquired through the sensing of visual or any other segment of the electromagnetic spectrum by sensors, such as thermal infrared, and high resolution radar and stored in digital format | +| documentHardcopy | Hardcopy document | Representation of a primarily textual item (can contain illustrations also) on paper, photographic material, or other media | +| imageHardcopy | Hardcopy image | Likeness of natural or man-made features, objects, and activities acquired through the sensing of visual or any other segment of the electromagnetic spectrum by sensors, such as thermal infrared, and high resolution radar and reproduced on paper, photographic material, or other media for use directly by the human user | +| mapDigital | Digital map | Map represented in raster or vector form | +| mapHardcopy | Hardcopy map | Map printed on paper, photographic material, or other media for use directly by the human user | +| modelDigital | Digital model | Multi-dimensional digital representation of a feature, process, etc. | +| modelHardcopy | Hardcopy model | 3-dimensional, physical model | +| profileDigital | Digital profile | Vertical cross-section in digital form | +| profileHardcopy | Hardcopy profile | Vertical cross-section printed on paper, etc. | +| tableDigital | Digital table | Digital representation of facts or figures systematically displayed, especially in columns | +| tableHardcopy | Hardcopy table | Representation of facts or figures systematically displayed, especially in columns, printed onpapers, photographic material, or other media | +| videoDigital | Digital video | Digital video recording | +| videoHardcopy | Hardcopy video | Video recording on film | + +### Responsible party {#iso19139-elem-gmd-CI_ResponsibleParty-3c64649ce322328d00e5c999aeceef06} + +Name + +: + +> gmd:CI_ResponsibleParty + +Description + +: + +```{=html} +Identification of, and means of communication with, person(s) and organizations + associated with the dataset +``` +### Role code {#iso19139-elem-gmd-CI_RoleCode-5979017c743ab287cf7d4188dc561d4e} + +Name + +: + +> gmd:CI_RoleCode + +Description + +: + +### Standard codelists Role code (gmd:CI_RoleCode) + +| code | label | description | +|-----------------------|------------------------|--------------------------------------------------------------------------------------------------------------------------------| +| resourceProvider | Resource provider | Party that supplies the resource | +| custodian | Custodian | Party that accepts accountability and responsibility for the data and ensures appropriate care and maintenance of the resource | +| owner | Owner | Party that owns the resource | +| user | User | Party who uses the resource | +| distributor | Distributor | Party who distributes the resource | +| originator | Originator | Party who created the resource | +| pointOfContact | Point of contact | Party who can be contacted for acquiring knowledge about or acquisition of the resource | +| principalInvestigator | Principal investigator | Key party responsible for gathering information and conducting research | +| processor | Processor | Party that has processed the data in a manner such that the resource has been modified | +| publisher | Publisher | Party who published the resource | +| author | Author | Party who authored the resource | + +### Series {#iso19139-elem-gmd-CI_Series-ceedc6d470330f24379e7dd4263132c9} + +Name + +: + +> gmd:CI_Series + +Description + +: + +```{=html} +Information about the series, or aggregate dataset, to which a dataset + belongs +``` +### Telephone {#iso19139-elem-gmd-CI_Telephone-a8a5286743a9be34bb502ffd91756c35} + +Name + +: + +> gmd:CI_Telephone + +Description + +: + +```{=html} +Telephone numbers for contacting the responsible individual or + organization +``` +### Citation {#iso19139-elem-gmd-citation-gmd-MD_Identification-4d43482062eba4f4d96d8c274ebd935c} + +Name + +: + +> gmd:citation + +Context + +: + +> gmd:MD_Identification + +Description + +: + +```{=html} +Citation data for the resource(s) +``` +``` xml + + + + Ecosystem types of Europe based on EUNIS level 1 (raster 100m) - + version 2.1, Dec. 2015 + + + + + + 2015-12-08 + + + + + + + + + + 2015-12-08 + + + + + + + + 2.1 + + + + + eea_r_3035_100_m_ecosystem-types-l1_2006_rev2-1 + + + + + + +``` + +### Citation {#iso19139-elem-gmd-citation-gmd-MD_Authority-c23fa4c41db4a321e376f2625a5b0bf9} + +Name + +: + +> gmd:citation + +Context + +: + +> gmd:MD_Authority + +Description + +: + +```{=html} +Citation which belongs to the authority +``` +``` xml + + + + Ecosystem types of Europe based on EUNIS level 1 (raster 100m) - + version 2.1, Dec. 2015 + + + + + + 2015-12-08 + + + + + + + + + + 2015-12-08 + + + + + + + + 2.1 + + + + + eea_r_3035_100_m_ecosystem-types-l1_2006_rev2-1 + + + + + + +``` + +### Citation {#iso19139-elem-gmd-citation-gmd-MD_Thesaurus-2de9a1c0b4ce344cc8452dceb1eb1f6d} + +Name + +: + +> gmd:citation + +Context + +: + +> gmd:MD_Thesaurus + +Description + +: + +```{=html} +Citation of the thesaurus +``` +``` xml + + + + Ecosystem types of Europe based on EUNIS level 1 (raster 100m) - + version 2.1, Dec. 2015 + + + + + + 2015-12-08 + + + + + + + + + + 2015-12-08 + + + + + + + + 2.1 + + + + + eea_r_3035_100_m_ecosystem-types-l1_2006_rev2-1 + + + + + + +``` + +### Citation {#iso19139-elem-gmd-citation-db812fc78bb9e3e6e756d4aeeed129fa} + +Name + +: + +> gmd:citation + +Description + +: + +```{=html} +Citation data for the resource(s) +``` +``` xml + + + + Ecosystem types of Europe based on EUNIS level 1 (raster 100m) - + version 2.1, Dec. 2015 + + + + + + 2015-12-08 + + + + + + + + + + 2015-12-08 + + + + + + + + 2.1 + + + + + eea_r_3035_100_m_ecosystem-types-l1_2006_rev2-1 + + + + + + +``` + +### Cited responsible party {#iso19139-elem-gmd-citedResponsibleParty-4995fda6b735448d4aaae3ba4568cd90} + +Name + +: + +> gmd:citedResponsibleParty + +Description + +: + +```{=html} +Name and position information for an individual or organization that is + responsible for the resource +``` +### City {#iso19139-elem-gmd-city-f40cb44555bb1278990e5f3799435366} + +Name + +: + +> gmd:city + +Description + +: + +```{=html} +City of the location +``` +### Classification {#iso19139-elem-gmd-classification-6718026907e4b1aead3cfd241f9b4d50} + +Name + +: + +> gmd:classification + +Description + +: + +```{=html} +Name of the handling restrictions on the resource or metadata +``` + +Condition + +: + +> mandatory + +### Classification system {#iso19139-elem-gmd-classificationSystem-010b22c4ad8a62f8521acbbbe6ff3398} + +Name + +: + +> gmd:classificationSystem + +Description + +: + +```{=html} +Name of the classification system +``` +### Cloud cover percentage {#iso19139-elem-gmd-cloudCoverPercentage-413e7fc75782e9add871c76f54773c87} + +Name + +: + +> gmd:cloudCoverPercentage + +Description + +: + +```{=html} +Area of the dataset obscured by clouds, expressed as a percentage of the + spatial extent +``` +### Unique resource identifier {#iso19139-elem-gmd-code-gmd-RS_Identifier-02da3b1f8d1566c861440d9a19132ad6} + +Name + +: + +> gmd:code + +Context + +: + +> gmd:RS_Identifier + +Description + +: + +```{=html} +Alphanumeric value identifying an instance in the namespace +``` + +Condition + +: + +> mandatory + +### Code {#iso19139-elem-gmd-code-gmd-MD_Identifier-41ff66cafe2cad1503b9d38a2447d249} + +Name + +: + +> gmd:code + +Context + +: + +> gmd:MD_Identifier + +Description + +: + +```{=html} +Alphanumeric value identifying an instance in the namespace +``` + +Condition + +: + +> mandatory + +### Code {#iso19139-elem-gmd-code-gmd-MD_CodeValue-d16c67ed008c738facc264888ac97356} + +Name + +: + +> gmd:code + +Context + +: + +> gmd:MD_CodeValue + +Description + +: + +```{=html} +Value code +``` +```{=html} +Value code (i.e. numeric) +``` +### Codespace {#iso19139-elem-gmd-codeSpace-02f6245083ede2af10bb3e9028ca4a7c} + +Name + +: + +> gmd:codeSpace + +Description + +: + +```{=html} +Name or identifier of the person or organization responsible for + namespace +``` +Recommended values + +| code | label | +|------|-------| +| EPSG | EPSG | + +``` xml + + OGP Surveying & Positioning Committee + +``` + +### Collective title {#iso19139-elem-gmd-collectiveTitle-0bc5974850084906d55ce76bb6787867} + +Name + +: + +> gmd:collectiveTitle + +Description + +: + +```{=html} +Common title with holdings note. NOTE title identifies elements of a series + collectively, combined with information about what volumes are available at the source + cited +``` +```{=html} +This field is used to name the Basic Geodata as defined in the GeoIV Annex I, as it is + possible that there are more than 1 "physical" datasets assigned to 1 legal entry. E.g.: Entry + no. 47 "Geophysikalisches Kartenwerk" consists of 3 datasets "Geophysikalische Karten + 1:500000", "Geophysikalische Spezialkarten" and "Gravimetrischer Atlas 1:100000" +``` +### Compliance code {#iso19139-elem-gmd-complianceCode-b796c3767c8744c392e3f2313329b30b} + +Name + +: + +> gmd:complianceCode + +Description + +: + +```{=html} +Indication of whether or not the cited feature catalogue complies with ISO + 19110 +``` +### ComposedOf {#iso19139-elem-gmd-composedOf-6f05d3ac23259e9892032b2da31de58c} + +Name + +: + +> gmd:composedOf + +Description + +: + +```{=html} +ComposedOf +``` +### Compression generation quantity {#iso19139-elem-gmd-compressionGenerationQuantity-8848b37883d12c673e2e9b280c7991ce} + +Name + +: + +> gmd:compressionGenerationQuantity + +Description + +: + +```{=html} +Count of the number of lossy compression cycles performed on the + image +``` +### Condition {#iso19139-elem-gmd-condition-9eb82cddebe8042afaa4010e913d0c79} + +Name + +: + +> gmd:condition + +Description + +: + +```{=html} +Condition under which the extended element is mandatory +``` +### Constraint language {#iso19139-elem-gmd-constraintLanguage-b9baafd989bb2bd8772ac36dc55e333d} + +Name + +: + +> gmd:constraintLanguage + +Description + +: + +```{=html} +Formal language used in Application Schema +``` + +Condition + +: + +> mandatory + +### Contact {#iso19139-elem-gmd-contact-gmd-MD_Metadata-2294585374798aea84d2876a5e8e7ade} + +Name + +: + +> gmd:contact + +Context + +: + +> gmd:MD_Metadata + +Description + +: + +```{=html} +Party responsible for the metadata information +``` + +Condition + +: + +> mandatory + +``` xml + + + + European Environment Agency + + + + + + + Kongens Nytorv 6 + + + Copenhagen + + + K + + + 1050 + + + Denmark + + + eea.enquiries@eea.europa.eu + + + + + + + + + + +``` + +### Contact {#iso19139-elem-gmd-contact-gmd-MD_MaintenanceInformation-0e2bd3597e71a41f1f85eed23ebb2005} + +Name + +: + +> gmd:contact + +Context + +: + +> gmd:MD_MaintenanceInformation + +Description + +: + +```{=html} +Identification of, and means of communication with, person(s) and + organization(s) with responsibility for maintaining the metadata +``` +``` xml + + + + European Environment Agency + + + + + + + Kongens Nytorv 6 + + + Copenhagen + + + K + + + 1050 + + + Denmark + + + eea.enquiries@eea.europa.eu + + + + + + + + + + +``` + +### Metadata author {#iso19139-elem-gmd-contact-1a17bee429a4ae3c87f4026bd2da8005} + +Name + +: + +> gmd:contact + +Description + +: + +```{=html} +Party responsible for the metadata information +``` + +Condition + +: + +> mandatory + +``` xml + + + + European Environment Agency + + + + + + + Kongens Nytorv 6 + + + Copenhagen + + + K + + + 1050 + + + Denmark + + + eea.enquiries@eea.europa.eu + + + + + + + + + + +``` + +### Contact Information {#iso19139-elem-gmd-contactInfo-3ae0765a28247f062c63bdc8eb973f50} + +Name + +: + +> gmd:contactInfo + +Description + +: + +```{=html} +Address of the responsible party +``` +### Contact instructions {#iso19139-elem-gmd-contactInstructions-794f3bd38398fc8ae39cce7c984087f0} + +Name + +: + +> gmd:contactInstructions + +Description + +: + +```{=html} +Supplemental instructions on how or when to contact the individual or + organization +``` +### Content Information {#iso19139-elem-gmd-contentInfo-da18cd6a5e91bae67187adc15ff47622} + +Name + +: + +> gmd:contentInfo + +Description + +: + +```{=html} +Provides information about the feature catalogue and describes the coverage and + image data characteristics +``` +``` xml + + + + false + + + + +``` + +### Content type {#iso19139-elem-gmd-contentType-f9d07b4b0ceec04f18bce420c5291a5e} + +Name + +: + +> gmd:contentType + +Description + +: + +```{=html} +Type of information represented by the cell value +``` + +Condition + +: + +> mandatory + +### Controlpoint Availability {#iso19139-elem-gmd-controlPointAvailability-f87c554dde9c2a5bc1413de637c47e2d} + +Name + +: + +> gmd:controlPointAvailability + +Description + +: + +```{=html} +Indication of whether or not control point(s) exists +``` + +Condition + +: + +> mandatory + +### Corner points {#iso19139-elem-gmd-cornerPoints-b92ddc8c05fd3950d850515164e26c5c} + +Name + +: + +> gmd:cornerPoints + +Description + +: + +```{=html} +Earth location in the coordinate system defined by the Spatial Reference System + and the grid coordinate of the cells at opposite ends of grid coverage along two + diagonals in the grid spatial dimensions. There are four corner points in a georectified + grid; at least two corner points along one diagonal are required +``` + +Condition + +: + +> mandatory + +### Country {#iso19139-elem-gmd-country-7819215af574621eb7dd1e63f32e1e19} + +Name + +: + +> gmd:country + +Description + +: + +```{=html} +Country of the physical address +``` +### Country {#iso19139-elem-gmd-country-gmd-MD_Legislation-84c810ce3efbda031bc28f55683d23a5} + +Name + +: + +> gmd:country + +Context + +: + +> gmd:MD_Legislation + +Description + +: + +```{=html} +Country in which the law was issued +``` +### Country {#iso19139-elem-gmd-country-PT_Group-c87df35752363f7e2f20c8a68953c0a6} + +Name + +: + +> gmd:country + +Context + +: + +> PT_Group + +Description + +: + +```{=html} +Country of language used for documenting a plain text +``` +### Credit {#iso19139-elem-gmd-credit-0b272311ef39699d6c413fe246ea5326} + +Name + +: + +> gmd:credit + +Description + +: + +```{=html} +Recognition of those who contributed to the resource(s) +``` +### Data quality info {#iso19139-elem-gmd-dataQualityInfo-9a53c25e2dacf5a7ab0aa1d155efc3dc} + +Name + +: + +> gmd:dataQualityInfo + +Description + +: + +```{=html} +Provides overall assessment of quality of a resource(s) +``` +``` xml + + + + + + + + + + + + + The data set production implied 2 steps. First re-classification of + CORINE Land Cover 2006 and bathymetry data using the 7 terrestrial (urban, cropland, + grassland, woodland and forest, heathland and shrub, sparsely vegetated land, + wetland), 1 freshwater (river and lakes), and 4 marine (marine inlets and transitional + waters, coastal, shelf, open ocean) classes of the MAES ecosystem typology (Maes et + al., 2013). The classes also provide links to major policy lines such as agriculture, + forestry, territorial cohesion, water and marine related policies. The second step + comprised refinement of the ecosystem types by attributing EUNIS habitat information + to each ecosystem type (see http://eunis.eea.europa.eu/habitats.jsp). The refinement + process used reference data such as potential natural vegetation, elevation, slope, + aspect, soil, geology, environmental regions and other spatial referenced information + which allowed attribution of the EUNIS habitat characteristics to the spatial mapping + units of the MAES ecosystem types. The geometric and thematic accuracy of EUNIS class + presence was also estimated and mapped. The method is described in the EEA Technical + Report 06/2015: European Ecosystem Assessment – Concept, Data, and Implementation. + The basis for the update was CORINE land cover 2006 (CLC 2006). It includes Albania, + Austria, Belgium, Bosnia and Herzegovina, Bulgaria, Croatia, Cyprus, Czech Republic, + Denmark, Estonia, Finland, France, Germany, Hungary, Iceland, Ireland, Italy, Kosovo + (under UNSCR 1244/99), Latvia, Liechtenstein, Lithuania, Luxembourg, the former + Yugoslavian Republic of Macedonia, Malta, Montenegro, the Netherlands, Norway, Poland, + Portugal, Romania, Serbia, Slovakia, Slovenia, Spain, Sweden, Switzerland, Turkey and + the United Kingdom. For Greece that has not participated in the CLC 2006 activity the + CLC 2000 data was used instead. + + + + + + + +``` + +### Dataset {#iso19139-elem-gmd-dataset-5262692d36cca930e0c50a2ae131301a} + +Name + +: + +> gmd:dataset + +Description + +: + +```{=html} +Dataset to which the information applies +``` +### Dataset URI {#iso19139-elem-gmd-dataSetURI-8e14b3e6d98f92a9356ba2f3ba1ee982} + +Name + +: + +> gmd:dataSetURI + +Description + +: + +```{=html} +Uniformed Resource Identifier (URI) of the dataset to which the metadata + applies +``` +```{=html} +Uniformed Resource Identifier (URI) of the dataset to which the metadata applies. This + link refers direct to the machine-readable dataset. +``` +### Data type {#iso19139-elem-gmd-dataType-8e2f4cdbb24b536e5df6aaee70047601} + +Name + +: + +> gmd:dataType + +Description + +: + +```{=html} +Code which identifies the kind of valueprovidedeprovided in the extended + element +``` + +Condition + +: + +> mandatory + +### Date {#iso19139-elem-gmd-date-ebb509445b6cf496cbf813a8b01a2362} + +Name + +: + +> gmd:date + +Description + +: + +```{=html} +Reference date for the cited resource (YYYY-MM-DD) +``` + +Condition + +: + +> mandatory + +### Date of last update {#iso19139-elem-gmd-date-gmd-MD_Revision-285564fda444a3437d34594df33c890e} + +Name + +: + +> gmd:date + +Context + +: + +> gmd:MD_Revision + +Description + +: + +```{=html} +Date of last update +``` +### Date of next update {#iso19139-elem-gmd-date-gmd-MD_MaintenanceInformation-9a98fdd70f046e77f1556ed865f56d0b} + +Name + +: + +> gmd:date + +Context + +: + +> gmd:MD_MaintenanceInformation + +Description + +: + +```{=html} +Scheduled revision date for resource +``` +### Date {#iso19139-elem-gmd-date-gmd-CI_Citation-478aeda64d149a8df6810bf35c93f39f} + +Name + +: + +> gmd:date + +Context + +: + +> gmd:CI_Citation + +Description + +: + +```{=html} +Reference date for the cited resource +``` + +Condition + +: + +> mandatory + +### Date {#iso19139-elem-gmd-date-gmd-CI_Date-6c9c8f825ef4f9c73ed94df2741d9ff5} + +Name + +: + +> gmd:date + +Context + +: + +> gmd:CI_Date + +Description + +: + +```{=html} +Reference date for the cited resource +``` + +Condition + +: + +> mandatory + +### Date of next update {#iso19139-elem-gmd-dateOfNextUpdate-efa132e2522617da74a9f2b6cac7f884} + +Name + +: + +> gmd:dateOfNextUpdate + +Description + +: + +```{=html} +Scheduled revision date for resource (YYYY-MM-DD) +``` +### Date stamp {#iso19139-elem-gmd-dateStamp-ee89eb65741d89aef14d153887f60948} + +Name + +: + +> gmd:dateStamp + +Description + +: + +```{=html} +Date that the metadata was created (YYYY-MM-DDThh:mm:ss) +``` + +Condition + +: + +> mandatory + +``` xml + + 2016-01-15T16:57:35 + +``` + +### Date / Time {#iso19139-elem-gmd-dateTime-f2e7c016069fc9e8b93cacb30bc5c30f} + +Name + +: + +> gmd:dateTime + +Description + +: + +```{=html} +Date and time or range of date and time on or over which the process step + occurred (YYYY-MM-DDThh:mm:ss) +``` +### Date / Time {#iso19139-elem-gmd-dateTime-LI_ProcessStep-0aea67a7cf3150b81bec5e552be93a4e} + +Name + +: + +> gmd:dateTime + +Context + +: + +> LI_ProcessStep + +Description + +: + +```{=html} +Date and time or range of date and time on or over which the process step + occurred (YYYY-MM-DDThh:mm:ss) +``` +### Date / Time {#iso19139-elem-gmd-dateTime-gmd-DQ_Element-a5f46c00ce539dddadc06ba486322a5b} + +Name + +: + +> gmd:dateTime + +Context + +: + +> gmd:DQ_Element + +Description + +: + +```{=html} +Date or range of dates on which a data quality measure was + applied +``` +### Date type {#iso19139-elem-gmd-dateType-7d228e2ac6b4932f0e011cc2521acccb} + +Name + +: + +> gmd:dateType + +Description + +: + +```{=html} +Event used for reference date +``` + +Condition + +: + +> mandatory + +### Definition {#iso19139-elem-gmd-definition-f8069fba68fd297eeca2c4a772339bab} + +Name + +: + +> gmd:definition + +Description + +: + +```{=html} +Definition of the extended element +``` + +Condition + +: + +> mandatory + +### Delivery point {#iso19139-elem-gmd-deliveryPoint-4d1627af441e956ac873875949365c46} + +Name + +: + +> gmd:deliveryPoint + +Description + +: + +```{=html} +Address line for the location (as described in ISO 11180, annex + A) +``` +### Denominator {#iso19139-elem-gmd-denominator-e807028ba183b3decd6aa631d0ca1ca3} + +Name + +: + +> gmd:denominator + +Description + +: + +```{=html} +The number below the line in a vulgar fraction +``` + +Condition + +: + +> add either a denominator or a distance + +Recommended values + +| code | label | +|---------|-------------| +| 5000 | 1:5´000 | +| 10000 | 1:10´000 | +| 25000 | 1:25´000 | +| 50000 | 1:50´000 | +| 100000 | 1:100´000 | +| 200000 | 1:200´000 | +| 300000 | 1:300´000 | +| 500000 | 1:500´000 | +| 1000000 | 1:1´000´000 | + +### Density {#iso19139-elem-gmd-density-91b875707b7dd43cd669efc4974331e4} + +Name + +: + +> gmd:density + +Description + +: + +```{=html} +Density at which the data is recorded +``` +### Density units {#iso19139-elem-gmd-densityUnits-8ce9ed433e80ccefc11d3af968194b20} + +Name + +: + +> gmd:densityUnits + +Description + +: + +```{=html} +Units of measure for the recording density +``` + +Condition + +: + +> conditional + +### Describes {#iso19139-elem-gmd-describes-ea7ef755fceda2ec8b1bf4486f5572bf} + +Name + +: + +> gmd:describes + +Description + +: + +```{=html} +Describes +``` +### Description {#iso19139-elem-gmd-description-eaa9ebfedd88eeab4424b4a0ede4ce7d} + +Name + +: + +> gmd:description + +Description + +: + +```{=html} +Description of the event, including related parameters or + tolerances +``` +### Description {#iso19139-elem-gmd-description-gmd-MD_AbstractClass-34fc68cb0bdaee5b3d63b2326c7869b3} + +Name + +: + +> gmd:description + +Context + +: + +> gmd:MD_AbstractClass + +Description + +: + +```{=html} +Description +``` +### Description {#iso19139-elem-gmd-description-LI_ProcessStep-f1b053819d7813cf9bd105eadd7570bf} + +Name + +: + +> gmd:description + +Context + +: + +> LI_ProcessStep + +Description + +: + +```{=html} +Description of the event, including related parameters or + tolerances +``` + +Condition + +: + +> mandatory + +### Description {#iso19139-elem-gmd-description-LI_Source-3e33abacd589d6d2d76d05d70e90613b} + +Name + +: + +> gmd:description + +Context + +: + +> LI_Source + +Description + +: + +```{=html} +Detailed description of the level of the source data +``` +### Description {#iso19139-elem-gmd-description-gmd-EX_Extent-5b2d427d98a833b825066fc5d95dbcb9} + +Name + +: + +> gmd:description + +Context + +: + +> gmd:EX_Extent + +Description + +: + +```{=html} +Spatial and temporal extent for the referring object +``` +### Description {#iso19139-elem-gmd-description-gmd-CI_OnlineResource-7b3dd389b32eff7af6fc0ce939edd2f7} + +Name + +: + +> gmd:description + +Context + +: + +> gmd:CI_OnlineResource + +Description + +: + +```{=html} +Detailed text description of what the online resource is/does +``` +Recommended values + +| code | label | +|-----------------------------------------------|---------------------------------------------------------------------------------| +| | ETRS89 / LAEA Europe | +| | Belge 1972 / Belgian Lambert 72 | +| | ETRS89-XYZ: 3D Cartesian in ETRS89 | +| | ETRS89-GRS80h: 3D geodetic in ETRS89 on GRS80 | +| | ETRS89-GRS802D: geodetic in ETRS89 on GRS80 | +| | ETRS89-LAEA2D: LAEA projection in ETRS89 on GRS80 | +| | ETRS89-LCC2D: LCC projection in ETRS89 on GRS80 | +| | ETRS89-TM26N2D: TM projection in ETRS89 on GRS80, zone 26N (30°W to 24°W) | +| | ETRS89-TM27N2D: TM projection in ETRS89 on GRS80, zone 27N (24°W to 18°W) | +| | ETRS89-TM28N: 2D TM projection in ETRS89 on GRS80, zone 28N (18°W to 12°W) | +| | ETRS89-TM29N: 2D TM projection in ETRS89 on GRS80, zone 29N (12°W to 6°W) | +| | ETRS89-TM30N: 2D TM projection in ETRS89 on GRS80, zone 30N (6°W to 0°) | +| | ETRS89-TM31N: 2D TM projection in ETRS89 on GRS80, zone 31N (0° to 6°E) | +| | ETRS89-TM32N: 2D TM projection in ETRS89 on GRS80, zone 32N (6°E to 12°E) | +| | ETRS89-TM33N: 2D TM projection in ETRS89 on GRS80, zone 33N (12°E to 18°E) | +| | ETRS89-TM34N: 2D TM projection in ETRS89 on GRS80, zone 34N (18°E to 24°E) | +| | ETRS89-TM35N: 2D TM projection in ETRS89 on GRS80, zone 35N (24°E to 30°E) | +| | ETRS89-TM36N: 2D TM projection in ETRS89 on GRS80, zone 36N (30°E to 36°E) | +| | ETRS89-TM37N: 2D TM projection in ETRS89 on GRS80, zone 37N (36°E to 42°E) | +| | ETRS89-TM38N: 2D TM projection in ETRS89 on GRS80, zone 38N (42°E to 48°E) | +| | ETRS89-TM39N: 2D TM projection in ETRS89 on GRS80, zone 39N (48°E to 54°E) | +| | EVRS: Height in EVRS | +| | ETRS89-GRS80-EVRS: 3D compound: 2D geodetic in ETRS89 on GRS80, and EVRS height | +| | RGF93 / Lambert-93 | +| | WGS 84 / UTM zone 20N | +| | RGFG95 / UTM zone 22N | +| | RGR92 / UTM zone 40S | +| | RGSPM06 / UTM zone 21N | +| | RGM04 / UTM zone 38S | + +### Description {#iso19139-elem-gmd-description-gmd-MD_CodeDomain-8103324c89de45c11315a8d351053359} + +Name + +: + +> gmd:description + +Context + +: + +> gmd:MD_CodeDomain + +Description + +: + +```{=html} +Description of the code domain +``` +### Value description {#iso19139-elem-gmd-description-gmd-MD_CodeValue-77dfb024af10e6d862075b803cc20dbf} + +Name + +: + +> gmd:description + +Context + +: + +> gmd:MD_CodeValue + +Description + +: + +```{=html} +Description of the value +``` +### Description {#iso19139-elem-gmd-description-gmd-MD_Attribute-75d5033891a8a34341d31ef9309f59b4} + +Name + +: + +> gmd:description + +Context + +: + +> gmd:MD_Attribute + +Description + +: + +```{=html} +Attribute description +``` +### Description {#iso19139-elem-gmd-description-gmd-MD_Role-c9f409ac11c4188ce914585f8c21e5c9} + +Name + +: + +> gmd:description + +Context + +: + +> gmd:MD_Role + +Description + +: + +```{=html} +Role description +``` +### Descriptive keywords {#iso19139-elem-gmd-descriptiveKeywords-d9044aa0856cf55d016da575dc037fa3} + +Name + +: + +> gmd:descriptiveKeywords + +Description + +: + +```{=html} +Provides category keywords, their type, and reference source +``` +### Descriptor {#iso19139-elem-gmd-descriptor-3b92c037212e359ee64699ddc5187d64} + +Name + +: + +> gmd:descriptor + +Description + +: + +```{=html} +Description of the range of a cell measurement value +``` +### Dimension {#iso19139-elem-gmd-dimension-21ead8c88a2cce69c91c967de032bb13} + +Name + +: + +> gmd:dimension + +Description + +: + +```{=html} +Information on the dimensions of the cell measurement value +``` +### Dimension name {#iso19139-elem-gmd-dimensionName-db894579835c31371c0bf5b98ec194dc} + +Name + +: + +> gmd:dimensionName + +Description + +: + +```{=html} +Name of the axis +``` + +Condition + +: + +> mandatory + +### Dimension size {#iso19139-elem-gmd-dimensionSize-6d8bbb1333af97b4020cd56044998ea9} + +Name + +: + +> gmd:dimensionSize + +Description + +: + +```{=html} +Number of elements along the axis +``` + +Condition + +: + +> mandatory + +### Distance {#iso19139-elem-gmd-distance-7b7fc9e19c5ebb9644dc51880d95a12d} + +Name + +: + +> gmd:distance + +Description + +: + +```{=html} +Ground sample distance +``` + +Condition + +: + +> Provide a distance if no equivalent Scale is documented + +Recommended values + +| code | label | +|------|-------| +| 0.10 | 10 cm | +| 0.25 | 25 cm | +| 0.50 | 50 cm | +| 1 | 1 m | +| 30 | 30 m | +| 100 | 100 m | + +``` xml + + 100 + +``` + +### Distribution format {#iso19139-elem-gmd-distributionFormat-5cad81c9a7af3991db918a5e8fc0c596} + +Name + +: + +> gmd:distributionFormat + +Description + +: + +```{=html} +Provides a description of the format of the data to be + distributed +``` + +Condition + +: + +> mandatory + +``` xml + + + + GTiff + + + + + + +``` + +### Distribution Information {#iso19139-elem-gmd-distributionInfo-3bddab6fda29c9ebd6f0ece68843fcff} + +Name + +: + +> gmd:distributionInfo + +Description + +: + +```{=html} +Provides information about the distributor of and options for obtaining the + resource(s) +``` +``` xml + + + + + + GTiff + + + + + + + + + + + + + http://www.eea.europa.eu/data-and-maps/data/ds_resolveuid/d851e1b7f678468b8f0b1b98930ba3e1 + + + + WWW:LINK-1.0-http--link + + + + + + + + + + +``` + +### Distribution / Order Process {#iso19139-elem-gmd-distributionOrderProcess-621478a21f4e3c305dc87af00248e875} + +Name + +: + +> gmd:distributionOrderProcess + +Description + +: + +```{=html} +Provides information about how the resource may be obtained, and related + instructions and fee information +``` +### Distributor {#iso19139-elem-gmd-distributor-b64067d4aecef8f15cc5a182fd00b195} + +Name + +: + +> gmd:distributor + +Description + +: + +```{=html} +Provides information about the distributor +``` +### Distributor contact {#iso19139-elem-gmd-distributorContact-57afbc495ed57e4d90c77442277e6961} + +Name + +: + +> gmd:distributorContact + +Description + +: + +```{=html} +Party from whom the resource may be obtained. This list need not be + exhaustive +``` + +Condition + +: + +> mandatory + +### Distributor format {#iso19139-elem-gmd-distributorFormat-d5712aab561d34322dd8328ad9362df6} + +Name + +: + +> gmd:distributorFormat + +Description + +: + +```{=html} +Provides information about the format used by the distributor +``` + +Condition + +: + +> conditional + +### Distributor transfer options {#iso19139-elem-gmd-distributorTransferOptions-6149d8c29d10ec5cf30b596582015a41} + +Name + +: + +> gmd:distributorTransferOptions + +Description + +: + +```{=html} +Provides information about the technical means and media used by the + distributor +``` +### Domain code {#iso19139-elem-gmd-domainCode-7ab4da558ea7aa9973cc9bb4514b14fe} + +Name + +: + +> gmd:domainCode + +Description + +: + +```{=html} +Three digit code assigned to the extended element +``` +### Domain of validity {#iso19139-elem-gmd-domainOfValidity-3b8814768dfd794c8bf6114e32bd5464} + +Name + +: + +> gmd:domainOfValidity + +Description + +: + +```{=html} +Range which is valid for the referencesystem +``` +### Domain value {#iso19139-elem-gmd-domainValue-d43089dafdacd9f762bfcebf7d39f850} + +Name + +: + +> gmd:domainValue + +Description + +: + +```{=html} +Valid values that can be assigned to the extended element +``` +### Absolute external positional accuracy {#iso19139-elem-gmd-DQ_AbsoluteExternalPositionalAccuracy-2d3004ba04cb5440553a71f72784b835} + +Name + +: + +> gmd:DQ_AbsoluteExternalPositionalAccuracy + +Description + +: + +```{=html} +Closeness of reported coordinate values to values accepted as or being + true +``` +### Accuracy of time measurement {#iso19139-elem-gmd-DQ_AccuracyOfATimeMeasurement-350c5e543ca98de6c417b2dfcec11ad2} + +Name + +: + +> gmd:DQ_AccuracyOfATimeMeasurement + +Description + +: + +```{=html} +Correctness of the temporal references of an item (reporting of error in time + measurement) +``` +### Completeness commission {#iso19139-elem-gmd-DQ_CompletenessCommission-3eb2187eca9bc68201978727eda4d550} + +Name + +: + +> gmd:DQ_CompletenessCommission + +Description + +: + +```{=html} +Excess data present in the dataset, as described by the scope +``` +### Completeness omission {#iso19139-elem-gmd-DQ_CompletenessOmission-0a19919745deecaf08e057f9d745bf9a} + +Name + +: + +> gmd:DQ_CompletenessOmission + +Description + +: + +```{=html} +Data absent from the dataset, as described by the scope +``` +### Conceptual consistency {#iso19139-elem-gmd-DQ_ConceptualConsistency-d42ad4a3a30578c7431606e8c1df4df8} + +Name + +: + +> gmd:DQ_ConceptualConsistency + +Description + +: + +```{=html} +Adherence to rules of the conceptual schema +``` +### Conformance result {#iso19139-elem-gmd-DQ_ConformanceResult-58ea50589a06c432ba3c0c1fc40caaf7} + +Name + +: + +> gmd:DQ_ConformanceResult + +Description + +: + +```{=html} +Information about the outcome of evaluating the obtained value (or set of + values) against a specified acceptable conformance quality level +``` +### Data quality {#iso19139-elem-gmd-DQ_DataQuality-16d17a37284f157b42d492a5960b5171} + +Name + +: + +> gmd:DQ_DataQuality + +Description + +: + +```{=html} +Quality information for the data specified by a data quality + scope +``` +``` xml + + + + + + + + + + + + The data set production implied 2 steps. First re-classification of + CORINE Land Cover 2006 and bathymetry data using the 7 terrestrial (urban, cropland, + grassland, woodland and forest, heathland and shrub, sparsely vegetated land, + wetland), 1 freshwater (river and lakes), and 4 marine (marine inlets and transitional + waters, coastal, shelf, open ocean) classes of the MAES ecosystem typology (Maes et + al., 2013). The classes also provide links to major policy lines such as agriculture, + forestry, territorial cohesion, water and marine related policies. The second step + comprised refinement of the ecosystem types by attributing EUNIS habitat information + to each ecosystem type (see http://eunis.eea.europa.eu/habitats.jsp). The refinement + process used reference data such as potential natural vegetation, elevation, slope, + aspect, soil, geology, environmental regions and other spatial referenced information + which allowed attribution of the EUNIS habitat characteristics to the spatial mapping + units of the MAES ecosystem types. The geometric and thematic accuracy of EUNIS class + presence was also estimated and mapped. The method is described in the EEA Technical + Report 06/2015: European Ecosystem Assessment – Concept, Data, and Implementation. + The basis for the update was CORINE land cover 2006 (CLC 2006). It includes Albania, + Austria, Belgium, Bosnia and Herzegovina, Bulgaria, Croatia, Cyprus, Czech Republic, + Denmark, Estonia, Finland, France, Germany, Hungary, Iceland, Ireland, Italy, Kosovo + (under UNSCR 1244/99), Latvia, Liechtenstein, Lithuania, Luxembourg, the former + Yugoslavian Republic of Macedonia, Malta, Montenegro, the Netherlands, Norway, Poland, + Portugal, Romania, Serbia, Slovakia, Slovenia, Spain, Sweden, Switzerland, Turkey and + the United Kingdom. For Greece that has not participated in the CLC 2006 activity the + CLC 2000 data was used instead. + + + + + + +``` + +### Domain consistency {#iso19139-elem-gmd-DQ_DomainConsistency-b77b3e42dfbc1799faaf486b19f37274} + +Name + +: + +> gmd:DQ_DomainConsistency + +Description + +: + +```{=html} +Adherence of values to the value domains +``` +### Evaluation method type code {#iso19139-elem-gmd-DQ_EvaluationMethodTypeCode-ef1611d0cbbf6e1995668d2724dee5d0} + +Name + +: + +> gmd:DQ_EvaluationMethodTypeCode + +Description + +: + +```{=html} +type of method for evaluating an identified data quality + measure +``` +### Standard codelists Evaluation method type code (gmd:DQ_EvaluationMethodTypeCode) + +| code | label | description | +|----------------|-----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| directInternal | Direct internal | Method of evaluating the quality of a dataset based on inspection of items within the dataset, where all data required is internal to the dataset being evaluated | +| directExternal | Direct external | Method of evaluating the quality of a dataset based on inspection of items within the dataset, where reference data external to the dataset being evaluated is required | +| indirect | Indirect | Method of evaluating the quality of a dataset based on external knowledge | + +### Format consistency {#iso19139-elem-gmd-DQ_FormatConsistency-19459f698decb189aed186574d4e433e} + +Name + +: + +> gmd:DQ_FormatConsistency + +Description + +: + +```{=html} +Degree to which data is stored in accordance with the physical structure of the + dataset, as described by the scope +``` +### Gridded data positional accuracy {#iso19139-elem-gmd-DQ_GriddedDataPositionalAccuracy-fc226f8ad8fedced9779bffe9d4b6db5} + +Name + +: + +> gmd:DQ_GriddedDataPositionalAccuracy + +Description + +: + +```{=html} +Closeness of gridded data position values to values accepted as or being + true +``` +### Non quantitative attribute accuracy {#iso19139-elem-gmd-DQ_NonQuantitativeAttributeAccuracy-6dd0c58c687f85dca3f14390846b4519} + +Name + +: + +> gmd:DQ_NonQuantitativeAttributeAccuracy + +Description + +: + +```{=html} +Correctness of non-quantitative attributes +``` +### Quantitative attribute accuracy {#iso19139-elem-gmd-DQ_QuantitativeAttributeAccuracy-318f4688c57ecac2edb9e81237c188f7} + +Name + +: + +> gmd:DQ_QuantitativeAttributeAccuracy + +Description + +: + +```{=html} +Accuracy of quantitative attributes +``` +### Quantitative result {#iso19139-elem-gmd-DQ_QuantitativeResult-9ff68c61fe2bfe850ba1c5da5f0475f8} + +Name + +: + +> gmd:DQ_QuantitativeResult + +Description + +: + +```{=html} +The values or information about the value(s) (or set of values) obtained from + applying a data quality measure +``` +### Relative internal positional accuracy {#iso19139-elem-gmd-DQ_RelativeInternalPositionalAccuracy-9d1661d32093ae34be463172ee4171b4} + +Name + +: + +> gmd:DQ_RelativeInternalPositionalAccuracy + +Description + +: + +```{=html} +Closeness of the relative positions of features in the scope to their + respective relative positions accepted as or being true +``` +### Scope {#iso19139-elem-gmd-DQ_Scope-bd775cb6e23ca10fa168f6837f60f149} + +Name + +: + +> gmd:DQ_Scope + +Description + +: + +```{=html} +Description of the data specified by the scope +``` +```{=html} +extent of characteristic(s) of the data for which quality information is + reported +``` +``` xml + + + + + +``` + +### Temporal consistency {#iso19139-elem-gmd-DQ_TemporalConsistency-cb9d4597a464c61d15952962479895d0} + +Name + +: + +> gmd:DQ_TemporalConsistency + +Description + +: + +```{=html} +Correctness of ordered events or sequences, if reported +``` +### Temporal validity {#iso19139-elem-gmd-DQ_TemporalValidity-fc6776c73908af8274103023abfb106c} + +Name + +: + +> gmd:DQ_TemporalValidity + +Description + +: + +```{=html} +Validity of data specified by the scope with respect to time +``` +### Thematic classification correctness {#iso19139-elem-gmd-DQ_ThematicClassificationCorrectness-bacc4f5d13c268c61ce4aaad44eacb00} + +Name + +: + +> gmd:DQ_ThematicClassificationCorrectness + +Description + +: + +```{=html} +Comparison of the classes assigned to features or their attributes to a + universe of discourse +``` +### Topological consistency {#iso19139-elem-gmd-DQ_TopologicalConsistency-14d0182e0c62de72433c7f3440489d0b} + +Name + +: + +> gmd:DQ_TopologicalConsistency + +Description + +: + +```{=html} +Correctness of the explicitly encoded topological characteristics of the + dataset as described by the scope +``` +### DS_Association {#iso19139-elem-gmd-DS_Association-ae4acbd2f543a91f8514b07a7f469222} + +Name + +: + +> gmd:DS_Association + +Description + +: + +```{=html} +DS_Association +``` +### Association Type {#iso19139-elem-gmd-DS_AssociationTypeCode-7cea96a5925a25c140f30c8577eb6813} + +Name + +: + +> gmd:DS_AssociationTypeCode + +Description + +: + +### Standard codelists Association Type (gmd:DS_AssociationTypeCode) + +| code | label | description | +|------------------------|---------------------------|-------------------------------------------------------------------------------------| +| crossReference | Cross reference | Reference from one dataset to another | +| largerWorkCitation | Larger work citation | Reference to a master dataset of which this one is a part | +| partOfSeamlessDatabase | Part of seamless database | Part of the same structured set of data held in a computer | +| source | Source | Mapping and charting information from which the dataset content originates | +| stereoMate | Stereo mate | Part of a set of imagery that when used together, provides three-dimensional images | + +### DS_DataSet {#iso19139-elem-gmd-DS_DataSet-197a02789f4acc67db14bbc70bdae13d} + +Name + +: + +> gmd:DS_DataSet + +Description + +: + +```{=html} +DS_DataSet +``` +### DS_Initiative {#iso19139-elem-gmd-DS_Initiative-99177f56cdac30c8bf8ae08807759c1e} + +Name + +: + +> gmd:DS_Initiative + +Description + +: + +```{=html} +DS_Initiative +``` +### Initiative Type {#iso19139-elem-gmd-DS_InitiativeTypeCode-1c08946c9359924c4e0560505d6ed92d} + +Name + +: + +> gmd:DS_InitiativeTypeCode + +Description + +: + +### Standard codelists Initiative Type (gmd:DS_InitiativeTypeCode) + +| code | label | description | +|---------------|---------------|-------------------------------------------------------------| +| campaign | Campaign | Series of organized planned actions | +| collection | Collection | Accumulation of datasets assembled for a specific purpose | +| exercise | Exercise | Specific performance of a function or group of functions | +| experiment | Experiment | Process designed to find if something is effective or valid | +| investigation | Investigation | Search or systematic inquiry | +| mission | Mission | Specific operation of a data collection system | +| sensor | Sensor | Device or piece of equipment which detects or records | +| operation | Operation | Action that is part of a series of actions | +| platform | Platform | Vehicle or other support base that holds a sensor | +| process | Process | Method of doing something involving a number of steps | +| program | Program | Specific planned activity | +| project | Project | Organized undertaking, research, or development | +| study | Study | Examination or investigation | +| task | Task | Piece of work | +| trial | Trial | Process of testing to discover or demonstrate something | + +### DS_OtherAggregate {#iso19139-elem-gmd-DS_OtherAggregate-d75f31e38b2c903fb77bee700fd67738} + +Name + +: + +> gmd:DS_OtherAggregate + +Description + +: + +```{=html} +DS_OtherAggregate +``` +### DS_Platform {#iso19139-elem-gmd-DS_Platform-1578fc8a9a6c1b3b001447d56dbf3be4} + +Name + +: + +> gmd:DS_Platform + +Description + +: + +```{=html} +DS_Platform +``` +### DS_ProductionSeries {#iso19139-elem-gmd-DS_ProductionSeries-dae0ba6d7c6e0c0774507987df27eddd} + +Name + +: + +> gmd:DS_ProductionSeries + +Description + +: + +```{=html} +DS_ProductionSeries +``` +### DS_Sensor {#iso19139-elem-gmd-DS_Sensor-99d8fff6c363ece657f8304d6114ae39} + +Name + +: + +> gmd:DS_Sensor + +Description + +: + +```{=html} +DS_Sensor +``` +### DS_Series {#iso19139-elem-gmd-DS_Series-fbba19e3982149ccdcca9e862ff983d3} + +Name + +: + +> gmd:DS_Series + +Description + +: + +```{=html} +DS_Series +``` +### DS_StereoMate {#iso19139-elem-gmd-DS_StereoMate-8034b71fd81debf0bc765b669a03d0d9} + +Name + +: + +> gmd:DS_StereoMate + +Description + +: + +```{=html} +DS_StereoMate +``` +### East bound {#iso19139-elem-gmd-eastBoundLongitude-d587a010e363b83d226fd0035e83d760} + +Name + +: + +> gmd:eastBoundLongitude + +Description + +: + +```{=html} +Eastern-most coordinate of the limit of the dataset extent, expressed in + longitude in decimal degrees (positive east) +``` + +Condition + +: + +> mandatory + +``` xml + + 38.1471 + +``` + +### Edition {#iso19139-elem-gmd-edition-b997ad6c7eb67deed33915d4691b4059} + +Name + +: + +> gmd:edition + +Description + +: + +```{=html} +Version of the cited resource +``` +``` xml + + 2.1 + +``` + +### Edition date {#iso19139-elem-gmd-editionDate-13359f87b19a72433b15f218e4026ee3} + +Name + +: + +> gmd:editionDate + +Description + +: + +```{=html} +Date of the edition (YYYY-MM-DD) +``` +### Electronic mail address {#iso19139-elem-gmd-electronicMailAddress-85d2f0b6b81c17b627c0640f7f49e872} + +Name + +: + +> gmd:electronicMailAddress + +Description + +: + +```{=html} +Address of the electronic mailbox of the responsible organization or + individual +``` +### Environment description {#iso19139-elem-gmd-environmentDescription-f09bfec0427a8a244e444ee494298c90} + +Name + +: + +> gmd:environmentDescription + +Description + +: + +```{=html} +Description of the dataset in the producer_s processing environment, including + items such as the software, the computer operating system, file name, and the dataset + size +``` +### Equivalent scale {#iso19139-elem-gmd-equivalentScale-450afb02a588e99273c4926c53620fb1} + +Name + +: + +> gmd:equivalentScale + +Description + +: + +```{=html} +Level of detail expressed as the scale of a comparable hardcopy map or + chart +``` +### Error statistic {#iso19139-elem-gmd-errorStatistic-29cd4bc20d224f1b99cd4cdc5f2afbc6} + +Name + +: + +> gmd:errorStatistic + +Description + +: + +```{=html} +Statistical method used to determine the value +``` +### Evaluation method description {#iso19139-elem-gmd-evaluationMethodDescription-cf7b77da8217834dc7e28ec9988dd6f7} + +Name + +: + +> gmd:evaluationMethodDescription + +Description + +: + +```{=html} +Description of the evaluation method +``` +### Evaluation Method {#iso19139-elem-gmd-evaluationMethodType-76b556cae8d468e563c04da4e16eaca8} + +Name + +: + +> gmd:evaluationMethodType + +Description + +: + +```{=html} +Type of method used to evaluate quality of the dataset +``` +### Evaluation procedure {#iso19139-elem-gmd-evaluationProcedure-2ca21440f6d62173cfe90752b85d2873} + +Name + +: + +> gmd:evaluationProcedure + +Description + +: + +```{=html} +Reference to the procedure information +``` +### Bounding Polygon {#iso19139-elem-gmd-EX_BoundingPolygon-59e3cbfd7fafe44aacd4370c5c9abf59} + +Name + +: + +> gmd:EX_BoundingPolygon + +Description + +: + +```{=html} +Boundary enclosing the dataset, expressed as the closed set of (x,y) + coordinates of the polygon (last point replicates first point) +``` +### Extent {#iso19139-elem-gmd-EX_Extent-d972ff3928d3ae0eb52e4853850e7484} + +Name + +: + +> gmd:EX_Extent + +Description + +: + +```{=html} +Information about spatial, vertical, and temporal extent +``` +### Geographic bounding box {#iso19139-elem-gmd-EX_GeographicBoundingBox-317fd5425b55f40c235ada8a89ee0519} + +Name + +: + +> gmd:EX_GeographicBoundingBox + +Description + +: + +```{=html} +Geographic position of the dataset +``` +``` xml + + + -33.90432 + + + 38.1471 + + + 26.988714 + + + 60.57849 + + +``` + +### Geographic description {#iso19139-elem-gmd-EX_GeographicDescription-edd6465b6e6b6a804db315a4f05303fb} + +Name + +: + +> gmd:EX_GeographicDescription + +Description + +: + +```{=html} +Description of the geographic area using identifiers +``` +### Spatial Temporal Extent {#iso19139-elem-gmd-EX_SpatialTemporalExtent-fb6c94e1d77ff12c5a4c7eefcca03fd0} + +Name + +: + +> gmd:EX_SpatialTemporalExtent + +Description + +: + +```{=html} +Extent with respect to date/time and spatial boundaries +``` +### Temporal Extent {#iso19139-elem-gmd-EX_TemporalExtent-49952a3862db59a39b01a7ad01337eab} + +Name + +: + +> gmd:EX_TemporalExtent + +Description + +: + +```{=html} +Time period covered by the content of the dataset +``` +``` xml + + + + 2006-01-01 + 2006-12-31 + + + +``` + +### Vertical extent {#iso19139-elem-gmd-EX_VerticalExtent-03de82207a2d25d3d8106293de357342} + +Name + +: + +> gmd:EX_VerticalExtent + +Description + +: + +```{=html} +Vertical domain of dataset +``` +### Explanation {#iso19139-elem-gmd-explanation-a2ff7a210f7f4e385b3f4bc09536eb0b} + +Name + +: + +> gmd:explanation + +Description + +: + +```{=html} +Explanation of the meaning of conformance for this result +``` + +Condition + +: + +> mandatory + +### Extended element information {#iso19139-elem-gmd-extendedElementInformation-df23e4d221faf1125b8d660000cc942d} + +Name + +: + +> gmd:extendedElementInformation + +Description + +: + +```{=html} +Provides information about a new metadata element, not found in ISO 19115, + which is required to describe geographic data +``` +### Extension Online resource {#iso19139-elem-gmd-extensionOnLineResource-f12177f44a4f70bde032489efa83c4d5} + +Name + +: + +> gmd:extensionOnLineResource + +Description + +: + +```{=html} +Information about on-line sources containing the community profile name and the + extended metadata elements. Information for all new metadata elements +``` +### Extent {#iso19139-elem-gmd-extent-gmd-MD_DataIdentification-ef6cafbbcf83a9c5f548fc0e2a6e4a67} + +Name + +: + +> gmd:extent + +Context + +: + +> gmd:MD_DataIdentification + +Description + +: + +```{=html} +Extent information including the bounding polygon, vertical, and temporal + extent of the dataset +``` +### Extent {#iso19139-elem-gmd-extent-gmd-DQ_Scope-cf877c587ba9ea326503a5f7f10db5b4} + +Name + +: + +> gmd:extent + +Context + +: + +> gmd:DQ_Scope + +Description + +: + +```{=html} +Information about the horizontal, vertical and temporal extent of the data + specified by the scope +``` +### Extent {#iso19139-elem-gmd-extent-gmd-EX_TemporalExtent-47e5bb94d809c840b870705288059fa9} + +Name + +: + +> gmd:extent + +Context + +: + +> gmd:EX_TemporalExtent + +Description + +: + +```{=html} +Date and time for the content of the dataset +``` +### Extent type code {#iso19139-elem-gmd-extentTypeCode-3ff35ceb2d2f687d2c8ce3d323884d96} + +Name + +: + +> gmd:extentTypeCode + +Description + +: + +```{=html} +Indication of whether the bounding polygon encompasses an area covered by the + data or an area where data is not present. Possible values: '1' for inclusion or '0' for + exclusion +``` +### Facsimile {#iso19139-elem-gmd-facsimile-b648543ae1d0726685e437bf567ad655} + +Name + +: + +> gmd:facsimile + +Description + +: + +```{=html} +Telephone number of a facsimile machine for the responsible organization or + individual +``` +### Feature attribute {#iso19139-elem-gmd-featureAttribute-ed65880b0d966b5862d0d434b26fd36b} + +Name + +: + +> gmd:featureAttribute + +Description + +: + +### Feature catalogue citation {#iso19139-elem-gmd-featureCatalogueCitation-0d490aca236a02c867c265dc0656143b} + +Name + +: + +> gmd:featureCatalogueCitation + +Description + +: + +```{=html} +Complete bibliographic reference to one or more external feature + catalogues +``` + +Condition + +: + +> mandatory + +``` xml + +``` + +### Feature instances {#iso19139-elem-gmd-featureInstances-2ec1ea3d86d2e7b1a0438f31d90abe5a} + +Name + +: + +> gmd:featureInstances + +Description + +: + +```{=html} +Feature instances to which the information applies +``` +### Features {#iso19139-elem-gmd-features-0649c9efc070f5cf773f06bf959cf517} + +Name + +: + +> gmd:features + +Description + +: + +```{=html} +Features to which the information applies +``` +### Feature type {#iso19139-elem-gmd-featureType-1a7ddaf6d70b2bca513bbb097769f7a5} + +Name + +: + +> gmd:featureType + +Description + +: + +```{=html} +Subset of feature types from cited feature catalogue occurring in + data +``` +### Feature types {#iso19139-elem-gmd-featureTypes-57cc98cc1ff094047cfff115a60c96e3} + +Name + +: + +> gmd:featureTypes + +Description + +: + +```{=html} +Subset of feature types from cited feature catalogue occurring in + data +``` +### Fees {#iso19139-elem-gmd-fees-f12184afc6c48c767b43b36d9044e1c9} + +Name + +: + +> gmd:fees + +Description + +: + +```{=html} +Fees and terms for retrieving the resource. Include monetary units (as + specified in ISO 4217) +``` +### File decompression technique {#iso19139-elem-gmd-fileDecompressionTechnique-e3c08caebc6eb48277ca074c5e8e547a} + +Name + +: + +> gmd:fileDecompressionTechnique + +Description + +: + +```{=html} +Recommendations of algorithms or processes that can be applied to read or + expand resources to which compression techniques have been applied +``` +### File description {#iso19139-elem-gmd-fileDescription-146f4502c53733e708c1bd8a795522d7} + +Name + +: + +> gmd:fileDescription + +Description + +: + +```{=html} +Text description of the illustration +``` +### File identifier {#iso19139-elem-gmd-fileIdentifier-353be7794d17e5435ce2fe57d91966ba} + +Name + +: + +> gmd:fileIdentifier + +Description + +: + +```{=html} +Unique identifier for this metadata file +``` +``` xml + + e8a366b7-0029-44d7-ae33-7578253179c0 + +``` + +### File name {#iso19139-elem-gmd-fileName-22a500ee0f0599f36ee1e97aff0fe087} + +Name + +: + +> gmd:fileName + +Description + +: + +```{=html} +Name of the file that contains a graphic that provides an illustration of the + dataset. It could be a public image document URL. +``` + +Condition + +: + +> mandatory + +``` xml + + + http://sdi.eea.europa.eu/public/catalogue-graphic-overview/e8a366b7-0029-44d7-ae33-7578253179c0.png + + +``` + +### File type {#iso19139-elem-gmd-fileType-b4c84bb6fe0143438998bfddb778200c} + +Name + +: + +> gmd:fileType + +Description + +: + +```{=html} +Format in which the illustration is encoded +``` +```{=html} +format in which the illustration is encoded Examples: CGM, EPS, GIF, JPEG, PBM, PS, + TIFF, XWD +``` +### Film distortion information availability {#iso19139-elem-gmd-filmDistortionInformationAvailability-a778dce0bc8a88cdba2c1315d18d0e28} + +Name + +: + +> gmd:filmDistortionInformationAvailability + +Description + +: + +```{=html} +Indication of whether or not Calibration Reseau information is + available +``` +### Format distributor {#iso19139-elem-gmd-formatDistributor-36ea0561d2f735b297700bf79e7dbe09} + +Name + +: + +> gmd:formatDistributor + +Description + +: + +```{=html} +Provides information about the distributor’s format +``` +### Function {#iso19139-elem-gmd-function-c66a8adca4499131f846c360fca82678} + +Name + +: + +> gmd:function + +Description + +: + +```{=html} +Code for function performed by the online resource +``` +### Geographic element {#iso19139-elem-gmd-geographicElement-4b7f68f3310760569dbdba10bad944c2} + +Name + +: + +> gmd:geographicElement + +Description + +: + +```{=html} +Provides geographic component of the extent of the referring + object +``` +``` xml + + + + -33.90432 + + + 38.1471 + + + 26.988714 + + + 60.57849 + + + +``` + +### Geographic identifier {#iso19139-elem-gmd-geographicIdentifier-6e21f053992dfa6b4eb02d6b91cbbe44} + +Name + +: + +> gmd:geographicIdentifier + +Description + +: + +```{=html} +Identifier used to represent a geographic area +``` + +Condition + +: + +> mandatory + +### Geometric object count {#iso19139-elem-gmd-geometricObjectCount-465f480e8e30a8c083af02492722eefc} + +Name + +: + +> gmd:geometricObjectCount + +Description + +: + +```{=html} +Total number of the point or vector object type occurring in the + dataset +``` +### Geometric objects {#iso19139-elem-gmd-geometricObjects-e10321f246589a7ed91638fa939b766b} + +Name + +: + +> gmd:geometricObjects + +Description + +: + +```{=html} +Information about the geometric objects used in the dataset +``` +### Geometric object type {#iso19139-elem-gmd-geometricObjectType-bf17aa906a7cd305707e10d6acd0e62d} + +Name + +: + +> gmd:geometricObjectType + +Description + +: + +```{=html} +Name of point and vector spatial objects used to locate zero-, one-, and + two-dimensional spatial locations in the dataset +``` + +Condition + +: + +> mandatory + +### GeoreferencedParameters {#iso19139-elem-gmd-georeferencedParameters-252d097ee7c185a35fde200a066e1c51} + +Name + +: + +> gmd:georeferencedParameters + +Description + +: + +```{=html} +GeoreferencedParameters +``` +### Graphic overview {#iso19139-elem-gmd-graphicOverview-f08bb356ded2aa6be5b6e67f15770173} + +Name + +: + +> gmd:graphicOverview + +Description + +: + +```{=html} +Provides a graphic that illustrates the resource(s) (should include a legend + for the graphic) +``` +``` xml + + + + + http://sdi.eea.europa.eu/public/catalogue-graphic-overview/e8a366b7-0029-44d7-ae33-7578253179c0.png + + + + +``` + +### Graphics file {#iso19139-elem-gmd-graphicsFile-e812a025f08ccad44b6f3a37fcc7d6c5} + +Name + +: + +> gmd:graphicsFile + +Description + +: + +```{=html} +Full application schema given as a graphics file +``` +### Handling description {#iso19139-elem-gmd-handlingDescription-0c88196efd7b0ce89bc76138514281ff} + +Name + +: + +> gmd:handlingDescription + +Description + +: + +```{=html} +Additional information about the restrictions on handling the + resource +``` +### Has {#iso19139-elem-gmd-has-f3ff1915df87b300aba1f0a17c387f0f} + +Name + +: + +> gmd:has + +Description + +: + +```{=html} +Has +``` +### Hierarchy level {#iso19139-elem-gmd-hierarchyLevel-2b6d53b433d8f9c0cc58606d27eecc17} + +Name + +: + +> gmd:hierarchyLevel + +Description + +: + +```{=html} +Scope to which the metadata applies (see annex H for more information about + metadata hierarchy levels) +``` +``` xml + + + +``` + +### Hierarchy level name {#iso19139-elem-gmd-hierarchyLevelName-1c79276b0501d07055d7480b292899f0} + +Name + +: + +> gmd:hierarchyLevelName + +Description + +: + +```{=html} +Name of the hierarchy levels for which the metadata is provided +``` +### Hours of service {#iso19139-elem-gmd-hoursOfService-52bbcc8182a0293962afd16ee768c579} + +Name + +: + +> gmd:hoursOfService + +Description + +: + +```{=html} +Time period (including time zone) when individuals can contact the organization + or individual +``` +### Identification info {#iso19139-elem-gmd-identificationInfo-4fe68a205ff13feeccf0b58e08f39472} + +Name + +: + +> gmd:identificationInfo + +Description + +: + +```{=html} +Basic information about the resource(s) to which the metadata + applies +``` + +Condition + +: + +> mandatory + +``` xml + + + + + + Ecosystem types of Europe based on EUNIS level 1 (raster 100m) - + version 2.1, Dec. 2015 + + + + + + 2015-12-08 + + + + + + + + + + 2015-12-08 + + + + + + + + 2.1 + + + + + eea_r_3035_100_m_ecosystem-types-l1_2006_rev2-1 + + + + + + + + The data set combines the Corine based MAES (Mapping and Assessment of + Ecosystems and their Services) ecosystem classes with the non-spatial EUNIS habitat + classification (LEVEL 1) for a better biological characterization of ecosystems across + Europe (EEA-39). As such it represents probabilities of EUNIS habitat presence for each + MAES ecosystem type. + + The data set aims to combine spatially explicit land cover information with non-spatially + referenced habitat information to improve our knowledge about ecosystems and their + distribution across Europe. The work supports the MAES process, Target 2 Action 5 of the + implementation of the EU Biodiversity Strategy to 2020, established to achieve the Aichi + targets of the Convention of Biological Diversity (CBD). + + The objective of the ecosystem data set produced by EEA and its Topic Centre ETC/SIA was + to improve the biological description of land cover based ecosystem types. It represents + probabilities of EUNIS habitat presence in ecosystem types at European level. Since it is + not based on spatial explicit mapping the spatial and thematic accuracy is not of same + quality as delineated maps. + + The MAES ecosystem typology differentiates three levels: whereas the level 2 of the MAES + proposal follows closely the EUNIS level 1, the third level of the MAES typology + corresponds to the EUNIS level 2. This level will be the base for the mapping approach. + + + + + + European Environment Agency + + + + + + + Kongens Nytorv 6 + + + Copenhagen + + + K + + + 1050 + + + Denmark + + + eea.enquiries@eea.europa.eu + + + + + + + http://www.eea.europa.eu + + + WWW:LINK-1.0-http--link + + + Europen Environment Agency public website + + + + + + + + + + + + + + + + + + + + + + + + + + http://sdi.eea.europa.eu/public/catalogue-graphic-overview/e8a366b7-0029-44d7-ae33-7578253179c0.png + + + + + + + + Land cover + + + Habitats and biotopes + + + + + + + + GEMET - INSPIRE themes, version 1.0 + + + + + 2008-06-01 + + + + + + + + + + + geonetwork.thesaurus.external.theme.httpinspireeceuropaeutheme-theme + + + + + + + + + + + + ecosystem + + + ecosystem type + + + land cover + + + environmental assessment + + + habitat + + + + + + + + GEMET - Concepts, version 2.4 + + + + + 2010-01-13 + + + + + + + + + + + geonetwork.thesaurus.external.theme.gemet + + + + + + + + + + + + Unless otherwise indicated, re-use of content on the EEA website + for commercial or non-commercial purposes is permitted free of charge, provided that + the source is acknowledged. The EEA re-use policy follows Directive 2003/98/EC of the + European Parliament and the Council on the re-use of public sector information + throughout the European Union and Commission Decision 2006/291/EC, Euratom on the + re-use of Commission information. The EEA accepts no responsibility or liability + whatsoever for the re-use of content accessible on its website. Any inquiries about + re-use of content on the EEA website should be addressed to Ove Caspersen, EEA, + Kongens Nytorv 6, DK-1050 Copenhagen K, Tel +45 33 36 71 00, Fax +45 33 36 71 99, + e-mail copyrights at eea.europa.eu + + + + + + + + + + + no limitations + + + + + + + + + + 100 + + + + + + + + biota + + + environment + + + + + + + -33.90432 + + + 38.1471 + + + 26.988714 + + + 60.57849 + + + + + + + + + + + + 2006-01-01 + 2006-12-31 + + + + + + + + +``` + +### Identifier {#iso19139-elem-gmd-identifier-c4f31fd808ee0eaa1e5525c5ff0edd23} + +Name + +: + +> gmd:identifier + +Description + +: + +```{=html} +Unique identifier for the resource. EXAMPLE: Universal Product Code (UPC), + National Stock Number (NSN) +``` +### Citation identifier {#iso19139-elem-gmd-identifier-gmd-CI_Citation-20221b6aedbb9cb4a515e5d396ea859e} + +Name + +: + +> gmd:identifier + +Context + +: + +> gmd:CI_Citation + +Description + +: + +```{=html} +Identifier of the citation +``` +### Identifier {#iso19139-elem-gmd-identifier-gmd-MD_Authority-85169d0c6f948867bbf79c0907e0fdfe} + +Name + +: + +> gmd:identifier + +Context + +: + +> gmd:MD_Authority + +Description + +: + +```{=html} +Identifier which belongs to the authority +``` +### Illumination azimuth angle {#iso19139-elem-gmd-illuminationAzimuthAngle-9c67704111e2bddeebc608da99ff3d92} + +Name + +: + +> gmd:illuminationAzimuthAngle + +Description + +: + +```{=html} +Illumination azimuth measured in degrees clockwise from true north at the time + the image is taken. For images from a scanning device, refer to the centre pixel of the + image +``` +### Illumination elevation angle {#iso19139-elem-gmd-illuminationElevationAngle-fadd6e99799d86a8d2817d3154e4c615} + +Name + +: + +> gmd:illuminationElevationAngle + +Description + +: + +```{=html} +Illumination elevation measured in degrees clockwise from the target plane at + intersection of the optical line of sight with the Earth_s surface. For images from a + scanning device, refer to the centre pixel of the image +``` +### Image quality code {#iso19139-elem-gmd-imageQualityCode-fc1f077f8b9f3893a031f8b27beaac71} + +Name + +: + +> gmd:imageQualityCode + +Description + +: + +```{=html} +Specifies the image quality +``` +```{=html} +specifies the image quality +``` +### Imaging condition {#iso19139-elem-gmd-imagingCondition-e9c7d7a924d3b3e2c92c646337c793d1} + +Name + +: + +> gmd:imagingCondition + +Description + +: + +```{=html} +Conditions affected the image +``` +### Included with dataset {#iso19139-elem-gmd-includedWithDataset-0148507e25f25653e843ec66cf6cb878} + +Name + +: + +> gmd:includedWithDataset + +Description + +: + +```{=html} +Indication of whether or not the feature catalogue is included with the + dataset +``` + +Condition + +: + +> mandatory + +``` xml + + false + +``` + +### Individual name {#iso19139-elem-gmd-individualName-60930dbb71e453e392be49149226d811} + +Name + +: + +> gmd:individualName + +Description + +: + +```{=html} +Name of the responsible person- surname, given name, title separated by a + delimiter +``` +### Initiative Type {#iso19139-elem-gmd-initiativeType-94726ec412440a3e8b82802d3ebffa3e} + +Name + +: + +> gmd:initiativeType + +Description + +: + +```{=html} +Type of initiative under which the aggregate dataset was produced +``` +### ISBN {#iso19139-elem-gmd-ISBN-a7253d49f82ee6bb2b5a531fb70a3820} + +Name + +: + +> gmd:ISBN + +Description + +: + +```{=html} +International Standard Book Number +``` +### ISSN {#iso19139-elem-gmd-ISSN-9bed905bb20090904f7fc371e411169b} + +Name + +: + +> gmd:ISSN + +Description + +: + +```{=html} +International Standard Serial Number +``` +### Issue identification {#iso19139-elem-gmd-issueIdentification-4722b88dd305fc8ebd00fbf712853119} + +Name + +: + +> gmd:issueIdentification + +Description + +: + +```{=html} +Information identifying the issue of the series +``` +### Keyword {#iso19139-elem-gmd-keyword-9589bb538b9fd1c10931fcfb09274b90} + +Name + +: + +> gmd:keyword + +Description + +: + +```{=html} +Commonly used word(s) or formalised word(s) or phrase(s) used to describe the + subject +``` +### Metadata language {#iso19139-elem-gmd-language-98a1fec5ea30c100ef63f1ca4bd6dbdb} + +Name + +: + +> gmd:language + +Description + +: + +```{=html} +Language used for documenting metadata +``` + +Condition + +: + +> conditional + +### Language {#iso19139-elem-gmd-language-gmd-MD_DataIdentification-beb634f41383e04b84205a263a51618b} + +Name + +: + +> gmd:language + +Context + +: + +> gmd:MD_DataIdentification + +Description + +: + +```{=html} +Language(s) used within the dataset +``` +```{=html} +language(s) used within the dataset +``` +### Language {#iso19139-elem-gmd-language-gmd-MD_FeatureCatalogueDescription-71920ebc293a169b2af5b096755545eb} + +Name + +: + +> gmd:language + +Context + +: + +> gmd:MD_FeatureCatalogueDescription + +Description + +: + +```{=html} +Language(s) used within the catalogue +``` +### Language {#iso19139-elem-gmd-languageCode-09e902b21da745d04364587ce8c4b5de} + +Name + +: + +> gmd:languageCode + +Description + +: + +```{=html} +Language code +``` +### ISO Language code {#iso19139-elem-gmd-LanguageCode-c2d8944958443fe48234c4019a990643} + +Name + +: + +> gmd:LanguageCode + +Description + +: + +```{=html} +Language code +``` +### Lens distortion information availability {#iso19139-elem-gmd-lensDistortionInformationAvailability-16305ddb1c7fe831e1d0bd2856b18441} + +Name + +: + +> gmd:lensDistortionInformationAvailability + +Description + +: + +```{=html} +Indication of whether or not lens aberration correction information is + available +``` +### Hierarchy level {#iso19139-elem-gmd-level-cb01720c4e97d12d16a28aea6ce52f8a} + +Name + +: + +> gmd:level + +Description + +: + +```{=html} +Hierarchical level of the data specified by the scope +``` + +Condition + +: + +> mandatory + +``` xml + + + +``` + +### Level description {#iso19139-elem-gmd-levelDescription-a2ac63be295342f5027433592380cbe8} + +Name + +: + +> gmd:levelDescription + +Description + +: + +```{=html} +Detailed description about the level of the data specified by the + scope +``` +### Lineage {#iso19139-elem-gmd-LI_Lineage-d8883febc8ab15d913eae9f7582b776d} + +Name + +: + +> gmd:LI_Lineage + +Description + +: + +```{=html} +Information about the events or source data used in constructing the data + specified by the scope or lack of knowledge about lineage +``` +``` xml + + + The data set production implied 2 steps. First re-classification of + CORINE Land Cover 2006 and bathymetry data using the 7 terrestrial (urban, cropland, + grassland, woodland and forest, heathland and shrub, sparsely vegetated land, + wetland), 1 freshwater (river and lakes), and 4 marine (marine inlets and transitional + waters, coastal, shelf, open ocean) classes of the MAES ecosystem typology (Maes et + al., 2013). The classes also provide links to major policy lines such as agriculture, + forestry, territorial cohesion, water and marine related policies. The second step + comprised refinement of the ecosystem types by attributing EUNIS habitat information + to each ecosystem type (see http://eunis.eea.europa.eu/habitats.jsp). The refinement + process used reference data such as potential natural vegetation, elevation, slope, + aspect, soil, geology, environmental regions and other spatial referenced information + which allowed attribution of the EUNIS habitat characteristics to the spatial mapping + units of the MAES ecosystem types. The geometric and thematic accuracy of EUNIS class + presence was also estimated and mapped. The method is described in the EEA Technical + Report 06/2015: European Ecosystem Assessment – Concept, Data, and Implementation. + The basis for the update was CORINE land cover 2006 (CLC 2006). It includes Albania, + Austria, Belgium, Bosnia and Herzegovina, Bulgaria, Croatia, Cyprus, Czech Republic, + Denmark, Estonia, Finland, France, Germany, Hungary, Iceland, Ireland, Italy, Kosovo + (under UNSCR 1244/99), Latvia, Liechtenstein, Lithuania, Luxembourg, the former + Yugoslavian Republic of Macedonia, Malta, Montenegro, the Netherlands, Norway, Poland, + Portugal, Romania, Serbia, Slovakia, Slovenia, Spain, Sweden, Switzerland, Turkey and + the United Kingdom. For Greece that has not participated in the CLC 2006 activity the + CLC 2000 data was used instead. + + + + +``` + +### Process step {#iso19139-elem-gmd-LI_ProcessStep-df37dc21ccbd656f4dd53e1e6e4aa42e} + +Name + +: + +> gmd:LI_ProcessStep + +Description + +: + +```{=html} +Information about an event in the creation process for the data specified by + the scope +``` +```{=html} +information about an event or transformation in the life of a dataset including the + process used to maintain the dataset +``` +### Source {#iso19139-elem-gmd-LI_Source-29725376e7b2367004e7834b84786158} + +Name + +: + +> gmd:LI_Source + +Description + +: + +```{=html} +Information about the source data used in creating the data specified by the + scope +``` +### Lineage {#iso19139-elem-gmd-lineage-7ec1911d2050ab2ba82079b8fa118182} + +Name + +: + +> gmd:lineage + +Description + +: + +```{=html} +Non-quantitative quality information about the lineage of the data specified by + the scope +``` +``` xml + + + + The data set production implied 2 steps. First re-classification of + CORINE Land Cover 2006 and bathymetry data using the 7 terrestrial (urban, cropland, + grassland, woodland and forest, heathland and shrub, sparsely vegetated land, + wetland), 1 freshwater (river and lakes), and 4 marine (marine inlets and transitional + waters, coastal, shelf, open ocean) classes of the MAES ecosystem typology (Maes et + al., 2013). The classes also provide links to major policy lines such as agriculture, + forestry, territorial cohesion, water and marine related policies. The second step + comprised refinement of the ecosystem types by attributing EUNIS habitat information + to each ecosystem type (see http://eunis.eea.europa.eu/habitats.jsp). The refinement + process used reference data such as potential natural vegetation, elevation, slope, + aspect, soil, geology, environmental regions and other spatial referenced information + which allowed attribution of the EUNIS habitat characteristics to the spatial mapping + units of the MAES ecosystem types. The geometric and thematic accuracy of EUNIS class + presence was also estimated and mapped. The method is described in the EEA Technical + Report 06/2015: European Ecosystem Assessment – Concept, Data, and Implementation. + The basis for the update was CORINE land cover 2006 (CLC 2006). It includes Albania, + Austria, Belgium, Bosnia and Herzegovina, Bulgaria, Croatia, Cyprus, Czech Republic, + Denmark, Estonia, Finland, France, Germany, Hungary, Iceland, Ireland, Italy, Kosovo + (under UNSCR 1244/99), Latvia, Liechtenstein, Lithuania, Luxembourg, the former + Yugoslavian Republic of Macedonia, Malta, Montenegro, the Netherlands, Norway, Poland, + Portugal, Romania, Serbia, Slovakia, Slovenia, Spain, Sweden, Switzerland, Turkey and + the United Kingdom. For Greece that has not participated in the CLC 2006 activity the + CLC 2000 data was used instead. + + + + + +``` + +### Linkage {#iso19139-elem-gmd-linkage-ddec55285da8318007d8ba8df6febcb5} + +Name + +: + +> gmd:linkage + +Description + +: + +```{=html} +Location (address) for on-line access using a Uniform Resource Locator address + or similar addressing scheme such as http://www.statkart.no/isotc211 +``` + +Condition + +: + +> mandatory + +### Other language {#iso19139-elem-gmd-locale-826113f1d130f65f95c78f6b16227c4b} + +Name + +: + +> gmd:locale + +Description + +: + +```{=html} +Use this section to define other metadata language (multilingual metadata). +``` +### Localised string {#iso19139-elem-gmd-LocalisedCharacterString-9fd46342f3b1b7c5b63898df1b997f3a} + +Name + +: + +> gmd:LocalisedCharacterString + +Description + +: + +### Localised string {#iso19139-elem-gmd-localisedString-56cb8674dae4c0ea7855baaf3d864ff3} + +Name + +: + +> gmd:localisedString + +Description + +: + +### Maintenance and update frequency {#iso19139-elem-gmd-maintenanceAndUpdateFrequency-a1048fe8ad8a58b19b4a8d93d9276069} + +Name + +: + +> gmd:maintenanceAndUpdateFrequency + +Description + +: + +```{=html} +Frequency with which changes and additions are made to the resource after the + initial resource is completed +``` + +Condition + +: + +> mandatory + +``` xml + + + +``` + +### Maintenance note {#iso19139-elem-gmd-maintenanceNote-9d819b6669d1940c147b60f1d769a43e} + +Name + +: + +> gmd:maintenanceNote + +Description + +: + +```{=html} +Information regarding specific requirements for maintaining the + resource +``` +### Maximum occurrence {#iso19139-elem-gmd-maximumOccurrence-586bc521966d29003dc6cea416d0cc02} + +Name + +: + +> gmd:maximumOccurrence + +Description + +: + +```{=html} +Maximum occurrence of the extended element +``` +### Maximum value {#iso19139-elem-gmd-maximumValue-46bb37dbbb47d975b9c88ee47687a50a} + +Name + +: + +> gmd:maximumValue + +Description + +: + +```{=html} +Highest vertical extent contained in the dataset +``` + +Condition + +: + +> mandatory + +### Maximum value {#iso19139-elem-gmd-maxValue-c5b953b90711bd9c01bc5efaeeeb51e1} + +Name + +: + +> gmd:maxValue + +Description + +: + +```{=html} +Longest wavelength that the sensor is capable of collecting within a designated + band +``` +### Aggregate Information {#iso19139-elem-gmd-MD_AggregateInformation-878370a145c71919312573e325a5657a} + +Name + +: + +> gmd:MD_AggregateInformation + +Description + +: + +```{=html} +Aggregate dataset information +``` +### Application Schema Information {#iso19139-elem-gmd-MD_ApplicationSchemaInformation-bdc5888debf009cc4d4e8527e7a46bc3} + +Name + +: + +> gmd:MD_ApplicationSchemaInformation + +Description + +: + +```{=html} +Information about the application schema used to build the + dataset +``` +### Band {#iso19139-elem-gmd-MD_Band-3997e9a8c1d5b8a25690a55dd55c107b} + +Name + +: + +> gmd:MD_Band + +Description + +: + +```{=html} +Range of wavelengths in the electromagnetic spectrum +``` +```{=html} +range of wavelengths in the electromagnetic spectrum +``` +### Browse Graphic {#iso19139-elem-gmd-MD_BrowseGraphic-bdf4d487d1e389d01ed977eb34d5fc1b} + +Name + +: + +> gmd:MD_BrowseGraphic + +Description + +: + +```{=html} +Graphic that provides an illustration of the dataset (should include a legend + for the graphic) +``` +``` xml + + + + http://sdi.eea.europa.eu/public/catalogue-graphic-overview/e8a366b7-0029-44d7-ae33-7578253179c0.png + + + +``` + +### Cell geometry code {#iso19139-elem-gmd-MD_CellGeometryCode-35ad1470fb7f4d2e62f3fe43080d5f6a} + +Name + +: + +> gmd:MD_CellGeometryCode + +Description + +: + +```{=html} +code indicating whether grid data is point or area +``` +### Standard codelists Cell geometry code (gmd:MD_CellGeometryCode) + +| code | label | description | +|-------|-------|------------------------------| +| point | Point | Each cell represents a point | +| area | Area | Each cell represents an area | + +### Characterset code {#iso19139-elem-gmd-MD_CharacterSetCode-d8a4713835858ceca74003ca966d0a21} + +Name + +: + +> gmd:MD_CharacterSetCode + +Description + +: + +```{=html} +name of the character coding standard used for the + resource +``` +### Standard codelists Characterset code (gmd:MD_CharacterSetCode) + +| code | label | description | +|------------|--------------|-----------------------------------------------------------------------------------------------------------------------------------| +| ucs2 | UCS2 | 16-bit fixed size Universal Character Set, based on ISO/IEC 10646 | +| ucs4 | UCS4 | 32-bit fixed size Universal Character Set, based on ISO/IEC 10646 | +| utf7 | UTF7 | 7-bit variable size UCS Transfer Format, based on ISO/IEC 10646 | +| utf8 | UTF8 | 8-bit variable size UCS Transfer Format, based on ISO/IEC 10646 | +| utf16 | UTF16 | 16-bit variable size UCS Transfer Format, based on ISO/IEC 10646 | +| 8859part1 | 8859 Part 1 | ISO/IEC 8859-1, Information technology - 8-bit single byte coded graphic character sets - Part 1 : Latin alphabet No.1 | +| 8859part2 | 8859 Part 2 | ISO/IEC 8859-2, Information technology - 8-bit single byte coded graphic character sets - Part 2 : Latin alphabet No.2 | +| 8859part3 | 8859 Part 3 | ISO/IEC 8859-3, Information technology - 8-bit single byte coded graphic character sets - Part 3 : Latin alphabet No.3 | +| 8859part4 | 8859 Part 4 | ISO/IEC 8859-4, Information technology - 8-bit single byte coded graphic character sets - Part 4 : Latin alphabet No.4 | +| 8859part5 | 8859 Part 5 | ISO/IEC 8859-5, Information technology - 8-bit single byte coded graphic character sets - Part 5 : Latin/Cyrillic alphabet | +| 8859part6 | 8859 Part 6 | ISO/IEC 8859-6, Information technology - 8-bit single byte coded graphic character sets - Part 6 : Latin/Arabic alphabet | +| 8859part7 | 8859 Part 7 | ISO/IEC 8859-7, Information technology - 8-bit single byte coded graphic character sets - Part 7 : Latin/Greek alphabet | +| 8859part8 | 8859 Part 8 | ISO/IEC 8859-8, Information technology - 8-bit single byte coded graphic character sets - Part 8 : Latin/Hebrew alphabet | +| 8859part9 | 8859 Part 9 | ISO/IEC 8859-9, Information technology - 8-bit single byte coded graphic character sets - Part 9 : Latin alphabet No.5 | +| 8859part10 | 8859 Part 10 | ISO/IEC 8859-10, Information technology - 8-bit single byte coded graphic character sets - Part 10 : Latin alphabet No.6 | +| 8859part11 | 8859 Part 11 | ISO/IEC 8859-11, Information technology - 8-bit single byte coded graphic character sets - Part 11 : Latin/Thai alphabet | +| 8859part13 | 8859 Part 13 | ISO/IEC 8859-13, Information technology - 8-bit single byte coded graphic character sets - Part 13 : Latin alphabet No.7 | +| 8859part14 | 8859 Part 14 | ISO/IEC 8859-14, Information technology - 8-bit single byte coded graphic character sets - Part 14 : Latin alphabet No.8 (Celtic) | +| 8859part15 | 8859 Part 15 | ISO/IEC 8859-15, Information technology - 8-bit single byte coded graphic character sets - Part 15 : Latin alphabet No.9 | +| 8859part16 | 8859 Part 16 | ISO/IEC 8859-16, Information technology - 8-bit single byte coded graphic character sets - Part 16 : Latin alphabet No.10 | +| jis | JIS | Japanese code set used for electronic transmission | +| shiftJIS | Shift JIS | Japanese code set used on MS-DOS machines | +| eucJP | EUC JP | Japanese code set used on UNIX based machines | +| usAscii | US ASCII | United States ASCII code set (ISO 646 US) | +| ebcdic | EBCDIC | IBM mainframe code set | +| eucKR | EUC KR | Korean code set | +| big5 | Big 5 | Traditional Chinese code set used in Taiwan, Hong Kong of China and other areas | +| GB2312 | GB2312 | Simplified Chinese code set | + +``` xml + +``` + +### Classification code {#iso19139-elem-gmd-MD_ClassificationCode-f8c03303f33489e96e1e8063a4468c46} + +Name + +: + +> gmd:MD_ClassificationCode + +Description + +: + +```{=html} +Name of the handling restrictions on the dataset +``` +### Standard codelists Classification code (gmd:MD_ClassificationCode) + +| code | label | description | +|--------------|--------------|--------------------------------------------------------------------------------------------| +| unclassified | Unclassified | Available for general disclosure | +| restricted | Restricted | Not for general disclosure | +| confidential | Confidential | Available for someone who can be entrusted with information | +| secret | Secret | Kept or meant to be kept private, unknown, or hidden from all but a select group of people | +| topSecret | Top secret | Of the highest secrecy | + +### Constraints {#iso19139-elem-gmd-MD_Constraints-324782b12272766c3ea9027e10fb6b8a} + +Name + +: + +> gmd:MD_Constraints + +Description + +: + +``` xml + + + Unless otherwise indicated, re-use of content on the EEA website + for commercial or non-commercial purposes is permitted free of charge, provided that + the source is acknowledged. The EEA re-use policy follows Directive 2003/98/EC of the + European Parliament and the Council on the re-use of public sector information + throughout the European Union and Commission Decision 2006/291/EC, Euratom on the + re-use of Commission information. The EEA accepts no responsibility or liability + whatsoever for the re-use of content accessible on its website. Any inquiries about + re-use of content on the EEA website should be addressed to Ove Caspersen, EEA, + Kongens Nytorv 6, DK-1050 Copenhagen K, Tel +45 33 36 71 00, Fax +45 33 36 71 99, + e-mail copyrights at eea.europa.eu + + + +``` + +### Content type code {#iso19139-elem-gmd-MD_CoverageContentTypeCode-3a8fb87615b97ed59c74b013dfebf5fe} + +Name + +: + +> gmd:MD_CoverageContentTypeCode + +Description + +: + +```{=html} +specific type of information represented in the cell +``` +### Standard codelists Content type code (gmd:MD_CoverageContentTypeCode) + +| code | label | description | +|------------------------|-------------------------|--------------------------------------------------------------------------------------------------------------------| +| image | Image | Meaningful numerical representation of a physical parameter that is not the actual value of the physical parameter | +| thematicClassification | Thematic classification | Code value with no quantitative meaning, used to represent a physical quantity | +| physicalMeasurement | Physical measurement | Value in physical units of the quantity being measured | + +### Coverage Description {#iso19139-elem-gmd-MD_CoverageDescription-1f81296a593d08ad1a336c34877d7307} + +Name + +: + +> gmd:MD_CoverageDescription + +Description + +: + +```{=html} +information about the content of a grid data cell +``` +### Data identification {#iso19139-elem-gmd-MD_DataIdentification-f23816274b5af937b7fc035607866193} + +Name + +: + +> gmd:MD_DataIdentification + +Description + +: + +```{=html} +Information required to identify a dataset +``` +``` xml + + + + + Ecosystem types of Europe based on EUNIS level 1 (raster 100m) - + version 2.1, Dec. 2015 + + + + + + 2015-12-08 + + + + + + + + + + 2015-12-08 + + + + + + + + 2.1 + + + + + eea_r_3035_100_m_ecosystem-types-l1_2006_rev2-1 + + + + + + + + The data set combines the Corine based MAES (Mapping and Assessment of + Ecosystems and their Services) ecosystem classes with the non-spatial EUNIS habitat + classification (LEVEL 1) for a better biological characterization of ecosystems across + Europe (EEA-39). As such it represents probabilities of EUNIS habitat presence for each + MAES ecosystem type. + + The data set aims to combine spatially explicit land cover information with non-spatially + referenced habitat information to improve our knowledge about ecosystems and their + distribution across Europe. The work supports the MAES process, Target 2 Action 5 of the + implementation of the EU Biodiversity Strategy to 2020, established to achieve the Aichi + targets of the Convention of Biological Diversity (CBD). + + The objective of the ecosystem data set produced by EEA and its Topic Centre ETC/SIA was + to improve the biological description of land cover based ecosystem types. It represents + probabilities of EUNIS habitat presence in ecosystem types at European level. Since it is + not based on spatial explicit mapping the spatial and thematic accuracy is not of same + quality as delineated maps. + + The MAES ecosystem typology differentiates three levels: whereas the level 2 of the MAES + proposal follows closely the EUNIS level 1, the third level of the MAES typology + corresponds to the EUNIS level 2. This level will be the base for the mapping approach. + + + + + + European Environment Agency + + + + + + + Kongens Nytorv 6 + + + Copenhagen + + + K + + + 1050 + + + Denmark + + + eea.enquiries@eea.europa.eu + + + + + + + http://www.eea.europa.eu + + + WWW:LINK-1.0-http--link + + + Europen Environment Agency public website + + + + + + + + + + + + + + + + + + + + + + + + + + http://sdi.eea.europa.eu/public/catalogue-graphic-overview/e8a366b7-0029-44d7-ae33-7578253179c0.png + + + + + + + + Land cover + + + Habitats and biotopes + + + + + + + + GEMET - INSPIRE themes, version 1.0 + + + + + 2008-06-01 + + + + + + + + + + + geonetwork.thesaurus.external.theme.httpinspireeceuropaeutheme-theme + + + + + + + + + + + + ecosystem + + + ecosystem type + + + land cover + + + environmental assessment + + + habitat + + + + + + + + GEMET - Concepts, version 2.4 + + + + + 2010-01-13 + + + + + + + + + + + geonetwork.thesaurus.external.theme.gemet + + + + + + + + + + + + Unless otherwise indicated, re-use of content on the EEA website + for commercial or non-commercial purposes is permitted free of charge, provided that + the source is acknowledged. The EEA re-use policy follows Directive 2003/98/EC of the + European Parliament and the Council on the re-use of public sector information + throughout the European Union and Commission Decision 2006/291/EC, Euratom on the + re-use of Commission information. The EEA accepts no responsibility or liability + whatsoever for the re-use of content accessible on its website. Any inquiries about + re-use of content on the EEA website should be addressed to Ove Caspersen, EEA, + Kongens Nytorv 6, DK-1050 Copenhagen K, Tel +45 33 36 71 00, Fax +45 33 36 71 99, + e-mail copyrights at eea.europa.eu + + + + + + + + + + + no limitations + + + + + + + + + + 100 + + + + + + + + biota + + + environment + + + + + + + -33.90432 + + + 38.1471 + + + 26.988714 + + + 60.57849 + + + + + + + + + + + + 2006-01-01 + 2006-12-31 + + + + + + + +``` + +### Data type code {#iso19139-elem-gmd-MD_DatatypeCode-0bba106513fd53d5cba911355f212732} + +Name + +: + +> gmd:MD_DatatypeCode + +Description + +: + +```{=html} +datatype of element or entity +``` +### Standard codelists Data type code (gmd:MD_DatatypeCode) + +| code | label | description | +|-----------------|------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| class | Class | Descriptor of a set of objects that share the same attributes, operations, methods, relationships, and behavior | +| codelist | Codelist | Descriptor of a set of objects that share the same attributes, operations, methods, relationships, and behavior | +| enumeration | Enumeration | Data type whose instances form a list of named literal values, not extendable | +| codelistElement | Codelist element | Permissible value for a codelist or enumeration | +| abstractClass | Abstract class | Class that cannot be directly instantiated | +| aggregateClass | Aggregate class | Class that is composed of classes it is connected to by an aggregate relationship | +| specifiedClass | Specified class | Subclass that may be substituted for its superclass | +| datatypeClass | Datatype class | Class with few or no operations whose primary purpose is to hold the abstract state of another class for transmittal, storage, encoding or persistent storage | +| interfaceClass | Interface class | Named set of operations that characterize the behavior of an element | +| unionClass | Union class | Class describing a selection of one of the specified types | +| metaClass | Meta class | Class whose instances are classes | +| typeClass | Type class | Class used for specification of a domain of instances (objects), together with the operations applicable to the objects. A type may have attributes and associations | +| characterString | Character string | Free text field | +| integer | Integer | Numerical field | +| association | Association | Semantic relationship between two classes that involves connections among their instances | + +### Digital transfer options {#iso19139-elem-gmd-MD_DigitalTransferOptions-2c4f72aed0a9f9f5330a03d767a19e18} + +Name + +: + +> gmd:MD_DigitalTransferOptions + +Description + +: + +```{=html} +Technical means and media by which a resource is obtained from the + distributor +``` +``` xml + + + + + + http://www.eea.europa.eu/data-and-maps/data/ds_resolveuid/d851e1b7f678468b8f0b1b98930ba3e1 + + + + WWW:LINK-1.0-http--link + + + + + + + +``` + +### Dimension {#iso19139-elem-gmd-MD_Dimension-bc1cce714363bca430f062ece77911bb} + +Name + +: + +> gmd:MD_Dimension + +Description + +: + +```{=html} +Axis properties +``` +### Dimension type code {#iso19139-elem-gmd-MD_DimensionNameTypeCode-18f3e8f68c2b8cfbaed2e3f76dbfa8c7} + +Name + +: + +> gmd:MD_DimensionNameTypeCode + +Description + +: + +```{=html} +name of the dimension +``` +### Standard codelists Dimension type code (gmd:MD_DimensionNameTypeCode) + +| code | label | description | +|------------|-------------|------------------------------------------------------------| +| row | Row | Ordinate (y) axis | +| column | Column | Abscissa (x) axis | +| vertical | Vertical | Vertical (z) axis | +| track | Track | Along the direction of motion of the scan point | +| crossTrack | Cross track | Perpendicular to the direction of motion of the scan point | +| line | Line | Scan line of a sensor | +| sample | Sample | Element along a scan line | +| time | Time | Duration | + +### Distribution {#iso19139-elem-gmd-MD_Distribution-54490632933db13de8c9b59dfa70abe1} + +Name + +: + +> gmd:MD_Distribution + +Description + +: + +```{=html} +Information about the distributor of and options for obtaining the + resource +``` +``` xml + + + + + GTiff + + + + + + + + + + + + + http://www.eea.europa.eu/data-and-maps/data/ds_resolveuid/d851e1b7f678468b8f0b1b98930ba3e1 + + + + WWW:LINK-1.0-http--link + + + + + + + + + +``` + +### Distribution Units {#iso19139-elem-gmd-MD_DistributionUnits-ec18c729b051ecf4cbef23146d4c6b51} + +Name + +: + +> gmd:MD_DistributionUnits + +Description + +: + +### Distributor {#iso19139-elem-gmd-MD_Distributor-d6824c3ac5e1b658b17c1547ded49dba} + +Name + +: + +> gmd:MD_Distributor + +Description + +: + +```{=html} +Information about the distributor +``` +### Extended Element Information {#iso19139-elem-gmd-MD_ExtendedElementInformation-42b92809323020ccb9cb0def9d6ba040} + +Name + +: + +> gmd:MD_ExtendedElementInformation + +Description + +: + +```{=html} +New metadata element, not found in ISO 19115, which is required to describe + geographic data +``` +### Feature catalogue description {#iso19139-elem-gmd-MD_FeatureCatalogueDescription-1b529353783b4f3bb4f593e052f37339} + +Name + +: + +> gmd:MD_FeatureCatalogueDescription + +Description + +: + +```{=html} +Information identifying the feature catalogue or the conceptual + schema +``` +``` xml + + + false + + + +``` + +### Format {#iso19139-elem-gmd-MD_Format-de100d011b7723caf6cfed1dfd2d521e} + +Name + +: + +> gmd:MD_Format + +Description + +: + +```{=html} +Description of the computer language construct that specifies the + representation of data objects in a record, file, message, storage device or + transmission channel +``` +``` xml + + + GTiff + + + + + +``` + +### Geometric objects {#iso19139-elem-gmd-MD_GeometricObjects-194ec1e062c0a1e8a95764b03ba61b2c} + +Name + +: + +> gmd:MD_GeometricObjects + +Description + +: + +```{=html} +Number of objects, listed by geometric object type, used in the + dataset +``` +### Geometric Object Type {#iso19139-elem-gmd-MD_GeometricObjectTypeCode-0343e1ce72823eeb2e13f5c1c7d8a362} + +Name + +: + +> gmd:MD_GeometricObjectTypeCode + +Description + +: + +### Standard codelists Geometric Object Type (gmd:MD_GeometricObjectTypeCode) + +| code | label | description | +|-----------|-----------|----------------------------------------------------------------------------------------------------------------| +| complex | Complex | Set of geometric primitives such that their boundaries can be represented as a union of other primitives | +| composite | Composite | Connected set of curves, solids or surfaces | +| curve | Curve | Bounded, 1-dimensional geometric primitive, representing the continuous image of a line | +| point | Point | Zero-dimensional geometric primitive, representing a position but not having an extent | +| solid | Solid | Bounded, connected 3-dimensional geometric primitive, representing the continuous image of a region of space | +| surface | Surface | Bounded, connected 2-dimensional geometric primitive, representing the continuous image of a region of a plane | + +### Georectified {#iso19139-elem-gmd-MD_Georectified-a0093e969409fbdfa09e2fbbd2d856c2} + +Name + +: + +> gmd:MD_Georectified + +Description + +: + +```{=html} +Grid whose cells are regularly spaced in a geographic (i.e., lat / long) or map + coordinate system defined in the Spatial Referencing System (SRS) so that any cell in + the grid can be geolocated given its grid coordinate and the grid origin, cell spacing, + and orientation +``` +### Georeferenceable {#iso19139-elem-gmd-MD_Georeferenceable-758d9a268ea6785de91ddd68102f643b} + +Name + +: + +> gmd:MD_Georeferenceable + +Description + +: + +```{=html} +Grid with cells irregularly spaced in any given geographic/map projection + coordinate system, whose individual cells can be geolocated using geolocation + information supplied with the data but cannot be geolocated from the grid properties + alone +``` +### Grid spatial representation {#iso19139-elem-gmd-MD_GridSpatialRepresentation-f6383abd79082f30ad3d9e0e6d582ae4} + +Name + +: + +> gmd:MD_GridSpatialRepresentation + +Description + +: + +```{=html} +Information about grid spatial objects in the dataset +``` +### Identifier {#iso19139-elem-gmd-MD_Identifier-a8075d9fcf78f296408f5a47a15f72e3} + +Name + +: + +> gmd:MD_Identifier + +Description + +: + +```{=html} +Value uniquely identifying an object within a namespace +``` +### Image description {#iso19139-elem-gmd-MD_ImageDescription-36a3b51ff28072d6b260523149eeb9bd} + +Name + +: + +> gmd:MD_ImageDescription + +Description + +: + +```{=html} +Information about an image's suitability for use +``` +### Imaging Condition Code {#iso19139-elem-gmd-MD_ImagingConditionCode-606883a4bccc60f4019ebc03e22ec7e9} + +Name + +: + +> gmd:MD_ImagingConditionCode + +Description + +: + +```{=html} +code which indicates conditions which may affect the + image +``` +### Standard codelists Imaging Condition Code (gmd:MD_ImagingConditionCode) + +| code | label | description | +|--------------------|---------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| blurredImage | Blurred image | Portion of the image is blurred | +| cloud | Cloud | Portion of the image is partially obscured by cloud cover | +| degradingObliquity | Degrading obliquity | Acute angle between the plane of the ecliptic (the plane of the Earth s orbit) and the plane of the celestial equator | +| fog | Fog | Portion of the image is partially obscured by fog | +| heavySmokeOrDust | Heavy smoke or dust | Portion of the image is partially obscured by heavy smoke or dust | +| night | Night | Image was taken at night | +| rain | Rain | Image was taken during rainfall | +| semiDarkness | Semi darkness | Image was taken during semi-dark conditions -- twilight conditions | +| shadow | Shadow | Portion of the image is obscured by shadow | +| snow | Snow | Portion of the image is obscured by snow | +| terrainMasking | Terrain masking | The absence of collection data of a given point or area caused by the relative location of topographic features which obstruct the collection path between the collector(s) and the subject(s) of interest | + +### Keywords {#iso19139-elem-gmd-MD_Keywords-aa987246245f8ec027b557d023a95fc4} + +Name + +: + +> gmd:MD_Keywords + +Description + +: + +```{=html} +Keywords, their type and reference source +``` +### Keyword Type Code {#iso19139-elem-gmd-MD_KeywordTypeCode-2f0c82ed31f17b806c452ec469485a6a} + +Name + +: + +> gmd:MD_KeywordTypeCode + +Description + +: + +```{=html} +methods used to group similar keywords +``` +### Standard codelists Keyword Type Code (gmd:MD_KeywordTypeCode) + +| code | label | description | +|------------|------------|--------------------------------------------------------------------| +| discipline | Discipline | Keyword identifies a branch of instruction or specialized learning | +| place | Place | Keyword identifies a location | +| stratum | Stratum | Keyword identifies the layer(s) of any deposited substance | +| temporal | Temporal | Keyword identifies a time period related to the dataset | +| theme | Theme | Keyword identifies a particular subject or topic | + +### Legal constraints {#iso19139-elem-gmd-MD_LegalConstraints-6ed172b96e894f417fd71106ceb3e0f7} + +Name + +: + +> gmd:MD_LegalConstraints + +Description + +: + +```{=html} +Restrictions and legal prerequisites for accessing and using the resource or + metadata +``` +``` xml + + + + + + no limitations + + +``` + +### Maintenance Frequency {#iso19139-elem-gmd-MD_MaintenanceFrequencyCode-2338217a3e7f51c06e6f18cca73afb6c} + +Name + +: + +> gmd:MD_MaintenanceFrequencyCode + +Description + +: + +### Standard codelists Maintenance Frequency (gmd:MD_MaintenanceFrequencyCode) + +| code | label | description | +|-------------|-------------|----------------------------------------------------------| +| continual | Continual | Data is repeatedly and frequently updated | +| daily | Daily | Data is updated each day | +| weekly | Weekly | Data is updated on a weekly basis | +| fortnightly | Fortnightly | Data is updated every two weeks | +| monthly | Monthly | Data is updated each month | +| quarterly | Quarterly | Data is updated every three months | +| biannually | Biannually | Data is updated twice each year | +| annually | Annually | Data is updated every year | +| asNeeded | As needed | Data is updated as deemed necessary | +| irregular | Irregular | Data is updated in intervals that are uneven in duration | +| notPlanned | Not planned | There are no plans to update the data | +| unknown | Unknown | Frequency of maintenance for the data is not known | + +``` xml + +``` + +### Maintenance information {#iso19139-elem-gmd-MD_MaintenanceInformation-c8cc0a8f25b6943b1df7d5a1b46f915d} + +Name + +: + +> gmd:MD_MaintenanceInformation + +Description + +: + +```{=html} +Information about the scope and frequency of updating +``` +``` xml + + + + + +``` + +### Medium {#iso19139-elem-gmd-MD_Medium-e532adb6d35b09f1dd8cc793984c3723} + +Name + +: + +> gmd:MD_Medium + +Description + +: + +```{=html} +Information about the media on which the resource can be + distributed +``` +### Medium format {#iso19139-elem-gmd-MD_MediumFormatCode-25bd3e7951957655817e6b930a2923fd} + +Name + +: + +> gmd:MD_MediumFormatCode + +Description + +: + +```{=html} +method used to write to the medium +``` +### Standard codelists Medium format (gmd:MD_MediumFormatCode) + +| code | label | description | +|------------------|--------------------|------------------------------------------------------------| +| cpio | CPIO | CoPy In / Out (UNIX file format and command) | +| tar | TAR | Tape ARchive | +| highSierra | High sierra | High sierra file system | +| iso9660 | ISO9660 | Information processing volume and file structure of CD-ROM | +| iso9660RockRidge | ISO9660 Rock Ridge | Rock ridge interchange protocol (UNIX) | +| iso9660AppleHFS | ISO9660 Apple HFS | Hierarchical file system (Macintosh) | + +### Medium name code {#iso19139-elem-gmd-MD_MediumNameCode-a9abbe36f3dcf64d224bef1bfea190e7} + +Name + +: + +> gmd:MD_MediumNameCode + +Description + +: + +```{=html} +name of the medium +``` +### Standard codelists Medium name code (gmd:MD_MediumNameCode) + +| code | label | description | +|---------------------------|-------------------------------|----------------------------------------------------| +| cdRom | CDROM | Read-only optical disk | +| dvd | DVD | Digital versatile disk | +| dvdRom | DVDROM | Digital versatile disk, read only | +| 3halfInchFloppy | 3 Half Inch Floppy | 3,5 inch magnetic disk | +| 5quarterInchFloppy | 5 Quarter Inch Floppy | 5,25 inch magnetic disk | +| 7trackTape | 7 Track tape | 7 track magnetic tape | +| 9trackTape | 9 track tape | 9 track magnetic tape | +| 3480Cartridge | 3480 Cartridge | 3480 cartridge tape drive | +| 3490Cartridge | 3490 Cartridge | 3490 cartridge tape drive | +| 3580Cartridge | 3580 Cartridge | 3580 cartridge tape drive | +| 4mmCartridgeTape | 4 mm Cartridge tape | 4 millimetre magnetic tape | +| 8mmCartridgeTape | 8 mm Cartridge tape | 8 millimetre magnetic tape | +| 1quarterInchCartridgeTape | 1 Quarter inch cartridge tape | 0,25 inch magnetic tape | +| digitalLinearTap | Digital linear tape | Half inch cartridge streaming tape drive | +| onLine | Online | Direct computer linkage | +| satellite | Satellite | Linkage through a satellite communication system | +| telephoneLink | Telephone link | Communication through a telephone network | +| hardcopy | Hardcopy | Pamphlet or leaflet giving descriptive information | + +### Metadata {#iso19139-elem-gmd-MD_Metadata-c2690d5de6984085623477c3bdc3275b} + +Name + +: + +> gmd:MD_Metadata + +Description + +: + +```{=html} +Root entity which defines metadata about a resource or resources +``` +``` xml + + + e8a366b7-0029-44d7-ae33-7578253179c0 + + + + + + + + + df69de7e-3af1-4b4d-94d4-8bebe84c80b0 + + + + + + + + European Environment Agency + + + + + + + Kongens Nytorv 6 + + + Copenhagen + + + K + + + 1050 + + + Denmark + + + eea.enquiries@eea.europa.eu + + + + + + + + + + + + 2016-01-15T16:57:35 + + + ISO 19115:2003/19139 + + + + 1.0 + + + + + + + + urn:ogc:def:crs:EPSG:7.1:3035 + + + OGP Surveying & Positioning Committee + + + + + + + + + + + Ecosystem types of Europe based on EUNIS level 1 (raster 100m) - + version 2.1, Dec. 2015 + + + + + + 2015-12-08 + + + + + + + + + + 2015-12-08 + + + + + + + + 2.1 + + + + + eea_r_3035_100_m_ecosystem-types-l1_2006_rev2-1 + + + + + + + + The data set combines the Corine based MAES (Mapping and Assessment of + Ecosystems and their Services) ecosystem classes with the non-spatial EUNIS habitat + classification (LEVEL 1) for a better biological characterization of ecosystems across + Europe (EEA-39). As such it represents probabilities of EUNIS habitat presence for each + MAES ecosystem type. + + The data set aims to combine spatially explicit land cover information with non-spatially + referenced habitat information to improve our knowledge about ecosystems and their + distribution across Europe. The work supports the MAES process, Target 2 Action 5 of the + implementation of the EU Biodiversity Strategy to 2020, established to achieve the Aichi + targets of the Convention of Biological Diversity (CBD). + + The objective of the ecosystem data set produced by EEA and its Topic Centre ETC/SIA was + to improve the biological description of land cover based ecosystem types. It represents + probabilities of EUNIS habitat presence in ecosystem types at European level. Since it is + not based on spatial explicit mapping the spatial and thematic accuracy is not of same + quality as delineated maps. + + The MAES ecosystem typology differentiates three levels: whereas the level 2 of the MAES + proposal follows closely the EUNIS level 1, the third level of the MAES typology + corresponds to the EUNIS level 2. This level will be the base for the mapping approach. + + + + + + European Environment Agency + + + + + + + Kongens Nytorv 6 + + + Copenhagen + + + K + + + 1050 + + + Denmark + + + eea.enquiries@eea.europa.eu + + + + + + + http://www.eea.europa.eu + + + WWW:LINK-1.0-http--link + + + Europen Environment Agency public website + + + + + + + + + + + + + + + + + + + + + + + + + + http://sdi.eea.europa.eu/public/catalogue-graphic-overview/e8a366b7-0029-44d7-ae33-7578253179c0.png + + + + + + + + Land cover + + + Habitats and biotopes + + + + + + + + GEMET - INSPIRE themes, version 1.0 + + + + + 2008-06-01 + + + + + + + + + + + geonetwork.thesaurus.external.theme.httpinspireeceuropaeutheme-theme + + + + + + + + + + + + ecosystem + + + ecosystem type + + + land cover + + + environmental assessment + + + habitat + + + + + + + + GEMET - Concepts, version 2.4 + + + + + 2010-01-13 + + + + + + + + + + + geonetwork.thesaurus.external.theme.gemet + + + + + + + + + + + + Unless otherwise indicated, re-use of content on the EEA website + for commercial or non-commercial purposes is permitted free of charge, provided that + the source is acknowledged. The EEA re-use policy follows Directive 2003/98/EC of the + European Parliament and the Council on the re-use of public sector information + throughout the European Union and Commission Decision 2006/291/EC, Euratom on the + re-use of Commission information. The EEA accepts no responsibility or liability + whatsoever for the re-use of content accessible on its website. Any inquiries about + re-use of content on the EEA website should be addressed to Ove Caspersen, EEA, + Kongens Nytorv 6, DK-1050 Copenhagen K, Tel +45 33 36 71 00, Fax +45 33 36 71 99, + e-mail copyrights at eea.europa.eu + + + + + + + + + + + no limitations + + + + + + + + + + 100 + + + + + + + + biota + + + environment + + + + + + + -33.90432 + + + 38.1471 + + + 26.988714 + + + 60.57849 + + + + + + + + + + + + 2006-01-01 + 2006-12-31 + + + + + + + + + + + + false + + + + + + + + + + GTiff + + + + + + + + + + + + + http://www.eea.europa.eu/data-and-maps/data/ds_resolveuid/d851e1b7f678468b8f0b1b98930ba3e1 + + + + WWW:LINK-1.0-http--link + + + + + + + + + + + + + + + + + + + + + + + The data set production implied 2 steps. First re-classification of + CORINE Land Cover 2006 and bathymetry data using the 7 terrestrial (urban, cropland, + grassland, woodland and forest, heathland and shrub, sparsely vegetated land, + wetland), 1 freshwater (river and lakes), and 4 marine (marine inlets and transitional + waters, coastal, shelf, open ocean) classes of the MAES ecosystem typology (Maes et + al., 2013). The classes also provide links to major policy lines such as agriculture, + forestry, territorial cohesion, water and marine related policies. The second step + comprised refinement of the ecosystem types by attributing EUNIS habitat information + to each ecosystem type (see http://eunis.eea.europa.eu/habitats.jsp). The refinement + process used reference data such as potential natural vegetation, elevation, slope, + aspect, soil, geology, environmental regions and other spatial referenced information + which allowed attribution of the EUNIS habitat characteristics to the spatial mapping + units of the MAES ecosystem types. The geometric and thematic accuracy of EUNIS class + presence was also estimated and mapped. The method is described in the EEA Technical + Report 06/2015: European Ecosystem Assessment – Concept, Data, and Implementation. + The basis for the update was CORINE land cover 2006 (CLC 2006). It includes Albania, + Austria, Belgium, Bosnia and Herzegovina, Bulgaria, Croatia, Cyprus, Czech Republic, + Denmark, Estonia, Finland, France, Germany, Hungary, Iceland, Ireland, Italy, Kosovo + (under UNSCR 1244/99), Latvia, Liechtenstein, Lithuania, Luxembourg, the former + Yugoslavian Republic of Macedonia, Malta, Montenegro, the Netherlands, Norway, Poland, + Portugal, Romania, Serbia, Slovakia, Slovenia, Spain, Sweden, Switzerland, Turkey and + the United Kingdom. For Greece that has not participated in the CLC 2006 activity the + CLC 2000 data was used instead. + + + + + + + + +``` + +### Metadata Extension Information {#iso19139-elem-gmd-MD_MetadataExtensionInformation-646aa4503013cf2231a72dc4403c14e3} + +Name + +: + +> gmd:MD_MetadataExtensionInformation + +Description + +: + +```{=html} +Information describing metadata extensions +``` +### Obligation code {#iso19139-elem-gmd-MD_ObligationCode-50bf58bf346f8ea1982cbebde314ed79} + +Name + +: + +> gmd:MD_ObligationCode + +Description + +: + +```{=html} +Obligation of the element or entity +``` +### Standard codelists Obligation code (gmd:MD_ObligationCode) + +| code | label | description | +|-------------|-------------|------------------------------------------------------| +| mandatory | Mandatory | Element is always required | +| optional | Optional | Element is not required | +| conditional | Conditional | Element is required when a specific condition is met | + +### Pixel orientation code {#iso19139-elem-gmd-MD_PixelOrientationCode-7517f9a6da0ddf97e3a3edafceff4fc9} + +Name + +: + +> gmd:MD_PixelOrientationCode + +Description + +: + +```{=html} +Point in a pixel corresponding to the Earth location of the pixel +``` +### Standard codelists Pixel orientation code (gmd:MD_PixelOrientationCode) + +| code | label | description | +|------------|-------------|----------------------------------------------------------------------------------------------------------------------------------------------| +| center | Center | Point halfway between the lower left and the upper right of the pixel | +| lowerLeft | Lower left | The corner in the pixel closest to the origin of the SRS; if two are at the same distance from the origin, the one with the smallest x-value | +| lowerRight | Lower right | Next corner counterclockwise from the lower left | +| upperRight | Upper right | Next corner counterclockwise from the lower right | +| upperLeft | Upper left | Next corner counterclockwise from the upper right | + +### Portrayal catalogue reference {#iso19139-elem-gmd-MD_PortrayalCatalogueReference-1de6d80081f48afcf87141f495b14382} + +Name + +: + +> gmd:MD_PortrayalCatalogueReference + +Description + +: + +```{=html} +Information identifying the portrayal catalogue used +``` +### Progress {#iso19139-elem-gmd-MD_ProgressCode-a705251bfb6aa840b2ddcdcb475e82ae} + +Name + +: + +> gmd:MD_ProgressCode + +Description + +: + +### Standard codelists Progress (gmd:MD_ProgressCode) + +| code | label | description | +|-------------------|--------------------|--------------------------------------------------------------------------------------| +| completed | Completed | Production of the data has been completed | +| historicalArchive | Historical archive | Data has been stored in an offline storage facility | +| obsolete | Obsolete | Data is no longer relevant | +| onGoing | On going | Data is continually being updated | +| planned | Planned | Fixed date has been established upon or by which the data will be created or updated | +| required | Required | Data needs to be generated or updated | +| underDevelopment | Under development | Data is currently in the process of being created | + +Those values are defined in the standard but hidden when editing. + +| code | label | description | +|-------------|--------------|-------------| +| notobsolete | Not obsolete | | + +### Range dimension {#iso19139-elem-gmd-MD_RangeDimension-6788b233d4b9866fff4fea73bb016784} + +Name + +: + +> gmd:MD_RangeDimension + +Description + +: + +```{=html} +Information on the range of each dimension of a cell measurement + value +``` +### Reference system {#iso19139-elem-gmd-MD_ReferenceSystem-2700a53ffd47f02aee2059e4520f399f} + +Name + +: + +> gmd:MD_ReferenceSystem + +Description + +: + +```{=html} +Information about the reference system. +``` +```{=html} +information about the reference system +``` +``` xml + + + + + urn:ogc:def:crs:EPSG:7.1:3035 + + + OGP Surveying & Positioning Committee + + + + +``` + +### Representative fraction {#iso19139-elem-gmd-MD_RepresentativeFraction-66b5d251e519833e03ebd5b5b0f2d075} + +Name + +: + +> gmd:MD_RepresentativeFraction + +Description + +: + +```{=html} +Derived from Scale where MD_RepresentativeFraction.denominator = 1 / + Scale.measure And Scale.targetUnits = Scale.sourceUnits +``` +### Resolution {#iso19139-elem-gmd-MD_Resolution-b305b6f73606a0b11af969489ef2b5ac} + +Name + +: + +> gmd:MD_Resolution + +Description + +: + +```{=html} +Level of detail expressed as a scale factor or a ground distance +``` +``` xml + + + 100 + + +``` + +### Access Restriction {#iso19139-elem-gmd-MD_RestrictionCode-gmd-accessConstraints-12f24e671b178093fc3c8cf32539ce44} + +Name + +: + +> gmd:MD_RestrictionCode + +Context + +: + +> gmd:accessConstraints + +Description + +: + +### Standard codelists Access Restriction (gmd:MD_RestrictionCode) + +| code | label | description | +|----------------------------|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| copyright | Copyright | Exclusive right to the publication, production, or sale of the rights to a literary, dramatic, musical, or artistic work, or to the use of a commercial print or label, granted by law for a specified period of time to an author, composer, artist, distributor | +| patent | Patent | Government has granted exclusive right to make, sell, use or license an invention or discovery | +| patentPending | Pending patent | Produced or sold information awaiting a patent | +| trademark | Trademark | A name, symbol, or other device identifying a product, officially registered and legally restricted to the use of the owner or manufacturer | +| license | License | Formal permission to do something | +| intellectualPropertyRights | Intellectual property rights | Rights to financial benefit from and control of distribution of non-tangible property that is a result of creativity | +| restricted | Restricted | Withheld from general circulation or disclosure | +| otherRestrictions | Other restrictions | Limitation not listed | + +``` xml + +``` + +### Use Restriction {#iso19139-elem-gmd-MD_RestrictionCode-gmd-useConstraints-56f57edb2ffb57e63fc7166ee5ae8350} + +Name + +: + +> gmd:MD_RestrictionCode + +Context + +: + +> gmd:useConstraints + +Description + +: + +### Standard codelists Access Restriction (gmd:MD_RestrictionCode) + +| code | label | description | +|----------------------------|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| copyright | Copyright | Exclusive right to the publication, production, or sale of the rights to a literary, dramatic, musical, or artistic work, or to the use of a commercial print or label, granted by law for a specified period of time to an author, composer, artist, distributor | +| patent | Patent | Government has granted exclusive right to make, sell, use or license an invention or discovery | +| patentPending | Pending patent | Produced or sold information awaiting a patent | +| trademark | Trademark | A name, symbol, or other device identifying a product, officially registered and legally restricted to the use of the owner or manufacturer | +| license | License | Formal permission to do something | +| intellectualPropertyRights | Intellectual property rights | Rights to financial benefit from and control of distribution of non-tangible property that is a result of creativity | +| restricted | Restricted | Withheld from general circulation or disclosure | +| otherRestrictions | Other restrictions | Limitation not listed | + +``` xml + +``` + +### Scope code {#iso19139-elem-gmd-MD_ScopeCode-9ffd6fc05da3527f72a3dcae95dd221e} + +Name + +: + +> gmd:MD_ScopeCode + +Description + +: + +```{=html} +Class of information to which the referencing entity applies +``` +### Standard codelists Scope code (gmd:MD_ScopeCode) + +| code | label | description | +|----------------------|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| attribute | Attribute | Information applies to the attribute class | +| attributeType | Attribute type | Information applies to the characteristic of a feature | +| collectionHardware | Collection hardware | Information applies to the collection hardware class | +| collectionSession | Collection session | Information applies to the collection session | +| dataset | Dataset | Information applies to the dataset | +| series | Series | Information applies to the series | +| nonGeographicDataset | Non geographic dataset | Information applies to non-geographic data | +| dimensionGroup | Dimension group | Information applies to a dimension group | +| feature | Feature | Information applies to a feature | +| featureType | Feature type | Information applies to a feature type | +| propertyType | Property type | Information applies to a property type | +| fieldSession | Field session | Information applies to a field session | +| software | Software | Information applies to a computer program or routine | +| service | Service | Information applies to a capability which a service provider entity makes available to a service user entity through a set of interfaces that define a behaviour, such as a use case | +| model | Model | Information applies to a copy or imitation of an existing or hypothetical object | +| tile | Tile | Information applies to a tile, a spatial subset of geographic data | + +Those values are defined in the standard but hidden when editing. + +| code | label | description | +|---------------------------------------------|------------------------------------------------|-------------| +| map staticMap interactiveMap featureCatalog | Map Static map Interactive map Feature catalog | | + +Displayed only if + +: + +> /ancestor::node()[name()='gmd:MD_Metadata']/gmd:identificationInfo/srv:SV_ServiceIdentification + +### Standard codelists Scope code (gmd:MD_ScopeCode) + +| code | label | description | +|---------|---------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| service | Service | Information applies to a capability which a service provider entity makes available to a service user entity through a set of interfaces that define a behaviour, such as a use case | + +### Scope description {#iso19139-elem-gmd-MD_ScopeDescription-8c0d8bbef826207eed5daeb5852c1538} + +Name + +: + +> gmd:MD_ScopeDescription + +Description + +: + +```{=html} +Description of the class of information covered by the + information +``` + +Condition + +: + +> Either attributes, features, featureInstances, attributeInstnaces, dataset or other must be provided + +### Security constraints {#iso19139-elem-gmd-MD_SecurityConstraints-50cffe217644bdac6008fbf9f8b569c5} + +Name + +: + +> gmd:MD_SecurityConstraints + +Description + +: + +```{=html} +Handling restrictions imposed on the resource or metadata for national security + or similar security concerns +``` +### Service Identification {#iso19139-elem-gmd-MD_ServiceIdentification-fa001e116566fc975db65c9f5847bf42} + +Name + +: + +> gmd:MD_ServiceIdentification + +Description + +: + +```{=html} +Identification of capabilities which a service provider makes available to a + service user through a set of interfaces that define a behaviour - See ISO 19119 - + Services for further information +``` +### Spatial Representation Type {#iso19139-elem-gmd-MD_SpatialRepresentationTypeCode-7f5f469869ef3a8a1951b287a3494e69} + +Name + +: + +> gmd:MD_SpatialRepresentationTypeCode + +Description + +: + +### Standard codelists Spatial Representation Type (gmd:MD_SpatialRepresentationTypeCode) + +| code | label | description | +|-------------|--------------|----------------------------------------------------------------------------------------------------| +| vector | Vector | Vector data is used to represent geographic data | +| grid | Grid | Grid data is used to represent geographic data | +| textTable | Text, table | Textual or tabular data is used to represent geographic data | +| tin | TIN | Triangulated irregular network | +| stereoModel | Stereo model | Three-dimensional view formed by the intersecting homologous rays of an overlapping pair of images | +| video | Video | Scene from a video recording | + +``` xml + +``` + +### Standard order process {#iso19139-elem-gmd-MD_StandardOrderProcess-3d3f736b3cad83dea0c4232e97bb7af4} + +Name + +: + +> gmd:MD_StandardOrderProcess + +Description + +: + +```{=html} +Common ways in which the resource may be obtained or received, and related + instructions and fee information +``` +### Topic category code {#iso19139-elem-gmd-MD_TopicCategoryCode-cb06862958376a6cf77f91294821ba48} + +Name + +: + +> gmd:MD_TopicCategoryCode + +Description + +: + +```{=html} +High-level geographic data thematic classification to assist in the grouping + and search of available geographic data sets. Can be used to group keywords as well. + Listed examples are not exhaustive. NOTE It is understood there are overlaps between + general categories and the user is encouraged to select the one most + appropriate. +``` +### Standard codelists Topic category code (gmd:MD_TopicCategoryCode) + +| code | label | description | +|----------------------------------|--------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| farming | Farming | Rearing of animals and/or cultivation of plants. Examples: agriculture, irrigation, aquaculture, plantations, herding, pests and diseases affecting crops and livestock | +| biota | Biota | Flora and/or fauna in natural environment. Examples: wildlife, vegetation, biological sciences, ecology, wilderness, sealife, wetlands, habitat | +| boundaries | Boundaries | Legal land descriptions. Examples: political and administrative boundaries | +| climatologyMeteorologyAtmosphere | Climatology, meteorology, atmosphere | Processes and phenomena of the atmosphere. Examples: cloud cover, weather, climate, atmospheric conditions, climate change, precipitation | +| economy | Economy | Economic activities, conditions and employment. Examples: production, labour, revenue, commerce, industry, tourism and ecotourism, forestry, fisheries, commercial or subsistence hunting, exploration and exploitation of resources such as minerals, oil and gas | +| elevation | Elevation | Height above or below sea level. Examples: altitude, bathymetry, digital elevation models, slope, derived products | +| environment | Environment | Environmental resources, protection and conservation. Examples: environmental pollution, waste storage and treatment, environmental impact assessment, monitoring environmental risk, nature reserves, landscape | +| geoscientificInformation | Geoscientific information | Information pertaining to earth sciences. Examples: geophysical features and processes, geology, minerals, sciences dealing with the composition, structure and origin of the earth s rocks, risks of earthquakes, volcanic activity, landslides, gravity information, soils, permafrost, hydrogeology, erosion | +| health | Health | Health, health services, human ecology, and safety. Examples: disease and illness, factors affecting health, hygiene, substance abuse, mental and physical health, health services | +| imageryBaseMapsEarthCover | Imagery base maps earth cover | Base maps. Examples: land cover, topographic maps, imagery, unclassified images, annotations | +| intelligenceMilitary | Intelligence military | Military bases, structures, activities. Examples: barracks, training grounds, military transportation, information collection | +| inlandWaters | Inland waters | Inland water features, drainage systems and their characteristics. Examples: rivers and glaciers, salt lakes, water utilization plans, dams, currents, floods, water quality, hydrographic charts | +| location | Location | Positional information and services. Examples: addresses, geodetic networks, control points, postal zones and services, place names | +| oceans | Oceans | Features and characteristics of salt water bodies (excluding inland waters). Examples: tides, tidal waves, coastal information, reefs | +| planningCadastre | Planning cadastre | Information used for appropriate actions for future use of the land. Examples: land use maps, zoning maps, cadastral surveys, land ownership | +| society | Society | Characteristics of society and cultures. Examples: settlements, anthropology, archaeology, education, traditional beliefs, manners and customs, demographic data, recreational areas and activities, social impact assessments, crime and justice, census information | +| structure | Structure | Man-made construction. Examples: buildings, museums, churches, factories, housing, monuments, shops, towers | +| transportation | Transportation | Means and aids for conveying persons and/or goods. Examples: roads, airports/airstrips, shipping routes, tunnels, nautical charts, vehicle or vessel location, aeronautical charts, railways | +| utilitiesCommunication | Utilities communication | Energy, water and waste systems and communications infrastructure and services. Examples: hydroelectricity, geothermal, solar and nuclear sources of energy, water purification and distribution, sewage collection and disposal, electricity and gas distribution, data communication, telecommunication, radio, communication networks | + +### Topology Level {#iso19139-elem-gmd-MD_TopologyLevelCode-3b51519b669d9d171a75a1fd49e8f9c0} + +Name + +: + +> gmd:MD_TopologyLevelCode + +Description + +: + +### Standard codelists Topology Level (gmd:MD_TopologyLevelCode) + +| code | label | description | +|------------------|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| geometryOnly | Geometry only | Geometry objects without any additional structure which describes topology | +| topology1D | Topology 1D | 1-dimensional topological complex -- commonly called chain-node topology | +| planarGraph | Planar graph | 1-dimensional topological complex that is planar. (A planar graph is a graph that can be drawn in a plane in such a way that no two edges intersect except at a vertex.) | +| fullPlanarGraph | Full planar graph | 2-dimensional topological complex that is planar. (A 2-dimensional topological complex is commonly called full topology in a cartographic 2D environment.) | +| surfaceGraph | Surface graph | 1-dimensional topological complex that is isomorphic to a subset of a surface. (A geometric complex is isomorphic to a topological complex if their elements are in a one-to-one, dimensional-and boundry-preserving correspondence to one another.) | +| fullSurfaceGraph | Full surface graph | 2-dimensional topological complex that is isomorphic to a subset of a surface | +| topology3D | Topology 3D | 3-dimensional topological complex. (A topological complex is a collection of topological primitives that are closed under the boundary operations.) | +| fullTopology3D | Full topology 3D | Complete coverage of a 3D Euclidean coordinate space | +| abstract | Abstract | Topological complex without any specified geometric realisation | + +### Usage {#iso19139-elem-gmd-MD_Usage-44b9e97d1ee076443e0f48c0f7d40819} + +Name + +: + +> gmd:MD_Usage + +Description + +: + +```{=html} +Brief description of ways in which the resource(s) is/are currently + used +``` +### Vector spatial representation {#iso19139-elem-gmd-MD_VectorSpatialRepresentation-080252d44368083a0c7b0d9d9560f519} + +Name + +: + +> gmd:MD_VectorSpatialRepresentation + +Description + +: + +```{=html} +Information about the vector spatial objects in the dataset +``` +### Measure description {#iso19139-elem-gmd-measureDescription-15e866aef3e37fc22a1e5777bbf435b1} + +Name + +: + +> gmd:measureDescription + +Description + +: + +```{=html} +Description of the measure being determined +``` +### Measure identification {#iso19139-elem-gmd-measureIdentification-d039c0be36450237d6b0e484e65d9330} + +Name + +: + +> gmd:measureIdentification + +Description + +: + +```{=html} +Code identifying a registered standard procedure +``` +### Medium format {#iso19139-elem-gmd-mediumFormat-2b3a955cfb7c1a5ab43b7ce1341888be} + +Name + +: + +> gmd:mediumFormat + +Description + +: + +```{=html} +Method used to write to the medium +``` +### Medium note {#iso19139-elem-gmd-mediumNote-668533707740bae1759a882d1db591a5} + +Name + +: + +> gmd:mediumNote + +Description + +: + +```{=html} +Description of other limitations or requirements for using the + medium +``` +### Metadata constraints {#iso19139-elem-gmd-metadataConstraints-gmd-MD_Metadata-130ad5b9aa5c191c31ca2a97d2ad629b} + +Name + +: + +> gmd:metadataConstraints + +Context + +: + +> gmd:MD_Metadata + +Description + +: + +```{=html} +Provides restrictions on the access and use of metadata +``` +### Metadata constraints {#iso19139-elem-gmd-metadataConstraints-0547cb4265a8d2f9663d558a9ac72d43} + +Name + +: + +> gmd:metadataConstraints + +Description + +: + +```{=html} +Provides restrictions on the access and use of data +``` +### Metadata Extension Information {#iso19139-elem-gmd-metadataExtensionInfo-4819d91b9727143a6c12cdb9ffeef2da} + +Name + +: + +> gmd:metadataExtensionInfo + +Description + +: + +```{=html} +Information describing metadata extensions +``` +### Metadata maintenance {#iso19139-elem-gmd-metadataMaintenance-2af9bf1fc8f71819e7361e5d6987358c} + +Name + +: + +> gmd:metadataMaintenance + +Description + +: + +```{=html} +Provides information about the frequency of metadata updates, and the scope of + those updates +``` +### Metadata standard name {#iso19139-elem-gmd-metadataStandardName-1e8d324f913f2da08b656d26e73e994d} + +Name + +: + +> gmd:metadataStandardName + +Description + +: + +```{=html} +Name of the metadata standard (including profile name) used +``` +``` xml + + ISO 19115:2003/19139 + + +``` + +### Metadata standard version {#iso19139-elem-gmd-metadataStandardVersion-ab0dd515a6ca9c890bc32d3615cd427f} + +Name + +: + +> gmd:metadataStandardVersion + +Description + +: + +```{=html} +Version (profile) of the metadata standard used +``` +``` xml + + 1.0 + + +``` + +### Minimum value {#iso19139-elem-gmd-minimumValue-d7415ce6a0445916b518cbced9bf748d} + +Name + +: + +> gmd:minimumValue + +Description + +: + +```{=html} +Lowest vertical extent contained in the dataset +``` + +Condition + +: + +> mandatory + +### Minimum value {#iso19139-elem-gmd-minValue-ca30535d2283f60660d6cb8c3e06264a} + +Name + +: + +> gmd:minValue + +Description + +: + +```{=html} +Shortest wavelength that the sensor is capable of collecting within a + designated band +``` +### Name {#iso19139-elem-gmd-name-gmd-MD_AbstractClass-55c76e5e1d36308ca08192f0f34145ef} + +Name + +: + +> gmd:name + +Context + +: + +> gmd:MD_AbstractClass + +Description + +: + +```{=html} +Name +``` +### Name {#iso19139-elem-gmd-name-gmd-MD_Medium-5e756c272348337b91b38d9f904b491a} + +Name + +: + +> gmd:name + +Context + +: + +> gmd:MD_Medium + +Description + +: + +```{=html} +Name of the medium on which the resource can be received +``` +### Name {#iso19139-elem-gmd-name-gmd-RS_ReferenceSystem-02b2a8b0e707e9507d341c5d67eaaa0d} + +Name + +: + +> gmd:name + +Context + +: + +> gmd:RS_ReferenceSystem + +Description + +: + +```{=html} +Name of reference system used +``` + +Condition + +: + +> mandatory + +### Name {#iso19139-elem-gmd-name-gmd-MD_Format-6a971c2939bcf530ff1ef0496661407f} + +Name + +: + +> gmd:name + +Context + +: + +> gmd:MD_Format + +Description + +: + +```{=html} +Name of the data transfer format(s) +``` +```{=html} +name of the data transfer format(s) +``` + +Condition + +: + +> mandatory + +Recommended values + +| code | label | +|-----------------|-----------------| +| Text | Text | +| ESRI Shapefile | ESRI Shapefile | +| Mapinfo MIF/MID | Mapinfo MIF/MID | +| Mapinfo TAB | Mapinfo TAB | +| KML | KML | +| GML | GML | +| GeoTIFF | GeoTIFF | +| TIFF | TIFF | +| ECW | ECW | +| JPEG2000 | JPEG2000 | +| ZIP | ZIP | +| PDF | PDF | +| PNG | PNG | +| JPEG | JPEG | +| OGC:WMC | OGC:WMC | +| OGC:OWS-C | OGC OWS Context | + +### Name {#iso19139-elem-gmd-name-gmd-MD_ExtendedElementInformation-6f3a3922c51040816e19474d667dfae0} + +Name + +: + +> gmd:name + +Context + +: + +> gmd:MD_ExtendedElementInformation + +Description + +: + +```{=html} +Name of the extended metadata element +``` + +Condition + +: + +> mandatory + +### Name {#iso19139-elem-gmd-name-gmd-MD_ApplicationSchemaInformation-8d1b515ce0e50b245935cd51d2c69e76} + +Name + +: + +> gmd:name + +Context + +: + +> gmd:MD_ApplicationSchemaInformation + +Description + +: + +```{=html} +Name of the application schema used +``` + +Condition + +: + +> mandatory + +### Name of the resource {#iso19139-elem-gmd-name-gmd-CI_OnlineResource-440837e17f2a3bf02e6188d6cf477809} + +Name + +: + +> gmd:name + +Context + +: + +> gmd:CI_OnlineResource + +Description + +: + +```{=html} +Name of the online resource +``` +### Name {#iso19139-elem-gmd-name-gmd-CI_Series-d8b38970368c2e8adf6a26f354b4e4a9} + +Name + +: + +> gmd:name + +Context + +: + +> gmd:CI_Series + +Description + +: + +```{=html} +Name of the series, or aggregate dataset, of which the dataset is a + part +``` +### Name {#iso19139-elem-gmd-name-gmd-MD_CodeDomain-8f86c5309156f1cc30b5d6f56f08e8ad} + +Name + +: + +> gmd:name + +Context + +: + +> gmd:MD_CodeDomain + +Description + +: + +```{=html} +Name of the code domain +``` +### Name {#iso19139-elem-gmd-name-gmd-MD_CodeValue-870d040c56a98b1502ead34afc6ff2c6} + +Name + +: + +> gmd:name + +Context + +: + +> gmd:MD_CodeValue + +Description + +: + +```{=html} +Value name +``` +### Name {#iso19139-elem-gmd-name-gmd-MD_Attribute-5c723d5a648b525de45efddc22615249} + +Name + +: + +> gmd:name + +Context + +: + +> gmd:MD_Attribute + +Description + +: + +```{=html} +Attribute name +``` +### Name {#iso19139-elem-gmd-name-gmd-MD_Role-5a5e776d6bb1ee8d8cb7a5d518314bef} + +Name + +: + +> gmd:name + +Context + +: + +> gmd:MD_Role + +Description + +: + +```{=html} +Role name +``` +### Name {#iso19139-elem-gmd-name-9796db4d1cab411f64fa97871fd1dd7e} + +Name + +: + +> gmd:name + +Description + +: + +### Name of measure {#iso19139-elem-gmd-nameOfMeasure-9f6986c5c2ab012a799560402287fc82} + +Name + +: + +> gmd:nameOfMeasure + +Description + +: + +```{=html} +Name of the test applied to the data +``` +Recommended values + +| code | label | +|-----------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------| +| | -- Completeness -- | +| Excess item | Excess item | +| Number of excess items | Number of excess items | +| Rate of excess items | Rate of excess items | +| Number of duplicate feature instances | Number of duplicate feature instances | +| Missing item | Missing item | +| Number of missing items | Number of missing items | +| Rate of missing items | Rate of missing items -- Logical consistency / Conceptual consistency -- | +| Conceptual schema noncompliance | Conceptual schema noncompliance | +| Conceptual schema compliance | Conceptual schema compliance | +| Number of items noncompliant to the rules of the conceptual schema | Number of items noncompliant to the rules of the conceptual schema | +| Number of invalid overlaps of surfaces | Number of invalid overlaps of surfaces | +| Non-compliance rate with respect to the rules of the conceptual schema | Non-compliance rate with respect to the rules of the conceptual schema | +| Compliance rate with the rules of the conceptual schema | Compliance rate with the rules of the conceptual schema -- Logical consistency / Domain consistency -- | +| Value domain non-conformance | Value domain non-conformance | +| Value domain conformance | Value domain conformance | +| Number of items not in conformance with their value domain | Number of items not in conformance with their value domain | +| Value domain conformance rate | Value domain conformance rate | +| Value domain non-conformance rate | Value domain non-conformance rate | +| Physical structure conflicts | Physical structure conflicts | +| Physical structure conflict rate | Physical structure conflict rate -- Logical consistency / Topological consistency -- | +| Number of faulty point-curve connections | Number of faulty point-curve connections | +| Rate of faulty point-curve connections | Rate of faulty point-curve connections | +| Number of missing connection due to undershoots | Number of missing connection due to undershoots | +| Number of missing connections due to overshoots | Number of missing connections due to overshoots | +| Number of invalid slivers | Number of invalid slivers | +| Number of invalid self intersect errors | Number of invalid self intersect errors | +| Number of invalid self overlap errors | Number of invalid self overlap errors -- Positional accuracy / Absolute or external accuracy / General measures -- | +| Mean value of positional uncertainties | Mean value of positional uncertainties | +| Mean value of positional uncertainties excluding outliers | Mean value of positional uncertainties excluding outliers | +| Number of positional uncertainties above a given threshold | Number of positional uncertainties above a given threshold | +| Rate of positional errors above a given threshold | Rate of positional errors above a given threshold | +| Covariance matrix | Covariance matrix -- Positional accuracy / Absolute or external accuracy / Vertical -- | +| Linear error probable | Linear error probable | +| Standard linear error | Standard linear error | +| Linear map accuracy at 90% significance level | Linear map accuracy at 90% significance level | +| Linear map accuracy at 95% significance level | Linear map accuracy at 95% significance level | +| Linear map accuracy at 99% significance level | Linear map accuracy at 99% significance level | +| Near certainty linear error | Near certainty linear error | +| Root mean square error | Root mean square error | +| Absolute linear error at 90% significance level of biased vertical data (Alternative 1) | Absolute linear error at 90% significance level of biased vertical data (Alternative 1) | +| Absolute linear error at 90% significance level of biased vertical data | Absolute linear error at 90% significance level of biased vertical data -- Positional accuracy / Absolute or external accuracy / Horizontal -- | +| Circular standard deviation | Circular standard deviation | +| Circular error probable | Circular error probable | +| Circular map accuracy standard | Circular map accuracy standard | +| Circular error at 95% significance level | Circular error at 95% significance level | +| Circular near certainty error | Circular near certainty error | +| Root mean square error of planimetry | Root mean square error of planimetry | +| Absolute circular error at 90% significance level of biased data (Alternative 2) | Absolute circular error at 90% significance level of biased data (Alternative 2) | +| Absolute circular error at 90% significance level of biased data | Absolute circular error at 90% significance level of biased data | +| Uncertainty ellipse | Uncertainty ellipse | +| Confidence ellipse | Confidence ellipse -- Positional accuracy / Relative or internal accuracy -- | +| Relative vertical error | Relative vertical error | +| Relative horizontal error | Relative horizontal error -- Temporal accuracy / Accuracy of a time measurement -- | +| Time accuracy at 68.3% significance level | Time accuracy at 68.3% significance level | +| Time accuracy at 50% significance level | Time accuracy at 50% significance level | +| Time accuracy at 90% significance level | Time accuracy at 90% significance level | +| Time accuracy at 95% significance level | Time accuracy at 95% significance level | +| Time accuracy at 99% significance level | Time accuracy at 99% significance level | +| Time accuracy at 99.8% significance level | Time accuracy at 99.8% significance level -- Thematic accuracy / Classification correctness -- | +| Number of incorrectly classified features | Number of incorrectly classified features | +| Misclassification rate | Misclassification rate | +| Misclassification matrix | Misclassification matrix | +| Relative misclassification matrix | Relative misclassification matrix | +| Kappa coefficient | Kappa coefficient -- Thematic accuracy / Non-quantitative attribute correctness -- | +| Number of incorrect attribute values | Number of incorrect attribute values | +| Rate of correct attribute values | Rate of correct attribute values | +| Rate of incorrect attribute values | Rate of incorrect attribute values -- Thematic accuracy / Quantitative attribute accuracy -- | +| Attribute value uncertainty at 68.3% significance level | Attribute value uncertainty at 68.3% significance level | +| Attribute value uncertainty at 50% significance level | Attribute value uncertainty at 50% significance level | +| Attribute value uncertainty at 90% significance level | Attribute value uncertainty at 90% significance level | +| Attribute value uncertainty at 95% significance level | Attribute value uncertainty at 95% significance level | +| Attribute value uncertainty at 99% significance level | Attribute value uncertainty at 99% significance level | +| Attribute value uncertainty at 99.8% significance level | Attribute value uncertainty at 99.8% significance level | + +### North bound {#iso19139-elem-gmd-northBoundLatitude-7f5fd77fbea072c35f6d4c938f74dee5} + +Name + +: + +> gmd:northBoundLatitude + +Description + +: + +```{=html} +Northern-most, coordinate of the limit of the dataset extent expressed in + latitude in decimal degrees (positive north) +``` + +Condition + +: + +> mandatory + +``` xml + + 60.57849 + +``` + +### Number of dimensions {#iso19139-elem-gmd-numberOfDimensions-be36128610852a3a86fe52230c125ae8} + +Name + +: + +> gmd:numberOfDimensions + +Description + +: + +```{=html} +Number of independent spatial-temporal axes +``` + +Condition + +: + +> mandatory + +### Obligation {#iso19139-elem-gmd-obligation-bd4d5c2002cbae677396f4195cfad3a6} + +Name + +: + +> gmd:obligation + +Description + +: + +```{=html} +Obligation of the extended element +``` +### Offline {#iso19139-elem-gmd-offLine-74ad66cbe02f22813b168bb80273d2fe} + +Name + +: + +> gmd:offLine + +Description + +: + +```{=html} +Information about offline media on which the resource can be + obtained +``` +### Offset {#iso19139-elem-gmd-offset-4d077570ef50ba2b1ea4f00396f1bb0a} + +Name + +: + +> gmd:offset + +Description + +: + +```{=html} +The physical value corresponding to a cell value of zero +``` +### OnLine resource {#iso19139-elem-gmd-onLine-c0b191c96e7e4d7dfc2a4ba2fd8946f4} + +Name + +: + +> gmd:onLine + +Description + +: + +```{=html} +Information about online sources from which the resource can be + obtained +``` +``` xml + + + + + http://www.eea.europa.eu/data-and-maps/data/ds_resolveuid/d851e1b7f678468b8f0b1b98930ba3e1 + + + + WWW:LINK-1.0-http--link + + + + + + +``` + +### Website {#iso19139-elem-gmd-onlineResource-8df8ae9d58f947d5aac1e7f95e5b7d59} + +Name + +: + +> gmd:onlineResource + +Description + +: + +```{=html} +Define URL to access the website +``` +```{=html} +On-line information that can be used to contact the individual or + organisation +``` +``` xml + + + + http://www.eea.europa.eu + + + WWW:LINK-1.0-http--link + + + Europen Environment Agency public website + + + + + + + +``` + +### Ordering instructions {#iso19139-elem-gmd-orderingInstructions-c6c68523c931c7138263c7d7895d9a16} + +Name + +: + +> gmd:orderingInstructions + +Description + +: + +```{=html} +General instructions, terms and services provided by the + distributor +``` +### Organisation name {#iso19139-elem-gmd-organisationName-d57c55f60d4bce260583a0e176106a31} + +Name + +: + +> gmd:organisationName + +Description + +: + +```{=html} +Name of the responsible organization +``` + +Condition + +: + +> conditional + +### Orientation parameter availability {#iso19139-elem-gmd-orientationParameterAvailability-f4f1451cd1e6fada4b70115d7a0db4de} + +Name + +: + +> gmd:orientationParameterAvailability + +Description + +: + +```{=html} +Indication of whether or not orientation parameters are available +``` + +Condition + +: + +> mandatory + +### Orientation parameter description {#iso19139-elem-gmd-orientationParameterDescription-871dba0b5e91443d58af60139e3483f0} + +Name + +: + +> gmd:orientationParameterDescription + +Description + +: + +```{=html} +Description of parameters used to describe sensor orientation +``` +### Other {#iso19139-elem-gmd-other-351c20974743a02b7c727421fd10411e} + +Name + +: + +> gmd:other + +Description + +: + +```{=html} +Class of information that does not fall into the other categories to which the + information applies +``` +### Other citation details {#iso19139-elem-gmd-otherCitationDetails-6045d0424a57c57988ec6627e728189a} + +Name + +: + +> gmd:otherCitationDetails + +Description + +: + +```{=html} +Other information required to complete the citation that is not recorded + elsewhere +``` +### Other constraints {#iso19139-elem-gmd-otherConstraints-696de5ef421a230cf560f7566a3c5028} + +Name + +: + +> gmd:otherConstraints + +Description + +: + +```{=html} +Other restrictions and legal prerequisites for accessing and using the + resource +``` + +Condition + +: + +> conditional + +``` xml + + no limitations + +``` + +### Page {#iso19139-elem-gmd-page-7e8d6e17c5fe0179acfb038d3475d5dd} + +Name + +: + +> gmd:page + +Description + +: + +```{=html} +Details on which pages of the publication the article was + published +``` +### Parameter citation {#iso19139-elem-gmd-parameterCitation-6b75cc829b57fd174fa3d5f26ff52591} + +Name + +: + +> gmd:parameterCitation + +Description + +: + +```{=html} +Reference providing description of the parameters +``` +### Parent entity {#iso19139-elem-gmd-parentEntity-b8e88cd3a75905b5911d9c84d25a79c6} + +Name + +: + +> gmd:parentEntity + +Description + +: + +```{=html} +Name of the metadata entity(s) under which this extended metadata element may + appear. The name(s) may be standard metadata element(s) or other extended metadata + element(s). +``` + +Condition + +: + +> mandatory + +### Parent identifier {#iso19139-elem-gmd-parentIdentifier-e660d48fcd79782e330d99a6eee272bc} + +Name + +: + +> gmd:parentIdentifier + +Description + +: + +```{=html} +File identifier of the metadata to which this metadata is a subset + (child) +``` +``` xml + + df69de7e-3af1-4b4d-94d4-8bebe84c80b0 + +``` + +### PartOf {#iso19139-elem-gmd-partOf-9ede50dac93d135983484fd0d7e44495} + +Name + +: + +> gmd:partOf + +Description + +: + +```{=html} +PartOf +``` +### Pass {#iso19139-elem-gmd-pass-bcbea9f82051424feefdcaa4953655c4} + +Name + +: + +> gmd:pass + +Description + +: + +```{=html} +Indication of the conformance result where 0 = fail and 1 = pass +``` + +Condition + +: + +> mandatory + +### Peak response {#iso19139-elem-gmd-peakResponse-47e14bef5b9ed8cac08540f6b2ebb11a} + +Name + +: + +> gmd:peakResponse + +Description + +: + +```{=html} +Wavelength at which the response is the highest +``` +### Phone {#iso19139-elem-gmd-phone-7bed516b088bd0d9ab349b4eaf477328} + +Name + +: + +> gmd:phone + +Description + +: + +```{=html} +Telephone numbers at which the organization or individual may be + contacted +``` +### Planned available datetime {#iso19139-elem-gmd-plannedAvailableDateTime-79d43570482162c903674e901789147c} + +Name + +: + +> gmd:plannedAvailableDateTime + +Description + +: + +```{=html} +Date and time when the dataset will be available + (CCYY-MM-DDThh:mm:ss) +``` +### Point in Pixel {#iso19139-elem-gmd-pointInPixel-39b5630aab74d9327175514d0b64f427} + +Name + +: + +> gmd:pointInPixel + +Description + +: + +```{=html} +Point in a pixel corresponding to the Earth location of the pixel +``` + +Condition + +: + +> mandatory + +### Point of contact {#iso19139-elem-gmd-pointOfContact-2a38035f4c8b63a35a4e6c44e6f4b624} + +Name + +: + +> gmd:pointOfContact + +Description + +: + +```{=html} +Identification of, and means of communication with, person(s) and + organizations(s) associated with the resource(s) +``` +``` xml + + + + European Environment Agency + + + + + + + Kongens Nytorv 6 + + + Copenhagen + + + K + + + 1050 + + + Denmark + + + eea.enquiries@eea.europa.eu + + + + + + + http://www.eea.europa.eu + + + WWW:LINK-1.0-http--link + + + Europen Environment Agency public website + + + + + + + + + + + + + + +``` + +### Polygon {#iso19139-elem-gmd-polygon-136906da71badd3d1d6c10c5e703e952} + +Name + +: + +> gmd:polygon + +Description + +: + +```{=html} +Sets of points defining the bounding polygon +``` + +Condition + +: + +> mandatory + +### Portrayal catalogue citation {#iso19139-elem-gmd-portrayalCatalogueCitation-7d46a0799fd5dc5455fa1122c5e45608} + +Name + +: + +> gmd:portrayalCatalogueCitation + +Description + +: + +```{=html} +Bibliographic reference to the portrayal catalogue cited +``` + +Condition + +: + +> mandatory + +### Portrayal catalogue info {#iso19139-elem-gmd-portrayalCatalogueInfo-0a09defe8c7ca8431460b5690da9a52d} + +Name + +: + +> gmd:portrayalCatalogueInfo + +Description + +: + +```{=html} +Provides information about the catalogue of rules defined for the portrayal of + a resource(s) +``` +### Position name {#iso19139-elem-gmd-positionName-9d7a0dfd5bc41e337c9deae85d95b272} + +Name + +: + +> gmd:positionName + +Description + +: + +```{=html} +Role or position of the responsible person +``` + +Condition + +: + +> conditional + +### Postal code {#iso19139-elem-gmd-postalCode-c108b19cdeff41b0d6c4c3cc2dde38c9} + +Name + +: + +> gmd:postalCode + +Description + +: + +```{=html} +ZIP or other postal code +``` +### Presentation form {#iso19139-elem-gmd-presentationForm-98bab46932258a48a69ea02060e41909} + +Name + +: + +> gmd:presentationForm + +Description + +: + +```{=html} +Mode in which the resource is represented +``` +### Processing level code {#iso19139-elem-gmd-processingLevelCode-9e2c3bf1cbd69b356f1c4f854ece6474} + +Name + +: + +> gmd:processingLevelCode + +Description + +: + +```{=html} +Image distributor_s code that identifies the level of radiometric and geometric + processing that has been applied +``` +### Processor {#iso19139-elem-gmd-processor-9ef327f7c0d24ccd64eb52cbc0dc76fe} + +Name + +: + +> gmd:processor + +Description + +: + +```{=html} +Identification of, and means of communication with, person(s) and + organization(s) associated with the process step +``` +### Process step {#iso19139-elem-gmd-processStep-e129334e8e68357571622aba3880e659} + +Name + +: + +> gmd:processStep + +Description + +: + +```{=html} +Information about an event in the creation process for the data specified by + the scope +``` + +Condition + +: + +> conditional + +### PropertyType {#iso19139-elem-gmd-propertyType-12fff0b8b43529f0300c32a5e13c9f89} + +Name + +: + +> gmd:propertyType + +Description + +: + +```{=html} +PropertyType +``` +### Protocol {#iso19139-elem-gmd-protocol-447dfb15f197f008cd2326a7dab836e8} + +Name + +: + +> gmd:protocol + +Description + +: + +```{=html} +Connection protocol to be used +``` +Recommended values + +| code | label | +|--------------------------------------|------------------------------------------------| +| ESRI:REST | ArcGIS REST Services | +| GLG:KML-2.0-http-get-map | Google Earth KML service (ver 2.0) | +| OGC API - Coverages | OGC API - Coverages | +| OGC API - Features | OGC API - Features | +| OGC API - Maps | OGC API - Maps | +| OGC API - Records | OGC API - Records | +| OGC:CSW | OGC-CSW Catalogue Service for the Web | +| OGC:KML | OGC-KML Keyhole Markup Language | +| OGC:GML | OGC-GML Geography Markup Language | +| OGC:ODS | OGC-ODS OpenLS Directory Service | +| OGC:OGS | OGC-ODS OpenLS Gateway Service | +| OGC:OUS | OGC-ODS OpenLS Utility Service | +| OGC:OPS | OGC-ODS OpenLS Presentation Service | +| OGC:ORS | OGC-ODS OpenLS Route Service | +| OGC:SOS | OGC-SOS Sensor Observation Service | +| OGC:SPS | OGC-SPS Sensor Planning Service | +| OGC:SAS | OGC-SAS Sensor Alert Service | +| OGC:WCS | OGC-WCS Web Coverage Service | +| OGC:WCS-1.1.0-http-get-capabilities | OGC-WCS Web Coverage Service (ver 1.1.0) | +| OGC:WCTS | OGC-WCTS Web Coordinate Transformation Service | +| OGC:WFS | OGC-WFS Web Feature Service | +| INSPIRE Atom | INSPIRE Atom | +| OGC:WFS-1.0.0-http-get-capabilities | OGC-WFS Web Feature Service (ver 1.0.0) | +| OGC:WFS-G | OGC-WFS-G Gazzetteer Service | +| OGC:WMC | OGC-WMC Web Map Context | +| OGC:WMS | OGC-WMS Web Map Service | +| OGC:WMS-1.1.1-http-get-capabilities | OGC-WMS Capabilities service (ver 1.1.1) | +| OGC:WMS-1.3.0-http-get-capabilities | OGC-WMS Capabilities service (ver 1.3.0) | +| OGC:WMS-1.1.1-http-get-map | OGC Web Map Service (ver 1.1.1) | +| OGC:WMS-1.3.0-http-get-map | OGC Web Map Service (ver 1.3.0) | +| OGC:WMTS | OGC-WMTS Web Map Tiled Service | +| OGC:WMTS-1.0.0-http-get-capabilities | OGC-WMTS Capabilities service (ver 1.0.0) | +| OGC:SOS-1.0.0-http-get-observation | OGC-SOS Get Observation (ver 1.0.0) | +| OGC:SOS-1.0.0-http-post-observation | OGC-SOS Get Observation (POST) (ver 1.0.0) | +| OGC:WNS | OGC-WNS Web Notification Service | +| OGC:WPS | OGC-WPS Web Processing Service | +| OGC:OWS-C | OGC OWS Context | +| TMS | Tiled Map Service | +| WWW:DOWNLOAD-1.0-ftp--download | File for download through FTP | +| WWW:DOWNLOAD-1.0-http--download | File for download | +| | GIS file | +| | GIS RASTER file | +| WWW:LINK-1.0-http--ical | iCalendar (URL) | +| WWW:LINK-1.0-http--link | Web address (URL) | +| DOI | Digital Object Identifier (DOI) | +| WWW:LINK-1.0-http--partners | Partner web address (URL) | +| WWW:LINK-1.0-http--related | Related link (URL) | +| WWW:LINK-1.0-http--rss | RSS News feed (URL) | +| WWW:LINK-1.0-http--samples | Showcase product (URL) | +| DB:POSTGIS | PostGIS database table | +| DB:ORACLE | ORACLE database table | +| WWW:LINK-1.0-http--opendap | OPeNDAP URL | +| RBNB:DATATURBINE | Data Turbine | +| UKST | Unknown Service Type | + +### Free text {#iso19139-elem-gmd-PT_FreeText-00c48876cdf6707df460773d91476446} + +Name + +: + +> gmd:PT_FreeText + +Description + +: + +```{=html} +Description of a multi-language free text metadata element +``` +### Locale {#iso19139-elem-gmd-PT_Locale-8114a4813936b84f0e6b123bb5e3018b} + +Name + +: + +> gmd:PT_Locale + +Description + +: + +```{=html} +Locale +``` +### PT_LocaleContainer {#iso19139-elem-gmd-PT_LocaleContainer-ec355086fbe079f5ebbbc4857c6eb002} + +Name + +: + +> gmd:PT_LocaleContainer + +Description + +: + +```{=html} +PT_LocaleContainer +``` +### Purpose {#iso19139-elem-gmd-purpose-b905736188713702d2a05d889f970ffa} + +Name + +: + +> gmd:purpose + +Description + +: + +```{=html} +Summary of the intentions with which the resource(s) was + developed +``` +### Radiometric calibration data availability {#iso19139-elem-gmd-radiometricCalibrationDataAvailability-92db9f55cf1ae86606dbd3b7ed2d0b3e} + +Name + +: + +> gmd:radiometricCalibrationDataAvailability + +Description + +: + +```{=html} +Indication of whether or not the radiometric calibration information for + generating the radiometrically calibrated standard data product is + available +``` +### Rationale {#iso19139-elem-gmd-rationale-a89f98c606cd39bd67cf29f996518913} + +Name + +: + +> gmd:rationale + +Description + +: + +```{=html} +Requirement or purpose for the process step +``` +### Rationale {#iso19139-elem-gmd-rationale-gmd-MD_ExtendedElementInformation-64a2e17ba633ec3f5d97e33b725e8f57} + +Name + +: + +> gmd:rationale + +Context + +: + +> gmd:MD_ExtendedElementInformation + +Description + +: + +```{=html} +Reason for creating the extended element +``` +### Reference system identifier {#iso19139-elem-gmd-referenceSystemIdentifier-5393a29789a4b6def1795d5a9e70f665} + +Name + +: + +> gmd:referenceSystemIdentifier + +Description + +: + +```{=html} +Name of reference system +``` + +Condition + +: + +> conditional + +``` xml + + + + urn:ogc:def:crs:EPSG:7.1:3035 + + + OGP Surveying & Positioning Committee + + + +``` + +### Reference System Information {#iso19139-elem-gmd-referenceSystemInfo-c7702a2e8ac03097e306ab3a02406765} + +Name + +: + +> gmd:referenceSystemInfo + +Description + +: + +```{=html} +Description of the spatial and temporal reference systems used in the + dataset +``` +``` xml + + + + + + urn:ogc:def:crs:EPSG:7.1:3035 + + + OGP Surveying & Positioning Committee + + + + + +``` + +### Report {#iso19139-elem-gmd-report-b06b527383afbca245b4712f3bf3ae44} + +Name + +: + +> gmd:report + +Description + +: + +```{=html} +Quantitative quality information for the data specified by the + scope +``` + +Condition + +: + +> conditional + +### Resolution {#iso19139-elem-gmd-resolution-0e9dc8264836da5a43380f555c0b608a} + +Name + +: + +> gmd:resolution + +Description + +: + +```{=html} +Degree of detail in the grid dataset +``` +### Resource constraints {#iso19139-elem-gmd-resourceConstraints-3ce815f506c31e6b5ef8e4e7022eefad} + +Name + +: + +> gmd:resourceConstraints + +Description + +: + +```{=html} +Provides information about constraints which apply to the + resource(s) +``` +### Resource format {#iso19139-elem-gmd-resourceFormat-0c19b5193142c6b6f0aac987fffe8f20} + +Name + +: + +> gmd:resourceFormat + +Description + +: + +```{=html} +Provides a description of the format of the resource(s) +``` +### Resource maintenance {#iso19139-elem-gmd-resourceMaintenance-a3c2f1eb185aa1d3e7d475c40a1ff637} + +Name + +: + +> gmd:resourceMaintenance + +Description + +: + +```{=html} +Provides information about the frequency of resource updates, and the scope of + those updates +``` +``` xml + + + + + + + +``` + +### Resource specific usage {#iso19139-elem-gmd-resourceSpecificUsage-c0f6662f0924e6ebd022b685a53e20ea} + +Name + +: + +> gmd:resourceSpecificUsage + +Description + +: + +```{=html} +Provides basic information about specific application(s) for which the + resource(s) has/have been or is being used by different users +``` +### Responsible Party {#iso19139-elem-gmd-responsibleParty-b189af81ab93bbbf28bf2b083d6872fd} + +Name + +: + +> gmd:responsibleParty + +Description + +: + +### Result {#iso19139-elem-gmd-result-83539788e54d2fc7d166ac779dc43f0b} + +Name + +: + +> gmd:result + +Description + +: + +```{=html} +Value (or set of values) obtained from applying a data quality measure or the + out come of evaluating the obtained value (or set of values) against a specified + acceptable conformance quality level +``` + +Condition + +: + +> mandatory + +### Role {#iso19139-elem-gmd-role-gmd-MD_Association-55ee20aa2f0f637012d7953158864d2a} + +Name + +: + +> gmd:role + +Context + +: + +> gmd:MD_Association + +Description + +: + +```{=html} +Reference to the ends (roles) of a concrete association +``` +### Role {#iso19139-elem-gmd-role-9b10bc0f5a8317c592877c27ad3012a4} + +Name + +: + +> gmd:role + +Description + +: + +```{=html} +Function performed by the responsible party +``` + +Condition + +: + +> mandatory + +### Identifier {#iso19139-elem-gmd-RS_Identifier-025635f516171e942cfaac8bbf43e014} + +Name + +: + +> gmd:RS_Identifier + +Description + +: + +```{=html} +Identifier used for reference systems +``` +### Rule {#iso19139-elem-gmd-rule-887b5f15d45db38bcc0ee11f1a6ca843} + +Name + +: + +> gmd:rule + +Description + +: + +```{=html} +Specifies how the extended element relates to other existing elements and + entities +``` + +Condition + +: + +> mandatory + +### Scale Denominator {#iso19139-elem-gmd-scaleDenominator-973704798e0501bf6ac83bd85b435b61} + +Name + +: + +> gmd:scaleDenominator + +Description + +: + +```{=html} +Denominator of the representative fraction on a source map +``` +### Scale factor {#iso19139-elem-gmd-scaleFactor-398805b3fa36127ee65a6de3b4f55118} + +Name + +: + +> gmd:scaleFactor + +Description + +: + +```{=html} +Scale factor which has been applied to the cell value +``` +### Schema ASCII {#iso19139-elem-gmd-schemaAscii-385bafc95d8b97ba2389183fd84d899e} + +Name + +: + +> gmd:schemaAscii + +Description + +: + +```{=html} +Full application schema given as an ASCII file +``` +### Schema language {#iso19139-elem-gmd-schemaLanguage-f8c161d4db9348a3a2305531704febf0} + +Name + +: + +> gmd:schemaLanguage + +Description + +: + +```{=html} +Identification of the schema language used +``` + +Condition + +: + +> mandatory + +### Scope {#iso19139-elem-gmd-scope-66b29437893946bbaf08cabb26cdabbd} + +Name + +: + +> gmd:scope + +Description + +: + +```{=html} +The specific data to which the data quality information applies +``` +``` xml + + + + + + + +``` + +### Sequence identifier {#iso19139-elem-gmd-sequenceIdentifier-eba100dcb9223d7b7564306d0df388fb} + +Name + +: + +> gmd:sequenceIdentifier + +Description + +: + +```{=html} +Number that uniquely identifies instances of bands of wavelengths on which a + sensor operates +``` +### Series {#iso19139-elem-gmd-series-98524248b047e1a31966f4fc05c765fb} + +Name + +: + +> gmd:series + +Description + +: + +```{=html} +Information about the series, or aggregate dataset, of which the dataset is a + part +``` +### SeriesMetadata {#iso19139-elem-gmd-seriesMetadata-4c8e5c0d23156817b1195ca9ab10846d} + +Name + +: + +> gmd:seriesMetadata + +Description + +: + +```{=html} +SeriesMetadata +``` +### Short name {#iso19139-elem-gmd-shortName-917a52683f1b7433b4aed3ffc10fc6b3} + +Name + +: + +> gmd:shortName + +Description + +: + +```{=html} +Short form suitable for use in an implementation method such as XML or SGML. + NOTE other methods may be used +``` +### Software development file {#iso19139-elem-gmd-softwareDevelopmentFile-7a4e9679561964e460d50c3c6584e9e7} + +Name + +: + +> gmd:softwareDevelopmentFile + +Description + +: + +```{=html} +Full application schema given as a software development file +``` +### Software development file format {#iso19139-elem-gmd-softwareDevelopmentFileFormat-4dc69820e56575d743271b86b05dea17} + +Name + +: + +> gmd:softwareDevelopmentFileFormat + +Description + +: + +```{=html} +Software dependent format used for the application schema software dependent + file +``` +### Source {#iso19139-elem-gmd-source-056931601d7cb713381cbf1eea87f599} + +Name + +: + +> gmd:source + +Description + +: + +```{=html} +Information about the source data used in creating the data specified by the + scope +``` + +Condition + +: + +> mandatory + +``` xml + +``` + +### Source {#iso19139-elem-gmd-source-gmd-MD_ExtendedElementInformation-459f928a9ea29688b69af501b0fc033e} + +Name + +: + +> gmd:source + +Context + +: + +> gmd:MD_ExtendedElementInformation + +Description + +: + +```{=html} +Name of the person or organization creating the extended element +``` + +Condition + +: + +> mandatory + +``` xml + +``` + +### Source citation {#iso19139-elem-gmd-sourceCitation-4988d0a64d3bd85bdf52c9faa14103de} + +Name + +: + +> gmd:sourceCitation + +Description + +: + +```{=html} +Recommended reference to be used for the source data +``` +### Source extent {#iso19139-elem-gmd-sourceExtent-51d5c1b2516371920a3f12b76a38f48b} + +Name + +: + +> gmd:sourceExtent + +Description + +: + +```{=html} +Information about the spatial, vertical and temporal extent of the source + data +``` + +Condition + +: + +> conditional + +### Source reference system {#iso19139-elem-gmd-sourceReferenceSystem-fb3e6e3ecd849e31bc89d8f8aeae43a6} + +Name + +: + +> gmd:sourceReferenceSystem + +Description + +: + +```{=html} +Spatial reference system used by the source data +``` +### Source step {#iso19139-elem-gmd-sourceStep-d6d84c09e8e8991a68956351c1398122} + +Name + +: + +> gmd:sourceStep + +Description + +: + +```{=html} +Information about an event in the creation process for the source + data +``` +### South bound {#iso19139-elem-gmd-southBoundLatitude-894a6499ac85eb19180f3fa2a4582263} + +Name + +: + +> gmd:southBoundLatitude + +Description + +: + +```{=html} +Southern-most coordinate of the limit of the dataset extent, expressed in + latitude in decimal degrees (positive north) +``` + +Condition + +: + +> mandatory + +``` xml + + 26.988714 + +``` + +### Spatial extent {#iso19139-elem-gmd-spatialExtent-7e0ee4e6812d3469ab8b3853903d1b34} + +Name + +: + +> gmd:spatialExtent + +Description + +: + +```{=html} +Spatial extent component of composite spatial and temporal extent +``` + +Condition + +: + +> mandatory + +### Spatial representation info {#iso19139-elem-gmd-spatialRepresentationInfo-f93705d4877ccd4c41819cc79677d6f2} + +Name + +: + +> gmd:spatialRepresentationInfo + +Description + +: + +```{=html} +Digital representation of spatial information in the dataset +``` +### Spatial representation type {#iso19139-elem-gmd-spatialRepresentationType-1617a07231ac2246d0844778962d4ca0} + +Name + +: + +> gmd:spatialRepresentationType + +Description + +: + +```{=html} +Method used to spatially represent geographic information +``` +``` xml + + + +``` + +### Spatial resolution {#iso19139-elem-gmd-spatialResolution-c248e07cdd5b0b6d769bd187d279535a} + +Name + +: + +> gmd:spatialResolution + +Description + +: + +```{=html} +Factor which provides a general understanding of the density of spatial data in + the dataset +``` +``` xml + + + + 100 + + + +``` + +### Specification {#iso19139-elem-gmd-specification-gmd-DQ_ConformanceResult-a820ababbd31f20c7492dd90785ec10b} + +Name + +: + +> gmd:specification + +Context + +: + +> gmd:DQ_ConformanceResult + +Description + +: + +```{=html} +Citation of product specification or user requirement against which data is + being evaluated +``` + +Condition + +: + +> mandatory + +### Specification {#iso19139-elem-gmd-specification-gmd-MD_Format-1888e6a22d633ee827c05b7f0bcd948c} + +Name + +: + +> gmd:specification + +Context + +: + +> gmd:MD_Format + +Description + +: + +```{=html} +Name of a subset, profile, or product specification of the format +``` +### Specification {#iso19139-elem-gmd-specification-4e210a94d2d6b382f34228d46d514e0f} + +Name + +: + +> gmd:specification + +Description + +: + +### Specific usage {#iso19139-elem-gmd-specificUsage-4791e1ef0814b94a33276de9cc4e28d7} + +Name + +: + +> gmd:specificUsage + +Description + +: + +```{=html} +Brief description of the resource and/or resource series usage +``` + +Condition + +: + +> mandatory + +### Statement {#iso19139-elem-gmd-statement-593ac58687a7831e3112879ec00a306e} + +Name + +: + +> gmd:statement + +Description + +: + +```{=html} +General explanation of the data producer_s knowledge about the lineage of a + dataset +``` + +Condition + +: + +> conditional + +``` xml + + The data set production implied 2 steps. First re-classification of + CORINE Land Cover 2006 and bathymetry data using the 7 terrestrial (urban, cropland, + grassland, woodland and forest, heathland and shrub, sparsely vegetated land, + wetland), 1 freshwater (river and lakes), and 4 marine (marine inlets and transitional + waters, coastal, shelf, open ocean) classes of the MAES ecosystem typology (Maes et + al., 2013). The classes also provide links to major policy lines such as agriculture, + forestry, territorial cohesion, water and marine related policies. The second step + comprised refinement of the ecosystem types by attributing EUNIS habitat information + to each ecosystem type (see http://eunis.eea.europa.eu/habitats.jsp). The refinement + process used reference data such as potential natural vegetation, elevation, slope, + aspect, soil, geology, environmental regions and other spatial referenced information + which allowed attribution of the EUNIS habitat characteristics to the spatial mapping + units of the MAES ecosystem types. The geometric and thematic accuracy of EUNIS class + presence was also estimated and mapped. The method is described in the EEA Technical + Report 06/2015: European Ecosystem Assessment – Concept, Data, and Implementation. + The basis for the update was CORINE land cover 2006 (CLC 2006). It includes Albania, + Austria, Belgium, Bosnia and Herzegovina, Bulgaria, Croatia, Cyprus, Czech Republic, + Denmark, Estonia, Finland, France, Germany, Hungary, Iceland, Ireland, Italy, Kosovo + (under UNSCR 1244/99), Latvia, Liechtenstein, Lithuania, Luxembourg, the former + Yugoslavian Republic of Macedonia, Malta, Montenegro, the Netherlands, Norway, Poland, + Portugal, Romania, Serbia, Slovakia, Slovenia, Spain, Sweden, Switzerland, Turkey and + the United Kingdom. For Greece that has not participated in the CLC 2006 activity the + CLC 2000 data was used instead. + + +``` + +### Status {#iso19139-elem-gmd-status-d9744a135669d7e6915b63168cf07b27} + +Name + +: + +> gmd:status + +Description + +: + +```{=html} +Status of the resource(s) +``` +### Subset {#iso19139-elem-gmd-subset-0bdb2733b084445c24aa766c936bbbf1} + +Name + +: + +> gmd:subset + +Description + +: + +```{=html} +Subset +``` +### Superset {#iso19139-elem-gmd-superset-5bde61a529de9ae44e7fdda16a962a52} + +Name + +: + +> gmd:superset + +Description + +: + +```{=html} +Superset +``` +### Supplemental Information {#iso19139-elem-gmd-supplementalInformation-70bc533abfda351b79e707eb88576e9a} + +Name + +: + +> gmd:supplementalInformation + +Description + +: + +```{=html} +Any other descriptive information about the dataset +``` +### Temporal element {#iso19139-elem-gmd-temporalElement-98c13f1732cd7f7c06320d907eec27ce} + +Name + +: + +> gmd:temporalElement + +Description + +: + +```{=html} +Provides temporal component of the extent of the referring object +``` + +Condition + +: + +> conditional + +``` xml + + + + + 2006-01-01 + 2006-12-31 + + + + +``` + +### TextGroup {#iso19139-elem-gmd-textGroup-a4c4555fd1e21193bfead46ef919ddb2} + +Name + +: + +> gmd:textGroup + +Description + +: + +```{=html} +TextGroup +``` +### Thesaurus name {#iso19139-elem-gmd-thesaurusName-9b47e5bba6e4b04eb489a597f7052fa7} + +Name + +: + +> gmd:thesaurusName + +Description + +: + +```{=html} +Name of the formally registered thesaurus or a similar authoritative source of + keywords +``` +### Title {#iso19139-elem-gmd-title-cc3002a2d81bcdbc5bf4c8735faf6980} + +Name + +: + +> gmd:title + +Description + +: + +```{=html} +Name by which the cited resource is known +``` + +Condition + +: + +> mandatory + +### Title {#iso19139-elem-gmd-title-gmd-MD_Legislation-8081549b6348e976f57d3e1e1649febd} + +Name + +: + +> gmd:title + +Context + +: + +> gmd:MD_Legislation + +Description + +: + +```{=html} +Reference to legal title +``` +### Tone gradation {#iso19139-elem-gmd-toneGradation-428708b5612bd1414b331fed6f3006a3} + +Name + +: + +> gmd:toneGradation + +Description + +: + +```{=html} +Number of discrete numerical values in the grid data +``` +### Topic category {#iso19139-elem-gmd-topicCategory-beb19f9aa38425d24bc8c438657fff74} + +Name + +: + +> gmd:topicCategory + +Description + +: + +```{=html} +Main theme(s) of the dataset +``` + +Condition + +: + +> mandatory + +### Topology level {#iso19139-elem-gmd-topologyLevel-329db7737da48376e857292bb39d799a} + +Name + +: + +> gmd:topologyLevel + +Description + +: + +```{=html} +Code which identifies the degree of complexity of the spatial + relationships +``` +### Transfer options {#iso19139-elem-gmd-transferOptions-5d585a7834225f656f9b59b8a350324f} + +Name + +: + +> gmd:transferOptions + +Description + +: + +```{=html} +Provides information about technical means and media by which a resource is + obtained from the distributor +``` +``` xml + + + + + + + http://www.eea.europa.eu/data-and-maps/data/ds_resolveuid/d851e1b7f678468b8f0b1b98930ba3e1 + + + + WWW:LINK-1.0-http--link + + + + + + + + +``` + +### Transfer size {#iso19139-elem-gmd-transferSize-6fb8cca7a1c7bf60b84b95ffc22c87d1} + +Name + +: + +> gmd:transferSize + +Description + +: + +```{=html} +Estimated size of a unit in the specified transfer format, expressed in + megabytes. The transfer size is > 0.0 +``` +### Transformation dimension description {#iso19139-elem-gmd-transformationDimensionDescription-fecd0ea824eac2e867a85d80ba80807f} + +Name + +: + +> gmd:transformationDimensionDescription + +Description + +: + +```{=html} +Description of the information about which grid dimensions are the spatial + dimensions +``` +### Transformation dimension mapping {#iso19139-elem-gmd-transformationDimensionMapping-38cf0a9e5888085e44c75c1dd91663d0} + +Name + +: + +> gmd:transformationDimensionMapping + +Description + +: + +```{=html} +Information about which grid dimensions are the spatial + dimensions +``` +### Transformation parameter availability {#iso19139-elem-gmd-transformationParameterAvailability-11c9a0d6d9a25e8cf235b1e22c31f83e} + +Name + +: + +> gmd:transformationParameterAvailability + +Description + +: + +```{=html} +Indication of whether or not parameters for transformation between image + coordinates and geographic or map coordinates exist (are available) +``` + +Condition + +: + +> mandatory + +### Triangulation indicator {#iso19139-elem-gmd-triangulationIndicator-823a9f2b26c8ebb297aad2682939cee2} + +Name + +: + +> gmd:triangulationIndicator + +Description + +: + +```{=html} +Indication of whether or not triangulation has been performed upon the + image +``` +### Turnaround {#iso19139-elem-gmd-turnaround-b28170fffa4b93f27be7f98c1f5277d9} + +Name + +: + +> gmd:turnaround + +Description + +: + +```{=html} +Typical turnaround time for the filling of an order +``` +### Type {#iso19139-elem-gmd-type-3fcd7fe79fb12bc2f3687ac760ab3896} + +Name + +: + +> gmd:type + +Description + +: + +```{=html} +Subject matter used to group similar keywords +``` +### Type {#iso19139-elem-gmd-type-gmd-MD_CodeDomain-136dd2846e6d50fe2afe1fbee0b111e1} + +Name + +: + +> gmd:type + +Context + +: + +> gmd:MD_CodeDomain + +Description + +: + +```{=html} +Datatype of the code domain +``` +### Type definition {#iso19139-elem-gmd-type-gmd-MD_Type-4a34cb5da02cab9e18a0ece8b743a12e} + +Name + +: + +> gmd:type + +Context + +: + +> gmd:MD_Type + +Description + +: + +```{=html} +Data type definition +``` +```{=html} +Data type definition, formal of informal (i.e. Text12, Line) +``` +### Value unit {#iso19139-elem-gmd-units-b4d317a2179c6ac4d27f23f2e44414c4} + +Name + +: + +> gmd:units + +Description + +: + +```{=html} +Units in which sensor wavelengths are expressed +``` +### Units of distribution {#iso19139-elem-gmd-unitsOfDistribution-fba1dcd6123d4448a543ca1b292783c8} + +Name + +: + +> gmd:unitsOfDistribution + +Description + +: + +```{=html} +Tiles, layers, geographic areas, etc., in which data is available +``` +### Update scope {#iso19139-elem-gmd-updateScope-789803d91659dcd11b3b3393c90922f2} + +Name + +: + +> gmd:updateScope + +Description + +: + +```{=html} +Scope of data to which maintenance is applied +``` +### Update scope description {#iso19139-elem-gmd-updateScopeDescription-998eb6c6cec2e3f5f61934d06123ad2c} + +Name + +: + +> gmd:updateScopeDescription + +Description + +: + +```{=html} +Additional information about the range or extent of the resource +``` +### URL {#iso19139-elem-gmd-URL-1926834a548a71264f070931031c7163} + +Name + +: + +> gmd:URL + +Description + +: + +```{=html} +URL +``` +### Usage datetime {#iso19139-elem-gmd-usageDateTime-eb4261bf01930ac70a65c335557a0ffa} + +Name + +: + +> gmd:usageDateTime + +Description + +: + +```{=html} +Date and time of the first use or range of uses of the resource and/or resource + series (YYYY-MM-DDThh:mm:ss) +``` +### Use constraints {#iso19139-elem-gmd-useConstraints-9f5825b49b04c7539ccf1b67d89cae3a} + +Name + +: + +> gmd:useConstraints + +Description + +: + +```{=html} +Constraints applied to assure the protection of privacy or intellectual + property, and any special restrictions or limitations or warnings on using the + resource +``` +### Use limitation {#iso19139-elem-gmd-useLimitation-07252e81be8d86aea4553aa3df807d8b} + +Name + +: + +> gmd:useLimitation + +Description + +: + +```{=html} +Limitation affecting the fitness for use of the resource. Example, _not to be + used for navigation_ +``` +``` xml + + Unless otherwise indicated, re-use of content on the EEA website + for commercial or non-commercial purposes is permitted free of charge, provided that + the source is acknowledged. The EEA re-use policy follows Directive 2003/98/EC of the + European Parliament and the Council on the re-use of public sector information + throughout the European Union and Commission Decision 2006/291/EC, Euratom on the + re-use of Commission information. The EEA accepts no responsibility or liability + whatsoever for the re-use of content accessible on its website. Any inquiries about + re-use of content on the EEA website should be addressed to Ove Caspersen, EEA, + Kongens Nytorv 6, DK-1050 Copenhagen K, Tel +45 33 36 71 00, Fax +45 33 36 71 99, + e-mail copyrights at eea.europa.eu + + +``` + +### User contact info {#iso19139-elem-gmd-userContactInfo-441ca49469790a846c9fd368696c77f8} + +Name + +: + +> gmd:userContactInfo + +Description + +: + +```{=html} +Identification of and means of communicating with person(s) and organization(s) + using the resource(s) +``` + +Condition + +: + +> mandatory + +### User defined maintenance frequency {#iso19139-elem-gmd-userDefinedMaintenanceFrequency-ad78ef111593b28eb264caef44637052} + +Name + +: + +> gmd:userDefinedMaintenanceFrequency + +Description + +: + +```{=html} +Maintenance period other than those defined +``` +### User determined limitations {#iso19139-elem-gmd-userDeterminedLimitations-7298d0a46cbf569447e0db1962896136} + +Name + +: + +> gmd:userDeterminedLimitations + +Description + +: + +```{=html} +Applications, determined by the user for which the resource and/or resource + series is not suitable +``` +### User note {#iso19139-elem-gmd-userNote-c06ef82acaa22bad47a878213d4a8dea} + +Name + +: + +> gmd:userNote + +Description + +: + +```{=html} +Explanation of the application of the legal constraints or other restrictions + and legal prerequisites for obtaining and using the resource or metadata +``` +### Value {#iso19139-elem-gmd-value-gmd-DQ_QuantitativeResult-4da008be3457344e7b9b220bd613e546} + +Name + +: + +> gmd:value + +Context + +: + +> gmd:DQ_QuantitativeResult + +Description + +: + +```{=html} +Quantitative value or values, content determined by the evaluation procedure + used +``` + +Condition + +: + +> mandatory + +### Value {#iso19139-elem-gmd-value-00279de566515e1bf93ae185e5ffe42f} + +Name + +: + +> gmd:value + +Description + +: + +### Value {#iso19139-elem-gmd-value-gmd-MD_Type-41077608c8230790f00082e7545295d2} + +Name + +: + +> gmd:value + +Context + +: + +> gmd:MD_Type + +Description + +: + +```{=html} +Data type value +``` +### Value type {#iso19139-elem-gmd-valueType-3f097375c7a73b4f120433e3774ef780} + +Name + +: + +> gmd:valueType + +Description + +: + +```{=html} +Quantitative conformance quality level value or range of values +``` +Recommended values + +| code | label | +|---------------------------------|---------------------------------| +| Boolean | Boolean | +| Real | Real | +| Integer | Integer | +| Ratio | Ratio | +| Percentage | Percentage | +| Measure(s) (value(s) + unit(s)) | Measure(s) (value(s) + unit(s)) | + +### Value unit {#iso19139-elem-gmd-valueUnit-65c0838f9052c0ff77f2372033ae87d2} + +Name + +: + +> gmd:valueUnit + +Description + +: + +```{=html} +Value unit for reporting a data quality result +``` + +Condition + +: + +> mandatory + +### Version {#iso19139-elem-gmd-version-gmd-RS_Identifier-d861feedf8dd2aef87eb06aeb0e4a2eb} + +Name + +: + +> gmd:version + +Context + +: + +> gmd:RS_Identifier + +Description + +: + +```{=html} +Version identifier for the namespace +``` +``` xml + + + +``` + +### Version {#iso19139-elem-gmd-version-30c3096d796063300c4dd7a64593e2aa} + +Name + +: + +> gmd:version + +Description + +: + +```{=html} +Version of the format (date, number, etc.) +``` + +Condition + +: + +> mandatory + +``` xml + + + +``` + +### Vertical CRS {#iso19139-elem-gmd-verticalCRS-34034733808b1ab00927f9445d415259} + +Name + +: + +> gmd:verticalCRS + +Description + +: + +```{=html} +Provides information about the origin from which the maximum and minimum elevation + values are measured +``` +### Vertical element {#iso19139-elem-gmd-verticalElement-28aa2675a263f8317e4046addeeae416} + +Name + +: + +> gmd:verticalElement + +Description + +: + +```{=html} +Provides vertical component of the extent of the referring object +``` + +Condition + +: + +> conditional + +### Voice {#iso19139-elem-gmd-voice-4387e4ef043bc3002639aee8885c0a96} + +Name + +: + +> gmd:voice + +Description + +: + +```{=html} +Telephone number by which individuals can speak to the responsible organization + or individual +``` +### Volumes {#iso19139-elem-gmd-volumes-546112edbc2350b220b2ac0a3b22cf80} + +Name + +: + +> gmd:volumes + +Description + +: + +```{=html} +Number of items in the media identified +``` +### West bound {#iso19139-elem-gmd-westBoundLongitude-e24eb3c341fa09426f2c5f733a9151f0} + +Name + +: + +> gmd:westBoundLongitude + +Description + +: + +```{=html} +Western-most coordinate of the limit of the dataset extent, expressed in + longitude in decimal degrees (positive east) +``` + +Condition + +: + +> mandatory + +``` xml + + -33.90432 + +``` + +### Axis {#iso19139-elem-gml-axis-3fefc5dac3952c40be7017bc2a26f9b7} + +Name + +: + +> gml:axis + +Description + +: + +### Axis abbreviation {#iso19139-elem-gml-axisAbbrev-df25e0618e0c705cdc907bc2965b6239} + +Name + +: + +> gml:axisAbbrev + +Description + +: + +### Axis direction {#iso19139-elem-gml-axisDirection-7c5e69d4b1a66ecd9567ae9529e20da9} + +Name + +: + +> gml:axisDirection + +Description + +: + +### Begin {#iso19139-elem-gml-begin-fcd7703f3e5afd04b33646f5b0d6ea36} + +Name + +: + +> gml:begin + +Description + +: + +### Begin date {#iso19139-elem-gml-beginPosition-1d6323a4d959ef33b6f719047ae9a25d} + +Name + +: + +> gml:beginPosition + +Description + +: + +```{=html} +Formatted as 2007-09-12T15:00:00 (YYYY-MM-DDTHH:mm:ss) +``` +``` xml +2006-01-01 +``` + +### Catalogue symbol {#iso19139-elem-gml-catalogSymbol-8f175b4e3cadb1e37646c4c134f9bcc5} + +Name + +: + +> gml:catalogSymbol + +Description + +: + +### Coordinates {#iso19139-elem-gml-coordinates-d446715f3936aafc2075e980669135bd} + +Name + +: + +> gml:coordinates + +Description + +: + +```{=html} +Used to record an array of tuples or coordinates. +``` +### Coordinate system axis {#iso19139-elem-gml-CoordinateSystemAxis-50e3c608cbb8fb6d07159798b299a8b3} + +Name + +: + +> gml:CoordinateSystemAxis + +Description + +: + +### Description {#iso19139-elem-gml-description-473b14977bb5684339b11d3ad6ab4630} + +Name + +: + +> gml:description + +Description + +: + +```{=html} +Text description of the element +``` +### Description reference {#iso19139-elem-gml-descriptionReference-0e8fc63ab0aeb3d807a818fad310d15c} + +Name + +: + +> gml:descriptionReference + +Description + +: + +### Domain of validity {#iso19139-elem-gml-domainOfValidity-8c497852e8c983accd03d26668bf6fc4} + +Name + +: + +> gml:domainOfValidity + +Description + +: + +### Duration {#iso19139-elem-gml-duration-6f1b3e01444852276db9d1615edb9cd2} + +Name + +: + +> gml:duration + +Description + +: + +```{=html} +Conforms to the ISO 8601 syntax for temporal length as implemented by the XML + Schema duration type. +``` +### End {#iso19139-elem-gml-end-b99c9d3cc2fa4edcdc69ee20ca1b674e} + +Name + +: + +> gml:end + +Description + +: + +### End date {#iso19139-elem-gml-endPosition-466dd41e369b5b90bb57a53dcf488685} + +Name + +: + +> gml:endPosition + +Description + +: + +```{=html} +Formatted as 2007-09-12T15:00:00 (YYYY-MM-DDTHH:mm:ss) +``` +``` xml +2006-12-31 +``` + +### Outer boundary {#iso19139-elem-gml-exterior-49870353f6025fcb331e0d0e87168e54} + +Name + +: + +> gml:exterior + +Description + +: + +```{=html} +The outer boundary of a solid. +``` +### Identifier {#iso19139-elem-gml-id-e8faeae0ab7c5bebeb5cba50387cfd35} + +Name + +: + +> gml:id + +Description + +: + +```{=html} +Unique identifier +``` +### Ellipsoid {#iso19139-elem-gml-id-gmd-MD_CRS-e2a3e87e63c806772242ecb35ff81500} + +Name + +: + +> gml:id + +Context + +: + +> gmd:MD_CRS + +Description + +: + +```{=html} +Identity of the ellipsoid used +``` +```{=html} +identity of the ellipsoid used +``` +### Identifier {#iso19139-elem-gml-identifier-d7806b0981ddec95743cf0e85ac8d36f} + +Name + +: + +> gml:identifier + +Description + +: + +### Inner boundary {#iso19139-elem-gml-interior-6ddebd0b5c7dc0777295fc86afb4313c} + +Name + +: + +> gml:interior + +Description + +: + +```{=html} +The inner boundary of a solid +``` +### Linear ring {#iso19139-elem-gml-LinearRing-1bc0cfb7a90a767379f93b111300ac0e} + +Name + +: + +> gml:LinearRing + +Description + +: + +```{=html} +A gml:LinearRing is defined by four or more coordinate tuples, with linear + interpolation between them; the first and last coordinates shall be + coincident. +``` +### Line {#iso19139-elem-gml-LineString-b166d0e353c3e73518b724843023efa3} + +Name + +: + +> gml:LineString + +Description + +: + +```{=html} +A gml:LineString is a special curve that consists of a single segment with + linear interpolation. It is defined by two or more coordinate tuples, with linear + interpolation between them. +``` +### Maximum value {#iso19139-elem-gml-maximumValue-68f16f3f15cbadbf4b0c79c0de6f6d66} + +Name + +: + +> gml:maximumValue + +Description + +: + +### Metadata property {#iso19139-elem-gml-metaDataProperty-af33b267cd577920546a32c08acec8c5} + +Name + +: + +> gml:metaDataProperty + +Description + +: + +### Minimum value {#iso19139-elem-gml-minimumValue-6223553305a9824c34b3609d668a341e} + +Name + +: + +> gml:minimumValue + +Description + +: + +### Name {#iso19139-elem-gml-name-14e682acf85693b8dfb78d998145cf51} + +Name + +: + +> gml:name + +Description + +: + +### Point {#iso19139-elem-gml-Point-236f5581e92c5dfacd954d5bed8a1b5c} + +Name + +: + +> gml:Point + +Description + +: + +```{=html} +A gml:Point is defined by a single coordinate tuple. +``` +### Polygon {#iso19139-elem-gml-Polygon-b82b498d78a2b6eec8fe7f45ea7211f7} + +Name + +: + +> gml:Polygon + +Description + +: + +```{=html} +A gml:Polygon is a special surface that is defined by a single surface patch. + The boundary of this patch is coplanar and the polygon uses planar interpolation in its + interior. +``` +### Projected CRS {#iso19139-elem-gml-ProjectedCRS-f948bfb32d6ed749c86a752010533ba7} + +Name + +: + +> gml:ProjectedCRS + +Description + +: + +### Quantity Type {#iso19139-elem-gml-quantityType-d7b9caf379c87262ea3f4942b6ce87a0} + +Name + +: + +> gml:quantityType + +Description + +: + +### Quantity Type Reference {#iso19139-elem-gml-quantityTypeReference-2cfae888d8691872634683ab688ee495} + +Name + +: + +> gml:quantityTypeReference + +Description + +: + +### Range meaning {#iso19139-elem-gml-rangeMeaning-49f4157213948e7780595134a0b92110} + +Name + +: + +> gml:rangeMeaning + +Description + +: + +### Realization epoch {#iso19139-elem-gml-realizationEpoch-e4489082a0b01cdc199d2888a25a963f} + +Name + +: + +> gml:realizationEpoch + +Description + +: + +### Related time {#iso19139-elem-gml-relatedTime-505f65f26a66aa61f3d6646b84b1013b} + +Name + +: + +> gml:relatedTime + +Description + +: + +```{=html} +Defines the relation of a given time to the object. +``` +### Remarks {#iso19139-elem-gml-remarks-f62f842081ee60b9c42dd65a57b7f45d} + +Name + +: + +> gml:remarks + +Description + +: + +### Scope {#iso19139-elem-gml-scope-8a0aa936cc32e5ee6b5973381fe80db5} + +Name + +: + +> gml:scope + +Description + +: + +### Time edge {#iso19139-elem-gml-TimeEdge-2b29e2f8f85c4fc53a553674e4277644} + +Name + +: + +> gml:TimeEdge + +Description + +: + +### Time instant {#iso19139-elem-gml-TimeInstant-e042092aa87a5391fc360ec34e412e96} + +Name + +: + +> gml:TimeInstant + +Description + +: + +### Time interval {#iso19139-elem-gml-timeInterval-b6f129024d67efd7c0614e30e6564f32} + +Name + +: + +> gml:timeInterval + +Description + +: + +```{=html} +conforms to ISO 11404 which is based on floating point values for temporal length. + ISO 11404 syntax specifies the use of a positiveInteger together with appropriate values for + radix and factor. The resolution of the time interval is to one radix ^(-factor) of the + specified time unit. + The value of the unit is either selected from the units for time intervals from ISO 31-1:1992, + or is another suitable unit. The encoding is defined for GML in gml:TimeUnitType. The second + component of this union type provides a method for indicating time units other than the six + standard units given in the enumeration. +``` +### Time node {#iso19139-elem-gml-TimeNode-c03fe80fbd29824670ed95a8a519b5c6} + +Name + +: + +> gml:TimeNode + +Description + +: + +### Time period {#iso19139-elem-gml-TimePeriod-a5053bd95c76a6e191ffaa0b8e83f68c} + +Name + +: + +> gml:TimePeriod + +Description + +: + +``` xml + + 2006-01-01 + 2006-12-31 + +``` + +### Time position {#iso19139-elem-gml-timePosition-659967113b43569d7fc2280efe5729b3} + +Name + +: + +> gml:timePosition + +Description + +: + +### Time position {#iso19139-elem-gml-TimePosition-68b54fb54b86e8c5a00afe7d12b835c5} + +Name + +: + +> gml:TimePosition + +Description + +: + +### unitsSystem {#iso19139-elem-gml-unitsSystem-0206dd6fb8b96985f94443d14d675927} + +Name + +: + +> gml:unitsSystem + +Description + +: + +### Unit of measure {#iso19139-elem-gml-uom-d45a808198fd4d356dcf4684218aed03} + +Name + +: + +> gml:uom + +Description + +: + +### Vertical CRS {#iso19139-elem-gml-VerticalCRS-a414c00efb0426d91a8c140471c7a36d} + +Name + +: + +> gml:VerticalCRS + +Description + +: + +### Vertical CS {#iso19139-elem-gml-verticalCS-e44a286116a042cd66d8c9a185537785} + +Name + +: + +> gml:verticalCS + +Description + +: + +### Vertical CS {#iso19139-elem-gml-VerticalCS-e37f66628a9000cd0b4e612a1112becf} + +Name + +: + +> gml:VerticalCS + +Description + +: + +### Vertical datum {#iso19139-elem-gml-verticalDatum-8b0192217f46b813d6fbd5d5cbe6ff87} + +Name + +: + +> gml:verticalDatum + +Description + +: + +### Vertical datum {#iso19139-elem-gml-VerticalDatum-31b851524264ca4dd621e6d16600b4d4} + +Name + +: + +> gml:VerticalDatum + +Description + +: + +### Anchor {#iso19139-elem-gmx-Anchor-d0ccf7ef89bd129a31fe766fae38f1df} + +Name + +: + +> gmx:Anchor + +Description + +: + +```{=html} +Supports hyper-linking capabilities and ensures a web-like implementation of + CharacterStrings +``` +### Field of application {#iso19139-elem-gmx-fieldOfApplication-f2323295efe7d63cdd639724e044b20b} + +Name + +: + +> gmx:fieldOfApplication + +Description + +: + +```{=html} +Field of application +``` +### File name {#iso19139-elem-gmx-FileName-37df0ee2c2072b5a1f6088f3a8d1b023} + +Name + +: + +> gmx:FileName + +Description + +: + +```{=html} +File name and source URL. +``` +### Name {#iso19139-elem-gmx-name-c095560004def24f75abbb05e2d62079} + +Name + +: + +> gmx:name + +Description + +: + +```{=html} +Feature catalogue name +``` +### Scope {#iso19139-elem-gmx-scope-d18924953739105e2d01daf31cf284e0} + +Name + +: + +> gmx:scope + +Description + +: + +```{=html} +Scope definition +``` +### Date {#iso19139-elem-gmx-versionDate-3f4501418cb1164a3da629e121552ecd} + +Name + +: + +> gmx:versionDate + +Description + +: + +```{=html} +Catalogue date +``` +### Version {#iso19139-elem-gmx-versionNumber-45d0e848e304b12f16f75be3f780c97c} + +Name + +: + +> gmx:versionNumber + +Description + +: + +```{=html} +Catalogue version +``` +### Period duration {#iso19139-elem-gts-TM_PeriodDuration-e6be5bc9a1ef33b78246171f9d092eb5} + +Name + +: + +> gts:TM_PeriodDuration + +Description + +: + +```{=html} +The duration data type is used to specify a time interval. + +The time interval is specified in the following form "PnYnMnDTnHnMnS" where: + +* P indicates the period (required) +* nY indicates the number of years +* nM indicates the number of months +* nD indicates the number of days +* T indicates the start of a time section (required if you are going to specify hours, +minutes, or seconds) +* nH indicates the number of hours +* nM indicates the number of minutes +* nS indicates the number of seconds +``` +### Hidden Elements {#iso19139-elem-hidden-elements-3fcbdb1b81d4fa9c9694a3e7fa33ae88} + +Name + +: + +> hidden-elements + +Description + +: + +```{=html} +Child elements and attributes have been hidden because you do no have access to + view those elements +``` +### Identifier {#iso19139-elem-id-0dd23b8448c65513bc5df360f10d9f80} + +Name + +: + +> id + +Description + +: + +```{=html} +Unique identifier +``` +### Indeterminate position {#iso19139-elem-indeterminatePosition-260a886b2a2f47a9172910d795854c9c} + +Name + +: + +> indeterminatePosition + +Description + +: + +### Standard codelists Indeterminate position (indeterminatePosition) + +| code | label | +|---------|---------| +| after | After | +| before | Before | +| now | Now | +| unknown | Unknown | + +### Indirect projection system (for non geographical resources) {#iso19139-elem-InDirectReferenceSystem-0267274a7311c04c19a066850b7c34da} + +Name + +: + +> InDirectReferenceSystem + +Description + +: + +```{=html} +ReferenceSystem derived / specify that it is an indirect + reference +``` +### Radix {#iso19139-elem-radix-f013f1c6757bf6c47831308d9161bdc0} + +Name + +: + +> radix + +Description + +: + +### Source URL {#iso19139-elem-src-45b17fa1ca5386cd5f963342f4af3e0d} + +Name + +: + +> src + +Description + +: + +```{=html} +URL of the document. +``` +### Spatial Reference System Name {#iso19139-elem-srsName-b8afc1ab5f5b09552205c4795ccadeaa} + +Name + +: + +> srsName + +Description + +: + +```{=html} +Name of the Spatial Reference System. By default set to + geographic (epsg:4326) +``` +### Access Properties {#iso19139-elem-srv-accessProperties-0b17bae21a9a08a66679b18470ccc23e} + +Name + +: + +> srv:accessProperties + +Description + +: + +```{=html} +Information about the availability of the service eg. fees, availability, + oredering instructions +``` +### Connect Point {#iso19139-elem-srv-connectPoint-7982557d282f2f8e26ce6349f893e18f} + +Name + +: + +> srv:connectPoint + +Description + +: + +```{=html} +Handle for accessing the service interface +``` +### Contains Operations {#iso19139-elem-srv-containsOperations-5765a967aadd33b5ba92cde03c9ce30e} + +Name + +: + +> srv:containsOperations + +Description + +: + +```{=html} +Provides information about the operations that comprise the + service +``` +### Coupled Resource {#iso19139-elem-srv-coupledResource-09de21d33ee8e6c814d675f23350d40e} + +Name + +: + +> srv:coupledResource + +Description + +: + +```{=html} +Details of services coupled with this one +``` +### Coupling Type {#iso19139-elem-srv-couplingType-bc1606dff717a83807e97a1a3789e30a} + +Name + +: + +> srv:couplingType + +Description + +: + +```{=html} +Type of Coupling +``` +### Distributed Computing Platforms {#iso19139-elem-srv-DCP-4da4ef80cec961d437cc5191b256fb0f} + +Name + +: + +> srv:DCP + +Description + +: + +```{=html} +Distributed computing platforms on which the operation has been + implemented +``` +### Distributed Computing Platforms list {#iso19139-elem-srv-DCPList-dbbe623a769e6242e8fc2c6cb1ab4a6e} + +Name + +: + +> srv:DCPList + +Description + +: + +### Standard codelists Distributed Computing Platforms list (srv:DCPList) + +| description | code | label | +|--------------------|-------------|--------------| +| DCP is XML | XML | XML | +| DCP is CORBA | CORBA | CORBA | +| DCP is JAVA | JAVA | JAVA | +| DCP is COM | COM | COM | +| DCP is SQL | SQL | SQL | +| DCP is WebServices | WebServices | Web services | + +### Depends On {#iso19139-elem-srv-dependsOn-f4d4b9fc1640b60874e70642ab2280be} + +Name + +: + +> srv:dependsOn + +Description + +: + +```{=html} +List of operations that must be completed immediately before current operation + is invoked, structured as a list for capturing alternate predecessor paths and sets for + capturing parallel predecessor paths +``` +### Description {#iso19139-elem-srv-description-5b9e6dc049d103b7b405144a4b2ddc54} + +Name + +: + +> srv:description + +Description + +: + +```{=html} +Narrative explanation of the services in the chain and resulting output or role + of the parameter +``` +### Direction {#iso19139-elem-srv-direction-6554a8cbde610419936242537ba0f647} + +Name + +: + +> srv:direction + +Description + +: + +### Extent {#iso19139-elem-srv-extent-64a5e3a1fb91876497dd5bad40e89e49} + +Name + +: + +> srv:extent + +Description + +: + +```{=html} +Geographic/Temporal Extent of Service +``` +### Identifier {#iso19139-elem-srv-identifier-c2dabee10730bbcfc96d13572c1cec92} + +Name + +: + +> srv:identifier + +Description + +: + +```{=html} +Identifier of resource to which the operation applies +``` +### Invocation Name {#iso19139-elem-srv-invocationName-ff1507450b257e37f591b7f95addbdad} + +Name + +: + +> srv:invocationName + +Description + +: + +```{=html} +The name used to invoke this interface within the context of the DCP. The name + is identical for all DCPs +``` +### Keywords {#iso19139-elem-srv-keywords-f46cb2bd1f2e70ef2e62eb2edb510123} + +Name + +: + +> srv:keywords + +Description + +: + +```{=html} +Keywords describing service +``` +### Name {#iso19139-elem-srv-name-9889811abcd6d2d0bc76dc5467a06f7e} + +Name + +: + +> srv:name + +Description + +: + +```{=html} +The name, as used by the service for this chain or parameter +``` +### Operates On {#iso19139-elem-srv-operatesOn-fc0165e60dcb452c05c9f1d95416b89a} + +Name + +: + +> srv:operatesOn + +Description + +: + +```{=html} +Provides information on the datasets that the service operates on +``` +### Operation Description {#iso19139-elem-srv-operationDescription-61305b5372e54d3cdd60a8dc8b1587c7} + +Name + +: + +> srv:operationDescription + +Description + +: + +```{=html} +Free text description of the intent of the operation and the results of the + operation +``` +### Operation Name {#iso19139-elem-srv-operationName-33abdef7fb8954ae3842f74904326896} + +Name + +: + +> srv:operationName + +Description + +: + +```{=html} +A unique identifier for this interface +``` +### Optionality {#iso19139-elem-srv-optionality-32be37d11746cc993b5b447b15480f70} + +Name + +: + +> srv:optionality + +Description + +: + +```{=html} +Indication if the parameter is required +``` +### Parameters {#iso19139-elem-srv-parameters-c842f4d88772de0790d36a4789c54b0c} + +Name + +: + +> srv:parameters + +Description + +: + +```{=html} +The parameters that are required for this interface +``` +### Provider Name {#iso19139-elem-srv-providerName-67c5eeff01e2702cdca4d5543566b572} + +Name + +: + +> srv:providerName + +Description + +: + +```{=html} +A unique identifier for this organization +``` +### Repeatability {#iso19139-elem-srv-repeatability-20aecf37a789cf6d34f906ca151e6cfb} + +Name + +: + +> srv:repeatability + +Description + +: + +```{=html} +Indication if more than one value of the parameter may be + provided +``` +### Restrictions {#iso19139-elem-srv-restrictions-eddcbda30442882032776be29da19b00} + +Name + +: + +> srv:restrictions + +Description + +: + +```{=html} +Legal and security constraints on accessing the service and distributing data + generated by the service +``` +### Service Contact {#iso19139-elem-srv-serviceContact-ecd84df84bea000426f14d1faaf78266} + +Name + +: + +> srv:serviceContact + +Description + +: + +```{=html} +Information for contacting the service provider +``` +### Service Type {#iso19139-elem-srv-serviceType-31230933e2a7436c80955195b74bc0a0} + +Name + +: + +> srv:serviceType + +Description + +: + +```{=html} +Service type name from a registry of services. For example, the values of the + nameSpace and name attributes of GeneralName may be 'OGC' and 'catalogue' +``` +Recommended values + +| code | label | +|-------------------|-------------------------------------------------| +| OGC:WMS | OGC Web Map Service (OGC:WMS) | +| OGC:WFS | OGC Web Feature Service (OGC:WFS) | +| OGC:WCS | OGC Web Coverage Service (OGC:WCS) | +| W3C:HTML:DOWNLOAD | Download (W3C:HTML:DOWNLOAD) | +| W3C:HTML:LINK | Information (W3C:HTML:LINK) | +| discovery | INSPIRE Discovery Service (discovery) | +| view | INSPIRE View Service (view) | +| download | INSPIRE Download Service (download) | +| transformation | INSPIRE Transformation Service (transformation) | +| other | INSPIRE Other Services (other) | + +### Service Version {#iso19139-elem-srv-serviceTypeVersion-4187a8061f591f97903093667295daa0} + +Name + +: + +> srv:serviceTypeVersion + +Description + +: + +```{=html} +Provides for searching based on the version of serviceType. For example, we may + only be interested in OGC Catalogue V1.1 services. If version is maintained as a + separate attribute, users can easily search for all services of a type regardless of the + version +``` +### Coupled Resource {#iso19139-elem-srv-SV_CoupledResource-2d85cb6b044791b72116ba2a107bf03e} + +Name + +: + +> srv:SV_CoupledResource + +Description + +: + +```{=html} +Details of services coupled with this one +``` +### Coupling Type {#iso19139-elem-srv-SV_CouplingType-0ccd187bb4e974353b2967aeda26bb4f} + +Name + +: + +> srv:SV_CouplingType + +Description + +: + +```{=html} +Type of Coupling +``` +### Standard codelists Coupling Type (srv:SV_CouplingType) + +| code | label | description | +|-------|-------|-------------------------------------------------------------------------------| +| tight | Tight | Tightly coupled: data associated | +| mixed | Mixed | Mixed coupled: data associated; in addition, external data might be processed | +| loose | Loose | Loosely coupled: no data associated | + +### Operation {#iso19139-elem-srv-SV_OperationMetadata-360f31d3dfaf07269e52a98bdfd0782a} + +Name + +: + +> srv:SV_OperationMetadata + +Description + +: + +```{=html} +Operation Metadata +``` +### Parameter {#iso19139-elem-srv-SV_Parameter-614c824c473c037ce821444bc369929f} + +Name + +: + +> srv:SV_Parameter + +Description + +: + +```{=html} +The parameters that are required for this interface +``` +### Parameter direction {#iso19139-elem-srv-SV_ParameterDirection-fb7b80e085fc9d52b922e6ff63de2c0a} + +Name + +: + +> srv:SV_ParameterDirection + +Description + +: + +### Standard codelists Parameter direction (srv:SV_ParameterDirection) + +| code | label | +|--------|--------------| +| in | Input | +| out | Output | +| in/out | Input/output | + +### Service Identification (19119) {#iso19139-elem-srv-SV_ServiceIdentification-a03600ef3a3f59be9f022c9137a72deb} + +Name + +: + +> srv:SV_ServiceIdentification + +Description + +: + +```{=html} +ISO 19119-2005 Service Identification +``` +### Value type {#iso19139-elem-srv-valueType-5760ec25a3f9d6ee283d5fb5c6248c7c} + +Name + +: + +> srv:valueType + +Description + +: + +### Unit {#iso19139-elem-unit-945d85b3b91c6edfaa79c28f5354e396} + +Name + +: + +> unit + +Description + +: + +### Units of measure {#iso19139-elem-uom-deee964fae8827c5a9435a07abe4ceea} + +Name + +: + +> uom + +Description + +: + +Recommended values + +| code | label | +|------|--------| +| m | meters | + +### Metadata uuid {#iso19139-elem-uuidref-6f0ce82fb9f437e7a80804c85857a44a} + +Name + +: + +> uuidref + +Description + +: + +```{=html} +Unique identifier +``` +### URL {#iso19139-elem-xlink-href-24b46a26bc2f93ddbf7ff3a48bed324f} + +Name + +: + +> xlink:href + +Description + +: + +```{=html} +Supplies the data that allows an XLink application to find a remote resource (or + resource fragment) [W3C XLINK] +``` +### URL title {#iso19139-elem-xlink-title-83b73e889fe529eac02adecd853aa587} + +Name + +: + +> xlink:title + +Description + +: + +### Link {#iso19139-elem-xlink-type-2f3d5b15ae49cb486c0f798f25eb6ca0} + +Name + +: + +> xlink:type + +Description + +: + +```{=html} +Link type +``` +### Years {#iso19139-elem-years-b93df09e5de0ac46f913523035856630} + +Name + +: + +> years + +Description + +: + +### Zone {#iso19139-elem-zone-30b632c8b09244100577dcf6c0ddf419} + +Name + +: + +> zone + +Description + +: + +```{=html} +Unique identifier for 100,000 metre grid zone +``` +## Standard codelists + +List of all codelists available in the standard. + +### Standard codelists Date type code (gmd:CI_DateTypeCode) {#iso19139-cl-gmd-CI_DateTypeCode} + +| code | label | description | +|-------------|-------------|---------------------------------------------------------------------------------------| +| creation | Creation | Date identifies when the resource was brought into existence | +| publication | Publication | Date identifies when the resource was issued | +| revision | Revision | Date identifies when the resource was examined or re-examined and improved or amended | + +### Standard codelists OnLine function code (gmd:CI_OnLineFunctionCode) {#iso19139-cl-gmd-CI_OnLineFunctionCode} + +| code | label | description | +|---------------|----------------|----------------------------------------------------------------------------------------| +| download | Download | Online instructions for transferring data from one storage device or system to another | +| information | Information | Online information about the resource | +| offlineAccess | Offline access | Online instructions for requesting the resource from the provider | +| order | Order | Online order process for obtening the resource | +| search | Search | Online search interface for seeking out information about the resource | + +### Standard codelists Presentatiewijze code (gmd:CI_PresentationFormCode) {#iso19139-cl-gmd-CI_PresentationFormCode} + +| code | label | description | +|------------------|-------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| documentDigital | Digital document | Digital representation of a primarily textual item (can contain illustrations also) | +| imageDigital | Digital image | Likeness of natural or man-made features, objects, and activities acquired through the sensing of visual or any other segment of the electromagnetic spectrum by sensors, such as thermal infrared, and high resolution radar and stored in digital format | +| documentHardcopy | Hardcopy document | Representation of a primarily textual item (can contain illustrations also) on paper, photographic material, or other media | +| imageHardcopy | Hardcopy image | Likeness of natural or man-made features, objects, and activities acquired through the sensing of visual or any other segment of the electromagnetic spectrum by sensors, such as thermal infrared, and high resolution radar and reproduced on paper, photographic material, or other media for use directly by the human user | +| mapDigital | Digital map | Map represented in raster or vector form | +| mapHardcopy | Hardcopy map | Map printed on paper, photographic material, or other media for use directly by the human user | +| modelDigital | Digital model | Multi-dimensional digital representation of a feature, process, etc. | +| modelHardcopy | Hardcopy model | 3-dimensional, physical model | +| profileDigital | Digital profile | Vertical cross-section in digital form | +| profileHardcopy | Hardcopy profile | Vertical cross-section printed on paper, etc. | +| tableDigital | Digital table | Digital representation of facts or figures systematically displayed, especially in columns | +| tableHardcopy | Hardcopy table | Representation of facts or figures systematically displayed, especially in columns, printed onpapers, photographic material, or other media | +| videoDigital | Digital video | Digital video recording | +| videoHardcopy | Hardcopy video | Video recording on film | + +### Standard codelists Role code (gmd:CI_RoleCode) {#iso19139-cl-gmd-CI_RoleCode} + +| code | label | description | +|-----------------------|------------------------|--------------------------------------------------------------------------------------------------------------------------------| +| resourceProvider | Resource provider | Party that supplies the resource | +| custodian | Custodian | Party that accepts accountability and responsibility for the data and ensures appropriate care and maintenance of the resource | +| owner | Owner | Party that owns the resource | +| user | User | Party who uses the resource | +| distributor | Distributor | Party who distributes the resource | +| originator | Originator | Party who created the resource | +| pointOfContact | Point of contact | Party who can be contacted for acquiring knowledge about or acquisition of the resource | +| principalInvestigator | Principal investigator | Key party responsible for gathering information and conducting research | +| processor | Processor | Party that has processed the data in a manner such that the resource has been modified | +| publisher | Publisher | Party who published the resource | +| author | Author | Party who authored the resource | + +### Standard codelists Evaluation method type code (gmd:DQ_EvaluationMethodTypeCode) {#iso19139-cl-gmd-DQ_EvaluationMethodTypeCode} + +| code | label | description | +|----------------|-----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| directInternal | Direct internal | Method of evaluating the quality of a dataset based on inspection of items within the dataset, where all data required is internal to the dataset being evaluated | +| directExternal | Direct external | Method of evaluating the quality of a dataset based on inspection of items within the dataset, where reference data external to the dataset being evaluated is required | +| indirect | Indirect | Method of evaluating the quality of a dataset based on external knowledge | + +### Standard codelists Association Type (gmd:DS_AssociationTypeCode) {#iso19139-cl-gmd-DS_AssociationTypeCode} + +| code | label | description | +|------------------------|---------------------------|-------------------------------------------------------------------------------------| +| crossReference | Cross reference | Reference from one dataset to another | +| largerWorkCitation | Larger work citation | Reference to a master dataset of which this one is a part | +| partOfSeamlessDatabase | Part of seamless database | Part of the same structured set of data held in a computer | +| source | Source | Mapping and charting information from which the dataset content originates | +| stereoMate | Stereo mate | Part of a set of imagery that when used together, provides three-dimensional images | + +### Standard codelists Initiative Type (gmd:DS_InitiativeTypeCode) {#iso19139-cl-gmd-DS_InitiativeTypeCode} + +| code | label | description | +|---------------|---------------|-------------------------------------------------------------| +| campaign | Campaign | Series of organized planned actions | +| collection | Collection | Accumulation of datasets assembled for a specific purpose | +| exercise | Exercise | Specific performance of a function or group of functions | +| experiment | Experiment | Process designed to find if something is effective or valid | +| investigation | Investigation | Search or systematic inquiry | +| mission | Mission | Specific operation of a data collection system | +| sensor | Sensor | Device or piece of equipment which detects or records | +| operation | Operation | Action that is part of a series of actions | +| platform | Platform | Vehicle or other support base that holds a sensor | +| process | Process | Method of doing something involving a number of steps | +| program | Program | Specific planned activity | +| project | Project | Organized undertaking, research, or development | +| study | Study | Examination or investigation | +| task | Task | Piece of work | +| trial | Trial | Process of testing to discover or demonstrate something | + +### Standard codelists Cell geometry code (gmd:MD_CellGeometryCode) {#iso19139-cl-gmd-MD_CellGeometryCode} + +| code | label | description | +|-------|-------|------------------------------| +| point | Point | Each cell represents a point | +| area | Area | Each cell represents an area | + +### Standard codelists Characterset code (gmd:MD_CharacterSetCode) {#iso19139-cl-gmd-MD_CharacterSetCode} + +| code | label | description | +|------------|--------------|-----------------------------------------------------------------------------------------------------------------------------------| +| ucs2 | UCS2 | 16-bit fixed size Universal Character Set, based on ISO/IEC 10646 | +| ucs4 | UCS4 | 32-bit fixed size Universal Character Set, based on ISO/IEC 10646 | +| utf7 | UTF7 | 7-bit variable size UCS Transfer Format, based on ISO/IEC 10646 | +| utf8 | UTF8 | 8-bit variable size UCS Transfer Format, based on ISO/IEC 10646 | +| utf16 | UTF16 | 16-bit variable size UCS Transfer Format, based on ISO/IEC 10646 | +| 8859part1 | 8859 Part 1 | ISO/IEC 8859-1, Information technology - 8-bit single byte coded graphic character sets - Part 1 : Latin alphabet No.1 | +| 8859part2 | 8859 Part 2 | ISO/IEC 8859-2, Information technology - 8-bit single byte coded graphic character sets - Part 2 : Latin alphabet No.2 | +| 8859part3 | 8859 Part 3 | ISO/IEC 8859-3, Information technology - 8-bit single byte coded graphic character sets - Part 3 : Latin alphabet No.3 | +| 8859part4 | 8859 Part 4 | ISO/IEC 8859-4, Information technology - 8-bit single byte coded graphic character sets - Part 4 : Latin alphabet No.4 | +| 8859part5 | 8859 Part 5 | ISO/IEC 8859-5, Information technology - 8-bit single byte coded graphic character sets - Part 5 : Latin/Cyrillic alphabet | +| 8859part6 | 8859 Part 6 | ISO/IEC 8859-6, Information technology - 8-bit single byte coded graphic character sets - Part 6 : Latin/Arabic alphabet | +| 8859part7 | 8859 Part 7 | ISO/IEC 8859-7, Information technology - 8-bit single byte coded graphic character sets - Part 7 : Latin/Greek alphabet | +| 8859part8 | 8859 Part 8 | ISO/IEC 8859-8, Information technology - 8-bit single byte coded graphic character sets - Part 8 : Latin/Hebrew alphabet | +| 8859part9 | 8859 Part 9 | ISO/IEC 8859-9, Information technology - 8-bit single byte coded graphic character sets - Part 9 : Latin alphabet No.5 | +| 8859part10 | 8859 Part 10 | ISO/IEC 8859-10, Information technology - 8-bit single byte coded graphic character sets - Part 10 : Latin alphabet No.6 | +| 8859part11 | 8859 Part 11 | ISO/IEC 8859-11, Information technology - 8-bit single byte coded graphic character sets - Part 11 : Latin/Thai alphabet | +| 8859part13 | 8859 Part 13 | ISO/IEC 8859-13, Information technology - 8-bit single byte coded graphic character sets - Part 13 : Latin alphabet No.7 | +| 8859part14 | 8859 Part 14 | ISO/IEC 8859-14, Information technology - 8-bit single byte coded graphic character sets - Part 14 : Latin alphabet No.8 (Celtic) | +| 8859part15 | 8859 Part 15 | ISO/IEC 8859-15, Information technology - 8-bit single byte coded graphic character sets - Part 15 : Latin alphabet No.9 | +| 8859part16 | 8859 Part 16 | ISO/IEC 8859-16, Information technology - 8-bit single byte coded graphic character sets - Part 16 : Latin alphabet No.10 | +| jis | JIS | Japanese code set used for electronic transmission | +| shiftJIS | Shift JIS | Japanese code set used on MS-DOS machines | +| eucJP | EUC JP | Japanese code set used on UNIX based machines | +| usAscii | US ASCII | United States ASCII code set (ISO 646 US) | +| ebcdic | EBCDIC | IBM mainframe code set | +| eucKR | EUC KR | Korean code set | +| big5 | Big 5 | Traditional Chinese code set used in Taiwan, Hong Kong of China and other areas | +| GB2312 | GB2312 | Simplified Chinese code set | + +### Standard codelists Classification code (gmd:MD_ClassificationCode) {#iso19139-cl-gmd-MD_ClassificationCode} + +| code | label | description | +|--------------|--------------|--------------------------------------------------------------------------------------------| +| unclassified | Unclassified | Available for general disclosure | +| restricted | Restricted | Not for general disclosure | +| confidential | Confidential | Available for someone who can be entrusted with information | +| secret | Secret | Kept or meant to be kept private, unknown, or hidden from all but a select group of people | +| topSecret | Top secret | Of the highest secrecy | + +### Standard codelists Content type code (gmd:MD_CoverageContentTypeCode) {#iso19139-cl-gmd-MD_CoverageContentTypeCode} + +| code | label | description | +|------------------------|-------------------------|--------------------------------------------------------------------------------------------------------------------| +| image | Image | Meaningful numerical representation of a physical parameter that is not the actual value of the physical parameter | +| thematicClassification | Thematic classification | Code value with no quantitative meaning, used to represent a physical quantity | +| physicalMeasurement | Physical measurement | Value in physical units of the quantity being measured | + +### Standard codelists Data type code (gmd:MD_DatatypeCode) {#iso19139-cl-gmd-MD_DatatypeCode} + +| code | label | description | +|-----------------|------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| class | Class | Descriptor of a set of objects that share the same attributes, operations, methods, relationships, and behavior | +| codelist | Codelist | Descriptor of a set of objects that share the same attributes, operations, methods, relationships, and behavior | +| enumeration | Enumeration | Data type whose instances form a list of named literal values, not extendable | +| codelistElement | Codelist element | Permissible value for a codelist or enumeration | +| abstractClass | Abstract class | Class that cannot be directly instantiated | +| aggregateClass | Aggregate class | Class that is composed of classes it is connected to by an aggregate relationship | +| specifiedClass | Specified class | Subclass that may be substituted for its superclass | +| datatypeClass | Datatype class | Class with few or no operations whose primary purpose is to hold the abstract state of another class for transmittal, storage, encoding or persistent storage | +| interfaceClass | Interface class | Named set of operations that characterize the behavior of an element | +| unionClass | Union class | Class describing a selection of one of the specified types | +| metaClass | Meta class | Class whose instances are classes | +| typeClass | Type class | Class used for specification of a domain of instances (objects), together with the operations applicable to the objects. A type may have attributes and associations | +| characterString | Character string | Free text field | +| integer | Integer | Numerical field | +| association | Association | Semantic relationship between two classes that involves connections among their instances | + +### Standard codelists Dimension type code (gmd:MD_DimensionNameTypeCode) {#iso19139-cl-gmd-MD_DimensionNameTypeCode} + +| code | label | description | +|------------|-------------|------------------------------------------------------------| +| row | Row | Ordinate (y) axis | +| column | Column | Abscissa (x) axis | +| vertical | Vertical | Vertical (z) axis | +| track | Track | Along the direction of motion of the scan point | +| crossTrack | Cross track | Perpendicular to the direction of motion of the scan point | +| line | Line | Scan line of a sensor | +| sample | Sample | Element along a scan line | +| time | Time | Duration | + +### Standard codelists Geometric Object Type (gmd:MD_GeometricObjectTypeCode) {#iso19139-cl-gmd-MD_GeometricObjectTypeCode} + +| code | label | description | +|-----------|-----------|----------------------------------------------------------------------------------------------------------------| +| complex | Complex | Set of geometric primitives such that their boundaries can be represented as a union of other primitives | +| composite | Composite | Connected set of curves, solids or surfaces | +| curve | Curve | Bounded, 1-dimensional geometric primitive, representing the continuous image of a line | +| point | Point | Zero-dimensional geometric primitive, representing a position but not having an extent | +| solid | Solid | Bounded, connected 3-dimensional geometric primitive, representing the continuous image of a region of space | +| surface | Surface | Bounded, connected 2-dimensional geometric primitive, representing the continuous image of a region of a plane | + +### Standard codelists Imaging Condition Code (gmd:MD_ImagingConditionCode) {#iso19139-cl-gmd-MD_ImagingConditionCode} + +| code | label | description | +|--------------------|---------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| blurredImage | Blurred image | Portion of the image is blurred | +| cloud | Cloud | Portion of the image is partially obscured by cloud cover | +| degradingObliquity | Degrading obliquity | Acute angle between the plane of the ecliptic (the plane of the Earth s orbit) and the plane of the celestial equator | +| fog | Fog | Portion of the image is partially obscured by fog | +| heavySmokeOrDust | Heavy smoke or dust | Portion of the image is partially obscured by heavy smoke or dust | +| night | Night | Image was taken at night | +| rain | Rain | Image was taken during rainfall | +| semiDarkness | Semi darkness | Image was taken during semi-dark conditions -- twilight conditions | +| shadow | Shadow | Portion of the image is obscured by shadow | +| snow | Snow | Portion of the image is obscured by snow | +| terrainMasking | Terrain masking | The absence of collection data of a given point or area caused by the relative location of topographic features which obstruct the collection path between the collector(s) and the subject(s) of interest | + +### Standard codelists Keyword Type Code (gmd:MD_KeywordTypeCode) {#iso19139-cl-gmd-MD_KeywordTypeCode} + +| code | label | description | +|------------|------------|--------------------------------------------------------------------| +| discipline | Discipline | Keyword identifies a branch of instruction or specialized learning | +| place | Place | Keyword identifies a location | +| stratum | Stratum | Keyword identifies the layer(s) of any deposited substance | +| temporal | Temporal | Keyword identifies a time period related to the dataset | +| theme | Theme | Keyword identifies a particular subject or topic | + +### Standard codelists Maintenance Frequency (gmd:MD_MaintenanceFrequencyCode) {#iso19139-cl-gmd-MD_MaintenanceFrequencyCode} + +| code | label | description | +|-------------|-------------|----------------------------------------------------------| +| continual | Continual | Data is repeatedly and frequently updated | +| daily | Daily | Data is updated each day | +| weekly | Weekly | Data is updated on a weekly basis | +| fortnightly | Fortnightly | Data is updated every two weeks | +| monthly | Monthly | Data is updated each month | +| quarterly | Quarterly | Data is updated every three months | +| biannually | Biannually | Data is updated twice each year | +| annually | Annually | Data is updated every year | +| asNeeded | As needed | Data is updated as deemed necessary | +| irregular | Irregular | Data is updated in intervals that are uneven in duration | +| notPlanned | Not planned | There are no plans to update the data | +| unknown | Unknown | Frequency of maintenance for the data is not known | + +### Standard codelists Medium format (gmd:MD_MediumFormatCode) {#iso19139-cl-gmd-MD_MediumFormatCode} + +| code | label | description | +|------------------|--------------------|------------------------------------------------------------| +| cpio | CPIO | CoPy In / Out (UNIX file format and command) | +| tar | TAR | Tape ARchive | +| highSierra | High sierra | High sierra file system | +| iso9660 | ISO9660 | Information processing volume and file structure of CD-ROM | +| iso9660RockRidge | ISO9660 Rock Ridge | Rock ridge interchange protocol (UNIX) | +| iso9660AppleHFS | ISO9660 Apple HFS | Hierarchical file system (Macintosh) | + +### Standard codelists Medium name code (gmd:MD_MediumNameCode) {#iso19139-cl-gmd-MD_MediumNameCode} + +| code | label | description | +|---------------------------|-------------------------------|----------------------------------------------------| +| cdRom | CDROM | Read-only optical disk | +| dvd | DVD | Digital versatile disk | +| dvdRom | DVDROM | Digital versatile disk, read only | +| 3halfInchFloppy | 3 Half Inch Floppy | 3,5 inch magnetic disk | +| 5quarterInchFloppy | 5 Quarter Inch Floppy | 5,25 inch magnetic disk | +| 7trackTape | 7 Track tape | 7 track magnetic tape | +| 9trackTape | 9 track tape | 9 track magnetic tape | +| 3480Cartridge | 3480 Cartridge | 3480 cartridge tape drive | +| 3490Cartridge | 3490 Cartridge | 3490 cartridge tape drive | +| 3580Cartridge | 3580 Cartridge | 3580 cartridge tape drive | +| 4mmCartridgeTape | 4 mm Cartridge tape | 4 millimetre magnetic tape | +| 8mmCartridgeTape | 8 mm Cartridge tape | 8 millimetre magnetic tape | +| 1quarterInchCartridgeTape | 1 Quarter inch cartridge tape | 0,25 inch magnetic tape | +| digitalLinearTap | Digital linear tape | Half inch cartridge streaming tape drive | +| onLine | Online | Direct computer linkage | +| satellite | Satellite | Linkage through a satellite communication system | +| telephoneLink | Telephone link | Communication through a telephone network | +| hardcopy | Hardcopy | Pamphlet or leaflet giving descriptive information | + +### Standard codelists Obligation code (gmd:MD_ObligationCode) {#iso19139-cl-gmd-MD_ObligationCode} + +| code | label | description | +|-------------|-------------|------------------------------------------------------| +| mandatory | Mandatory | Element is always required | +| optional | Optional | Element is not required | +| conditional | Conditional | Element is required when a specific condition is met | + +### Standard codelists Pixel orientation code (gmd:MD_PixelOrientationCode) {#iso19139-cl-gmd-MD_PixelOrientationCode} + +| code | label | description | +|------------|-------------|----------------------------------------------------------------------------------------------------------------------------------------------| +| center | Center | Point halfway between the lower left and the upper right of the pixel | +| lowerLeft | Lower left | The corner in the pixel closest to the origin of the SRS; if two are at the same distance from the origin, the one with the smallest x-value | +| lowerRight | Lower right | Next corner counterclockwise from the lower left | +| upperRight | Upper right | Next corner counterclockwise from the lower right | +| upperLeft | Upper left | Next corner counterclockwise from the upper right | + +### Standard codelists Progress (gmd:MD_ProgressCode) {#iso19139-cl-gmd-MD_ProgressCode} + +| code | label | description | +|-------------------|--------------------|--------------------------------------------------------------------------------------| +| completed | Completed | Production of the data has been completed | +| historicalArchive | Historical archive | Data has been stored in an offline storage facility | +| obsolete | Obsolete | Data is no longer relevant | +| onGoing | On going | Data is continually being updated | +| planned | Planned | Fixed date has been established upon or by which the data will be created or updated | +| required | Required | Data needs to be generated or updated | +| underDevelopment | Under development | Data is currently in the process of being created | + +Those values are defined in the standard but hidden when editing. + +| code | label | description | +|-------------|--------------|-------------| +| notobsolete | Not obsolete | | + +### Standard codelists Access Restriction (gmd:MD_RestrictionCode) {#iso19139-cl-gmd-MD_RestrictionCode} + +| code | label | description | +|----------------------------|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| copyright | Copyright | Exclusive right to the publication, production, or sale of the rights to a literary, dramatic, musical, or artistic work, or to the use of a commercial print or label, granted by law for a specified period of time to an author, composer, artist, distributor | +| patent | Patent | Government has granted exclusive right to make, sell, use or license an invention or discovery | +| patentPending | Pending patent | Produced or sold information awaiting a patent | +| trademark | Trademark | A name, symbol, or other device identifying a product, officially registered and legally restricted to the use of the owner or manufacturer | +| license | License | Formal permission to do something | +| intellectualPropertyRights | Intellectual property rights | Rights to financial benefit from and control of distribution of non-tangible property that is a result of creativity | +| restricted | Restricted | Withheld from general circulation or disclosure | +| otherRestrictions | Other restrictions | Limitation not listed | + +### Standard codelists Scope code (gmd:MD_ScopeCode) {#iso19139-cl-gmd-MD_ScopeCode} + +| code | label | description | +|----------------------|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| attribute | Attribute | Information applies to the attribute class | +| attributeType | Attribute type | Information applies to the characteristic of a feature | +| collectionHardware | Collection hardware | Information applies to the collection hardware class | +| collectionSession | Collection session | Information applies to the collection session | +| dataset | Dataset | Information applies to the dataset | +| series | Series | Information applies to the series | +| nonGeographicDataset | Non geographic dataset | Information applies to non-geographic data | +| dimensionGroup | Dimension group | Information applies to a dimension group | +| feature | Feature | Information applies to a feature | +| featureType | Feature type | Information applies to a feature type | +| propertyType | Property type | Information applies to a property type | +| fieldSession | Field session | Information applies to a field session | +| software | Software | Information applies to a computer program or routine | +| service | Service | Information applies to a capability which a service provider entity makes available to a service user entity through a set of interfaces that define a behaviour, such as a use case | +| model | Model | Information applies to a copy or imitation of an existing or hypothetical object | +| tile | Tile | Information applies to a tile, a spatial subset of geographic data | + +Those values are defined in the standard but hidden when editing. + +| code | label | description | +|---------------------------------------------|------------------------------------------------|-------------| +| map staticMap interactiveMap featureCatalog | Map Static map Interactive map Feature catalog | | + +Displayed only if + +: + +> /ancestor::node()[name()='gmd:MD_Metadata']/gmd:identificationInfo/srv:SV_ServiceIdentification + +### Standard codelists Scope code (gmd:MD_ScopeCode) + +| code | label | description | +|---------|---------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| service | Service | Information applies to a capability which a service provider entity makes available to a service user entity through a set of interfaces that define a behaviour, such as a use case | + +### Standard codelists Spatial Representation Type (gmd:MD_SpatialRepresentationTypeCode) {#iso19139-cl-gmd-MD_SpatialRepresentationTypeCode} + +| code | label | description | +|-------------|--------------|----------------------------------------------------------------------------------------------------| +| vector | Vector | Vector data is used to represent geographic data | +| grid | Grid | Grid data is used to represent geographic data | +| textTable | Text, table | Textual or tabular data is used to represent geographic data | +| tin | TIN | Triangulated irregular network | +| stereoModel | Stereo model | Three-dimensional view formed by the intersecting homologous rays of an overlapping pair of images | +| video | Video | Scene from a video recording | + +### Standard codelists Topic category code (gmd:MD_TopicCategoryCode) {#iso19139-cl-gmd-MD_TopicCategoryCode} + +| code | label | description | +|----------------------------------|--------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| farming | Farming | Rearing of animals and/or cultivation of plants. Examples: agriculture, irrigation, aquaculture, plantations, herding, pests and diseases affecting crops and livestock | +| biota | Biota | Flora and/or fauna in natural environment. Examples: wildlife, vegetation, biological sciences, ecology, wilderness, sealife, wetlands, habitat | +| boundaries | Boundaries | Legal land descriptions. Examples: political and administrative boundaries | +| climatologyMeteorologyAtmosphere | Climatology, meteorology, atmosphere | Processes and phenomena of the atmosphere. Examples: cloud cover, weather, climate, atmospheric conditions, climate change, precipitation | +| economy | Economy | Economic activities, conditions and employment. Examples: production, labour, revenue, commerce, industry, tourism and ecotourism, forestry, fisheries, commercial or subsistence hunting, exploration and exploitation of resources such as minerals, oil and gas | +| elevation | Elevation | Height above or below sea level. Examples: altitude, bathymetry, digital elevation models, slope, derived products | +| environment | Environment | Environmental resources, protection and conservation. Examples: environmental pollution, waste storage and treatment, environmental impact assessment, monitoring environmental risk, nature reserves, landscape | +| geoscientificInformation | Geoscientific information | Information pertaining to earth sciences. Examples: geophysical features and processes, geology, minerals, sciences dealing with the composition, structure and origin of the earth s rocks, risks of earthquakes, volcanic activity, landslides, gravity information, soils, permafrost, hydrogeology, erosion | +| health | Health | Health, health services, human ecology, and safety. Examples: disease and illness, factors affecting health, hygiene, substance abuse, mental and physical health, health services | +| imageryBaseMapsEarthCover | Imagery base maps earth cover | Base maps. Examples: land cover, topographic maps, imagery, unclassified images, annotations | +| intelligenceMilitary | Intelligence military | Military bases, structures, activities. Examples: barracks, training grounds, military transportation, information collection | +| inlandWaters | Inland waters | Inland water features, drainage systems and their characteristics. Examples: rivers and glaciers, salt lakes, water utilization plans, dams, currents, floods, water quality, hydrographic charts | +| location | Location | Positional information and services. Examples: addresses, geodetic networks, control points, postal zones and services, place names | +| oceans | Oceans | Features and characteristics of salt water bodies (excluding inland waters). Examples: tides, tidal waves, coastal information, reefs | +| planningCadastre | Planning cadastre | Information used for appropriate actions for future use of the land. Examples: land use maps, zoning maps, cadastral surveys, land ownership | +| society | Society | Characteristics of society and cultures. Examples: settlements, anthropology, archaeology, education, traditional beliefs, manners and customs, demographic data, recreational areas and activities, social impact assessments, crime and justice, census information | +| structure | Structure | Man-made construction. Examples: buildings, museums, churches, factories, housing, monuments, shops, towers | +| transportation | Transportation | Means and aids for conveying persons and/or goods. Examples: roads, airports/airstrips, shipping routes, tunnels, nautical charts, vehicle or vessel location, aeronautical charts, railways | +| utilitiesCommunication | Utilities communication | Energy, water and waste systems and communications infrastructure and services. Examples: hydroelectricity, geothermal, solar and nuclear sources of energy, water purification and distribution, sewage collection and disposal, electricity and gas distribution, data communication, telecommunication, radio, communication networks | + +### Standard codelists Topology Level (gmd:MD_TopologyLevelCode) {#iso19139-cl-gmd-MD_TopologyLevelCode} + +| code | label | description | +|------------------|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| geometryOnly | Geometry only | Geometry objects without any additional structure which describes topology | +| topology1D | Topology 1D | 1-dimensional topological complex -- commonly called chain-node topology | +| planarGraph | Planar graph | 1-dimensional topological complex that is planar. (A planar graph is a graph that can be drawn in a plane in such a way that no two edges intersect except at a vertex.) | +| fullPlanarGraph | Full planar graph | 2-dimensional topological complex that is planar. (A 2-dimensional topological complex is commonly called full topology in a cartographic 2D environment.) | +| surfaceGraph | Surface graph | 1-dimensional topological complex that is isomorphic to a subset of a surface. (A geometric complex is isomorphic to a topological complex if their elements are in a one-to-one, dimensional-and boundry-preserving correspondence to one another.) | +| fullSurfaceGraph | Full surface graph | 2-dimensional topological complex that is isomorphic to a subset of a surface | +| topology3D | Topology 3D | 3-dimensional topological complex. (A topological complex is a collection of topological primitives that are closed under the boundary operations.) | +| fullTopology3D | Full topology 3D | Complete coverage of a 3D Euclidean coordinate space | +| abstract | Abstract | Topological complex without any specified geometric realisation | + +### Standard codelists (gmd:MX_ScopeCode) {#iso19139-cl-gmd-MX_ScopeCode} + +| code | label | description | +|----------------------|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| attribute | Attribute | Information applies to the attribute class | +| attributeType | Attribute type | Information applies to the characteristic of a feature | +| collectionHardware | Collection hardware | Information applies to the collection hardware class | +| collectionSession | Collection session | Information applies to the collection session | +| dataset | Dataset | Information applies to the dataset | +| series | Series | Information applies to the series | +| nonGeographicDataset | Non geographic dataset | Information applies to non-geographic data | +| dimensionGroup | Dimension group | Information applies to a dimension group | +| feature | Feature | Information applies to a feature | +| featureType | Feature type | Information applies to a feature type | +| propertyType | Property type | Information applies to a property type | +| fieldSession | Field session | Information applies to a field session | +| software | Software | Information applies to a computer program or routine | +| service | Service | Information applies to a capability which a service provider entity makes available to a service user entity through a set of interfaces that define a behaviour, such as a use case | +| model | Model | Information applies to a copy or imitation of an existing or hypothetical object | +| tile | Tile | Information applies to a tile, a spatial subset of geographic data | +| initiative | Initiative | The referencing entity applies to a transfer aggregate which was originally identified as an initiative (DS_Initiative) | +| stereomate | Stereo mate | The referencing entity applies to a transfer aggregate which was originally identified as a stereo mate (DS_StereoMate) | +| sensor | Sensor | The referencing entity applies to a transfer aggregate which was originally identified as a sensor (DS_Sensor) | +| platformSeries | Platform series | The referencing entity applies to a transfer aggregate which was originally identified as a platform series (DS_PlatformSeries) | +| sensorSeries | Sensor series | The referencing entity applies to a transfer aggregate which was originally identified as a sensor series (DS_SensorSeries) | +| productionSeries | Production series | The referencing entity applies to a transfer aggregate which was originally identified as a production series (DS_ProductionSeries) | +| transferAggregate | Transfer aggregate | The referencing entity applies to a transfer aggregate which has no existence outside of the transfer context | +| otherAggregate | Other aggregate | The referencing entity applies to a transfer aggregate which has an existence outside of the transfer context, but which does not pertains to a specific aggregate type. | + +### Standard codelists Distributed Computing Platforms list (srv:DCPList) {#iso19139-cl-srv-DCPList} + +| description | code | label | +|--------------------|-------------|--------------| +| DCP is XML | XML | XML | +| DCP is CORBA | CORBA | CORBA | +| DCP is JAVA | JAVA | JAVA | +| DCP is COM | COM | COM | +| DCP is SQL | SQL | SQL | +| DCP is WebServices | WebServices | Web services | + +### Standard codelists Coupling Type (srv:SV_CouplingType) {#iso19139-cl-srv-SV_CouplingType} + +| code | label | description | +|-------|-------|-------------------------------------------------------------------------------| +| tight | Tight | Tightly coupled: data associated | +| mixed | Mixed | Mixed coupled: data associated; in addition, external data might be processed | +| loose | Loose | Loosely coupled: no data associated | + +### Standard codelists Parameter direction (srv:SV_ParameterDirection) {#iso19139-cl-srv-SV_ParameterDirection} + +| code | label | +|--------|--------------| +| in | Input | +| out | Output | +| in/out | Input/output | + +### Standard codelists (SDS_category) {#iso19139-cl-SDS_category} + +| code | label | description | +|------------------------------------------------------------------------|---------------|---------------| +| | harmonised | Harmonised | +| | interoperable | Interoperable | +| | invocable | Invocable | + +### Standard codelists (SDS_DCP) {#iso19139-cl-SDS_DCP} + +| code | label | description | +|-------------|--------------|--------------| +| xml | XML | XML | +| corba | CORBA | CORBA | +| java | JAVA | JAVA | +| com | COM | COM | +| sql | SQL | SQL | +| webServices | Web Services | Web Services | + +### Standard codelists Nil reason (gco:nilReason) {#iso19139-cl-gco-nilReason} + +| code | label | +|--------------|--------------| +| missing | Missing | +| inapplicable | Inapplicable | +| template | Template | +| unknown | Unknown | +| withheld | Withheld | + +### Standard codelists Indeterminate position (indeterminatePosition) {#iso19139-cl-indeterminatePosition} + +| code | label | +|---------|---------| +| after | After | +| before | Before | +| now | Now | +| unknown | Unknown | diff --git a/docs/manual/docs/api/csw.md b/docs/manual/docs/api/csw.md new file mode 100644 index 00000000000..672b1f85fdf --- /dev/null +++ b/docs/manual/docs/api/csw.md @@ -0,0 +1,79 @@ +# OGC Catalog Service (CSW) {#csw-api} + +The CSW end point exposes the metadata records in your catalog in XML format using the OGC CSW protocol (version 2.0.2). + +Two Catalogue Service profiles are available: + +- Catalogue Services for the Web (CSW): Provides the ability to search and publish metadata for data, services and related information. +- Catalogue Services for the Web Transaction (CSW-T): Provides additional operations for creating, modifying and deleting catalog records via the CSW protocol. + +Reference: + +* [Catalogue Service](https://www.ogc.org/standard/cat/) (OGC) + +## Configuration + +See [Configuring CSW](../administrator-guide/configuring-the-catalog/csw-configuration.md) for details of how to configure the CSW end point. + +## URL + +The following URL is the standard end point for the catalog (substitute your GeoNetwork URL): + +- ? + +Generally, the `VERSION` and `SERVICE` parameter are also added, along with the `REQUEST` parameter as detailed below: + +- + +## Requests + +The full set of requests supported by GeoNetwork can be found in `CSW test`, in the `Settings` section of the Admin Dashboard. + +See [Configuring CSW](../administrator-guide/configuring-the-catalog/csw-configuration.md) for more details of this function. + +When using the GetRecords operation for searching, 2 types of parameter can be use for searching: + +- The list of queryable listed in the GetCapabilities document +- The fields in the index + +Example of a request using a standard queryable: + +``` xml + + + + + + OnlineResourceType + OGC:WFS-1.1.0-http-get-feature + + + + + +``` + +Example of a request using an index field name: + +``` xml + + + + + + linkProtocol + OGC:WMS + + + + + +``` + +The mapping between CSW standard queryable and the index fields are defined in **`web/src/main/webapp/WEB-INF/config-csw.xml`**. + +## Upgrading from GeoNetwork 3.0 Guidance + +The configuration of "Virtual CSW" end-points are replaced by [sub-portals](../administrator-guide/configuring-the-catalog/portal-configuration.md). diff --git a/docs/manual/docs/api/img/admin-console-api.png b/docs/manual/docs/api/img/admin-console-api.png new file mode 100644 index 00000000000..156e75cb5a0 Binary files /dev/null and b/docs/manual/docs/api/img/admin-console-api.png differ diff --git a/docs/manual/docs/api/img/dcat-in-download-menu.png b/docs/manual/docs/api/img/dcat-in-download-menu.png new file mode 100644 index 00000000000..5de86b80f02 Binary files /dev/null and b/docs/manual/docs/api/img/dcat-in-download-menu.png differ diff --git a/docs/manual/docs/api/img/geonetwork-api-document.png b/docs/manual/docs/api/img/geonetwork-api-document.png new file mode 100644 index 00000000000..20b1a59c511 Binary files /dev/null and b/docs/manual/docs/api/img/geonetwork-api-document.png differ diff --git a/docs/manual/docs/api/img/geonetwork-api-html.png b/docs/manual/docs/api/img/geonetwork-api-html.png new file mode 100644 index 00000000000..743172258d7 Binary files /dev/null and b/docs/manual/docs/api/img/geonetwork-api-html.png differ diff --git a/docs/manual/docs/api/img/geonetwork-api-test.png b/docs/manual/docs/api/img/geonetwork-api-test.png new file mode 100644 index 00000000000..a753a469904 Binary files /dev/null and b/docs/manual/docs/api/img/geonetwork-api-test.png differ diff --git a/docs/manual/docs/api/img/googlesheets-fn.png b/docs/manual/docs/api/img/googlesheets-fn.png new file mode 100644 index 00000000000..b73d2347c47 Binary files /dev/null and b/docs/manual/docs/api/img/googlesheets-fn.png differ diff --git a/docs/manual/docs/api/img/googlesheets-script.png b/docs/manual/docs/api/img/googlesheets-script.png new file mode 100644 index 00000000000..6d7fe0ea990 Binary files /dev/null and b/docs/manual/docs/api/img/googlesheets-script.png differ diff --git a/docs/manual/docs/api/img/swagger-search-endpoint.png b/docs/manual/docs/api/img/swagger-search-endpoint.png new file mode 100644 index 00000000000..881492551c2 Binary files /dev/null and b/docs/manual/docs/api/img/swagger-search-endpoint.png differ diff --git a/docs/manual/docs/api/index.md b/docs/manual/docs/api/index.md new file mode 100644 index 00000000000..e27bd0ec161 --- /dev/null +++ b/docs/manual/docs/api/index.md @@ -0,0 +1,24 @@ +# API Guide + +The API guide describes entry points that can be used to interact with the catalog. + +- [GeoNetwork API](the-geonetwork-api.md) + + The GeoNetwork API allows to manage all the catalog (eg. users, groups, editing, formatter, processing). + +- [Search Service](search.md) + + The main GeoNetwork search service for fast and flexible record retrieval. + +- [Catalog Service for the Web](csw.md) + + The OGC Industry standard to search, retrieve record in XML format. Can be used to manage records with transaction operation. + +No longer supported: + +- [INSPIRE ATOM](inspire_atom.md) +- [Open Archive Initiative](oai-pmh.md) +- [OpenSearch](opensearch.md) +- [Q Search](q-search.md) +- [RDF DCAT](rdf-dcat.md) +- [Z39-50](z39-50.md) diff --git a/docs/manual/docs/api/inspire_atom.md b/docs/manual/docs/api/inspire_atom.md new file mode 100644 index 00000000000..06430c45101 --- /dev/null +++ b/docs/manual/docs/api/inspire_atom.md @@ -0,0 +1,18 @@ +## INSPIRE ATOM + +The INSPIRE technical guideline for download services facilitates an option to set up a download service based on OpenSearch and Atom. A separate OpenSearch endpoint is created for every Atom-based download service. + +!!! note + + Only records based on the ISO19139 standard can be used with Atom. ISO19115-3 records are not. + + +A remote ATOM feed can be registered in a metadata record (see [Linking data using ATOM feeds](../user-guide/associating-resources/linking-online-resources.md#linking-data-using-atom-feed)), but the catalog can also create ATOM feeds from records describing datasets and services. + +For a service metadata record, the corresponding ATOM feed is accessed at: `http://localhost:8080/geonetwork/srv/atom/describe/service?uuid=8b719ebd-646e-4963-b9e0-16b3c2a6d94e`. If the service is attached to one or more datasets (see [Linking a dataset with a service](../user-guide/associating-resources/linking-dataset-or-service.md)), then the feed will also expose each dataset as an `entry` in the feed. Check that the service type is set to `download` (if not, the dataset feed will return an exception). + +The dataset feed is accessible at: `http://localhost:8080/geonetwork/srv/atom/describe/dataset?spatial_dataset_identifier_code=b795de68-726c-4bdf-a62a-a42686aa5b6f`. Links will be created for each online resource flagged with a `function` set to `download`. + +Examples: + +- diff --git a/docs/manual/docs/api/oai-pmh.md b/docs/manual/docs/api/oai-pmh.md new file mode 100644 index 00000000000..0887cbeee36 --- /dev/null +++ b/docs/manual/docs/api/oai-pmh.md @@ -0,0 +1,20 @@ +# Open Archive Initiative (OAI) {#oai-pmh} + +!!! warning + + Unavailable since version 4.0.0. + + There is some interest migrating OAI-PMH to Elasticsearch engine used by GeoNetwork 4. + Interested parties are encouraged to contact the project team for direction on this topic. + +The Open Archives Initiative Protocol for Metadata Harvesting (OAI-PMH) standard exposes the metadata records in your catalog in an XML format defined by version 2.0 of the OAI-PMH protocol. + +Reference: + +* [Open Archives Initiative Protocol for Metadata Harvesting (OAI-PMH)](https://www.openarchives.org/OAI/openarchivesprotocol.html) + +## Upgrading from GeoNetwork 3.0 Guidance + +The OAI-PMH API is no longer available. + +Recommend migrating to use of [Catalog Service for the Web (CSW)](csw.md) API which provides XML document access. diff --git a/docs/manual/docs/api/opensearch.md b/docs/manual/docs/api/opensearch.md new file mode 100644 index 00000000000..d349117fc40 --- /dev/null +++ b/docs/manual/docs/api/opensearch.md @@ -0,0 +1,32 @@ +# OpenSearch + +!!! warning + + Unavailable since version 4.0.0. + + There is no known sponsor or interested party for implementing OpenSearch. + +The OpenSerach API provides a serivce description advertised in the HTML. + +Browsers detect the availability of opensearch by checking the index page at the root of the (sub)domain. Setup required defining a rewrite rule forwarding requests to the geonetwork application. + +Reference: + +* [OpenSearch](https://www.ogc.org/standard/opensearch/) (Open Geospatial Consortium) + +## Upgrading from GeoNetwork 3.0 Guidance + +OpenSearch API is no longer available. + +* Recommend migrating to [GeoNetwork OpenAPI](the-geonetwork-api.md) if html discoverability is of primary importance. + + This provides a self-describing service, and automation tools for developer access in different programming languages. + However the result is specific to the GeoNetwork application, and not an industry standard for interoperability. + +* Recommend migration to [OpenGIS Web Catalogue Service (CSW)](csw.md) if standards compliance is of primary importance. + +!!! note OGC API - Records + + The OGC API - Records standard is not yet ready, but is expected to provide the best of both worlds: html discoverability, and standards compliance. + + Interested parties are encouraged to contribute towards this roadmap activity. diff --git a/docs/manual/docs/api/q-search.md b/docs/manual/docs/api/q-search.md new file mode 100644 index 00000000000..e92850ae7f6 --- /dev/null +++ b/docs/manual/docs/api/q-search.md @@ -0,0 +1,13 @@ +# Q Search {#q-search} + +!!! warning + + Unavailable since version 4.0.0. + +The Q Search endpoint was built using the GeoNetwork 3.0 Lucene search engine and is no longer available. + +## Upgrading from GeoNetwork 3.0 Guidance + +The Q Search endpoint is replaced by the Elasticsearch ``/srv/api/search/records/_search`` endpoint. + +GeoNetwork 3.0 scripts will need to be migrated to the Elasticsearch API, using POST requests in the Elasticsearch syntax. diff --git a/docs/manual/docs/api/rdf-dcat.md b/docs/manual/docs/api/rdf-dcat.md new file mode 100644 index 00000000000..c8d5d2c135a --- /dev/null +++ b/docs/manual/docs/api/rdf-dcat.md @@ -0,0 +1,131 @@ +# DCAT {#rdf-dcat} + +The catalogue has the capability to convert ISO to DCAT format in various API endpoint. [The first implementation of DCAT output was done in 2012](https://trac.osgeo.org/geonetwork/wiki/proposals/DCATandRDFServices) and was targeting interaction with semantic service and semantic sitemap support. DCAT output was available using a service named `rdf.search`. This service was deprecated in version 4.0.0 in favor of producing DCAT output in the [Catalog Service for the Web (CSW)](csw.md) or using the formatters API. + + +## Supported DCAT profiles + +A base conversion is provided with complementary extensions for various profiles of DCAT developed in Europe: + +* a default DCAT export following W3C standard https://www.w3.org/TR/vocab-dcat-3/ +* an extension for the European DCAT-AP https://semiceu.github.io/DCAT-AP/releases/3.0.0/ + * an extension for the European GeoDCAT-AP https://semiceu.github.io/GeoDCAT-AP/releases/ + * an extension for the European DCAT-AP-Mobility https://mobilitydcat-ap.github.io/mobilityDCAT-AP/releases/1.0.0/index.html + * an extension for the European DCAT-AP-HVD https://semiceu.github.io/DCAT-AP/releases/2.2.0-hvd/ + +The mapping is done from ISO19115-3 to DCAT*. An ISO19139 to ISO19115-3 conversion can be applied before if needed. + +[The SEMICeu XSLT conversion](https://github.com/SEMICeu/iso-19139-to-dcat-ap/blob/master/iso-19139-to-dcat-ap.xsl)) is also included with minor improvements. This conversion is from ISO19139 to RDF and if needed a conversion from ISO19115-3 is applied. + +## Usage in the formatters API + +Each DCAT formats are available using a formatter eg. http://localhost:8080/geonetwork/srv/api/records/be44fe5a-65ca-4b70-9d29-ac5bf1f0ebc5/formatters/eu-dcat-ap?output=xml + +To add the formatter in the record view download list, the user interface configuration can be updated: + +![image](img/dcat-in-download-menu.png) + +```json +{ + "mods": { + "search": { + "downloadFormatter": [ + { + "label": "exportMEF", + "url": "/formatters/zip?withRelated=false", + "class": "fa-file-zip-o" + }, + { + "label": "exportPDF", + "url": "/formatters/xsl-view?output=pdf&language=${lang}", + "class": "fa-file-pdf-o" + }, + { + "label": "exportXML", + "url": "/formatters/xml", + "class": "fa-file-code-o" + }, + { + "label": "DCAT", + "url": "/formatters/dcat?output=xml" + }, + { + "label": "EU-DCAT-AP", + "url": "/formatters/eu-dcat-ap?output=xml" + }, + { + "label": "EU-GEO-DCAT-AP", + "url": "/formatters/eu-geodcat-ap?output=xml" + }, + { + "label": "EU-DCAT-AP-MOBILITY", + "url": "/formatters/eu-dcat-ap-mobility?output=xml" + }, + { + "label": "EU-DCAT-AP-HVD", + "url": "/formatters/eu-dcat-ap-hvd?output=xml" + } + ] +``` + + +## Usage in the CSW service + +All DCAT profiles are also accessible using CSW protocol. + +A `GetRecordById` operation can be used: http://localhost:8080/geonetwork/srv/eng/csw?SERVICE=CSW&VERSION=2.0.2&REQUEST=GetRecordById&ID=da165110-88fd-11da-a88f-000d939bc5d8&outputSchema=https://semiceu.github.io/DCAT-AP/releases/2.2.0-hvd/ and is equivalent to the API http://localhost:8080/geonetwork/srv/api/records/da165110-88fd-11da-a88f-000d939bc5d8/formatters/eu-dcat-ap-hvd?output=xml. + +A `GetRecords` operation can be used to retrieve a set of records: http://localhost:8080/geonetwork/srv/fre/csw?SERVICE=CSW&VERSION=2.0.2&REQUEST=GetRecords&outputSchema=http://data.europa.eu/930/&elementSetName=full&resultType=results&maxRecords=300 + +Use the `outputSchema` parameter to select the DCAT profile to use. The following values are supported: + +```xml + + http://data.europa.eu/930/ + http://data.europa.eu/930/#semiceu + http://data.europa.eu/r5r/ + http://standards.iso.org/iso/19115/-3/mdb/2.0 + http://www.isotc211.org/2005/gfc + http://www.isotc211.org/2005/gmd + http://www.opengis.net/cat/csw/2.0.2 + http://www.w3.org/ns/dcat# + http://www.w3.org/ns/dcat#core + https://semiceu.github.io/DCAT-AP/releases/2.2.0-hvd/ + https://w3id.org/mobilitydcat-ap +``` + +Those values are listed in the `GetCapabilities` operation http://localhost:8080/geonetwork/srv/eng/csw?SERVICE=CSW&VERSION=2.0.2&REQUEST=GetCapabilities. + +## Usage in OGC API Records + +For the time being, OGC API Records provides a simplified DCAT output (based on the index document). + +## DCAT validation + +The DCAT validation can be done using online validation tool: +* https://www.itb.ec.europa.eu/shacl/dcat-ap/upload + +Depending on the target DCAT profile to use, it may be required to build proper ISO template and metadata record containing all required fields. Usually profiles are adding constraints for usage of specific vocabularies and fields (eg. [for High Value datasets, specific vocabularies are defined for categories, license, applicable legislations, ...](https://semiceu.github.io/DCAT-AP/releases/2.2.0-hvd/#controlled-vocabularies-to-be-used)). + + +## Mapping considerations + +The mapping is done from ISO19115-3 to DCAT. The mapping may not cover all usages and may be adapted. This can be done in the `iso19115-3.2018` schema plugin in the `formatter/dcat*` XSLT files. + +Some points under discussion are: +* Object vs Reference: + * Should we use object or reference for some fields (eg. contact, organisation, ...)? + * What should be the reference URI? + * Where is defined the reference URI in ISO? + +eg. for an organisation, the URI will be the first value in the following sequence: +```xml +(cit:partyIdentifier/*/mcc:code/*/text(), +cit:contactInfo/*/cit:onlineResource/*/cit:linkage/gco:CharacterString/text(), +cit:name/gcx:Anchor/@xlink:href, +@uuid)[1] +``` + +* No equivalent field in ISO (eg. Where to store `spdx:checksum` in ISO?) + +* Associated resources: Links between are not always bidirectional so using the associated API would allow to populate more relations. This is also mitigated with the complete RDF graph of the catalogue is retrieved providing relations from all records. diff --git a/docs/manual/docs/api/search.md b/docs/manual/docs/api/search.md new file mode 100644 index 00000000000..c33350f8ad6 --- /dev/null +++ b/docs/manual/docs/api/search.md @@ -0,0 +1,162 @@ +# Search Service + +GeoNetwork provides a access to ***Elasticsearch*** `/srv/api/search/records/_search` and `/srv/api/search/records/_msearch` end-points. These endpoints accept `POST` requests, with request body containing an Elasticsearch JSON query. + +Reference + +- [Search API](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html) ( Elasticsearch Guide ) +- [Multi search API](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-multi-search.html) (Elasticsearch Guide) + +## Search API examples + +This section provides some query `POST` examples of `/srv/api/search/records/_search` end-point: + +1. To test examples navigate Swagger API documentation at `/srv/api/index.html` + +2. Locate the *search* heading, and the `/search/records/_search` `POST` end-point + +3. Use the *Try it out* button with: + + * **bucket**: `metadata` + * **relatedType**: + * **Request body**: Chosen from the examples below + +4. Press **Execute** to run the example. + + ![](img/swagger-search-endpoint.png) + +### Text search query + +Query with any field for metadata containing the string `infrastructure`, using a query with Lucene syntax and excluding metadata templates: + +```json +{ + "query": { + "bool": { + "must": [ + { + "query_string": { + "query": "+anytext:infrastructure " + } + } + ], + "filter": [ + { + "term": { + "isTemplate": { + "value": "n" + } + } + } + ] + } + } +} +``` + +### Subset results + +Query with any field for metadata containing the string `infrastructure`, using a query with Lucene syntax and excluding metadata templates, returning a subset of the information: + +```json +{ + "query": { + "bool": { + "must": [ + { + "query_string": { + "query": "+anytext:infrastructure " + } + } + ], + "filter": [ + { + "term": { + "isTemplate": { + "value": "n" + } + } + } + ] + } + }, + "_source": { + "includes": [ + "uuid", + "id", + "resourceType", + "resourceTitle*", + "resourceAbstract*" + ] + } +} +``` + +### Dataset query + +Query datasets with title containing the string `infrastructure`, using a query with Lucene syntax and excluding metadata templates: + +```json +{ + "query": { + "bool": { + "must": [ + { + "query_string": { + "query": "+anytext:infrastructure +resourceType:dataset" + } + } + ], + "filter": [ + { + "term": { + "isTemplate": { + "value": "n" + } + } + } + ] + } + } +} +``` + +### Revision date query + +Query datasets with a revision date in June 2019 and excluding metadata templates: + +```json +{ + "query": { + "bool": { + "must": [ + { + "term": { + "resourceType": { + "value": "dataset" + } + } + }, + { + "range": { + "resourceTemporalDateRange": { + "gte": "2019-06-01", + "lte": "2019-06-30", + "relation": "intersects" + } + } + } + ], + "filter": [ + { + "term": { + "isTemplate": { + "value": "n" + } + } + } + ] + } + } +} +``` diff --git a/docs/manual/docs/api/the-geonetwork-api.md b/docs/manual/docs/api/the-geonetwork-api.md new file mode 100644 index 00000000000..0708f57c4bb --- /dev/null +++ b/docs/manual/docs/api/the-geonetwork-api.md @@ -0,0 +1,481 @@ +# GeoNetwork API + +The REST API and documentation are available in your catalog at page and linked from the footer on the home page. + +Reference: + +* [OpenAPI Specification](https://swagger.io/specification/) (swagger.io) + +## GeoNetwork API Access + +GeoNetwork API is provided as a self-describing OpenAPI document, browsable in html form, and avaialble as JSON or XML for script interactions. + +1. The API is available from the **Admin Console --> Catalogue admin tools** page: + + * http://localhost:8080/geonetwork/doc/api/index.html + + ![](img/admin-console-api.png) + **Catalogue admin tools** + +2. The OpenAPI document is browsable as an html page: + + ![](img/geonetwork-api-html.png) + **GeoNetwork API OpenAPI document** + +3. The page documents each service end-point, including parameters and output results. + + ![](img/geonetwork-api-document.png) + **GeoNetwork API Service Endpoint Description** + +4. Selecting **Server variables** at the top of the page allows API testing: + + ![](img/geonetwork-api-test.png) + **GeoNetwork API Service Endpoint Test** + +5. The OpenAPI document is also available as `text/json` and `text/xml` for script access: + + * https://localhost:8080/geonetwork/srv/api/doc + + ```json + { + "openapi": "3.0.1", + "info": { + "title": "GeoNetwork 4.0.1 OpenAPI Documentation", + "description": "This is the description of the GeoNetwork OpenAPI. Use this API to manage your catalog.", + "contact": { + "name": "GeoNetwork user mailing list", + "url": "https://sourceforge.net/p/geonetwork/mailman/geonetwork-users/", + "email": "geonetwork-users@lists.sourceforge.net" + }, + "license": { + "name": "GPL 2.0", + "url": "http://www.gnu.org/licenses/old-licenses/gpl-2.0.html" + }, + "version": "4.0.1" + }, + { + "description": "Learn how to access the catalog using the GeoNetwork REST API.", + "url": "http://localhost:8080/geonetwork/doc/api" + }, + ... + ``` + +## Upgrading from GeoNetwork 3 Guidance + +In version `4.0.1` onward the API description is provided using OpenAPI specification: + +- The version of the API correspond to the version of the GeoNetwork instance when the API changed. + +- The GeoNetwork API version number is indicated in the `html` page title available + +- The GeoNetwork API version number is available to scripts at in the `json` or `xml` info description. + +- Previously in GeoNetwork 3 the GeoNetwork API version was included in the path, ``/srv/api/0.1/\...`` + +!!! warning + + Lucene is no longer available, replaced by Elasticsearch. + +!!! warning + + The GeoNetwork API support for Report Uploads has not been migrated. + + Interested parties may contact the project team for guidance and to express their intent. + +!!! warning + + XLink / Remove directory entry used in other record has not been migrated. + + Interested parties may contact the project team for guidance and to express their intent. + + +## Using the API to apply an XSL process + +This is an example to trigger an XSL process on a set of records. It illustrates how to make a set of actions using the API: + +``` shell +CATALOG=http://localhost:8080/geonetwork +CATALOGUSER=admin +CATALOGPASS=admin +PROCESS=migrate-201904 + +rm -f /tmp/cookie; +curl -s -c /tmp/cookie -o /dev/null \ + -X GET \ + -H "Accept: application/json" \ + "$CATALOG/srv/api/me"; +TOKEN=`grep XSRF-TOKEN /tmp/cookie | cut -f 7`; +curl \ + -X GET \ + -H "Accept: application/json" \ + -H "X-XSRF-TOKEN: $TOKEN" --user $CATALOGUSER:$CATALOGPASS -b /tmp/cookie \ + "$CATALOG/srv/api/me" + +# MUST return user details + +curl -X POST "$CATALOG/srv/api/search/records/_search?bucket=111" \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json;charset=utf-8' \ + -H "X-XSRF-TOKEN: $TOKEN" -c /tmp/cookie -b /tmp/cookie --user $CATALOGUSER:$CATALOGPASS \ + -d '{"from":0,"size":0,"query":{"query_string":{"query":"+linkUrl:*data-and-maps*"}}}' + + +curl -X PUT "$CATALOG/srv/api/selections/111" -H "accept: application/json" \ + -H "X-XSRF-TOKEN: $TOKEN" -c /tmp/cookie -b /tmp/cookie --user $CATALOGUSER:$CATALOGPASS +#Body response = number of selected records + +curl -X GET "$CATALOG/srv/api/selections/111" -H "accept: application/json" \ + -H "X-XSRF-TOKEN: $TOKEN" -c /tmp/cookie -b /tmp/cookie --user $CATALOGUSER:$CATALOGPASS +#Body returns an array of selected records + +curl -X POST "$CATALOG/srv/api/processes/$PROCESS?bucket=111&index=false" \ + -H "accept: application/json" -H "X-XSRF-TOKEN: $TOKEN" -c /tmp/cookie -b /tmp/cookie --user $CATALOGUSER:$CATALOGPASS +``` + +## Loop on search results and apply changes (processing and batch editing) + +This is an example to highlight how to loop over specific search results (here only series) and apply various changes: + +``` shell +SERVER=http://localhost:8080/geonetwork +CATALOGUSER=admin +CATALOGPASS=admin + +type=series +from=0 +size=1000 + +rm results.json +rm -f /tmp/cookie; + +curl -s -c /tmp/cookie -o /dev/null \ + -X GET \ + --user $CATALOGUSER:$CATALOGPASS \ + -H "Accept: application/json" \ + "$SERVER/srv/api/me"; + +TOKEN=`grep XSRF-TOKEN /tmp/cookie | cut -f 7`; +JSESSIONID=`grep JSESSIONID /tmp/cookie | cut -f 7`; + +curl "$SERVER/srv/api/search/records/_search" \ + -X 'POST' \ + -H 'Accept: application/json, text/plain, */*' \ + -H 'Content-Type: application/json;charset=UTF-8' \ + --data-raw "{\"query\":{\"query_string\":{\"query\": \"+isHarvested:false +resourceType: $type\"}},\"from\":$from, \"size\":$size, \"_source\": {\"include\": [\"resourceTitleObject.default\"]}, \"sort\": [{\"resourceTitleObject.default.keyword\": \"asc\"}]}" \ + -H "X-XSRF-TOKEN: $TOKEN" -H "Cookie: XSRF-TOKEN=$TOKEN; JSESSIONID=$JSESSIONID" \ + --compressed \ + -o results.json + +for hit in $(jq -r '.hits.hits[] | @base64' results.json); do + _jq() { + echo "${hit}" | base64 --decode | jq -r "${1}" + } + + title=$(_jq '._source.resourceTitleObject.default') + uuid=$(_jq '._id') + echo "__________" + echo "### $uuid" + + # Update series from its members using XSL process + curl $AUTH "$SERVER/srv/api/records/$uuid/processes/collection-updater" \ + -X 'POST' \ + -H 'Accept: application/json, text/plain, */*' \ + -H "X-XSRF-TOKEN: $TOKEN" \ + -H "Cookie: XSRF-TOKEN=$TOKEN; JSESSIONID=$JSESSIONID" \ + --compressed + + curl $AUTH "$SERVER/srv/api/selections/s101" \ + -X 'DELETE' \ + -H 'Accept: application/json, text/javascript, */*; q=0.01' \ + -H "X-XSRF-TOKEN: $TOKEN" \ + -H "Cookie: XSRF-TOKEN=$TOKEN; JSESSIONID=$JSESSIONID" \ + --compressed + + curl $AUTH "$SERVER/srv/api/selections/s101?uuid=$uuid" \ + -X 'PUT' \ + -H 'Accept: application/json, text/javascript, */*; q=0.01' \ + -H "X-XSRF-TOKEN: $TOKEN" \ + -H "Cookie: XSRF-TOKEN=$TOKEN; JSESSIONID=$JSESSIONID" \ + --compressed + + # Keep only the first 2 resource identifiers using batch editing + curl $AUTH "$SERVER/srv/api/records/batchediting?bucket=s101" \ + -X 'PUT' \ + -H 'Accept: application/json, text/plain, */*' \ + -H 'Content-Type: application/json;charset=UTF-8' \ + -H "X-XSRF-TOKEN: $TOKEN" \ + -H "Cookie: XSRF-TOKEN=$TOKEN; JSESSIONID=$JSESSIONID" \ + --data-raw "[{\"xpath\":\"/gmd:identificationInfo/*/gmd:citation/*/gmd:identifier[position() > 2]\",\"value\":\"\"}]" \ + --compressed +done; +``` + +## Using the search API in Google sheet + +In Extensions --> App script create a new function. Here we create a function which run a search and return a list of matching UUIDs: + +![](img/googlesheets-script.png) + +``` js +function getUuidForSearch(query) { + var options = { + 'method' : 'post', + 'contentType': 'application/json', + 'payload' : "{\"query\":{\"query_string\":{\"query\":\"" + query + "\"}}}" + }; + var response = UrlFetchApp.fetch('http://localhost:8080/catalogue/srv/api/search/records/_search', options); + var hits = JSON.parse(response).hits; + Logger.log(hits.hits); + return hits.hits.length > 0 ? hits.hits.map(function(v) {return v._id}).join('###') : null; +} +``` + +Then use the function in formula. Here we search for records matching particular keywords: + +![](img/googlesheets-fn.png) + +## Building client for the API using codegen + +The API is described using the Open API specification. [Codegen](https://swagger.io/swagger-codegen/) is a tool to build an API client based on the specification. To build a Java client use the following procedure. + +First, create a configuration file apiconfig.json for the API: + +``` json +{ + "groupId":"org.geonetwork-opensource", + "artifactId":"OpenApiClient", + "artifactVersion":"0.0.1", + "library":"okhttp-gson", + "apiPackage":"org.fao.geonet.openapi", + "modelPackage":"org.fao.geonet.openapi.model" +} +``` + +``` shell +java -jar swagger-codegen-cli.jar generate \ + -i http://localhost:8080/geonetwork/srv/v2/api-docs \ + -l java \ + -c apiconfig.json \ + -o /tmp/gn-openapi-java-client + +cd /tmp/gn-openapi-java-client + +mvn clean install +``` + +Once compiled, the Java client can be used as a dependency; eg. for Maven: + +``` xml + + org.geonetwork-opensource + OpenApiClient + 0.0.1 + +``` + +Then the client API can be used in your Java application: + +``` java +import com.squareup.okhttp.Interceptor; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.Response; +import org.fao.geonet.ApiClient; +import org.fao.geonet.ApiException; +import org.fao.geonet.Configuration; +import org.fao.geonet.openapi.MeApi; +import org.fao.geonet.openapi.RecordsApi; +import org.fao.geonet.openapi.model.MeResponse; +import org.fao.geonet.openapi.model.SimpleMetadataProcessingReport; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Base64; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class GnJavaApiClientTest { + + private static final String CATALOGUE_URL = "http://localhost:8080/geonetwork"; + + ApiClient client; + + private static final String USERNAME = "admin"; + private static final String PASSWORD = "admin"; + + + @BeforeAll + private void initConfiguration() { + client + = Configuration.getDefaultApiClient(); + client.setBasePath(CATALOGUE_URL); + } + + /** + * Get user information when anonymous or connected. + */ + @Test + public void getMeInfoTest() { + try { + client.getHttpClient().networkInterceptors().clear(); + + MeApi meApi = new MeApi(); + MeResponse meResponse = meApi.getMe(); + // User is not authenticated + assertEquals(null, meResponse); + + // Configure HTTP basic authorization: basicAuth + client.getHttpClient().networkInterceptors().add(new BasicAuthInterceptor(USERNAME, PASSWORD)); + + meResponse = meApi.getMe(); + // User is authenticated + assertEquals(USERNAME, meResponse.getName()); + + } catch (ApiException e) { + e.printStackTrace(); + } + } + + + /** + * Insert and delete a record. + */ + @Test + public void insertAndDeleteRecord() { + + // Configure HTTP basic authorization: basicAuth + client.getHttpClient().networkInterceptors().add(new BasicAuthInterceptor(USERNAME, PASSWORD)); + + + try { + final RecordsApi api = new RecordsApi(); + + SimpleMetadataProcessingReport report = api.insert("METADATA", + null, + Arrays.asList(new String[]{"http://sextant.ifremer.fr/geonetwork/srv/fre/xml.metadata.get?uuid=ec41b8b2-c184-46e7-86c6-a24f0ac295ad"}), + null, null, + true, "NOTHING", + null, + null, + false, + null, + null, + null); + + int nbOfRecordInserted = report.getMetadataInfos().size(); + + + // One record MUST be inserted + assertEquals(1, nbOfRecordInserted); + + if (nbOfRecordInserted == 1) { + Object[] list = report.getMetadataInfos().keySet().toArray(); + String metadataId = (String) list[0]; + String record = api.getRecord(metadataId, "application/xml"); + assertNotNull(record); + + api.deleteRecord(metadataId, false); + + try { + api.getRecord(metadataId, "application/xml"); + } catch (ApiException e) { + assertEquals(404, e.getCode()); + } + } + } catch (ApiException e) { + e.printStackTrace(); + } + } + + + /** + * Interceptor to add basic authentication header on each request. + *

    + * TODO: How-to make generated client taking care of setting BA from swagger config. + * TODO: Add support for CSRF token. + */ + public class BasicAuthInterceptor implements Interceptor { + String username; + String password; + + public BasicAuthInterceptor(String username, String password) { + this.username = username; + this.password = password; + } + + @Override + public Response intercept(Interceptor.Chain chain) throws IOException { + byte[] auth = Base64.getEncoder() + .encode((username + ":" + password).getBytes()); + + Request compressedRequest = chain.request().newBuilder() + .header("Authorization", "Basic " + new String(auth)) + .build(); + + return chain.proceed(compressedRequest); + } + } +} +``` + +## Connecting to the API with python + +This is an example of how to use requests in python to authenticate to the API and generate an XRSF token. + +``` python +import requests + +# Set up your username and password: +username = 'username' +password = 'password' + +# Set up your server and the authentication URL: +server = "http://localhost:8080" +authenticate_url = server + '/geonetwork/srv/eng/info?type=me' + +# To generate the XRSF token, send a post request to the following URL: http://localhost:8080/geonetwork/srv/eng/info?type=me +session = requests.Session() +response = session.post(authenticate_url) + +# Extract XRSF token +xsrf_token = response.cookies.get("XSRF-TOKEN") +if xsrf_token: + print ("The XSRF Token is:", xsrf_token) +else: + print("Unable to find the XSRF token") + +# You can now use the username and password, along with the XRSF token to send requests to the API. + +# This example will add an online resource to a specified UUID using the http://localhost:8080/geonetwork/srv/api/records/batchediting endpoint + +# Set header for connection +headers = {'Accept': 'application/json', +'X-XSRF-TOKEN': xsrf_token +} + +# Set the parameters +params = {'uuids': 'the uuid to be updated', +'bucket': 'bucketname', +'updateDateStamp': 'true', +} + +# Set the JSON data: note that the value must have one of , , or +json_data = [{'condition': '', +'value': 'https://localhostWWW:LINK-1.0-http--linkThe Title of the URLThe description of the resource', +'xpath': '/gmd:MD_Metadata/gmd:distributionInfo/gmd:MD_Distribution/gmd:transferOptions/gmd:MD_DigitalTransferOptions', +}, +] + +# Send a put request to the endpoint +response = session.put(server + 'geonetwork/srv/api/records/batchediting', +params=params, +auth = (username, password), +headers=headers, +json=json_data, +) +print(response.text) +``` diff --git a/docs/manual/docs/api/z39-50.md b/docs/manual/docs/api/z39-50.md new file mode 100644 index 00000000000..299c6c35063 --- /dev/null +++ b/docs/manual/docs/api/z39-50.md @@ -0,0 +1,20 @@ +# Z39-50 + +!!! warning + + Unavailable since version 4.0.0. + + There is no known sponsor or interested party for implementing Z39.50. + Interested parties may contact the project team for guidance and to express their intent. + +Z39.50 is the name of an older communication protocol used for distributed searching across metadata catalogs. + +Reference: + +* [ISO 23950:1998 Information and documentation Information retrieval (Z39.50)](https://www.iso.org/standard/27446.html) + +## Upgrading from GeoNetwork 3.0 Guidance + +Z39-50 API is no longer available. + +Recommend migrating to use of [Catalog Service for the Web (CSW)](csw.md) API. diff --git a/docs/manual/docs/contributing/doing-a-release.md b/docs/manual/docs/contributing/doing-a-release.md new file mode 100644 index 00000000000..254ef9386c1 --- /dev/null +++ b/docs/manual/docs/contributing/doing-a-release.md @@ -0,0 +1,422 @@ +# Doing a GeoNetwork release {#doing-a-release} + +## Doing a release with scripts + +### Update Translations + +1. Update translations: + + ```bash + cd web-ui + ./download-from-transifex.sh + ``` + + Commit the changed files: + + ```bash + git add . + git commit -m "Transifix update" + ``` + +### Release Notes + +1. Prepare change-log notes. + + Git notes are managed in `ref/notes/commits` similar to push and pulling tags. Start by pulling the latest notes: + ``` + git fetch origin refs/notes/commits:refs/notes/commits + ``` + + Review changes along with any notes: + ``` + git log --pretty='format:%h: %s %n note: %N' $previousversion... + ``` + + Use `git note append` to document commits adding major features. + + ``` + git notes append -m "" + ``` + + Use `git note remove` if you need to clear a note and start again: + ``` + git notes remove + ``` + + Preview changes using: + + ``` + git log --pretty='format:* %N' $previousversion... | grep -v "^* $" + ``` + + Save your notes: + ``` + git push origin refs/notes/commits + ``` + +2. Generate release notes: + + ```bash + ./release-notes + ``` + + After the script runs it will produces: + + * ``docs/changes/changes4.4.4-0.txt`` + + The last couple commits here can be removed (from the release steps above). + + * ``docs/manual/docs/overview/change-log/version-4.4.4.md`` + + This file can be updated based on highlights from: [milestone closed issues](https://github.com/geonetwork/core-geonetwork/pulls?q=is%3Apr+milestone%3A4.4.4+is%3Aclosed) + + Filter using: + + * label: `changelog` as Major Features + * label: api change + * label: `index structure change` as Index + * label: `bug` as Fixes + +3. Update the navigation: + + * ``docs/manual/mkdocs.yml`` + * ``docs/manual/docs/overview/change-log/latest/index.md`` + +### Build the release locally + +1. Use release build script: + + ```bash + ./release-build.sh + ``` + +2. Startup Elasticsearch + +3. Remove local database: + + ```bash + rm ~/gn.mv.db + rm ~/gn.trace.db + ``` + +4. Test the release: + + ```bash + ./release-test.sh + ``` + +5. Smoke Test: + + * Load ISO19139 samples and templates + * Display a record and try each of the views, and the XML download + * Use Contributor board to create a new record (from the "preferred" template) + * Try validation (validation errors are expected we just wish to check it runs) + * Try each of the editor views + +### Publish the release + +1. Publish + + ```bash + ./release-publish.sh + ``` + +2. Cleanup + + ```bash + ./release-restore.sh + ``` + +## Doing a manual release + +This section documents the steps followed by the development team to do a new release. + +Once the release branch has been thoroughly tested and is stable a release can be made. + +The following script can be used on Linux and Mac. For this a running build environment is needed +with the following utilities: ***sed***, ***xmlstarlet*** and ***sftp***. + + +1. Prepare the release (examples prepairs version 4.4.1 as latest release): + + ``` shell + # Setup properties + from=origin + frombranch=origin/main + series=4.4 + versionbranch=$series.x + version=4.4.1 + minorversion=0 + release=latest + newversion=$version-$minorversion + currentversion=4.4.1-SNAPSHOT + previousversion=4.4.0 + nextversion=4.4.2-SNAPSHOT + nextMajorVersion=4.6.0-SNAPSHOT + + + # Get the branch + git clone --recursive https://github.com/geonetwork/core-geonetwork.git \ + geonetwork-$versionbranch + cd geonetwork-$versionbranch + + + # Create or move to the branch for the version + # Create it if it does not exist yet + git checkout -b $versionbranch $frombranch + # or move into it if it exist + # git checkout $versionbranch + # or stay in main branch if the release is on main + + + # Update version number (in pom.xml, installer config and SQL) + ./update-version.sh $currentversion $newversion + + # Generate list of changes + cat < docs/changes/changes$newversion.txt + ================================================================================ + === + === GeoNetwork $version: List of changes + === + ================================================================================ + EOF + git log --pretty='format:- %s' $previousversion... >> docs/changes/changes$newversion.txt + ``` + +2. Prepare change-log notes. + + Git notes are managed in `ref/notes/commits` similar to push and pulling tags. Start by pulling the latest notes: + ``` + git fetch origin refs/notes/commits:refs/notes/commits + ``` + + Review changes along with any notes: + ``` + git log --pretty='format:%h: %s %n note: %N' $previousversion... + ``` + + Use `git note append` to document commits adding major features. + + ``` + git notes append -m "" + ``` + + Use `git note remove` if you need to clear a note and start again: + ``` + git notes remove + ``` + + Preview changes using: + + ``` + git log --pretty='format:* %N' $previousversion... | grep -v "^* $" + ``` + + Save your notes: + ``` + git push origin refs/notes/commits + ``` + +3. Create change log page: `docs/manual/docs/overview/change-log/` + + ``` shell + cat < docs/manual/docs/overview/change-log/version-$version.md + # Version $version + + GeoNetwork $version is a minor release. + + ## Migration notes + + ### API changes + + ### Installation changes + + ### Index changes + + ## List of changes + + Major changes: + + EOF + + git log --pretty='format:* %N' $previousversion.. | grep -v "^* $" >> docs/manual/docs/overview/change-log/version-$version.md + + cat < docs/manual/docs/overview/change-log/version-$version.md + + and more \... see [$version issues](https://github.com/geonetwork/core-geonetwork/issues?q=is%3Aissue+milestone%3A$version+is%3Aclosed) and [pull requests](https://github.com/geonetwork/core-geonetwork/pulls?page=3&q=is%3Apr+milestone%3A$version+is%3Aclosed) for full details. + EOF + ``` + + Fill in the above markdown file, removing any unused headings. + +4. Update links and navigation: + + * ``docs/manual/mkdocs.yml`` + * ``docs/manual/docs/overview/change-log/index.md`` + * ``docs/manual/docs/overview/change-log/latest.md`` + * ``docs/manual/docs/overview/change-log/stable.md`` + * ``docs/manual/docs/overview/change-log/archive.md`` + + Test documentation locally: + ``` + cd docs/manual + mkdocs serve + ``` + Once running check the new page: + ``` + open http://localhost:8000/ocverview/change-log/$newversion + ``` + +5. Commit & tag the new version + + ``` shell + # Then commit the new version + git add . + git commit -m "Update version to $newversion" + + # Create the release tag + git tag -a $version -m "Tag for $version release" + ``` + +6. Build + + ``` shell + # deep clean + mvn clean:clean@reset + + # Build the new release + mvn install -Drelease + + # Create a minimal war (with only the default datasources) + cd web + mvn clean install -DskipTests -Pwar -Pwro4j-prebuild-cache + + # Download Jetty and create the installer + cd ../release + mvn clean install -Pjetty-download,bundle + + # Deploy to osgeo repository (requires credentials in ~/.m2/settings.xml) + cd .. + mvn deploy -Drelease + ``` + +7. Test + + ``` shell + cd target/GeoNetwork-$newversion + unzip geonetwork-bundle-$newversion.zip -d geonetwork-bundle-$newversion + cd geonetwork-bundle-$newversion/bin + ./startup.sh -f + ``` + +8. Set the next version + + ``` shell + # Set version number to SNAPSHOT + ./update-version.sh $newversion $nextversion + + nextversionnosnapshot=${nextversion//[-SNAPSHOT]/} + + # Add SQL migration step for the next version + mkdir web/src/main/webapp/WEB-INF/classes/setup/sql/migrate/v${nextversionnosnapshot//[.]/} + cat < web/src/main/webapp/WEB-INF/classes/setup/sql/migrate/v${nextversionnosnapshot//[.]/}/migrate-default.sql + UPDATE Settings SET value='${nextversionnosnapshot}' WHERE name='system/platform/version'; + UPDATE Settings SET value='SNAPSHOT' WHERE name='system/platform/subVersion'; + EOF + vi web/src/main/webResources/WEB-INF/config-db/database_migration.xml + ``` + + In `WEB-INF/config-db/database_migration.xml` add an entry for the new version in the 2 steps: + + ``` xml + + + WEB-INF/classes/setup/sql/migrate/v442/migrate- + + + ``` + + ``` shell + git add . + git commit -m "Update version to $nextversion" + ``` + +9. Publishing + + ``` shell + # Push the branch and tag + git push origin $versionbranch + git push origin $version + ``` + +10. Generate checksum files + + - If using Linux: + + ``` shell + cd web/target && md5sum geonetwork.war > geonetwork.war.md5 && cd ../.. + cd release/target/GeoNetwork-$version && md5sum geonetwork-bundle-$newversion.zip > geonetwork-bundle-$newversion.zip.md5 && cd ../../.. + ``` + + - If using Mac OS X: + + ``` shell + md5 -r web/target/geonetwork.war > web/target/geonetwork.war.md5 + md5 -r release/target/GeoNetwork-$version/geonetwork-bundle-$newversion.zip > release/target/GeoNetwork-$version/geonetwork-bundle-$newversion.zip.md5 + ``` + + On sourceforge first: + + ``` shell + sftp $sourceforge_username,geonetwork@frs.sourceforge.net + # For stable release + cd /home/frs/project/g/ge/geonetwork/GeoNetwork_opensource + # or for RC release + cd /home/frs/project/g/ge/geonetwork/GeoNetwork_unstable_development_versions/ + mkdir v4.4.1 + cd v4.4.1 + put docs/changes/changes4.4.1-0.txt + put release/target/GeoNetwork*/geonetwork-bundle*.zip* + put web/target/geonetwork.war* + bye + ``` + +11. Close the milestone on github with link to sourceforge download. + + Publish the release on github . + + Update the website links . + + - Add the changes file for the release to + - List the previous file in + - Update the version: + - Update the download link: + - Add the section for the new release: + + Send an email to the mailing lists. + +10. Merge in depending branches + + If a major version, then master version has to be updated to the next one (eg. if 3.8.0, then 3.7.x is 3.9.x). + + ``` shell + # Create it if it does not exist yet + git checkout master + ./update-version.sh $currentversion $nextMajorVersion + ``` + + Update documentation to reflect series change of `latest`, `stable`, `maintenance` and `archive`: + + * ``docs/manual/mkdocs.yml`` navigation changes as branches change role + * ``docs/manual/docs/overview/change-log/index.md`` + * ``docs/manual/docs/overview/change-log/latest.md`` + * ``docs/manual/docs/overview/change-log/stable.md`` + * ``docs/manual/docs/overview/change-log/archive.md`` + + Commit the new version + + ``` shell + git add . + git commit -m "Update version to $nextMajorVersion" + git push origin master + ``` diff --git a/docs/manual/docs/contributing/img/transifex.png b/docs/manual/docs/contributing/img/transifex.png new file mode 100644 index 00000000000..4dfca1b6e6d Binary files /dev/null and b/docs/manual/docs/contributing/img/transifex.png differ diff --git a/docs/manual/docs/contributing/index.md b/docs/manual/docs/contributing/index.md new file mode 100644 index 00000000000..ad0752b6d9f --- /dev/null +++ b/docs/manual/docs/contributing/index.md @@ -0,0 +1,7 @@ +# Contributing guide + +The guide for people who want to contribute to GeoNetwork. + +- [Translating the application](translating.md) +- [Making a pull request](making-a-pull-request.md) +- [Doing a GeoNetwork release](doing-a-release.md) diff --git a/docs/manual/docs/contributing/making-a-pull-request.md b/docs/manual/docs/contributing/making-a-pull-request.md new file mode 100644 index 00000000000..2a1adaaa7f2 --- /dev/null +++ b/docs/manual/docs/contributing/making-a-pull-request.md @@ -0,0 +1,49 @@ +# Making a pull request + +GeoNetwork uses a pull-request workflow allowing changes to be managed and reviewed. All work is done on branches and merged back. When developing start with the branch you want changed, create a new feature branch from there, make your changes on the feature branch, publish your feature branch to your GitHub repo, make a Pull Request asking your changes to be reviewed and merged. + +Occasionally core GeoNetwork developers will setup a feature branch on upstream to explore a specific topic. These shared feature-branch are subject to review when submitted as a pull-request against `master`. + +There are many great guides (See the links above) but here is a quick sequence illustrating how to make a change and commit the change. + +``` shell +$ git checkout master + # master is the 'trunk' and main development branch + # the checkout command "checks out" the requested branch + +$ git checkout -b myfeature + # the -b requests that the branch be created + # ``git branch`` will list all the branches you have checked out locally at some point + # ``git branch -a`` will list all branches in repository (checked out or not) + +# work work work + +$ git status + # See what files have been modified or added + +$ git add + # Add all files to be committed ``git add -u`` will add all modified (but not untracked) + +$ git commit -m "" + # Commit often. it is VERY fast to commit + # NOTE: doing a commit is a local operation. It does not push the change to Github + +# more work +# another commit + +$ git push origin myfeature + + # this pushed your new branch to Github + # now you are ready to make a Pull Request to get the new feature added to GeoNetwork + +# revise pull request based on review feedback +# another commit +# another push to update pull request +# Success!! +``` + +GeoNetwork uses git submodules in order to keep track of externals dependencies. It is necessary to init and update them after a branch change: + +``` shell +git submodule update --init +``` diff --git a/docs/manual/docs/contributing/translating.md b/docs/manual/docs/contributing/translating.md new file mode 100644 index 00000000000..fa4ac0a7d10 --- /dev/null +++ b/docs/manual/docs/contributing/translating.md @@ -0,0 +1,67 @@ +# Translating the application {#translating} + +To translate the client interface, go on [GeoNetwork on Transifex](https://www.transifex.com/geonetwork/core-geonetwork/). Only the reference language (ie. en) MUST be updated on github. All other translations MUST be on Transifex. + +Main files to translate are the `Angular UI` ones: + +![](img/transifex.png) + +Once translated, the new language needs to be added to the application. + +- Add the files to the client application in `web-ui/src/main/resources/catalog/locales` +- Register the new lang in `web-ui/src/main/resources/catalog/js/CatController.js` + +``` js +// Add the language here +module.constant('gnLangs', { + langs: { + 'eng': 'en', + 'dut': 'du', + 'fre': 'fr', + 'ger': 'ge', + 'kor': 'ko', + 'spa': 'es', + 'cze': 'cz' + }, + + +// Lang names to be displayed in language selector +$scope.langLabels = {'eng': 'English', 'dut': 'Nederlands', + 'fre': 'Français', 'ger': 'Deutsch', 'kor': '한국의', + 'spa': 'Español', 'cze': 'Czech'}; +``` + +To automatically retrieve and update translations files, the script `web-ui/download-from-transifex.sh` can be used. To use the script you have to join the translation team on Transifex. + +Register the new lang in the l variable of the transifex synchronization file: + +``` shell +SRC_DIR=src/main/resources/catalog/locales + +l=( + 'es::es' + 'fr::fr' + 'cz::cz' +``` + +and run the script + +``` shell +cd web-ui +./download-from-transifex.sh +``` + +Then on the Java application, register the new language in `src/main/webResources/WEB-INF/config-spring-geonetwork.xml`: + +``` xml + + ara + cze +``` + +Add a new SQL file for the database initialization in `src/main/webapp/WEB-INF/classes/setup/sql/data/loc-cze-default.sql` and update translations. This file is used to register the new language for database entity translations (eg. groups, status). + + +# Translating a standard + +To translate a standard, see the schema folder (`schemas/iso19139/src/main/plugin/iso19139/loc`). Those files are used in the editor and formatters to translate standard elements, to provide help text, recommended values list, \... diff --git a/docs/manual/docs/customizing-application/adding-static-pages.md b/docs/manual/docs/customizing-application/adding-static-pages.md new file mode 100644 index 00000000000..0d0fd982b9a --- /dev/null +++ b/docs/manual/docs/customizing-application/adding-static-pages.md @@ -0,0 +1,117 @@ +# Adding static pages + +This feature allows to store the HTML content for static pages and show the links to these pages in specific sections of the user interface: + +- The HTML content is stored in a new table of the GN's database. + +- The link to pages can be showed in different points of the GN's GUI according to a list of "sections" associated to each page. In this PR is introduced the support to show the links for the top toolbar and the footer. + +- Each page can be in 3 states: + + - `HIDDEN`: visible to administrator. + - `PRIVATE`: visible to logged users. + - `PUBLIC`: visible to everyone. + +- Pages can be added to different page sections. Currently the sections implemented are `TOP` (top menu of the main page) and `FOOTER` (footer of the main page). + +- Only the administrator can edit the pages and see the pages in `HIDDEN` status. + +- The creation and the management of the content is done via the API. + + ![](img/pages-api.png) + +Some restrictions: + +- It is not possible to apply custom CSS to the page. +- Any external image must be loaded externally. + +## Examples of API usage + +Before executing the following examples, see [Example of CSRF call using curl](misc.md#example-csrf-curl) for details on the usage of the CSRF token (instead of the value `"X-XSRF-TOKEN: e934f557-17a3-47f2-8e6b-bdf1a3c90a97"` used in the examples) and cookies in the requests. + +### Load a page in the top menu bar + +In this example we're going to upload a file ``contactus.html`` and link it in the top menu: + +1. Load the content by using the method POST `/api/pages/`, the mandatory fields are: + + - language (3 letters like 'eng', 'ita', 'fra' \...) + - pageId (the identifier/link description of the page) + - format (must be LINK if a link is associated to the page) + - the content: data (a file with the page content) or a link (URL to another page). Define both is not possible. + + ``` bash + $ curl -X POST "http://localhost:8080/geonetwork/srv/api/pages/?language=eng&pageId=contactus&format=HTML" -H "accept: */*" -H "Content-Type: multipart/form-data" -H "X-XSRF-TOKEN: e934f557-17a3-47f2-8e6b-bdf1a3c90a97" -d contactus.html + ``` + + At this point the page is created but not visible because is in status HIDDEN and is not loaded explicitly in any section of the page, except DRAFT that is not visible (in the future could be added to a page with an editor interface). Similar requests should be done for each UI language supported. + +2. To associate the link to the top bar is necessary to use the method POST `/api/pages/{language}/{pageId}/{section}` with the `TOP` value for the section. + + ``` bash + $ curl -X POST "http://localhost:8080/geonetwork/srv/api/pages/eng/contactus/TOP" -H "accept: */*" -H "X-XSRF-TOKEN: 7cfa1a0d-3335-4846-8061-a5bf176687b5" --user admin:admin -b /tmp/cookie + ``` + +### Load a link in the footer bar + +In this example we're going to add a link to an external resource and link it in the footer: + +1. Add the link by using the method POST `/api/pages/` with the `link` parameter in the request: + + ``` bash + $ curl -X POST "http://localhost:8080/geonetwork/srv/api/pages/?language=eng&pageId=contactus&format=LINK&link=http://myorganisation/contactus.html" -H "accept: */*" -H "X-XSRF-TOKEN: e934f557-17a3-47f2-8e6b-bdf1a3c90a97" + ``` + +2. To associate the link to the footer is necessary to use the method POST `/api/pages/{language}/{pageId}/{section}` with the `FOOTER` value for the section. + + ``` bash + $ curl -X POST "http://localhost:8080/geonetwork/srv/api/pages/eng/contactus/FOOTER" -H "accept: */*" -H "X-XSRF-TOKEN: 7cfa1a0d-3335-4846-8061-a5bf176687b5" --user admin:admin -b /tmp/cookie + ``` + +### Remove a page from a section + +To remove a page from a section DELETE `/api/pages/{language}/{pageId}/{section}` + +``` bash +curl -X DELETE "http://localhost:8080/geonetwork/srv/api/pages/eng/contactus?format=LINK" -H "accept: */*" -H "X-XSRF-TOKEN: 7cfa1a0d-3335-4846-8061-a5bf176687b5" --user admin:admin -b /tmp/cookie +``` + +### Change the page status + +The status of the page can be changed with the method PUT `/api/pages/{language}/{pageId}/{status}` where status could assume these values: + +- `PUBLIC` - Visible to every user +- `PUBLIC_ONLY` - Visible to not logged users +- `PRIVATE` - Visible to logged users +- `HIDDEN` - Hidden to anyone + +Other methods in the API are to change/delete a page and to GET the list of the pages or the info of a specific one. + +### Change the menu order in the top toolbar + +Pages can be inserted in between catalogue default menu which are: + +``` json +["gn-site-name-menu", + "gn-portal-switcher", + "gn-search-menu", + "gn-map-menu", + "gn-contribute-menu", + "gn-admin-menu"] +``` + +Insert a page as a simple menu using its id or as a submenu using an object: + +``` json +["gn-site-name-menu", + "gn-portal-switcher", + "gn-search-menu", + {"Quick search": [ + "searchForAfrica", + "forReview" + ]}, + "gn-map-menu", + "gn-contribute-menu", + "gn-admin-menu", + "documentation"] +``` diff --git a/docs/manual/docs/customizing-application/advanced-configuration.md b/docs/manual/docs/customizing-application/advanced-configuration.md new file mode 100644 index 00000000000..56ff60672b8 --- /dev/null +++ b/docs/manual/docs/customizing-application/advanced-configuration.md @@ -0,0 +1,13 @@ +# Advanced configuration + +## User session timeout configuration {#session-timeout-configuration} + +Default session timeout is set to 35 minutes (See [User session](../administrator-guide/managing-users-and-groups/index.md#user-session)). This timeout can be configured in `WEB-INF/web.xml` by changing the value of the session-timeout (time is in minute): + +``` xml + + 35 + +``` + +For developers, the timeout is defined as a build property and can be customized in filters. See `web/src/main/filters/dev.properties#L20` diff --git a/docs/manual/docs/customizing-application/changing-layout.md b/docs/manual/docs/customizing-application/changing-layout.md new file mode 100644 index 00000000000..9f0eb99c020 --- /dev/null +++ b/docs/manual/docs/customizing-application/changing-layout.md @@ -0,0 +1,3 @@ +# Theming {#configuring-layout} + +TBD diff --git a/docs/manual/docs/customizing-application/characterset.md b/docs/manual/docs/customizing-application/characterset.md new file mode 100644 index 00000000000..62d45109dd1 --- /dev/null +++ b/docs/manual/docs/customizing-application/characterset.md @@ -0,0 +1,17 @@ +# Characterset + +By default the character set of GeoNetwork is ``UTF-8``. This works well for many locales in the world and is compatible with ASCII that is typically used in US and Canada. However, if ``UTF-8`` is not a compatible characterset in your environment you can change the default. + +To change it within GeoNetwork simply start the application with the system property geonetwork.file.encoding set to the desired character set name. + +For example if you are running Tomcat you can set + +``` xml +JAVA_OPTS="-Dgeonetwork.file.encoding=UTF-16" +``` + +to the startup script and the default codec in GeoNetwork will be ``UTF-16``. + +It is also recommended to set the file.encoding parameter to the same codec as this dictates to the default encoding used in Java and the Web Server may reference at times use the default codec. + +Finally, by default the URL parameters are typically interpreted as ASCII characters which can be a problem when searching for metadata that are not in the english language. Each Web Server will have a method for configuring the encoding used when reading the parameters. For example, in Tomcat the encoding/charset configuration is in the **`server.xml`** Connector element. diff --git a/docs/manual/docs/customizing-application/configuring-faceted-search.md b/docs/manual/docs/customizing-application/configuring-faceted-search.md new file mode 100644 index 00000000000..292739175bc --- /dev/null +++ b/docs/manual/docs/customizing-application/configuring-faceted-search.md @@ -0,0 +1,495 @@ +# Configuring faceted search + +Facets also known as aggregation in Elasticsearch are used to provide simple search entries. GeoNetwork is using facet in different places: + +- Home page categories + + ![](img/agg-home.png) + +- Search results + + ![](img/agg-search.png) + +All facet configurations are stored in the user interface configuration (see [User Interface Configuration](../administrator-guide/configuring-the-catalog/user-interface-configuration.md)). The configuration are defined using JSON following Elasticsearch API (See ). + +By default, the facet configurations are defined as (see `web-ui/src/main/resources/catalog/js/CatController.js`). The home page display on the left side `th_httpinspireeceuropaeutheme-theme_tree.key` and `cl_topic.key` and on the right side, the last facet defined `resourceType`. + +## Term aggregation on a field + +``` js +"format": { + "terms": { + "field": "format" + } +} +``` + +This is using [Elasticsearch terms aggregations](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html). + +If a search error occurred after adding a new facet, check that it is not the following: + +``` +Text fields are not optimised for operations that require per-document field data +like aggregations and sorting, so these operations are disabled by default. +Please use a keyword field instead. +``` + +This means that the field used in the aggregation is indexed as a text field and can't be used in aggregations. In such case, check the index mapping and field definition. For example, a facet on `crsDetails.code` will fail with that error and can be fixed using `crsDetails.code.keyword` which is an additional field added by Elasticsearch while indexing. + +## Term aggregation on a codelist + +Codelist fields starts with prefix `cl_`. Codelist fields are object composed of a key, a default value for the record default language, additional field per languages and an optional link (if using Anchor). + +``` js +"cl_maintenanceAndUpdateFrequency": [ + { + "key": "daily", + "default": "Journalière", + "langfre": "Journalière", + "link": "http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_MaintenanceFrequencyCode" + } +] +``` + +For codelist, use `.default` for catalogue with no multilingual content and only one language for the UI. + +``` js +"cl_maintenanceAndUpdateFrequency.default": { + "terms": { + "field": "cl_maintenanceAndUpdateFrequency.default" + } + }, +``` + +Use `.key` for codelist for multilingual catalogue. The codelist translation needs to be loaded in the client app. See `web-ui/src/main/resources/catalog/js/GnSearchModule.js`. + +``` js +"cl_spatialRepresentationType.key": { + "terms": { + "field": "cl_spatialRepresentationType.key" + } + }, +``` + +## Term aggregation on a thesaurus + +Thesaurus are indexed in fields starting with `th_`. Each keywords are defined using multilingual fields (ie. default field + lang\...): + +``` js +"th_odatis_thematiques": [ + { + "default": "Dispositifs de surveillance", + "langfre": "Dispositifs de surveillance" + } +] +``` + +When the thesaurus define relations between concept a field `th_{thesaurusid}_tree` is also defined: + +``` js +"th_httpinspireeceuropaeutheme-theme_tree": { + "default": [ + "Installations de suivi environnemental" + ], + "key": [ + "http://inspire.ec.europa.eu/theme/ef" + ] +} +``` + +To use thesaurus as aggregation, use the following configuration: + +``` js +"th_httpinspireeceuropaeumetadatacodelistPriorityDataset-PriorityDataset_tree.default": { + "terms": { + "field": "th_httpinspireeceuropaeumetadatacodelistPriorityDataset-PriorityDataset_tree.default", + "size": 100, + "order" : { "_key" : "asc" } + } +}, +"th_httpinspireeceuropaeutheme-theme_tree.key": { + "terms": { + "field": "th_httpinspireeceuropaeutheme-theme_tree.key", + "size": 34 + } +}, +``` + +Note that using `size` and `order` properties you can configure the number of values to load in the aggregations and how to order them. + +For GEMET thesaurus, if the catalogue is not multilingual, then the default property contains the default language. All records having the same language, there will be no mix of languages. + +``` js +"th_gemet_tree.default": { + "terms": { + "field": "th_gemet_tree.default", + "size": 100, + "order" : { "_key" : "asc" }, + "include": "[^\^]+^?[^\^]+" + // Limit to 2 levels + } +}, +``` + +Note here that the `include` properties is used to filter the values to load. + +If records are not all in all the same languages, languages can be mixed together. In this case use the key which will be translated on client side by loading required concepts using the thesaurus API. + +``` js +"th_gemet_tree.key": { + "terms": { + "field": "th_gemet_tree.key", + "size": 100, + "order" : { "_key" : "asc" }, + "include": "[^\^]+^?[^\^]+" + } +} +``` + +## Filters aggregations + +Aggregation based on queries. One query will define one bucket in the aggregation. + +This is using [Elasticsearch filters aggregations](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-filters-aggregation.html). + +``` js +"availableInServices": { + "filters": { + "filters": { + "availableInViewService": { + "query_string": { + "query": "+linkProtocol:/OGC:WMS.*/" + } + }, + "availableInDownloadService": { + "query_string": { + "query": "+linkProtocol:/OGC:WFS.*/" + } + } + } + } +} +``` + +Key like `availableInViewService` may not be available in the translations. Use the translation API to add your custom translation in the database (see the Admin console --> Settings --> Languages). + +## Filtering aggregation values + +To enable filtering in a facet, add an include property: + +``` js +"tag.default": { + "terms": { + "field": "tag.default", + "include": ".*", + "size": 10 + }, + "meta": { + "caseInsensitiveInclude": true + } +} +``` + +`include` and `exclude` properties can be used to filter values too. A meta `caseInsensitiveInclude` can be added as Elasticsearch facet filter is case sensitive by default. + +Example adding only 4 specific values: + +``` js +"resourceType": { + "terms": { + "field": "resourceType", + "include": "dataset|series|service|nonGeographicDataset" + } + } +``` + +See [Elasticsearch terms aggregations filtering](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html#_filtering_values_4) for more details. + +## Collapse aggregation on load + +Aggregations can be collapsed by default and visible to users depending on roles: + +``` js +"dateStamp" : { + "auto_date_histogram" : { + "field" : "dateStamp", + "buckets": 50 + }, + "meta": { + "collapsed": true, + "userHasRole": "isReviewerOrMore" + } +``` + +- Use `"collapsed": true` to collapse the item on load +- Use `"userHasRole": "isReviewerOrMore"` to display the aggregation depending on user roles + +## Hierarchical aggregation based on separator (Experimental) + +A tree field which contains a URI eg. but with a translation which contains a hierarchy with a custom separator `/Regulation and Management/Technical and Management Zonations/Sensitive Zones` + +``` js +"th_sextant-theme_tree.key": { + "terms": { + "field": "th_sextant-theme_tree.key", + "size": 100, + "order" : { "_key" : "asc" } + }, + "meta": { + "translateOnLoad": true, + "treeKeySeparator": "/" + } +} +``` + +This will build a tree based on the value and the separator. + +## Nested aggregation + +Aggregation can be nested. eg. `resourceType` field is used at first level, `format` as second one. + +``` js +"facetConfig": { + "resourceType": { + "terms": { + "field": "resourceType" + }, + "aggs": { + "format": { + "terms": { + "field": "format" + } + } + } + }, +``` + +This is using [Elasticsearch nested aggregations](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-nested-aggregation.html). + +## Histogram aggregation + +When fields are number, histogram aggregation can be used: + +``` js +"resolutionScaleDenominator": { + "histogram": { + "field": "resolutionScaleDenominator", + "interval": 10000, + "keyed" : true, + "min_doc_count": 1 + } +}, +"creationYearForResource": { + "histogram": { + "field": "creationYearForResource", + "interval": 5, + "keyed" : true, + "min_doc_count": 1 + } +}, +``` + +This is using [Elasticsearch histogram aggregations](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-histogram-aggregation.html). + +## Translating source or group field + +Some fields are ids in the index eg. for harvesting source or groups. In such case use `orderByTranslation` and `filterByTranslation` to not filter on the id but on the translations. + +``` js +"sourceCatalogue": { + "terms": { + "field": "sourceCatalogue", + "size": 100, + "include": ".*" + }, + "meta": { + "orderByTranslation": true, + "filterByTranslation": true, + "displayFilter": true, + "collapsed": true + } + }, +``` + +## Custom labels and search fields + +When using a generic field like `tag.default` and including only a subset of keywords in various aggregations, the aggregation label can be customized. In the example below `IDP_TOPICS` and `IDP_DPSIR`. In this case, add a `meta.field` property to indicate which field to search on. + +``` js +"IDP_TOPICS": { + "terms": { + "field": "tag.default", + "size": 34, + "include": "IDP_topics.*" + }, + "meta": { + "field": "tag.default" + } +}, +"IDP_DPSIR": { + "terms": { + "field": "tag.default", + "size": 34, + "include": "IDP_DPSIR.*|IDP_dpsir." + }, + "meta": { + "field": "tag.default" + } +}, +``` + +## Decorate aggregations {#configuring-facet-decorator} + +All aggregations can be decorated by an icon or an image in the home page or in other pages. The decorator is configured in the `meta` properties of the facet: + +``` js +"resourceType": { + "terms": { + "field": "resourceType", + "size": 10 + }, + "meta": { + "decorator": { + "type": "icon", + "prefix": "fa fa-2x pull-left gn-icon-" + } +} +``` + +![](img/agg-decorator-home.png) + +Decorator types are described below. + +### Decorate with icons + +- Fixed icon. eg. adding a tag icon to all values + + ``` js + "decorator": { + "type": "icon", + "prefix": "fa fa-fw fa-tag " + } + ``` + + ![](img/agg-decorator-icon-fixed.png) + +- Icon defined in a CSS class name using the value. eg. used for resource types `gn-icon-dataset` + + ``` js + "decorator": { + "type": "icon", + "prefix": "fa fa-fw gn-icon-" + } + ``` + + ![](img/agg-decorator-icon.png) + +- Icon defined in a css class name which is using only a portion of the value. eg. used for INSPIRE themes. The expression allows to extract the value + + ``` js + "decorator": { + "type": "icon", + "prefix": "fa fa-fw gn-icon iti-", + "expression": "http://inspire.ec.europa.eu/theme/(.*)" + } + ``` + + ![](img/agg-decorator-icon-inspire.png) + +- Icon defined with a map of values for the class name to use. + + ``` js + "decorator": { + "type": "icon", + "prefix": "fa fa-fw ", + "map": { + "availableInViewService": "fa-globe", + "availableInDownloadService": "fa-download" + } + } + ``` + + ![](img/agg-decorator-icon-map.png) + +### Decorate with images + +Define the image to use for each values: + +``` js +"decorator": { + "type": "img", + "map": { + "EEA": "https://upload.wikimedia.org/wikipedia/en/thumb/7/79/EEA_agency_logo.svg/220px-EEA_agency_logo.svg.png" + } +} +``` + +![](img/agg-decorator-img-logo.png) + +Image decorator in the home page are rendered as background images: + +![](img/agg-decorator-img.png) + +## Aggregation as tab + +One aggregation from the facet configuration can be selected to be displayed above search results as tabs using the following: + +``` js +"mods": { + "search": { + "facetTabField": "resourceType" + } +``` + +## Interactive graphics {#configuring-facet-graphics} + +Use [Vega](https://vega.github.io/vega-lite/examples/) to render date histogram facet values or render term facets to display facet as simple pie. Vega is also used in Kibana so it can make dataviz converging in dashboards and in the app. + +Facet widget based on vega allow selection of a range for dates and/or click on bar/pie. + +![](img/vega.png) + +To use Vega based facet, enable mods.search.isVegaEnabled in the user interface configuration. This trigger the load of the Vega library. + +A simple date field: + +``` js +"dateStamp" : { + "auto_date_histogram" : { + "field" : "dateStamp", + "buckets": 50 + }, +``` + +A date range field: + +``` js +"resourceTemporalDateRange": { + "gnBuildFilterForRange": { + "field": "resourceTemporalDateRange", + "buckets": 51, //"2021 - 1970", + "dateFormat": "YYYY", + "vegaDateFormat": "%Y", + "from": "1970", + "to": "2021", + "mark": "area" + }, + "meta": { + "vega": "timeline" + } +``` + +A term as pie or bar chart: + +``` js +"cl_status.key": { + "terms": { + "field": "cl_status.key", + "size": 10 + }, + "meta": { + //"vega": "bar" + "vega": "arc" + } + }, +``` diff --git a/docs/manual/docs/customizing-application/configuring-search-fields.md b/docs/manual/docs/customizing-application/configuring-search-fields.md new file mode 100644 index 00000000000..a67a102493f --- /dev/null +++ b/docs/manual/docs/customizing-application/configuring-search-fields.md @@ -0,0 +1,292 @@ +# Configuring search fields + +In some cases it's relevant to modify or extend the search fields of the metadata index. For example to add a field (which is then searchable or can be used in a default view) or change the content of the field created from the metadata (indexation). + +## Index field types + +In the index, JSON document representing the metadata is stored. + +Simple fields are stored like a map of key = value. eg. + +``` js +"_source": { + "docType": "metadata", + "documentStandard": "iso19115-3.2018", + "document": "", + "metadataIdentifier": "7451e2bd-22e8-4a74-a999-01c58b630369", + "standardName": "ISO 19115", + "indexingDate": "2020-11-19T06:30:47.009Z", + "dateStamp": "2020-11-17T13:56:43", + "mainLanguage": "fre" +``` + +### Multilingual text field + +Multilingual fields are stored using an object with the following properties: + +- default the record default language value (this property is updated on the client side based on the UI language) +- lang{langCode} one or more properties containing all record languages values + +``` js +"_source": { + "resourceTitleObject": { + "default": "Aménagements routiers et autoroutiers - Série", + "langfre": "Aménagements routiers et autoroutiers - Série", + "langger": "Straßen- und Autobahnverbesserungen - Standard" +}, +``` + +### Codelist + +Codelists are stored as an object like titles, abstract, \... + +If the record is multilingual, codelist translations are stored in the index for the record languages: + +``` js +"cl_spatialRepresentationType" : { + "key": "grid", + "default": "Grid", + "langeng": "Grid", + "langfre": "Grid", + "text": "{{> inner text of the codelist element. Used in some profiles eg. ISO HNAP}}", + "link": "./resources/codeList.xml#MD_SpatialRepresentationTypeCode", + } +``` + +When creating a facets on a codelist, 2 options: + +- if the catalog content is in one language (and there is no need to translate codelist in other language), use the default property eg. cl_spatialRepresentationType.default +- if you have a catalog containing a mix of languages without having all records translated in all languages, use the key eg. cl_spatialRepresentationType.key and do translation on the client side. See GnSearchModule.js to load extra codelist translations on the Angular app. + +The second one is also required if you want the codelist to be translated in the user interface language (whatever the record language). The codelist translations are loaded by the application depending on the UI language. + +Use the default property in record view. Depending on the UI language, the default property contains the translation in the UI language or fallback to the record default. + +### Thesaurus + +Each thesaurus are described by the following fields: + +- ``th_{thesaurusId}Number`` with the count of non empty keywords +- ``th_{thesaurusId}``, an array of multilingual keyword which may contains a link (when using Anchor) +- (optional) ``th_{thesaurusId}_tree`` containing hierarchy when broader terms are found. default property contains the record default language hierarchy, key property contains the hierarchy of broader terms keys. This can be used to build tree depending on UI language (thesaurus translations has to be loaded by the client app). + +``` js +{ + "th_httpinspireeceuropaeumetadatacodelistPriorityDatasetPriorityDatasetNumber": "3", + "th_httpinspireeceuropaeumetadatacodelistPriorityDatasetPriorityDataset": [{ + "default": "Agglomerations - industrial noise exposure delineation (Noise Directive)", + "langfre": "Agglomerations - industrial noise exposure delineation (Noise Directive)", + "link": "http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset/Agglomerations-IndustrialNoiseExposureDelineation-dir-2002-49" + }, + { + "default": "Agglomerations - noise exposure delineation day-evening-night (Noise Directive)", + "langfre": "Agglomerations - noise exposure delineation day-evening-night (Noise Directive)", + "link": "http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset/Agglomerations-NoiseExposureDelineationDEN-dir-2002-49" + }, + { + "default": "Designated waters (Water Framework Directive)", + "langfre": "Designated waters (Water Framework Directive)", + "link": "http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset/DesignatedWaters-dir-2000-60" + } + ], + "th_httpinspireeceuropaeumetadatacodelistPriorityDatasetPriorityDataset_tree": { + "default": [ + "Directive 2000/60/EC", + "Directive 2000/60/EC^Protected areas (Water Framework Directive)", + "Directive 2000/60/EC^Protected areas (Water Framework Directive)^Designated waters (Water Framework Directive)", + "Directive 2002/49/EC", + "Directive 2002/49/EC^Environmental noise exposure (Noise Directive)", + "Directive 2002/49/EC^Environmental noise exposure (Noise Directive)^Agglomerations - industrial noise exposure delineation (Noise Directive)", + "Directive 2002/49/EC^Environmental noise exposure (Noise Directive)^Agglomerations - noise exposure delineation (Noise Directive)", + "Directive 2002/49/EC^Environmental noise exposure (Noise Directive)^Agglomerations - noise exposure delineation (Noise Directive)^Agglomerations - noise exposure delineation day-evening-night (Noise Directive)" + ], + "key": [ + "http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset/dir-2000-60", + "http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset/dir-2000-60^http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset/ProtectedAreas-dir-2000-60", + "http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset/dir-2000-60^http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset/ProtectedAreas-dir-2000-60^http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset/DesignatedWaters-dir-2000-60", + "http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset/dir-2002-49", + "http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset/dir-2002-49^http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset/EnvironmentalNoiseExposure-dir-2002-49", + "http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset/dir-2002-49^http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset/EnvironmentalNoiseExposure-dir-2002-49^http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset/Agglomerations-IndustrialNoiseExposureDelineation-dir-2002-49", + "http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset/dir-2002-49^http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset/EnvironmentalNoiseExposure-dir-2002-49^http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset/Agglomerations-NoiseExposureDelineation-dir-2002-49", + "http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset/dir-2002-49^http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset/EnvironmentalNoiseExposure-dir-2002-49^http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset/Agglomerations-NoiseExposureDelineation-dir-2002-49^http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset/Agglomerations-NoiseExposureDelineationDEN-dir-2002-49" + ] + } +} +``` + +### Other types + +Index document also contains other types of object for field like: + +- geom representing the bounding boxes of the record stored as GeoJSON +- contact stored as simple fields and as object: + +``` +{ + "Org": "Direction Asset Management (SPW - Mobilité et Infrastructure)", + "pointOfContactOrg": "Direction Asset Management (SPW - Mobilité et Infrastructure)", + "contact: [ + { + "organisation": "Direction Asset Management (SPW - Mobilité et Infrastructure)", + "role": "pointOfContact", + "email": "frederic.plumier@spw.wallonie.be", + "website": "", + "logo": "", + "individual": "", + "position": "", + "phone": "", + "address": "Boulevard du Nord, 8, NAMUR, 5000, Belgique" + } + ] +} +``` + +- link + +``` js +"link": [ + { + "protocol": "WWW:LINK-1.0-http--link", + "url": "http://geoapps.spw.wallonie.be/portailRoutes", + "name": "Portail cartographique des routes - Application sécurisée", + "description": "Application de consultation des routes et autoroutes de Wallonie. Cette application est sécurisée et n'est accessible que pour les agents de la DGO1 du SPW.", + "applicationProfile": "", + "group": 0 + }, +``` + +- recordLink + +``` js +"recordLink": [ + { + "type": "siblings", + "associationType": "isComposedOf", + "initiativeType": "collection", + "to": "f010eda4-e791-44b1-8b2a-309f352f7d8f", + "url": "", + "title": "", + "origin": "catalog" + }, +``` + +## Add a search field + +Indexed fields are defined on a per schema basis on the schema folder (see `schemas/iso19139/src/main/plugin/iso19139/index-fields/index.xsl`). + +This file define for each search criteria the corresponding element in a metadata record. For example, indexing the resource identifier of an ISO19139 record: + +``` xml + + + + + +``` + +Once the field added to the index, user could query using it as a search criteria in the different kind of search services. For example using: + +``` shell +curl -X POST "localhost:8080/geonetwork/srv/api/search/records/_search" \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json;charset=utf-8' \ + -d '{"from":0,"size":0,"query":{"query_string":{"query":"+resourceIdentifier:1234"}}}' +``` + +To customize how the field is indexed see `web/src/main/webResources/WEB-INF/data/config/index/records.json`. + +To return it in the search response, use the `_source` parameter of the query. See . + +## Boosting at search time + +See . + +By default, the search is defined as (see `web-ui/src/main/resources/catalog/js/CatController.js`): + +``` js +'queryBase': 'any:(${any}) resourceTitleObject.default:(${any})^2', +``` + +## Scoring + +By default the search engine compute score according to search criteria and the corresponding result set and the index content. + +By default, the search score is defined as (see `web-ui/src/main/resources/catalog/js/CatController.js`): + +``` js +'scoreConfig': { + "boost": "5", + "functions": [ + // Boost down member of a series + { + "filter": { "exists": { "field": "parentUuid" } }, + "weight": 0.3 + }, + // Boost down obsolete records + { + "filter": { "match": { "codelist_status": "obsolete" } }, + "weight": 0.3 + }, + // { + // "filter": { "match": { "codelist_resourceScope": "service" } }, + // "weight": 0.8 + // }, + // Start boosting down records more than 3 months old + { + "gauss": { + "dateStamp": { + "scale": "365d", + "offset": "90d", + "decay": 0.5 + } + } + } + ], + "score_mode": "multiply" + }, +``` + +## Language analyzer + + +By default a `standard` analyzer is used. If the catalog content is english, it may make sense to change the analyzer to `english`. To customize the analyzer see `web/src/main/webResources/WEB-INF/data/config/index/records.json` + +To add a new language, check first if Elasticsearch provides a specific analyzer for that language (see https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-lang-analyzer.html). Then configure fields that are multilingual +in `records.json` (eg. adding Danish): + +* If the field is used for full text search, use the language analyzer: + +```json +{ + "textField": { + "match": "*Object", + "mapping": { + "type": "object", + "properties": { + "default": {}, + ... + "langdan": { + "type": "text", + "analyzer": "danish" + }, +``` + +* If the field is a keyword like organisation name or tag field use type `keyword` (which is required for computing aggregations) + +```json +{ + "tag": { + "match": "th_*", + "mapping": { + "type": "object", + "copy_to": ["tag"], + "properties": { + "default": {}, + ... + "langdan": { + "type": "keyword", + "copy_to": [ + "any.langdan" + ] + }, +``` \ No newline at end of file diff --git a/docs/manual/docs/customizing-application/creating-custom-view.md b/docs/manual/docs/customizing-application/creating-custom-view.md new file mode 100644 index 00000000000..5174243d3ec --- /dev/null +++ b/docs/manual/docs/customizing-application/creating-custom-view.md @@ -0,0 +1,13 @@ +# Customizing metadata views {#creating-custom-view} + +GeoNetwork facilitates developers to easily change or add a metadata view. A User can change the view to his/her needs. + +By default the initial view is an AngularJS view on the results returned from the search service. Therefore the view can only contain the fields from the Lucene Index. If you require more fields, you can either add fields to the index or don't use the AngularJS view. This view is defined in `web-ui/src/main/resources/catalog/views/default/templates/recordView.html`. + +Metadata views are called 'formatters'. They are located in the schema-plugin related to the metadata that you are formatting. Formatters use either XSLT or Groovy to transform the XML to the required format (html, xml, pdf, json). + +A formatter can be updated from the web interface in the `admin console`, `metadata and templates`, tab 'formatters'. On this page you can upload, change and preview formatters. + +![](img/formatter.png) + +After having created a new formatter you will have to update your application code, so the new formatter-output can be visualised from your application. If the goal of the formatter is to introduce a new html view on metadata, then you can add a reference to it in `web-ui/src/main/resources/catalog/views/default/config.js` (searchSettings.formatter.list). diff --git a/docs/manual/docs/customizing-application/editor-ui/creating-custom-editor.md b/docs/manual/docs/customizing-application/editor-ui/creating-custom-editor.md new file mode 100644 index 00000000000..dad54a2adc6 --- /dev/null +++ b/docs/manual/docs/customizing-application/editor-ui/creating-custom-editor.md @@ -0,0 +1,909 @@ +# Customizing editor {#creating-custom-editor} + +!!! warning + + This file is produced automatically from the geonetwork-core repository. To make any suggestions to the content of the page please add your changes to [core-geonetwork/schemas/config.editor.xsd](https://github.com/geonetwork/core-geonetwork/blob/main/schemas/config-editor.xsd). + + +## Creating custom editor + +A metadata editor configuration is defined for a specific schema plugin standard (see [Implementing schema plugins](../implementing-a-schema-plugin.md)). + +The editor configuration defines the navigation menu for the editor (i.e. list of views and tabs), the list of fields and the type of control to use. Controls can be HTML-type (e.g. text, date) or more advanced controls built using [AngularJS directives](https://docs.angularjs.org/guide/directive). + +To build such an editor configuration, the user needs to know the XSD of the standard to properly build views, tabs and fields according to the element names (see `schemas/config-editor.xsd`). Create an editor root element and attach: + +- the schema and +- namespaces for the standards + +``` xml + +``` + +An editor configuration should first define some general element descriptions and then a set of views with at least one defined view. + +Child elements: + +- **fields**, Optional element (see [Defining field type](creating-custom-editor.md#creating-custom-editor-fields)) +- **fieldsWithFieldset**, Optional element (see [Grouping element from the standards](creating-custom-editor.md#creating-custom-editor-fieldsWithFieldset)) +- **multilingualFields**, Optional element (see [Defining multilingual fields](creating-custom-editor.md#creating-custom-editor-multilingualFields)) +- **views**, Mandatory element (see [Configuring views](creating-custom-editor.md#creating-custom-editor-views)) + +## Defining field type {#creating-custom-editor-fields} + +Define the form fields type configuration. The default is simple text input. This list contains a list of fields which do not use a simple text input. The list of possible values are: + +- all HTML5 input type or +- an AngularJS directive name. MUST start with `data-` and could end with `-textarea` to create a textarea element or with `-div` if the directive does not apply to the input or textarea but to the div element containing it. + +An element can only have one type defined. + +``` xml + + + + + + +``` + +The other option to define a more advanced field type is to catch the element using and XSL template. This approach is used for keywords in ISO19139 (see for example `schemas/iso19139/src/main/plugin/iso19139/layout/layout-custom-fields-keywords.xsl`). + +## Grouping element from the standards {#creating-custom-editor-fieldsWithFieldset} + +List of elements to be displayed in a fieldset (i.e. boxed element). Those elements usually contain children elements and define major sections in the standard. For example, in ISO19139, `identification` and `distribution` are major sections and should usually be displayed as a group of `information`. + +``` xml + + ... + + gmd:identificationInfo + gmd:distributionInfo +``` + +## Defining multilingual fields {#creating-custom-editor-multilingualFields} + +Configure here the list of multilingual fields for a standard. + +By default, if the standard has multilingual support like ISO19139, all fields will be displayed as multilingual fields. Define in the exclude section the exceptions (e.g. ``gmd:identifier`` in ISO19139). + +Then this section also allows to define how multilingual fields are displayed using the expanded elements. If expanded, then one field per language is displayed with no need to click on the language switcher. + +![](../../user-guide/describing-information/img/multilingual-editing.png) + +``` xml + + ... + ... + + + gmd:title + gmd:abstract + + + gmd:identifier + gmd:metadataStandardName +``` + +## Configuring views {#creating-custom-editor-views} + +At least one view MUST be defined, but more view modes can be defined depending on the needs. + +By default ISO19139 defines 3 views (i.e. default, advanced, xml) and has one disabled view (i.e. INSPIRE). See `schemas/iso19139/src/main/plugin/iso19139/layout/config-editor.xml` for the configuration. + +![](../../user-guide/describing-information/img/view-mode.png) + +Another basic example is the Dublin Core view (see `schemas/dublin-core/src/main/plugin/dublin-core/layout/config-editor.xml`). + +To create a new view, use the following: + +``` xml + + + ... + +``` + +Child elements: + +- **view**, One or more (see [Defining a view](creating-custom-editor.md#creating-custom-editor-view)) + +## Defining a view {#creating-custom-editor-view} + +A view has a label and defines a specific rendering of the metadata records. A view is composed of one or more tabs. + +``` xml + + + .... + +``` + +The view could be displayed or not according to the metadata record content or the current user session using the `displayIfRecord` and `displayIfServiceInfo` attributes. + +Attributes: + +- **name** (Mandatory) + +The key of the view name stored in `{schema}/loc/{lang}/strings.xml` or the element name with namespace prefix. + +``` xml + + Simple + INSPIRE + My view +``` + +- **disabled** (Optional) Fixed value: **true** + +Hide the view from the menu if the attribute is defined. Allows to easily disable a view. + +- **class** (Optional) + +Define custom CSS class to be set on the form element. This is mainly used to set the type of indent: + +- gn-label-above-input: to put label above form input +- gn-indent-colored: colored left border on each fieldset +- gn-indent-bluescale: blue scale colored left border on each fieldset + +See ``catalog/views/default/less/gn_editor_default.less`` to add your custom editor styles. + +- **upAndDownControlHidden** (Optional) Fixed value: **true** + +Define if up and down control should be displayed in that view. If not defined, controls are displayed. Hide those controls in a view to make it easier with less controls for the end-user. + +![](../../user-guide/describing-information/img/editor-control-updown.png) + +- **displayAttributes** (Optional) Fixed value: **true** + +Display attributes by default when loading the view. + +- **displayTooltips** (Optional) Fixed value: **true** + +Display help documentation for all elements by default when loading the view. + +- **displayTooltipsMode** (Optional) + +Display help documentation onhover elements (default) or by clicking on an icon. + +- **hideTimeInCalendar** (Optional) Fixed value: **true** + +Define if calendar control should allow users to set date only or datetime. If the attribute is not set, then date and datetime can be set. This is controlled at the view level, switching to another view may allow more control over the dates. + +- **displayIfRecord** (Optional) + +XPath expression returning boolean value which will be evaluated against the metadata record. if true the view will be displayed. eg. Display custom-view if metadata standard name contains Medsea: + +``` xml + + + +

    + +
    + + +``` + +Attributes: + +- **id** (Mandatory) + +The tab key used in URL parameter to activate that tab. The key is also use for the tab label as defined in `{schema}/loc/{lang}/strings.xml`. + +- **default** (Optional) Fixed value: **true** + +Define if this tab is the default one for the view. Only one tab should be the default in a view. + +- **hideIfNotDisplayed** (Optional) Fixed value: **true** + +Define if the tab should be hidden (and not disabled only) if not displayed based on display rules. + +- **toggle** (Optional) Fixed value: **true** + +Define if the tab should be displayed as a dropdown menu instead of a tab. This is used for advanced section, which is not used often by the end-user. More than one tab could be grouped in that dropdown tab menu. + +- **formatter-order** (Optional) + +Define the ordering index of this tab in the XSLT formatter (Note used for editor). + +- **mode** (Optional) Fixed value: **flat** + +The "flat" mode is an important concept to understand for the editor. It controls the way: + +- complex elements are displayed (i.e. elements having children) and +- non-existing elements are displayed (i.e. elements in the standard, not in the current document). + +When a tab is in flat mode, this tab will not display elements which are not in the current metadata document and it will display complex elements as a group only if defined in the list of elements with fieldset (see [Grouping element from the standards](creating-custom-editor.md#creating-custom-editor-fieldsWithFieldset)). + +Example for a contact in ""non-flat" mode: + +![](../../user-guide/describing-information/img/editor-contact-nonflatmode.png) + +Example for a contact in "flat" mode: + +![](../../user-guide/describing-information/img/editor-contact-flatmode.png) + +This mode makes the layout simpler, but does not provide all controls to remove some of the usually boxed elements. End-users can still change to the advanced view mode to access those hidden elements in flat mode. + +It's recommended to preserve at least one view in ""non-flat" mode for Reviewers or Administrators in order to be able: + +- to build proper templates based on the standards +- to fix any type of errors. +- **mode** (Mandatory) +- **displayIfRecord** (Optional) + +XPath expression returning boolean value which will be evaluated against the metadata record. if true the view will be displayed. eg. Display custom-view if metadata standard name contains Medsea: + +``` xml + + + + + + + + +``` + +### Customizing thesaurus {#creating-custom-editor-thesaurusList} + +To configure the type of transformations, or the number of keywords allowed, or if the widget has to be displayed in a fieldset, or as simple field for a thesaurus define a specific configuration: + +e.g. only 2 INSPIRE themes: + +``` xml + + + +``` + +## Adding a section to a tab {#creating-custom-editor-section} + +A section is a group of fields. If a `name` attribute is provided, then it will create an HTML fieldset which is collapsible. If no `name` attribute is provided, then it will just render the inner elements. For example, if you need a tab without a root fieldset, just create the mandatory section with no name and then the inner elements. + +Attributes: + +- **name** (Optional) + +An optional name to override the default one base on field name for the + +: section. The name must be defined in `{schema}/loc/{lang}/strings.xml`. + +- **xpath** (Optional) + +The XPath of the element to match. If an XPath is set for a section, it + +: should not contain any fields. + +- **collapsed** (Optional) Fixed value: **true** + +An optional attribute to collapse the section. If not set the section is expanded. + +- **collapsible** (Optional) Fixed value: **false** + +An optional attribute to not allow collapse for the section. If not set the section is expandable. + +- **mode** (Optional) Fixed value: **flat** + +The "flat" mode is an important concept to understand for the editor. It controls the way: + +- complex elements are displayed (i.e. elements having children) and +- non-existing elements are displayed (i.e. elements in the standard, not in the current document). + +When a tab is in flat mode, this tab will not display elements which are not in the current metadata document and it will display complex elements as a group only if defined in the list of elements with fieldset (see [Grouping element from the standards](creating-custom-editor.md#creating-custom-editor-fieldsWithFieldset)). + +Example for a contact in ""non-flat" mode: + +![](../../user-guide/describing-information/img/editor-contact-nonflatmode.png) + +Example for a contact in "flat" mode: + +![](../../user-guide/describing-information/img/editor-contact-flatmode.png) + +This mode makes the layout simpler, but does not provide all controls to remove some of the usually boxed elements. End-users can still change to the advanced view mode to access those hidden elements in flat mode. + +It's recommended to preserve at least one view in ""non-flat" mode for Reviewers or Administrators in order to be able: + +- to build proper templates based on the standards +- to fix any type of errors. +- **mode** (Mandatory) +- **or** (Optional) + +Local name to match if the element does not exist. + +- **or** (Optional) + +The local name of the geonet child (i.e. non-existing element) to match. + +``` xml + +``` + +- **or** (Optional) +- **in** (Optional) + +XPath of the geonet:child element with the or name to look for. Usually + +: points to the parent of last element of the XPath attribute. + +- **in** (Optional) + +The element to search in for the geonet child. + +- **displayIfRecord** (Optional) + +XPath expression returning boolean value which will be evaluated against the metadata record. if true the view will be displayed. eg. Display custom-view if metadata standard name contains Medsea: + +``` xml + +``` + +To override a field label use the `name` attribute and define that new label in `{schema}/loc/{lang}/strings.xml`: + +``` xml + +``` + +To display a complex element which exists in the metadata document: + +``` xml + +``` + +In this case all children elements are also displayed. + +To display a field if it exists in the metadata document or to provide an `add` button in case it does not exist (specify `in` and `or` attributes): + +``` xml + +``` + +Activate the "flat" mode at the tab level to make the form display only existing elements: + +``` xml + + +
    + + +
    +
    +
    +``` + +Attributes: + +- **xpath** (Mandatory) + +The xpath of the element to match. + +- **if** (Optional) + +An optional XPath expression to evaluate to define if the element should be displayed only in some situation (e.g. only for service metadata records). e.g. + +``` xml + +``` + +- **name** (Optional) + +A field name to override the default name. + +- **isMissingLabel** (Optional) + +The label to display if the element does not exist in the metadata record. It indicates that the element is missing in the current record. It could be used for a conformity section saying that the element is "not evaluated". **EXPERIMENTAL** + +- **or** (Optional) + +The local name of the geonet child (i.e. non-existing element) to match. + +``` xml + +``` + +- **in** (Optional) + +The element to search in for the geonet child. + +- **del** (Optional) + +Relative XPath of the element to remove when the `remove` button is clicked. + +e.g. If a template field match linkage and allows editing of field URL, the remove control should remove the parent element gmd:onLine. + +``` xml + +