From b24b6db2fb16741316096bb9fadfa9912a027187 Mon Sep 17 00:00:00 2001 From: Micah Cooper Date: Thu, 12 Oct 2023 09:37:55 -0500 Subject: [PATCH] August 2023 Sprint (#385) * [Issue 328] Resource not found exceptions (#329) * Return null to indicate not found * Add file not found exception handler * Add external asset directory config example * Update README.md * Add index collection name configuration and replace constant * Add initial index health indicator * [Issue 237] Add initial GitHub templates. (#342) * [Issue 347] Add configuration to disable individual document create on batch fail (#348) Co-authored-by: Rincy Mathew * Add configuration to enable/disable schematizing (#356) * Remove over encapsulation and correct separation of concern (#361) The helper classes in discovery package are violating common principles and are not providing abstraction to multiple implementations of their use. * Refactor research/er age with academic age (#363) * Add initial data and analytics view (#366) The additional properties required for data and analytics UI/UX has yet to be determined. * Add organization id to theme (#365) The organization could be removed and wherever rendered can be updated to fetch the organization by id. Note the non default constructor is for testing purposes. * [Issue 368] Refactor relationship date time interval properties (#369) * Refactor relationship date time interval properties The field types conflicted with property of the same name on Process. * Add eof newline to template file * [Issue 370] Add additional facet entity properties to control UI behavior (#371) * Add expandable/collapsible properties to facet entity * Support open dialog for facets * Update facet test for use dialog getters/setters * Use property paths where applicable in views (#374) * Add sub organization type to organization (#375) * Upgrade Jena lib, remove SDB triplestore support, and minor refactoring (#377) * Remove SDB triplestore support * Upgrade jena libs * Add caffeine as a dependency * Minor refactor and replace deprecation * Remove redundant field type creation * Cleanup triplestore harvester * [Issue 357] Individual medium for harvest/index (#378) * Individual medium for harvest/index and remove field binding from discovery model Note that Individual still uses Solr Java Object binding to SolrInputDocument for indexing. * Remove unused test dependency injection * [Issue 380] Data and analytic view container type (#381) * Add container type to data and analytics view * Update individual model resources * Update tests * Add eof newline to data and analytics default yaml * Update export view names * Fix analytics endpoint mapping for academicAge * Remove authorize for now * Fix copy field duplication (#384) * Docx exporter regression (#388) * Use individual for serialization instead of content * Minor refactor document to individual * Add facets to data and analytics views (#389) * Remove broken workflows (#392) * Upgrade some dependencies (#393) * Use liquibase (#394) * Use liquibase * Fix updating defaults * Update authorizations for data and analytics (#395) * Update authorizations for data and analytics * Add some missing ending newlines * Upgrade to solr docker to 9.3 * Use public tamu smtp as default * Now using stomp without sockjs * Upgrade spring security config * Minor cleanup and expose content disposition header * Fix zip exporter authorization * Prevent template error when type is not present (#397) --------- Co-authored-by: William Welling Co-authored-by: William Welling Co-authored-by: Rincy Mathew Co-authored-by: wwoops <144841721+wwoops@users.noreply.github.com> Co-authored-by: William Welling <144841721+wwhoop@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/feature.md | 25 + .github/ISSUE_TEMPLATE/issue.md | 23 + .github/ISSUE_TEMPLATE/question.md | 8 + .github/dependabot.yml | 17 - .github/pull_request_template.md | 15 + .github/workflows/codeql.yml | 76 - README.md | 20 +- pom.xml | 66 +- solr/Dockerfile | 2 +- .../conf/managed-schema.xml | 8 +- .../scholars-discovery/conf/solrconfig.xml | 159 +- .../administration/dataAndAnalyticsViews.adoc | 120 + .../administration/directoryViews.adoc | 4 +- .../administration/discoveryViews.adoc | 2 +- .../asciidoc/administration/displayViews.adoc | 2 +- src/main/asciidoc/administration/themes.adoc | 2 +- src/main/asciidoc/index.adoc | 1 + .../middleware/config/HttpSessionConfig.java | 19 - .../config/SecurityExpressionConfig.java | 2 +- .../middleware/config/WebMvcConfig.java | 4 + .../middleware/config/WebSecurityConfig.java | 39 +- .../middleware/config/WebSocketConfig.java | 4 +- .../config/WebSocketSecurityConfig.java | 1 + .../middleware/config/model/IndexConfig.java | 30 + .../middleware/defaults/AbstractDefaults.java | 14 +- .../defaults/AnalyticViewsDefaults.java | 35 + .../discovery/DiscoveryConstants.java | 6 +- .../advice/DiscoveryControllerAdvice.java | 9 + .../annotation/CollectionTarget.java | 19 - ...va => DiscoveryAcademicAgeDescriptor.java} | 10 +- .../discovery/component/Harvester.java | 5 +- .../discovery/component/Indexer.java | 5 +- .../component/jena/TriplestoreHarvester.java | 142 +- .../discovery/component/solr/SolrIndexer.java | 82 +- .../IndividualAnalyticsController.java | 11 +- .../indicator/IndexHealthIndicator.java | 74 + .../model/AbstractIndexDocument.java | 31 +- .../discovery/model/Collection.java | 36 +- .../middleware/discovery/model/Common.java | 13 +- .../middleware/discovery/model/Concept.java | 30 +- .../middleware/discovery/model/Document.java | 92 +- .../discovery/model/Individual.java | 95 +- .../discovery/model/Organization.java | 81 +- .../middleware/discovery/model/Person.java | 172 +- .../middleware/discovery/model/Process.java | 50 +- .../discovery/model/Relationship.java | 79 +- .../discovery/model/helper/ContentMapper.java | 33 - .../model/helper/IndividualHelper.java | 43 - .../model/repo/IndexDocumentRepo.java | 6 +- .../discovery/model/repo/IndividualRepo.java | 92 +- ...archAge.java => DiscoveryAcademicAge.java} | 326 +- .../DiscoveryFacetAndHighlightPage.java | 3 +- .../response/DiscoveryFacetPage.java | 3 +- .../UnwrappingIndividualSerializer.java | 26 +- .../discovery/service/IndexService.java | 40 +- .../discovery/utility/DiscoveryUtility.java | 60 +- .../export/advice/ExportControllerAdvice.java | 7 + .../IndividualExportController.java | 81 +- .../export/exception/ExportException.java | 2 +- ...ExportQueryParameterRequiredException.java | 2 +- .../UnauthorizedExportException.java | 11 + .../export/service/CsvExporter.java | 38 +- .../export/service/DocxExporter.java | 6 +- .../export/service/ZipDocxExporter.java | 10 +- .../export/utility/FilenameUtility.java | 29 +- ...pTriplestore.java => HttpTriplestore.java} | 16 +- .../middleware/service/SDBTriplestore.java | 64 - .../middleware/theme/model/Theme.java | 14 +- .../middleware/view/model/ContainerType.java | 5 + .../view/model/DataAndAnalyticsView.java | 27 + .../scholars/middleware/view/model/Facet.java | 40 +- .../middleware/view/model/Layout.java | 2 +- .../model/repo/DataAndAnalyticsViewRepo.java | 10 + .../DataAndAnalyticViewEventHandler.java | 18 + src/main/resources/application.yml | 57 +- .../db/changelog/db.changelog-master.yaml | 3243 +++++++++++++++++ .../defaults/dataAndanalyticViews.yml | 84 + .../resources/defaults/directoryViews.yml | 12 +- .../directoryViews/research/default.html | 4 +- .../resources/defaults/discoveryViews.yml | 42 +- .../discoveryViews/grants/default.html | 14 +- .../discoveryViews/publications/default.html | 4 +- src/main/resources/defaults/displayViews.yml | 26 +- .../displayViews/documents/other/tags.html | 2 +- .../overview/dateTimeInterval.html | 15 - .../displayViews/persons/asideTemplate.html | 4 +- .../academicArticles.html | 2 +- .../selectedPublications/book.html | 2 +- .../selectedPublications/chapter.html | 2 +- .../conferencePapers.html | 2 +- .../selectedPublications/default.html | 2 +- .../internetPublication.html | 2 +- .../selectedPublications/report.html | 2 +- .../selectedPublications/thesis.html | 2 +- .../overview/dateTimeInterval.html | 16 +- src/main/resources/defaults/themes.yml | 2 + .../hasSubOrganizationType.sparql | 12 + ...ntervalStart.sparql => endDateTime.sparql} | 0 ...ntervalEnd.sparql => startDateTime.sparql} | 0 .../middleware/config/SolrTestConfig.java | 8 +- .../config/model/MiddlewareConfigTest.java | 8 +- .../config/model/TriplestoreConfigTest.java | 5 +- .../AbstractSolrDocumentIntegrationTest.java | 88 +- .../AbstractSolrDocumentControllerTest.java | 7 +- .../messaging/EntityMessageTest.java | 6 +- .../theme/ThemeIntegrationTest.java | 2 +- .../theme/controller/ThemeControllerTest.java | 143 +- .../middleware/theme/model/ThemeTest.java | 5 +- .../middleware/view/ViewTestUtility.java | 97 +- .../DataAndAnalyticsViewControllerTest.java | 329 ++ .../view/model/DataAndAnalyticsViewTest.java | 81 + .../middleware/view/model/FacetTest.java | 6 + .../repo/DataAndAnalyticsViewRepoTest.java | 34 + src/test/resources/application.yml | 29 +- .../discovery/relationships/na971ae5b.json | 4 +- 115 files changed, 5499 insertions(+), 1660 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/feature.md create mode 100644 .github/ISSUE_TEMPLATE/issue.md create mode 100644 .github/ISSUE_TEMPLATE/question.md delete mode 100644 .github/dependabot.yml create mode 100644 .github/pull_request_template.md delete mode 100644 .github/workflows/codeql.yml create mode 100644 src/main/asciidoc/administration/dataAndAnalyticsViews.adoc delete mode 100644 src/main/java/edu/tamu/scholars/middleware/config/HttpSessionConfig.java create mode 100644 src/main/java/edu/tamu/scholars/middleware/defaults/AnalyticViewsDefaults.java delete mode 100644 src/main/java/edu/tamu/scholars/middleware/discovery/annotation/CollectionTarget.java rename src/main/java/edu/tamu/scholars/middleware/discovery/argument/{DiscoveryResearchAgeDescriptor.java => DiscoveryAcademicAgeDescriptor.java} (94%) create mode 100644 src/main/java/edu/tamu/scholars/middleware/discovery/indicator/IndexHealthIndicator.java delete mode 100644 src/main/java/edu/tamu/scholars/middleware/discovery/model/helper/ContentMapper.java delete mode 100644 src/main/java/edu/tamu/scholars/middleware/discovery/model/helper/IndividualHelper.java rename src/main/java/edu/tamu/scholars/middleware/discovery/response/{DiscoveryResearchAge.java => DiscoveryAcademicAge.java} (80%) create mode 100644 src/main/java/edu/tamu/scholars/middleware/export/exception/UnauthorizedExportException.java rename src/main/java/edu/tamu/scholars/middleware/service/{SparqlHttpTriplestore.java => HttpTriplestore.java} (75%) delete mode 100644 src/main/java/edu/tamu/scholars/middleware/service/SDBTriplestore.java create mode 100644 src/main/java/edu/tamu/scholars/middleware/view/model/ContainerType.java create mode 100644 src/main/java/edu/tamu/scholars/middleware/view/model/DataAndAnalyticsView.java create mode 100644 src/main/java/edu/tamu/scholars/middleware/view/model/repo/DataAndAnalyticsViewRepo.java create mode 100644 src/main/java/edu/tamu/scholars/middleware/view/model/repo/handler/DataAndAnalyticViewEventHandler.java create mode 100644 src/main/resources/db/changelog/db.changelog-master.yaml create mode 100644 src/main/resources/defaults/dataAndanalyticViews.yml delete mode 100644 src/main/resources/defaults/displayViews/organizations/overview/dateTimeInterval.html create mode 100644 src/main/resources/templates/sparql/organization/hasSubOrganizationType.sparql rename src/main/resources/templates/sparql/relationship/{dateTimeIntervalStart.sparql => endDateTime.sparql} (100%) rename src/main/resources/templates/sparql/relationship/{dateTimeIntervalEnd.sparql => startDateTime.sparql} (100%) create mode 100644 src/test/java/edu/tamu/scholars/middleware/view/controller/DataAndAnalyticsViewControllerTest.java create mode 100644 src/test/java/edu/tamu/scholars/middleware/view/model/DataAndAnalyticsViewTest.java create mode 100644 src/test/java/edu/tamu/scholars/middleware/view/model/repo/DataAndAnalyticsViewRepoTest.java diff --git a/.github/ISSUE_TEMPLATE/feature.md b/.github/ISSUE_TEMPLATE/feature.md new file mode 100644 index 000000000..103760cac --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature.md @@ -0,0 +1,25 @@ +--- +name: Tracking feature +about: Use this template for tracking new features. +title: "[DATE]: [FEATURE NAME]" +labels: tracking feature, needs planning +--- + +1. Purpose + > What use case is this for? + + +2. Scope + > What is the scope of the feature? + + +3. Overview + > Please provide as much detail as necessary to describe the feature. + + +4. Reference Material + > Please provide only links. + + +5. Definitions and Acronyms (optional) + > Provide a list of definitions and acronyms if any are used above. diff --git a/.github/ISSUE_TEMPLATE/issue.md b/.github/ISSUE_TEMPLATE/issue.md new file mode 100644 index 000000000..f7415252a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/issue.md @@ -0,0 +1,23 @@ +--- +name: Tracking issue +about: Use this template for tracking complaints. +title: "[DATE]: [ISSUE NAME]" +labels: tracking issue, needs triage +--- + +1. What is the type of this issue? + - [ ] Client + + - [ ] Documentation: documentation is missing, incomplete, incorrect, ambiguous, or incomprehensible. + - [ ] Functional: the expected or intended functionality is not provided. + - [ ] Behavioral: something happened that is not expected. + + > Please limit issues to a single type. + + - [ ] Developer + + > Please include any and all links from this repository suspected of causing the issue. + + - [ ] Operational + + > Please describe what changes are required. diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 000000000..529b7fb99 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,8 @@ +--- +name: Tracking question +about: Use this template for asking questions. +title: "[DATE]: [QUESTION NAME]" +labels: tracking question, needs answer +--- + +> Please limit to one question and only supporting statements necessary to convey. diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 9003d4ae9..000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,17 +0,0 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - -version: 2 -updates: - - package-ecosystem: "maven" # See documentation for possible values - directory: "/" # Location of package manifests - schedule: - interval: "weekly" - - # Maintain dependencies for GitHub Actions - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..230c13899 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,15 @@ +# Description +> Please provide only as much detail as needed to justify the changes. + +# Supporting Material +> Please provide the links necessary to support the claims made in description above. + +# Additional Comments +> Please provide any additional feedback here. + +# Helper Checklist (optional) +> Please ensure the following has been completed. + +- [ ] Changes reviewed and are acceptable to the best of your understanding. +- [ ] Changes are documented where necessary. +- [ ] Contacted code owners to evaluate. diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index ed94f6872..000000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,76 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" - -on: - push: - branches: [ "tamu-main", *main ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ "tamu-main" ] - schedule: - - cron: '0 0 * * 0' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'java', 'javascript' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Use only 'java' to analyze code written in Java, Kotlin or both - # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both - # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality - - - # Autobuild attempts to build any compiled languages (C/C++, C#, Go, 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 - - # ℹī¸ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - # If the Autobuild fails above, remove it and uncomment the following three lines. - # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. - - # - run: | - # echo "Run, Build Application using script" - # ./location_of_script_within_repo/buildscript.sh - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 - with: - category: "/language:${{matrix.language}}" diff --git a/README.md b/README.md index 719146648..e2c45ea02 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,22 @@ Here is a list of some dependencies used: The basic Spring Boot application configuration can be found at [src/main/resources/application.yml](https://github.com/vivo-community/scholars-discovery/blob/master/src/main/resources/application.yml). Here you be able to configure basic server and spring configuration as well as custom configuration for Scholars Discovery. There are several configuration POJOs to represent configurations. They can be found in [src/main/java/edu/tamu/scholars/middleware/config/model](https://github.com/vivo-community/scholars-discovery/tree/master/src/main/java/edu/tamu/scholars/middleware/config/model), and [src/main/java/edu/tamu/scholars/middleware/auth/config](https://github.com/vivo-community/scholars-discovery/tree/master/src/main/java/edu/tamu/scholars/middleware/auth/config). +## Assets + +Assets are hosted at `/file/:id/:filename` and configured location `middleware.assets-location`. + +Tested options are + +Assets stored in src/main/resources/assets +``` +middleware.assets-location: classpath:/assets +``` + +Assets stored in externally +``` +middleware.assets-location: file:/scholars/assets +``` + ### Harvesting Harvesting can be configured via ```middleware.harvesters``` and represented with [HarvesterConfig](https://github.com/vivo-community/scholars-discovery/blob/master/src/main/java/edu/tamu/scholars/middleware/config/model/HarvesterConfig.java). For each harvester, a bean will be created in which specifies the type of harvester and which document types it maps to. The reference implementation is the local triplestore harvester. @@ -59,9 +75,7 @@ Solr is configured via ```spring.data.solr```. 3. Start Solr ```bash - cd solr - docker build --tag=scholars/solr . - docker run -d -p 8983:8983 scholars/solr + cd solr && docker build --tag=scholars/solr . && docker run -d -p 8983:8983 scholars/solr && cd .. ``` 5. Build and Run the application diff --git a/pom.xml b/pom.xml index f1053396c..520bebffb 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ org.springframework.boot spring-boot-starter-parent - 2.6.14 + 2.6.15 @@ -29,8 +29,9 @@ UTF-8 - 2.17.1 - 3.17.0 + 4.23.2 + 2.17.2 + 4.9.0 9.1.1 @@ -160,7 +161,7 @@ com.jayway.jsonpath json-path - 2.7.0 + 2.8.0 @@ -172,7 +173,7 @@ org.apache.commons commons-compress - 1.22 + 1.24.0 @@ -218,28 +219,20 @@ org.apache.jena - jena-sdb + jena-serviceenhancer ${jena.version} - - - com.github.jsonld-java - jsonld-java - - - org.apache.commons - commons-compress - - - org.slf4j - slf4j-log4j12 - - + + + + com.github.ben-manes.caffeine + caffeine + 3.1.8 org.passay passay - 1.6.2 + 1.6.4 @@ -272,14 +265,20 @@ 8.2.1 + + org.liquibase + liquibase-core + ${liquibase.version} + + com.h2database h2 runtime - mysql - mysql-connector-java + com.mysql + mysql-connector-j org.postgresql @@ -310,19 +309,26 @@ test - - com.github.ben-manes.caffeine - caffeine - 3.1.1 - test - - + + + org.liquibase + liquibase-maven-plugin + ${liquibase.version} + + org.h2.Driver + jdbc:h2:./h2;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE + scholars + scholars + src/main/resources/db/changelog/db.changelog-master.yaml + + + org.springframework.boot spring-boot-maven-plugin diff --git a/solr/Dockerfile b/solr/Dockerfile index 35aa45418..3939a7366 100644 --- a/solr/Dockerfile +++ b/solr/Dockerfile @@ -1,4 +1,4 @@ -FROM solr:9.1 +FROM solr:9.3 USER root diff --git a/solr/configsets/scholars-discovery/conf/managed-schema.xml b/solr/configsets/scholars-discovery/conf/managed-schema.xml index 9b732b66a..db33a7e48 100644 --- a/solr/configsets/scholars-discovery/conf/managed-schema.xml +++ b/solr/configsets/scholars-discovery/conf/managed-schema.xml @@ -202,10 +202,6 @@ field first in an ascending sort and last in a descending sort. --> - - - - @@ -358,6 +354,10 @@ + + + + diff --git a/solr/configsets/scholars-discovery/conf/solrconfig.xml b/solr/configsets/scholars-discovery/conf/solrconfig.xml index e01f9abbb..bc3d62f63 100644 --- a/solr/configsets/scholars-discovery/conf/solrconfig.xml +++ b/solr/configsets/scholars-discovery/conf/solrconfig.xml @@ -35,7 +35,7 @@ that you fully re-index after changing this setting as it can affect both how text is indexed and queried. --> - 9.4 + 9.7 @@ -385,10 +385,9 @@ to occupy. Note that when this option is specified, the size and initialSize parameters are ignored. --> - - + - - + - + + autowarmCount="128"/> + - - - - - + + - - - - - - + + @@ -990,48 +969,6 @@ [EEE, ]dd MMM yyyy HH:mm[:ss] z EEEE, dd-MMM-yy HH:mm:ss z EEE MMM ppd HH:mm:ss [z ]yyyy - - yyyy-MM-dd'T'HH:mm:ss.SSS - yyyy-MM-dd'T'HH:mm:ss.SSSz - yyyy-MM-dd'T'HH:mm:ss.SSSZ - yyyy-MM-dd'T'HH:mm:ss.SSSZZ - - yyyy-MM-dd'T'HH:mm:ss,SSS - yyyy-MM-dd'T'HH:mm:ss,SSSz - yyyy-MM-dd'T'HH:mm:ss,SSSZ - yyyy-MM-dd'T'HH:mm:ss,SSSZZ - - yyyy-MM-dd'T'HH:mm:ss - yyyy-MM-dd'T'HH:mm:ssz - yyyy-MM-dd'T'HH:mm:ssZ - yyyy-MM-dd'T'HH:mm:ssZZ - - yyyy-MM-dd'T'HH:mm - yyyy-MM-dd'T'HH:mmz - yyyy-MM-dd'T'HH:mmZ - yyyy-MM-dd'T'HH:mmZZ - - yyyy-MM-dd HH:mm:ss.SSS - yyyy-MM-dd HH:mm:ss.SSSz - yyyy-MM-dd HH:mm:ss.SSSZ - yyyy-MM-dd HH:mm:ss.SSSZZ - - yyyy-MM-dd HH:mm:ss,SSS - yyyy-MM-dd HH:mm:ss,SSSz - yyyy-MM-dd HH:mm:ss,SSSZ - yyyy-MM-dd HH:mm:ss,SSSZZ - - yyyy-MM-dd HH:mm:ss - yyyy-MM-dd HH:mm:ssz - yyyy-MM-dd HH:mm:ssZ - yyyy-MM-dd HH:mm:ssZZ - - yyyy-MM-dd HH:mm - yyyy-MM-dd HH:mmz - yyyy-MM-dd HH:mmZ - yyyy-MM-dd HH:mmZZ - - yyyy-MM-dd diff --git a/src/main/asciidoc/administration/dataAndAnalyticsViews.adoc b/src/main/asciidoc/administration/dataAndAnalyticsViews.adoc new file mode 100644 index 000000000..225cdef78 --- /dev/null +++ b/src/main/asciidoc/administration/dataAndAnalyticsViews.adoc @@ -0,0 +1,120 @@ +=== Data And Analytics Views + +This section describes the data and analytics views of the application. This object is a persistent representation of a data and analytics UI. + +==== Data And Analytics + +This displays a list of all the data and analytics view objects based on parameters like page, size or sort feature based on name, collection etc as shown in *Request Parameters*. + +===== Request Parameters +include::../{snippets}/dataAndAnalyticsViews/directory/request-parameters.adoc[] + +===== Response Fields +include::../{snippets}/dataAndAnalyticsViews/directory/response-fields.adoc[] + +===== Sample Request +include::../{snippets}/dataAndAnalyticsViews/directory/http-request.adoc[] + +===== Sample Response +include::../{snippets}/dataAndAnalyticsViews/directory/http-response.adoc[] + +===== CURL Sample +include::../{snippets}/dataAndAnalyticsViews/directory/curl-request.adoc[] + +==== Create + +A data and analytics view is created by adding a fields like _name_, _collection_ etc along with other variables as shown in the *Request Fields*. + +===== Request Fields +include::../{snippets}/dataAndAnalyticsViews/create/request-fields.adoc[] + +===== Response Fields +include::../{snippets}/dataAndAnalyticsViews/create/response-fields.adoc[] + +===== Sample Request +include::../{snippets}/dataAndAnalyticsViews/create/http-request.adoc[] + +===== Sample Response +include::../{snippets}/dataAndAnalyticsViews/create/http-response.adoc[] + +===== CURL Sample +include::../{snippets}/dataAndAnalyticsViews/create/curl-request.adoc[] + +==== Delete + +A data and analytics view can be deleted by passing the _dataAndAnalyticsView id_ as a path parameter. This will return a *NO_CONTENT (204)* http status code as shown in the *Sample Response*. + +===== Path Parameters +include::../{snippets}/dataAndAnalyticsViews/delete/path-parameters.adoc[] + +===== Sample Request +include::../{snippets}/dataAndAnalyticsViews/delete/http-request.adoc[] + +===== Sample Response +include::../{snippets}/dataAndAnalyticsViews/delete/http-response.adoc[] + +===== CURL Sample +include::../{snippets}/dataAndAnalyticsViews/delete/curl-request.adoc[] + +==== Find by Id + +A user can find a data and analytics view by providing _dataAndAnalyticsView id_ as a path parameter. This returns a json response displaying the *HttpStatus.OK(200)* message along with the data and analytics view object as shown in the *Sample Response*. + +===== Path Parameters +include::../{snippets}/dataAndAnalyticsViews/find-by-id/path-parameters.adoc[] + +===== Response Fields +include::../{snippets}/dataAndAnalyticsViews/find-by-id/response-fields.adoc[] + +===== Sample Request +include::../{snippets}/dataAndAnalyticsViews/find-by-id/http-request.adoc[] + +===== Sample Response +include::../{snippets}/dataAndAnalyticsViews/find-by-id/http-response.adoc[] + +===== CURL Sample +include::../{snippets}/dataAndAnalyticsViews/find-by-id/curl-request.adoc[] + +==== Patch + +This helps an admin user to partially update a data and analytics view. This process utilizes the http patch protocol. + +===== Path Parameters +include::../{snippets}/dataAndAnalyticsViews/patch/path-parameters.adoc[] + +===== Request Parameters +include::../{snippets}/dataAndAnalyticsViews/patch/request-parameters.adoc[] + +===== Response Fields +include::../{snippets}/dataAndAnalyticsViews/patch/response-fields.adoc[] + +===== Sample Request +include::../{snippets}/dataAndAnalyticsViews/patch/http-request.adoc[] + +===== Sample Response +include::../{snippets}/dataAndAnalyticsViews/patch/http-response.adoc[] + +===== CURL Sample +include::../{snippets}/dataAndAnalyticsViews/patch/curl-request.adoc[] + +==== Update + +This helps an admin user to update a specifc data and analytics view based on the _dataAndAnalyticsView id_ provided in the path parameter. This utilizes the http put protocol. + +===== Path Parameters +include::../{snippets}/dataAndAnalyticsViews/update/path-parameters.adoc[] + +===== Request Fields +include::../{snippets}/dataAndAnalyticsViews/update/request-fields.adoc[] + +===== Response Fields +include::../{snippets}/dataAndAnalyticsViews/update/response-fields.adoc[] + +===== Sample Request +include::../{snippets}/dataAndAnalyticsViews/update/http-request.adoc[] + +===== Sample Response +include::../{snippets}/dataAndAnalyticsViews/update/http-response.adoc[] + +===== CURL Sample +include::../{snippets}/dataAndAnalyticsViews/update/curl-request.adoc[] diff --git a/src/main/asciidoc/administration/directoryViews.adoc b/src/main/asciidoc/administration/directoryViews.adoc index 3cfd5f689..688d60282 100644 --- a/src/main/asciidoc/administration/directoryViews.adoc +++ b/src/main/asciidoc/administration/directoryViews.adoc @@ -1,6 +1,6 @@ === Directory Views -This section describes about the directory views of the application. This object is a persistent representation of a directory UI. +This section describes the directory views of the application. This object is a persistent representation of a directory UI. ==== Directory @@ -117,4 +117,4 @@ include::../{snippets}/directoryViews/update/http-request.adoc[] include::../{snippets}/directoryViews/update/http-response.adoc[] ===== CURL Sample -include::../{snippets}/directoryViews/update/curl-request.adoc[] +include::../{snippets}/directoryViews/update/curl-request.adoc[] \ No newline at end of file diff --git a/src/main/asciidoc/administration/discoveryViews.adoc b/src/main/asciidoc/administration/discoveryViews.adoc index b0cf1bde8..9b385b45d 100644 --- a/src/main/asciidoc/administration/discoveryViews.adoc +++ b/src/main/asciidoc/administration/discoveryViews.adoc @@ -1,6 +1,6 @@ === Discovery Views -This section describes about the discovery views of the application. This object is a persistent representation of a discovery view. +This section describes the discovery views of the application. This object is a persistent representation of a discovery view. ==== Directory diff --git a/src/main/asciidoc/administration/displayViews.adoc b/src/main/asciidoc/administration/displayViews.adoc index e80917938..9b536b2ee 100644 --- a/src/main/asciidoc/administration/displayViews.adoc +++ b/src/main/asciidoc/administration/displayViews.adoc @@ -1,6 +1,6 @@ === Display Views -This section describes about the display views of the application. This object is a persistent representation of a display UI. +This section describes the display views of the application. This object is a persistent representation of a display UI. ==== Directory diff --git a/src/main/asciidoc/administration/themes.adoc b/src/main/asciidoc/administration/themes.adoc index 080d3870b..eee2cf1d9 100644 --- a/src/main/asciidoc/administration/themes.adoc +++ b/src/main/asciidoc/administration/themes.adoc @@ -1,6 +1,6 @@ === Themes -This section describes about the "look and feel" of the application. This object is a collection of properties like the header, logo, footer, color, size, styles etc. +This section describes the "look and feel" of the application. This object is a collection of properties like the header, logo, footer, color, size, styles etc. The default theme view is seen in the *Sample Response*. ==== Directory diff --git a/src/main/asciidoc/index.adoc b/src/main/asciidoc/index.adoc index f26aa8655..740ed577f 100644 --- a/src/main/asciidoc/index.adoc +++ b/src/main/asciidoc/index.adoc @@ -42,6 +42,7 @@ include::auth/user.adoc[] == Administration +include::administration/dataAndAnalyticsViews.adoc[] include::administration/directoryViews.adoc[] include::administration/discoveryViews.adoc[] include::administration/displayViews.adoc[] diff --git a/src/main/java/edu/tamu/scholars/middleware/config/HttpSessionConfig.java b/src/main/java/edu/tamu/scholars/middleware/config/HttpSessionConfig.java deleted file mode 100644 index 7045df157..000000000 --- a/src/main/java/edu/tamu/scholars/middleware/config/HttpSessionConfig.java +++ /dev/null @@ -1,19 +0,0 @@ -package edu.tamu.scholars.middleware.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.session.web.http.CookieSerializer; -import org.springframework.session.web.http.DefaultCookieSerializer; - -@Configuration -public class HttpSessionConfig { - - @Bean - public CookieSerializer cookieSerializer() { - DefaultCookieSerializer serializer = new DefaultCookieSerializer(); - serializer.setUseHttpOnlyCookie(false); - serializer.setUseSecureCookie(false); - return serializer; - } - -} diff --git a/src/main/java/edu/tamu/scholars/middleware/config/SecurityExpressionConfig.java b/src/main/java/edu/tamu/scholars/middleware/config/SecurityExpressionConfig.java index 5556046b7..43b685376 100644 --- a/src/main/java/edu/tamu/scholars/middleware/config/SecurityExpressionConfig.java +++ b/src/main/java/edu/tamu/scholars/middleware/config/SecurityExpressionConfig.java @@ -36,7 +36,7 @@ public SecurityExpressionHandler> messageSecurityExpressionHandl } private String buildRoleHierarchy() { - return "ROLE_SUPER_ADMIN > ROLE_ADMIN > ROLE_USER"; + return "ROLE_SUPER_ADMIN > ROLE_ADMIN\nROLE_ADMIN > ROLE_USER\n"; } } diff --git a/src/main/java/edu/tamu/scholars/middleware/config/WebMvcConfig.java b/src/main/java/edu/tamu/scholars/middleware/config/WebMvcConfig.java index 37a3dc674..62bc30897 100644 --- a/src/main/java/edu/tamu/scholars/middleware/config/WebMvcConfig.java +++ b/src/main/java/edu/tamu/scholars/middleware/config/WebMvcConfig.java @@ -71,6 +71,10 @@ protected Resource getResource(String resourcePath, Resource location) throws IO location = new FileUrlResource(resourcePath); } + if (!location.getFile().exists()) { + location = null; + } + return location; } diff --git a/src/main/java/edu/tamu/scholars/middleware/config/WebSecurityConfig.java b/src/main/java/edu/tamu/scholars/middleware/config/WebSecurityConfig.java index d54dc649c..371972767 100644 --- a/src/main/java/edu/tamu/scholars/middleware/config/WebSecurityConfig.java +++ b/src/main/java/edu/tamu/scholars/middleware/config/WebSecurityConfig.java @@ -10,8 +10,6 @@ import java.security.SecureRandom; import java.util.Arrays; -import com.fasterxml.jackson.databind.ObjectMapper; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.MessageSource; @@ -22,19 +20,24 @@ import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.token.KeyBasedPersistenceTokenService; import org.springframework.security.core.token.TokenService; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.FilterInvocation; +import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.savedrequest.NullRequestCache; +import org.springframework.session.web.http.CookieSerializer; +import org.springframework.session.web.http.DefaultCookieSerializer; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; +import com.fasterxml.jackson.databind.ObjectMapper; + import edu.tamu.scholars.middleware.auth.config.TokenConfig; import edu.tamu.scholars.middleware.auth.handler.CustomAccessDeniedExceptionHandler; import edu.tamu.scholars.middleware.auth.handler.CustomAuthenticationEntryPoint; @@ -46,7 +49,7 @@ @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) -public class WebSecurityConfig extends WebSecurityConfigurerAdapter { +public class WebSecurityConfig { @Value("${spring.profiles.active:default}") private String profile; @@ -112,7 +115,8 @@ public CorsFilter corsFilter() { primaryConfig.setAllowCredentials(true); primaryConfig.setAllowedOrigins(config.getAllowedOrigins()); primaryConfig.setAllowedMethods(Arrays.asList("GET", "DELETE", "PUT", "POST", "PATCH", "OPTIONS")); - primaryConfig.setAllowedHeaders(Arrays.asList("Authorization", "Origin", "Content-Type")); + primaryConfig.setAllowedHeaders(Arrays.asList("Authorization", "Origin", "Content-Type", "Content-Disposition")); + primaryConfig.setExposedHeaders(Arrays.asList("Content-Disposition")); // NOTE: most general path must be last source.registerCorsConfiguration("/**", primaryConfig); @@ -126,8 +130,16 @@ public LocalValidatorFactoryBean getValidator() { return bean; } - @Override - protected void configure(HttpSecurity http) throws Exception { + @Bean + public CookieSerializer cookieSerializer() { + DefaultCookieSerializer serializer = new DefaultCookieSerializer(); + serializer.setUseHttpOnlyCookie(false); + serializer.setUseSecureCookie(false); + return serializer; + } + + @Bean + protected SecurityFilterChain configure(HttpSecurity http) throws Exception { if (enableH2Console()) { // NOTE: permit all access to h2console http @@ -140,6 +152,7 @@ protected void configure(HttpSecurity http) throws Exception { .expressionHandler(securityExpressionHandler) .antMatchers(PATCH, + "/dataAndAnalyticsViews/{id}", "/directoryViews/{id}", "/discoveryViews/{id}", "/displayViews/{id}", @@ -152,6 +165,7 @@ protected void configure(HttpSecurity http) throws Exception { .permitAll() .antMatchers(POST, + "/dataAndAnalyticsViews/{id}", "/directoryViews/{id}", "/discoveryViews/{id}", "/displayViews/{id}", @@ -165,6 +179,7 @@ protected void configure(HttpSecurity http) throws Exception { .permitAll() .antMatchers(PUT, + "/dataAndAnalyticsViews/{id}", "/directoryViews/{id}", "/discoveryViews/{id}", "/displayViews/{id}", @@ -185,6 +200,7 @@ protected void configure(HttpSecurity http) throws Exception { .hasRole("ADMIN") .antMatchers(DELETE, + "/dataAndAnalyticsViews/{id}", "/directoryViews/{id}", "/discoveryViews/{id}", "/displayViews/{id}", @@ -204,7 +220,7 @@ protected void configure(HttpSecurity http) throws Exception { .permitAll() .and() .logout() - .deleteCookies("remove") + .deleteCookies("SESSION") .invalidateHttpSession(true) .logoutSuccessHandler(logoutSuccessHandler()) .permitAll() @@ -220,6 +236,13 @@ protected void configure(HttpSecurity http) throws Exception { .and() .csrf() .disable(); + + http.sessionManagement() + .sessionFixation() + .migrateSession() + .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED); + + return http.build(); } private CustomAuthenticationSuccessHandler authenticationSuccessHandler() { diff --git a/src/main/java/edu/tamu/scholars/middleware/config/WebSocketConfig.java b/src/main/java/edu/tamu/scholars/middleware/config/WebSocketConfig.java index a42c281dc..f39b04e69 100644 --- a/src/main/java/edu/tamu/scholars/middleware/config/WebSocketConfig.java +++ b/src/main/java/edu/tamu/scholars/middleware/config/WebSocketConfig.java @@ -35,8 +35,8 @@ protected void configureStompEndpoints(StompEndpointRegistry registry) { registry.setErrorHandler(new CustomStompSubProtocolErrorHandler()); registry .addEndpoint("/connect") - .setAllowedOrigins(config.getAllowedOrigins().toArray(new String[config.getAllowedOrigins().size()])).withSockJS() - .setInterceptors( + .setAllowedOrigins(config.getAllowedOrigins().toArray(new String[config.getAllowedOrigins().size()])) + .addInterceptors( new HttpSessionHandshakeInterceptor(), // TODO: remove when patched in spring-session, https://github.com/spring-projects/spring-session/issues/561 new HandshakeInterceptor() { diff --git a/src/main/java/edu/tamu/scholars/middleware/config/WebSocketSecurityConfig.java b/src/main/java/edu/tamu/scholars/middleware/config/WebSocketSecurityConfig.java index 05a805a44..0bd757e1b 100644 --- a/src/main/java/edu/tamu/scholars/middleware/config/WebSocketSecurityConfig.java +++ b/src/main/java/edu/tamu/scholars/middleware/config/WebSocketSecurityConfig.java @@ -29,6 +29,7 @@ protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) .simpSubscribeDestMatchers( "/queue/public", "/queue/themes", + "/queue/dataAndAnalyticsViews", "/queue/directoryViews", "/queue/discoveryViews", "/queue/displayViews", diff --git a/src/main/java/edu/tamu/scholars/middleware/config/model/IndexConfig.java b/src/main/java/edu/tamu/scholars/middleware/config/model/IndexConfig.java index 9395c7d02..b3758b64e 100644 --- a/src/main/java/edu/tamu/scholars/middleware/config/model/IndexConfig.java +++ b/src/main/java/edu/tamu/scholars/middleware/config/model/IndexConfig.java @@ -7,16 +7,30 @@ @ConfigurationProperties(prefix = "middleware.index") public class IndexConfig { + private String name = "scholars-discovery"; + private String cron = "0 0 0 * * SUN"; private String zone = "America/Chicago"; + private boolean schematize = true; + private boolean onStartup = true; + private boolean enableIndividualOnBatchFail = true; + private int onStartupDelay = 10000; private int batchSize = 10000; + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + public String getCron() { return cron; } @@ -33,6 +47,14 @@ public void setZone(String zone) { this.zone = zone; } + public boolean isSchematize() { + return schematize; + } + + public void setSchematize(boolean schematize) { + this.schematize = schematize; + } + public boolean isOnStartup() { return onStartup; } @@ -41,6 +63,14 @@ public void setOnStartup(boolean onStartup) { this.onStartup = onStartup; } + public boolean isEnableIndividualOnBatchFail() { + return enableIndividualOnBatchFail; + } + + public void setEnableIndividualOnBatchFail(boolean enableIndividualOnBatchFail) { + this.enableIndividualOnBatchFail = enableIndividualOnBatchFail; + } + public int getOnStartupDelay() { return onStartupDelay; } diff --git a/src/main/java/edu/tamu/scholars/middleware/defaults/AbstractDefaults.java b/src/main/java/edu/tamu/scholars/middleware/defaults/AbstractDefaults.java index 280aeaf97..41fb30492 100644 --- a/src/main/java/edu/tamu/scholars/middleware/defaults/AbstractDefaults.java +++ b/src/main/java/edu/tamu/scholars/middleware/defaults/AbstractDefaults.java @@ -1,5 +1,7 @@ package edu.tamu.scholars.middleware.defaults; +import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.ID; + import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.List; @@ -23,9 +25,9 @@ public abstract class AbstractDefaults> implements Defaults { - private static final String CREATED_DEFAULTS = "Created %s %s defaults."; + private static final String CREATED_DEFAULTS = "Created {} {} defaults."; - private static final String UPDATED_DEFAULTS = "Updated %s %s defaults."; + private static final String UPDATED_DEFAULTS = "Updated {} {} defaults."; protected static final String CLASSPATH = "classpath:%s"; @@ -66,16 +68,16 @@ public void process(E entity) { update(entity, existingEntity.get()); } else { repo.save(entity); - logger.info(String.format(CREATED_DEFAULTS, this.getClass().getSimpleName(), entity.getName())); + logger.info(CREATED_DEFAULTS, this.getClass().getSimpleName(), entity.getName()); } } @Override public void update(E entity, E existingEntity) { if (middleware.isUpdateDefaults()) { - BeanUtils.copyProperties(entity, existingEntity); - repo.save(entity); - logger.info(String.format(UPDATED_DEFAULTS, this.getClass().getSimpleName(), entity.getName())); + BeanUtils.copyProperties(entity, existingEntity, ID); + repo.save(existingEntity); + logger.info(UPDATED_DEFAULTS, this.getClass().getSimpleName(), entity.getName()); } } diff --git a/src/main/java/edu/tamu/scholars/middleware/defaults/AnalyticViewsDefaults.java b/src/main/java/edu/tamu/scholars/middleware/defaults/AnalyticViewsDefaults.java new file mode 100644 index 000000000..b9f574712 --- /dev/null +++ b/src/main/java/edu/tamu/scholars/middleware/defaults/AnalyticViewsDefaults.java @@ -0,0 +1,35 @@ +package edu.tamu.scholars.middleware.defaults; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +import org.springframework.stereotype.Service; + +import com.fasterxml.jackson.core.type.TypeReference; + +import edu.tamu.scholars.middleware.view.model.DataAndAnalyticsView; +import edu.tamu.scholars.middleware.view.model.repo.DataAndAnalyticsViewRepo; + +@Service +public class AnalyticViewsDefaults extends AbstractDefaults { + + public AnalyticViewsDefaults() { + super(); + } + + @Override + public String path() { + return "classpath:defaults/dataAndanalyticViews.yml"; + } + + @Override + public List read(InputStream is) throws IOException { + List views = mapper.readValue(is, new TypeReference>() {}); + for (DataAndAnalyticsView view : views) { + loadTemplateMap(view.getTemplates()); + } + return views; + } + +} diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/DiscoveryConstants.java b/src/main/java/edu/tamu/scholars/middleware/discovery/DiscoveryConstants.java index d44104d28..0e7f2ec00 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/DiscoveryConstants.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/DiscoveryConstants.java @@ -10,12 +10,16 @@ public class DiscoveryConstants { public static final String CLASS = "class"; + public static final String ABSTRACT = "abstract"; + public static final String TYPE = "type"; public static final String SNIPPET = "snippet"; public static final String MOD_TIME = "modTime"; + public static final String SYNC_IDS = "syncIds"; + public static final String QUERY_DELIMETER = ":"; public static final String DEFAULT_QUERY = WILDCARD + QUERY_DELIMETER + WILDCARD; @@ -29,7 +33,5 @@ public class DiscoveryConstants { public static final String DISCOVERY_MODEL_PACKAGE = "edu.tamu.scholars.middleware.discovery.model"; public static final String PARENTHESES_TEMPLATE = "(%s)"; - - public static final String COLLECTION = "scholars-discovery"; } diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/advice/DiscoveryControllerAdvice.java b/src/main/java/edu/tamu/scholars/middleware/discovery/advice/DiscoveryControllerAdvice.java index 8c38dbb9d..6067e4e13 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/advice/DiscoveryControllerAdvice.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/advice/DiscoveryControllerAdvice.java @@ -1,5 +1,7 @@ package edu.tamu.scholars.middleware.discovery.advice; +import java.io.FileNotFoundException; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; @@ -30,4 +32,11 @@ public class DiscoveryControllerAdvice { return exception.getMessage(); } + @ResponseStatus(value = HttpStatus.NOT_FOUND) + @ExceptionHandler(value = FileNotFoundException.class) + public @ResponseBody String handleFileNotFoundException(FileNotFoundException exception) { + logger.error(exception.getMessage(), exception); + return exception.getMessage(); + } + } diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/annotation/CollectionTarget.java b/src/main/java/edu/tamu/scholars/middleware/discovery/annotation/CollectionTarget.java deleted file mode 100644 index 519c54c0e..000000000 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/annotation/CollectionTarget.java +++ /dev/null @@ -1,19 +0,0 @@ -package edu.tamu.scholars.middleware.discovery.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.data.annotation.Persistent; - -@Persistent -@Inherited -@Retention(RetentionPolicy.RUNTIME) -@Target({ ElementType.TYPE }) -public @interface CollectionTarget { - - String name() default ""; - -} diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/argument/DiscoveryResearchAgeDescriptor.java b/src/main/java/edu/tamu/scholars/middleware/discovery/argument/DiscoveryAcademicAgeDescriptor.java similarity index 94% rename from src/main/java/edu/tamu/scholars/middleware/discovery/argument/DiscoveryResearchAgeDescriptor.java rename to src/main/java/edu/tamu/scholars/middleware/discovery/argument/DiscoveryAcademicAgeDescriptor.java index 081f22d2c..3f705fac1 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/argument/DiscoveryResearchAgeDescriptor.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/argument/DiscoveryAcademicAgeDescriptor.java @@ -4,8 +4,8 @@ import java.util.ArrayList; import java.util.List; -// TODO: refactor to DiscoveryResearchAgeDescriptorArg and add argument resolver -public class DiscoveryResearchAgeDescriptor { +// TODO: refactor to DiscoveryAcademicAgeDescriptorArg and add argument resolver +public class DiscoveryAcademicAgeDescriptor { private final String label; @@ -19,7 +19,7 @@ public class DiscoveryResearchAgeDescriptor { private final Integer groupingIntervalInYears; - private DiscoveryResearchAgeDescriptor( + private DiscoveryAcademicAgeDescriptor( String label, String dateField, Boolean accumulateMultivaluedDate, @@ -132,14 +132,14 @@ public List getLabeledRanges() { return labeledRanges; } - public static DiscoveryResearchAgeDescriptor of( + public static DiscoveryAcademicAgeDescriptor of( String label, String dateField, Boolean accumulateMultivaluedDate, Boolean averageOverInterval, Integer upperLimitInYears, Integer groupingIntervalInYears) { - return new DiscoveryResearchAgeDescriptor( + return new DiscoveryAcademicAgeDescriptor( label, dateField, accumulateMultivaluedDate, diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/component/Harvester.java b/src/main/java/edu/tamu/scholars/middleware/discovery/component/Harvester.java index 6371170ba..1302adc30 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/component/Harvester.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/component/Harvester.java @@ -1,13 +1,14 @@ package edu.tamu.scholars.middleware.discovery.component; import edu.tamu.scholars.middleware.discovery.model.AbstractIndexDocument; +import edu.tamu.scholars.middleware.discovery.model.Individual; import reactor.core.publisher.Flux; public interface Harvester { - public Flux harvest(); + public Flux harvest(); - public AbstractIndexDocument harvest(String subject); + public Individual harvest(String subject); public Class type(); diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/component/Indexer.java b/src/main/java/edu/tamu/scholars/middleware/discovery/component/Indexer.java index 10c07f3e5..81556bfe2 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/component/Indexer.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/component/Indexer.java @@ -3,14 +3,15 @@ import java.util.Collection; import edu.tamu.scholars.middleware.discovery.model.AbstractIndexDocument; +import edu.tamu.scholars.middleware.discovery.model.Individual; public interface Indexer { public void init(); - public void index(Collection documents); + public void index(Collection documents); - public void index(AbstractIndexDocument document); + public void index(Individual document); public void optimize(); diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/component/jena/TriplestoreHarvester.java b/src/main/java/edu/tamu/scholars/middleware/discovery/component/jena/TriplestoreHarvester.java index 0f8575a96..95642cd9f 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/component/jena/TriplestoreHarvester.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/component/jena/TriplestoreHarvester.java @@ -1,6 +1,5 @@ package edu.tamu.scholars.middleware.discovery.component.jena; -import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.ID; import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.NESTED_DELIMITER; import java.lang.reflect.Field; @@ -32,6 +31,7 @@ import edu.tamu.scholars.middleware.discovery.annotation.FieldType; import edu.tamu.scholars.middleware.discovery.component.Harvester; import edu.tamu.scholars.middleware.discovery.model.AbstractIndexDocument; +import edu.tamu.scholars.middleware.discovery.model.Individual; import edu.tamu.scholars.middleware.service.TemplateService; import edu.tamu.scholars.middleware.service.Triplestore; import reactor.core.publisher.Flux; @@ -40,7 +40,7 @@ public class TriplestoreHarvester implements Harvester { private static final Logger logger = LoggerFactory.getLogger(TriplestoreHarvester.class); - private static final String COLLECTION_SPARQL_TEMPLATE = "collection"; + private static final String COLLECTION = "collection"; private static final String FORWARD_SLASH = "/"; @@ -58,38 +58,39 @@ public class TriplestoreHarvester implements Harvester { private final List propertySourceTypeOps; - private final List indexedFields; + private final List nestedFields; public TriplestoreHarvester(Class type) { this.type = type; - this.propertySourceTypeOps = FieldUtils.getFieldsListWithAnnotation(type, FieldSource.class).stream().map(this::getTypeOp).collect(Collectors.toList()); - this.indexedFields = FieldUtils.getFieldsListWithAnnotation(type, FieldType.class); + this.propertySourceTypeOps = FieldUtils.getFieldsListWithAnnotation(type, FieldSource.class) + .stream() + .map(this::getTypeOp) + .collect(Collectors.toList()); + this.nestedFields = FieldUtils.getFieldsListWithAnnotation(type, FieldType.class) + .stream() + .filter(this::isNestedField) + .collect(Collectors.toList()); } - public Flux harvest() { + public Flux harvest() { CollectionSource source = type.getAnnotation(CollectionSource.class); - String query = templateService.templateSparql(COLLECTION_SPARQL_TEMPLATE, source.predicate()); - if (logger.isDebugEnabled()) { - logger.debug(String.format("%s:\n%s", COLLECTION_SPARQL_TEMPLATE, query)); - } + String query = templateService.templateSparql(COLLECTION, source.predicate()); + logger.debug("{}:\n{}", COLLECTION, query); QueryExecution queryExecution = triplestore.createQueryExecution(query); Iterator tripleIterator = queryExecution.execConstructTriples(); - Iterable triples = () -> tripleIterator; - return Flux.fromIterable(triples) + + return Flux.fromIterable(() -> tripleIterator) .map(this::subject) .map(this::harvest) .doFinally(onFinally -> queryExecution.close()); } - public AbstractIndexDocument harvest(String subject) { + public Individual harvest(String subject) { try { - return createDocument(subject); + return createIndividual(subject); } catch (Exception e) { - logger.error(String.format("Unable to index %s: %s", type.getSimpleName(), parse(subject))); - logger.error(String.format("Error: %s", e.getMessage())); - if (logger.isDebugEnabled()) { - e.printStackTrace(); - } + logger.debug("Error harvesting", e); + logger.error("Unable to harvest {} {}: {}", type.getSimpleName(), parse(subject), e.getMessage()); throw new RuntimeException(e); } } @@ -98,46 +99,43 @@ public Class type() { return type; } - private String subject(Triple triple) { - return triple.getSubject().toString(); - } + private Individual createIndividual(String subject) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { + Individual individual = new Individual(); + individual.setId(parse(subject)); + lookupProperties(individual, subject); + lookupSyncIds(individual); + individual.setProxy(type.getSimpleName()); - private AbstractIndexDocument createDocument(String subject) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { - AbstractIndexDocument document = construct(); - Field field = FieldUtils.getField(type, ID, true); - field.set(document, parse(subject)); - lookupProperties(document, subject); - lookupSyncIds(document); - return document; + return individual; } - private void lookupProperties(AbstractIndexDocument document, String subject) { + private void lookupProperties(Individual individual, String subject) { propertySourceTypeOps.parallelStream().forEach(typeOp -> { try { FieldSource source = typeOp.getPropertySource(); Model model = queryForModel(source, subject); List values = lookupProperty(typeOp, source, model); - populate(document, typeOp.getField(), values); - } catch (Exception e) { - logger.error(String.format("Unable to populate document %s: %s", name(), parse(subject))); - logger.error(String.format("Error: %s", e.getMessage())); - if (logger.isDebugEnabled()) { - e.printStackTrace(); + if (!values.isEmpty()) { + populate(individual, typeOp.getField(), values); + } else { + logger.debug("Could not find values for {}", typeOp.getField().getName()); } + } catch (Exception e) { + logger.error("Unable to populate individual {} {}: {}", type.getSimpleName(), parse(subject), e.getMessage()); + logger.debug("Error populating individual", e); } }); } private Model queryForModel(FieldSource source, String subject) { String query = templateService.templateSparql(source.template(), subject); - if (logger.isDebugEnabled()) { - logger.debug(String.format("%s:\n%s", source.template(), query)); - } + logger.debug("{}:\n{}", source.template(), query); try (QueryExecution qe = triplestore.createQueryExecution(query)) { Model model = qe.execConstruct(); if (logger.isDebugEnabled()) { model.write(System.out, "RDF/XML"); } + return model; } } @@ -157,9 +155,9 @@ private List queryForProperty(TypeOp typeOp, FieldSource source, Model m StmtIterator statements; try { statements = resource.listProperties(model.createProperty(source.predicate())); - } catch (InvalidPropertyURIException exception) { - logger.error(String.format("%s lookup by %s", typeOp.getField().getName(), source.predicate())); - throw exception; + } catch (InvalidPropertyURIException e) { + logger.error("{} lookup by {}: {}", typeOp.getField().getName(), source.predicate(), e.getMessage()); + throw e; } while (statements.hasNext()) { @@ -171,9 +169,7 @@ private List queryForProperty(TypeOp typeOp, FieldSource source, Model m value = value.substring(0, value.indexOf("^^")); } if (source.unique() && values.stream().map(v -> v.toString()).anyMatch(value::equalsIgnoreCase)) { - if (logger.isDebugEnabled()) { - logger.debug(String.format("%s has duplicate value %s", typeOp.getField().getName(), value)); - } + logger.debug("{} has duplicate value {}", typeOp.getField().getName(), value); } else { if (source.split()) { for (String v : value.split("\\|\\|")) { @@ -184,51 +180,39 @@ private List queryForProperty(TypeOp typeOp, FieldSource source, Model m } } } + return values; } - private void populate(AbstractIndexDocument document, Field field, List values) throws IllegalArgumentException, IllegalAccessException { + private void populate(Individual document, Field field, List values) throws IllegalArgumentException, IllegalAccessException { if (values.isEmpty()) { - if (logger.isDebugEnabled()) { - logger.debug(String.format("Could not find values for %s", field.getName())); - } + logger.debug("Could not find values for {}", field.getName()); } else { - field.setAccessible(true); - if (List.class.isAssignableFrom(field.getType())) { - field.set(document, values); + if (Collection.class.isAssignableFrom(field.getType())) { + document.getContent().put(field.getName(), values); } else { - field.set(document, values.get(0)); + document.getContent().put(field.getName(), values.get(0)); } } } - @SuppressWarnings("unchecked") - private void lookupSyncIds(AbstractIndexDocument document) { + private void lookupSyncIds(Individual individual) { Set syncIds = new HashSet(); - syncIds.add(document.getId()); - indexedFields.stream().filter(this::isNestedField).peek(field -> field.setAccessible(true)).forEach(field -> { - try { - Object value = field.get(document); + syncIds.add(individual.getId()); + nestedFields.stream() + .forEach(field -> { + Object value = individual.getContent().get(field.getName()); if (value != null) { if (Collection.class.isAssignableFrom(field.getType())) { - ((Collection) value).forEach(v -> addSyncId(syncIds, v)); + @SuppressWarnings("unchecked") + List values = (List) value; + values.forEach(v -> addSyncId(syncIds, v)); } else { addSyncId(syncIds, (String) value); } } - } catch (IllegalArgumentException | IllegalAccessException e) { - logger.error(String.format("Unable to get value of %s %s", name(), field.getName())); - logger.error(String.format("Error: %s", e.getMessage())); - if (logger.isDebugEnabled()) { - e.printStackTrace(); - } - } - }); - document.setSyncIds(new ArrayList<>(syncIds)); - } - - private boolean isNestedField(Field field) { - return !field.getName().equals(ID) && field.getAnnotation(FieldType.class).type().startsWith(NESTED); + }); + individual.setSyncIds(new ArrayList<>(syncIds)); } private void addSyncId(Set syncIds, String value) { @@ -238,12 +222,15 @@ private void addSyncId(Set syncIds, String value) { } } - private AbstractIndexDocument construct() throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { - return type.getConstructor().newInstance(new Object[0]); + private boolean isNestedField(Field field) { + return field.getAnnotation(FieldType.class) + .type() + .startsWith(NESTED); } - private String name() { - return type.getSimpleName(); + private String subject(Triple triple) { + return triple.getSubject() + .toString(); } private String parse(String uri) { @@ -281,7 +268,6 @@ private interface TypeOp { public Field getField(); public FieldSource getPropertySource(); - } private abstract class AbstractTypeOp implements TypeOp { diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/component/solr/SolrIndexer.java b/src/main/java/edu/tamu/scholars/middleware/discovery/component/solr/SolrIndexer.java index 2d136dca2..e46624f53 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/component/solr/SolrIndexer.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/component/solr/SolrIndexer.java @@ -1,6 +1,5 @@ package edu.tamu.scholars.middleware.discovery.component.solr; -import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.COLLECTION; import static edu.tamu.scholars.middleware.discovery.service.IndexService.CREATED_FIELDS; import java.lang.reflect.Field; @@ -16,10 +15,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import edu.tamu.scholars.middleware.discovery.annotation.FieldType; import edu.tamu.scholars.middleware.discovery.component.Indexer; import edu.tamu.scholars.middleware.discovery.model.AbstractIndexDocument; +import edu.tamu.scholars.middleware.discovery.model.Individual; public class SolrIndexer implements Indexer { @@ -28,6 +29,12 @@ public class SolrIndexer implements Indexer { @Autowired private SolrClient solrClient; + @Value("${middleware.index.name}") + private String collectionName; + + @Value("${middleware.index.enableIndividualOnBatchFail:false}") + private boolean enableIndividualOnBatchFail; + private final Class type; public SolrIndexer(Class type) { @@ -37,22 +44,22 @@ public SolrIndexer(Class type) { @Override public void init() { for (Field field : FieldUtils.getFieldsListWithAnnotation(type, FieldType.class)) { - FieldType indexed = field.getAnnotation(FieldType.class); + FieldType fieldType = field.getAnnotation(FieldType.class); - String name = StringUtils.isNotEmpty(indexed.value()) - ? indexed.value() + String name = StringUtils.isNotEmpty(fieldType.value()) + ? fieldType.value() : field.getName(); - if (!indexed.readonly() && !CREATED_FIELDS.contains(name) && CREATED_FIELDS.add(name)) { + if (!fieldType.readonly() && !CREATED_FIELDS.contains(name) && CREATED_FIELDS.add(name)) { Map fieldAttributes = new HashMap(); - fieldAttributes.put("type", indexed.type()); - fieldAttributes.put("stored", indexed.stored()); - fieldAttributes.put("indexed", indexed.searchable()); - fieldAttributes.put("required", indexed.required()); + fieldAttributes.put("type", fieldType.type()); + fieldAttributes.put("stored", fieldType.stored()); + fieldAttributes.put("indexed", fieldType.searchable()); + fieldAttributes.put("required", fieldType.required()); - if (StringUtils.isNotEmpty(indexed.defaultValue())) { - fieldAttributes.put("defaultValue", indexed.defaultValue()); + if (StringUtils.isNotEmpty(fieldType.defaultValue())) { + fieldAttributes.put("defaultValue", fieldType.defaultValue()); } fieldAttributes.put("multiValued", Collection.class.isAssignableFrom(field.getType())); @@ -61,52 +68,59 @@ public void init() { try { SchemaRequest.AddField addFieldRequest = new SchemaRequest.AddField(fieldAttributes); - addFieldRequest.process(solrClient, COLLECTION); + addFieldRequest.process(solrClient, collectionName); + + if (fieldType.copyTo().length > 0) { + try { + SchemaRequest.AddCopyField addCopyFieldRequest = new SchemaRequest.AddCopyField(name, Arrays.asList(fieldType.copyTo())); + addCopyFieldRequest.process(solrClient, collectionName); + } catch (Exception e) { + logger.error("Failed to add copy field", e); + } + } } catch (Exception e) { logger.debug("Failed to add field", e); } - - if (indexed.copyTo().length > 0) { - try { - SchemaRequest.AddCopyField addCopyFieldRequest = new SchemaRequest.AddCopyField(name, Arrays.asList(indexed.copyTo())); - addCopyFieldRequest.process(solrClient, COLLECTION); - } catch (Exception e) { - logger.debug("Failed to add copy field", e); - } - } } } } @Override - public void index(Collection documents) { + public void index(Collection individuals) { try { - solrClient.addBeans(COLLECTION, documents); - solrClient.commit(COLLECTION); - logger.info(String.format("Saved %s batch of %s", name(), documents.size())); + solrClient.addBeans(collectionName, individuals); + solrClient.commit(collectionName); + logger.info("Saved {} batch of {}", name(), individuals.size()); } catch (Exception e) { - logger.warn(String.format("Failed to save batch of %s. Attempting individually.", name()), e); - documents.stream().forEach(this::index); + logger.debug("Error saving batch", e); + if (enableIndividualOnBatchFail) { + logger.warn("Failed to save batch of {}. Attempting individually.", name()); + individuals.stream().forEach(this::index); + } else { + logger.warn("Skipping individuals of failed batch of {}. {}", name(), e.getMessage()); + } } } @Override - public void index(AbstractIndexDocument document) { + public void index(Individual individual) { try { - solrClient.addBean(COLLECTION, document); - solrClient.commit(COLLECTION); - logger.info(String.format("Saved %s with id %s", name(), document.getId())); + solrClient.addBean(collectionName, individual); + solrClient.commit(collectionName); + logger.info("Saved {} with id {}", name(), individual.getId()); } catch (Exception e) { - logger.warn(String.format("Failed to save %s with id %s", name(), document.getId()), e); + logger.debug("Error saving individual", e); + logger.warn("Failed to save {} with id {}", name(), individual.getId()); } } @Override public void optimize() { try { - solrClient.optimize(COLLECTION); + solrClient.optimize(collectionName); } catch (Exception e) { - logger.warn(String.format("Failed to optimize index"), e); + logger.debug("Error optimizing collection", e); + logger.warn("Failed to optimize collection. {}", e.getMessage()); } } diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/controller/IndividualAnalyticsController.java b/src/main/java/edu/tamu/scholars/middleware/discovery/controller/IndividualAnalyticsController.java index 8e1ea241f..e718967ae 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/controller/IndividualAnalyticsController.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/controller/IndividualAnalyticsController.java @@ -10,13 +10,13 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import edu.tamu.scholars.middleware.discovery.argument.DiscoveryAcademicAgeDescriptor; import edu.tamu.scholars.middleware.discovery.argument.DiscoveryQuantityDistributionDescriptor; -import edu.tamu.scholars.middleware.discovery.argument.DiscoveryResearchAgeDescriptor; import edu.tamu.scholars.middleware.discovery.argument.FilterArg; import edu.tamu.scholars.middleware.discovery.argument.QueryArg; import edu.tamu.scholars.middleware.discovery.model.repo.IndividualRepo; +import edu.tamu.scholars.middleware.discovery.response.DiscoveryAcademicAge; import edu.tamu.scholars.middleware.discovery.response.DiscoveryQuantityDistribution; -import edu.tamu.scholars.middleware.discovery.response.DiscoveryResearchAge; @RestController @RequestMapping("/individual/analytics") @@ -25,9 +25,9 @@ public class IndividualAnalyticsController { @Autowired private IndividualRepo repo; + @GetMapping("/academicAge") @PreAuthorize("hasRole('ROLE_ADMIN')") - @GetMapping("/researchAge") - public ResponseEntity researcherAge( + public ResponseEntity academicAge( QueryArg query, List filters, @RequestParam(name = "label", defaultValue = "Research") String label, @@ -38,10 +38,11 @@ public ResponseEntity researcherAge( @RequestParam(name = "upperLimitInYears", defaultValue = "40") Integer upperLimitInYears, @RequestParam(name = "groupingIntervalInYears", defaultValue = "5") Integer groupingIntervalInYears) { - return ResponseEntity.ok(repo.researcherAge(DiscoveryResearchAgeDescriptor.of(label, dateField, accumulateMultivaluedDate, averageOverInterval, upperLimitInYears, groupingIntervalInYears), query, filters)); + return ResponseEntity.ok(repo.academicAge(DiscoveryAcademicAgeDescriptor.of(label, dateField, accumulateMultivaluedDate, averageOverInterval, upperLimitInYears, groupingIntervalInYears), query, filters)); } @GetMapping("/quantityDistribution") + @PreAuthorize("hasRole('ROLE_ADMIN')") public ResponseEntity quantityDistribution( QueryArg query, List filters, diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/indicator/IndexHealthIndicator.java b/src/main/java/edu/tamu/scholars/middleware/discovery/indicator/IndexHealthIndicator.java new file mode 100644 index 000000000..ce21c9d6f --- /dev/null +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/indicator/IndexHealthIndicator.java @@ -0,0 +1,74 @@ +package edu.tamu.scholars.middleware.discovery.indicator; + +import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.DEFAULT_QUERY; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.solr.client.solrj.SolrClient; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.response.SolrPingResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.context.annotation.Lazy; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import edu.tamu.scholars.middleware.config.model.IndexConfig; +import edu.tamu.scholars.middleware.discovery.model.repo.IndividualRepo; + +@Component("index") +@Profile("!test") +public class IndexHealthIndicator implements HealthIndicator { + + @Autowired + private SolrClient solrClient; + + @Lazy + @Autowired + private IndividualRepo individualRepo; + + @Autowired + private IndexConfig index; + + @Override + public Health health() { + Health.Builder status = Health.down(); + + Map details = new HashMap(); + + try { + SolrPingResponse response = solrClient.ping(index.getName()); + + details.put("name", index.getName()); + + String message = (String) response.getResponse().get("status"); + + // NOTE: not a REST response status code + // 0 - successful ping response for given collection + // details.put("status", response.getStatus()); + details.put("message", message); + + if (response.getStatus() == 0 && message.equals("OK")) { + + long count = individualRepo.count(DEFAULT_QUERY, List.of()); + + details.put("count", count); + + status.up(); + + } else { + details.put("response", response.getResponse().asMap(3)); + } + } catch (SolrServerException | IOException e) { + e.printStackTrace(); + } + + return status.withDetails(details) + .build(); + } + +} diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/model/AbstractIndexDocument.java b/src/main/java/edu/tamu/scholars/middleware/discovery/model/AbstractIndexDocument.java index 6bb80cfea..d7e22af1b 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/model/AbstractIndexDocument.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/model/AbstractIndexDocument.java @@ -1,10 +1,10 @@ package edu.tamu.scholars.middleware.discovery.model; +import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.CLASS; + import java.util.ArrayList; import java.util.List; -import org.apache.solr.client.solrj.beans.Field; - import com.fasterxml.jackson.annotation.JsonProperty; import edu.tamu.scholars.middleware.discovery.annotation.FieldSource; @@ -12,38 +12,33 @@ public abstract class AbstractIndexDocument { - @Field + @JsonProperty(CLASS) + private String proxy; + @FieldType(required = true, readonly = true) private String id; - @JsonProperty("class") - @Field("class") - @FieldType(type = "string", value = "class", required = true) - private String clazz = this.getClass().getSimpleName(); - - @Field @FieldType(type = "whole_strings") @FieldSource(template = "common/type", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List type; - @Field @FieldType(type = "strings") private List syncIds = new ArrayList<>(); - public String getId() { - return id; + public String getProxy() { + return proxy; } - public void setId(String id) { - this.id = id; + public void setProxy(String proxy) { + this.proxy = proxy; } - public String getClazz() { - return clazz; + public String getId() { + return id; } - public void setClazz(String clazz) { - this.clazz = clazz; + public void setId(String id) { + this.id = id; } public List getType() { diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/model/Collection.java b/src/main/java/edu/tamu/scholars/middleware/discovery/model/Collection.java index fb9b6efea..15c34dc38 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/model/Collection.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/model/Collection.java @@ -1,145 +1,119 @@ package edu.tamu.scholars.middleware.discovery.model; import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; -import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.COLLECTION; +import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.ABSTRACT; import java.util.List; -import org.apache.solr.client.solrj.beans.Field; - import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import edu.tamu.scholars.middleware.discovery.annotation.CollectionSource; -import edu.tamu.scholars.middleware.discovery.annotation.CollectionTarget; -import edu.tamu.scholars.middleware.discovery.annotation.NestedObject; -import edu.tamu.scholars.middleware.discovery.annotation.NestedObject.Reference; import edu.tamu.scholars.middleware.discovery.annotation.FieldSource; import edu.tamu.scholars.middleware.discovery.annotation.FieldType; +import edu.tamu.scholars.middleware.discovery.annotation.NestedObject; +import edu.tamu.scholars.middleware.discovery.annotation.NestedObject.Reference; @JsonInclude(NON_EMPTY) -@CollectionTarget(name = COLLECTION) @CollectionSource(name = "collections", predicate = "http://purl.org/ontology/bibo/Collection") public class Collection extends Common { - @Field @FieldType(type = "tokenized_string", copyTo = { "_text_", "name_sort" }) @FieldSource(template = "collection/name", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private String name; - @Field("abstract") - @JsonProperty("abstract") - @FieldType(type = "tokenized_string", value = "abstract", copyTo = "_text_") + @JsonProperty(ABSTRACT) + @FieldType(type = "tokenized_string", value = ABSTRACT, copyTo = "_text_") @FieldSource(template = "collection/abstract", predicate = "http://purl.org/ontology/bibo/abstract") private String abstractText; - @Field @FieldType(type = "whole_string") @FieldSource(template = "collection/abbreviation", predicate = "http://vivoweb.org/ontology/core#abbreviation") private String abbreviation; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "collection/publicationVenueFor", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List publicationVenueFor; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "collection/editor", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List editors; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "collection/translator", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List translators; - @Field @FieldType(type = "pdate", searchable = false) @FieldSource(template = "collection/publicationDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private String publicationDate; - @Field @FieldType(type = "nested_whole_string") @NestedObject(properties = { @Reference(value = "publisherType", key = "type") }) @FieldSource(template = "collection/publisher", predicate = "http://www.w3.org/2000/01/rdf-schema#label", unique = true) private String publisher; - @Field @FieldType(type = "nested_whole_string") @FieldSource(template = "collection/publisherType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private String publisherType; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "collection/hasSubjectArea", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List subjectAreas; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "collection/feature", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List features; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "collection/outputOfProcessOrEvent", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List outputOfProcessOrEvent; - @Field @FieldType(type = "whole_strings", copyTo = "_text_") @FieldSource(template = "collection/keyword", predicate = "http://vivoweb.org/ontology/core#freetextKeyword") private List keywords; - @Field @FieldType(type = "whole_string") @FieldSource(template = "collection/issn", predicate = "http://purl.org/ontology/bibo/issn") private String issn; - @Field @FieldType(type = "whole_string") @FieldSource(template = "collection/eissn", predicate = "http://purl.org/ontology/bibo/eissn") private String eissn; - @Field @FieldType(type = "whole_string") @FieldSource(template = "collection/doi", predicate = "http://purl.org/ontology/bibo/doi") private String doi; - @Field @FieldType(type = "whole_string") @FieldSource(template = "collection/oclcnum", predicate = "http://purl.org/ontology/bibo/oclcnum") private String oclcnum; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "collection/isAbout", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List isAbout; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "collection/specifiedOutputOf", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List specifiedOutputOf; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "collection/mention", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List mentions; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "collection/participatesIn", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List participatesIn; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "collection/supportedBy", predicate = "http://www.w3.org/2000/01/rdf-schema#label") diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/model/Common.java b/src/main/java/edu/tamu/scholars/middleware/discovery/model/Common.java index a4f583945..1b842a33c 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/model/Common.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/model/Common.java @@ -2,49 +2,40 @@ import java.util.List; -import org.apache.solr.client.solrj.beans.Field; - -import edu.tamu.scholars.middleware.discovery.annotation.NestedObject; -import edu.tamu.scholars.middleware.discovery.annotation.NestedObject.Reference; import edu.tamu.scholars.middleware.discovery.annotation.FieldSource; import edu.tamu.scholars.middleware.discovery.annotation.FieldType; +import edu.tamu.scholars.middleware.discovery.annotation.NestedObject; +import edu.tamu.scholars.middleware.discovery.annotation.NestedObject.Reference; public class Common extends AbstractIndexDocument { - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "common/image", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/public#directDownloadUrl") private String image; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "common/thumbnail", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/public#directDownloadUrl") private String thumbnail; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "websiteUrl", key = "url") }) @FieldSource(template = "common/website", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List websites; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "common/websiteUrl", predicate = "http://www.w3.org/2006/vcard/ns#url") private List websiteUrl; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "common/geographicFocus", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List geographicFocus; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "common/sameAs", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List sameAs; - @Field @FieldType(type = "pdate") @FieldSource(template = "common/modTime", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#modTime") private String modTime; diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/model/Concept.java b/src/main/java/edu/tamu/scholars/middleware/discovery/model/Concept.java index 84df3de7f..c013b93a7 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/model/Concept.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/model/Concept.java @@ -1,139 +1,113 @@ package edu.tamu.scholars.middleware.discovery.model; import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; -import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.COLLECTION; import java.util.List; -import org.apache.solr.client.solrj.beans.Field; - import com.fasterxml.jackson.annotation.JsonInclude; import edu.tamu.scholars.middleware.discovery.annotation.CollectionSource; -import edu.tamu.scholars.middleware.discovery.annotation.CollectionTarget; +import edu.tamu.scholars.middleware.discovery.annotation.FieldSource; +import edu.tamu.scholars.middleware.discovery.annotation.FieldType; import edu.tamu.scholars.middleware.discovery.annotation.NestedMultiValuedProperty; import edu.tamu.scholars.middleware.discovery.annotation.NestedObject; import edu.tamu.scholars.middleware.discovery.annotation.NestedObject.Reference; -import edu.tamu.scholars.middleware.discovery.annotation.FieldSource; -import edu.tamu.scholars.middleware.discovery.annotation.FieldType; @JsonInclude(NON_EMPTY) -@CollectionTarget(name = COLLECTION) @CollectionSource(name = "concepts", predicate = "http://www.w3.org/2004/02/skos/core#Concept") public class Concept extends Common { - @Field @FieldType(type = "tokenized_string", copyTo = { "_text_", "name_sort" }) @FieldSource(template = "concept/name", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private String name; - @Field @NestedObject @FieldType(type = "nested_whole_strings") @FieldSource(template = "concept/associatedDepartment", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List associatedDepartments; - @Field @NestedObject @FieldType(type = "nested_whole_strings", copyTo = "_text_") @FieldSource(template = "concept/researchAreaOf", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List researchAreaOf; - @Field @FieldType(type = "nested_whole_strings", copyTo = "_text_") @NestedObject(properties = { @Reference(value = "awardOrHonorForType", key = "type") }) @FieldSource(template = "concept/awardOrHonorFor", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List awardOrHonorFor; - @Field @FieldType(type = "nested_whole_strings") @FieldSource(template = "concept/awardOrHonorForType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List awardOrHonorForType; - @Field @FieldType(type = "nested_tokenized_strings", copyTo = { "_text_", "awardConferredBy_nested_facets" }) @NestedObject(properties = { @Reference(value = "awardConferredByType", key = "type") }) @FieldSource(template = "concept/awardConferredBy", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List awardConferredBy; - @Field @FieldType(type = "nested_whole_strings") @FieldSource(template = "concept/awardConferredByType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List awardConferredByType; - @Field @FieldType(type = "whole_strings", copyTo = "_text_") @FieldSource(template = "concept/awardConferredByPreferredLabel", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#awardConferredBy_label") private List awardConferredByPreferredLabel; - @Field @FieldType(type = "pdate") @FieldSource(template = "concept/yearAwarded", predicate = "http://vivoweb.org/ontology/core#dateTime") private String yearAwarded; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "receiptRecipientName", key = "recipientName") }) @FieldSource(template = "concept/receipts", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List receipts; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "concept/receiptRecipientName", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List receiptRecipientName; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "concept/broaderConcept", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List broaderConcepts; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "concept/narrowerConcept", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List narrowerConcepts; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "concept/relatedConcept", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List relatedConcepts; - @Field @FieldType(type = "nested_tokenized_string", copyTo = { "_text_", "futureResearchIdeaOf_nested_facets" }) @NestedObject(properties = { @Reference(value = "futureResearchIdeaOfEmail", key = "email"), @Reference(value = "futureResearchIdeaOfTitle", key = "title"), @Reference(value = "futureResearchIdeaOfOrganization", key = "organizations") }) @FieldSource(template = "concept/futureResearchIdeaOf", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private String futureResearchIdeaOf; - @Field @FieldType(type = "nested_whole_string") @FieldSource(template = "concept/futureResearchIdeaOfEmail", predicate = "http://www.w3.org/2006/vcard/ns#email") private String futureResearchIdeaOfEmail; - @Field @FieldType(type = "nested_whole_string") @FieldSource(template = "concept/futureResearchIdeaOfTitle", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private String futureResearchIdeaOfTitle; - @Field @NestedMultiValuedProperty @NestedObject(root = false) @FieldType(type = "nested_whole_strings") @FieldSource(template = "concept/futureResearchIdeaOfOrganization", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List futureResearchIdeaOfOrganization; - @Field @FieldType(type = "whole_strings", copyTo = "_text_") @FieldSource(template = "concept/keyword", predicate = "http://vivoweb.org/ontology/core#freetextKeyword") private List keywords; - @Field @FieldType(type = "tokenized_string", copyTo = "_text_") @FieldSource(template = "concept/description", predicate = "http://vivoweb.org/ontology/core#description") private String description; - @Field @FieldType(type = "pdate") @FieldSource(template = "concept/createdDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private String createdDate; diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/model/Document.java b/src/main/java/edu/tamu/scholars/middleware/discovery/model/Document.java index 487d3ece5..857fbef75 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/model/Document.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/model/Document.java @@ -1,446 +1,364 @@ package edu.tamu.scholars.middleware.discovery.model; import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; -import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.COLLECTION; +import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.ABSTRACT; import java.util.List; -import org.apache.solr.client.solrj.beans.Field; - import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import edu.tamu.scholars.middleware.discovery.annotation.CollectionSource; -import edu.tamu.scholars.middleware.discovery.annotation.CollectionTarget; +import edu.tamu.scholars.middleware.discovery.annotation.FieldSource; +import edu.tamu.scholars.middleware.discovery.annotation.FieldType; import edu.tamu.scholars.middleware.discovery.annotation.NestedMultiValuedProperty; import edu.tamu.scholars.middleware.discovery.annotation.NestedObject; import edu.tamu.scholars.middleware.discovery.annotation.NestedObject.Reference; -import edu.tamu.scholars.middleware.discovery.annotation.FieldSource; -import edu.tamu.scholars.middleware.discovery.annotation.FieldType; @JsonInclude(NON_EMPTY) -@CollectionTarget(name = COLLECTION) @CollectionSource(name = "documents", predicate = "http://purl.org/ontology/bibo/Document") public class Document extends Common { - @Field @FieldType(type = "tokenized_string", copyTo = { "_text_", "title_sort" }) @FieldSource(template = "document/title", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private String title; - @Field("abstract") - @JsonProperty("abstract") - @FieldType(type = "tokenized_string", value = "abstract", copyTo = "_text_") + @JsonProperty(ABSTRACT) + @FieldType(type = "tokenized_string", value = ABSTRACT, copyTo = "_text_") @FieldSource(template = "document/abstract", predicate = "http://purl.org/ontology/bibo/abstract") private String abstractText; - @Field @FieldType(type = "whole_string", copyTo = "_text_") @FieldSource(template = "document/abbreviation", predicate = "http://vivoweb.org/ontology/core#abbreviation") private String abbreviation; - @Field @NestedObject @FieldType(type = "nested_whole_string", copyTo = "_text_") @FieldSource(template = "document/publicationVenue", predicate = "http://www.w3.org/2000/01/rdf-schema#label", unique = true) private String publicationVenue; - @Field @NestedObject @FieldType(type = "nested_whole_string", searchable = false) @FieldSource(template = "document/hasPublicationVenueFor", predicate = "http://www.w3.org/2000/01/rdf-schema#label", unique = true) private String hasPublicationVenueFor; - @Field @FieldType(type = "whole_string", copyTo = "_text_") @FieldSource(template = "document/publicationOutlet", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#publishedProceedings", unique = true) private String publicationOutlet; - @Field @FieldType(type = "whole_string", copyTo = "_text_") @FieldSource(template = "document/nameOfConference", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#nameOfConference", unique = true) private String nameOfConference; - @Field @FieldType(type = "nested_whole_strings", copyTo = "_text_") @NestedObject(properties = { @Reference(value = "authorOrganization", key = "organizations") }) @FieldSource(template = "document/author", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List authors; - @Field @NestedMultiValuedProperty @NestedObject(root = false) @FieldType(type = "nested_whole_strings") @FieldSource(template = "document/authorOrganization", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List authorOrganization; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/editor", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List editors; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/translator", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List translators; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "document/status", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private String status; - @Field @FieldType(type = "pdate") @FieldSource(template = "document/publicationDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private String publicationDate; - @Field @FieldType(type = "nested_whole_string") @NestedObject(properties = { @Reference(value = "publisherType", key = "type") }) @FieldSource(template = "document/publisher", predicate = "http://www.w3.org/2000/01/rdf-schema#label", unique = true) private String publisher; - @Field @FieldType(type = "nested_whole_string") @FieldSource(template = "document/publisherType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private String publisherType; - @Field @FieldType(type = "pdate", searchable = false) @FieldSource(template = "document/dateFiled", predicate = "http://vivoweb.org/ontology/core#dateTime") private String dateFiled; - @Field @FieldType(type = "pdate", searchable = false) @FieldSource(template = "document/dateIssued", predicate = "http://vivoweb.org/ontology/core#dateTime") private String dateIssued; - @Field @NestedObject @FieldType(type = "nested_whole_strings") @FieldSource(template = "document/hasSubjectArea", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List subjectAreas; - @Field @FieldType(type = "whole_strings", searchable = false) @FieldSource(template = "document/hasRestriction", predicate = "http://purl.obolibrary.org/obo/ERO_0000045") private List restrictions; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/documentPart", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List documentParts; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "document/chapter", predicate = "http://purl.org/ontology/bibo/chapter") private String chapter; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/feature", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List features; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "document/edition", predicate = "http://purl.org/ontology/bibo/edition") private String edition; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/documentationForProjectOrResource", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List documentationForProjectOrResource; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/outputOfProcessOrEvent", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List outputOfProcessOrEvent; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/presentedAt", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List presentedAt; - @Field @FieldType(type = "whole_strings", copyTo = "_text_") @FieldSource(template = "document/keyword", predicate = "http://vivoweb.org/ontology/core#freetextKeyword") private List keywords; - @Field @FieldType(type = "whole_string") @FieldSource(template = "document/eanucc13", predicate = "http://purl.org/ontology/bibo/eanucc13") private String eanucc13; - @Field @FieldType(type = "whole_string") @FieldSource(template = "document/nihmsid", predicate = "http://vivoweb.org/ontology/core#nihmsid") private String nihmsid; - @Field @FieldType(type = "whole_string") @FieldSource(template = "document/pmcid", predicate = "http://vivoweb.org/ontology/core#pmcid") private String pmcid; - @Field @FieldType(type = "whole_string") @FieldSource(template = "document/identifier", predicate = "http://purl.org/ontology/bibo/identifier") private String identifier; - @Field @FieldType(type = "whole_string") @FieldSource(template = "document/patentNumber", predicate = "http://vivoweb.org/ontology/core#patentNumber") private String patentNumber; - @Field @FieldType(type = "whole_string") @FieldSource(template = "document/doi", predicate = "http://purl.org/ontology/bibo/doi") private String doi; - @Field @FieldType(type = "whole_string") @FieldSource(template = "document/oclcnum", predicate = "http://purl.org/ontology/bibo/oclcnum") private String oclcnum; - @Field @FieldType(type = "whole_string") @FieldSource(template = "document/isbn10", predicate = "http://purl.org/ontology/bibo/isbn10") private String isbn10; - @Field @FieldType(type = "whole_string") @FieldSource(template = "document/isbn13", predicate = "http://purl.org/ontology/bibo/isbn13") private String isbn13; - @Field @FieldType(type = "whole_string") @FieldSource(template = "document/pmid", predicate = "http://purl.org/ontology/bibo/pmid") private String pmid; - @Field @FieldType(type = "whole_string") @FieldSource(template = "document/lccn", predicate = "http://purl.org/ontology/bibo/lccn") private String lccn; - @Field @FieldType(type = "whole_string") @FieldSource(template = "document/issn", predicate = "http://purl.org/ontology/bibo/issn") private String issn; - @Field @FieldType(type = "whole_string") @FieldSource(template = "document/eissn", predicate = "http://purl.org/ontology/bibo/eissn") private String eissn; - @Field @FieldType(type = "whole_string") @FieldSource(template = "document/uri", predicate = "http://purl.org/ontology/bibo/uri") private String uri; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/citedBy", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List citedBy; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/cites", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List cites; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/citesAsDataSource", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List citesAsDataSource; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/hasTranslation", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List translations; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/translationOf", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List translationOf; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/globalCitationFrequency", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List globalCitationFrequency; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "document/iclCode", predicate = "http://vivoweb.org/ontology/core#iclCode") private String iclCode; - @Field @FieldType(type = "pint") @FieldSource(template = "document/numberOfPages", predicate = "http://purl.org/ontology/bibo/numPages") private Integer numberOfPages; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "document/pageStart", predicate = "http://purl.org/ontology/bibo/pageStart") private String pageStart; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "document/pageEnd", predicate = "http://purl.org/ontology/bibo/pageEnd") private String pageEnd; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "document/number", predicate = "http://purl.org/ontology/bibo/number") private String number; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "document/volume", predicate = "http://purl.org/ontology/bibo/volume") private String volume; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "document/issue", predicate = "http://purl.org/ontology/bibo/issue") private String issue; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "document/placeOfPublication", predicate = "http://vivoweb.org/ontology/core#placeOfPublication") private String placeOfPublication; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/assignee", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List assignees; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/reproducedIn", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List reproducedIn; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/reproduces", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List reproduces; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/isAbout", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List isAbout; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/specifiedOutputOf", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List specifiedOutputOf; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "document/isTemplate", predicate = "http://purl.obolibrary.org/obo/ARG_0000001") private String isTemplate; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/mention", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List mentions; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/participatesIn", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List participatesIn; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/supportedBy", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List supportedBy; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/receipt", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List receipts; - @Field @FieldType(type = "pfloat") @FieldSource(template = "document/altmetricScore", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#AltmetricScore") private Float altmetricScore; - @Field @FieldType(type = "pint") @FieldSource(template = "document/citationCount", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#CitationCount") private Integer citationCount; - @Field @FieldType(type = "whole_strings") @FieldSource(template = "document/tag", predicate = "http://purl.obolibrary.org/obo/ARG_0000015") private List tags; - @Field @FieldType(type = "whole_string") @FieldSource(template = "document/note", predicate = "http://www.w3.org/2006/vcard/ns#note") private String note; - @Field @FieldType(type = "whole_string") @FieldSource(template = "document/key", predicate = "http://www.w3.org/2006/vcard/ns#key") private String key; - @Field @FieldType(type = "whole_string") @FieldSource(template = "document/url", predicate = "http://www.w3.org/2006/vcard/ns#url") private String url; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "document/etdChairedBy", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List etdChairedBy; - @Field @NestedObject @FieldType(type = "nested_whole_strings") @FieldSource(template = "document/advisedBy", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List advisedBy; - @Field @FieldType(type = "whole_strings") @FieldSource(template = "document/completeAuthorList", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#completeAuthorList", split = true) private List completeAuthorList; - @Field @FieldType(type = "whole_strings") @FieldSource(template = "document/authorList", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#fullAuthorList") private List authorList; - @Field @FieldType(type = "whole_strings", searchable = false) @FieldSource(template = "document/editorList", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#fullEditorList") private List editorList; - @Field @FieldType(type = "tokenized_string", copyTo = "_text_") @FieldSource(template = "document/bookTitle", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#bookTitleForChapter") private String bookTitle; - @Field @FieldType(type = "whole_string") @FieldSource(template = "document/newsOutlet", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#NewsOutlet") private String newsOutlet; diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/model/Individual.java b/src/main/java/edu/tamu/scholars/middleware/discovery/model/Individual.java index 41215835d..52f6169f5 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/model/Individual.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/model/Individual.java @@ -1,32 +1,119 @@ package edu.tamu.scholars.middleware.discovery.model; import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; +import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.CLASS; +import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.ID; +import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.SYNC_IDS; +import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.TYPE; import java.util.Collection; +import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; +import org.apache.lucene.document.StoredField; import org.apache.solr.client.solrj.beans.Field; +import org.apache.solr.common.SolrDocument; import org.springframework.hateoas.server.core.Relation; import com.fasterxml.jackson.annotation.JsonInclude; +import edu.tamu.scholars.middleware.discovery.utility.DiscoveryUtility; + @JsonInclude(NON_EMPTY) @Relation(collectionRelation = "individual", itemRelation = "individual") public class Individual extends AbstractIndexDocument { @Field("*") - private Map> content; + private final Map content; public Individual() { + this(new HashMap<>()); + } + private Individual(Map content) { + this.content = content; } - public Map> getContent() { + public Map getContent() { return content; } - public void setContent(Map> content) { - this.content = content; + public String getProxy() { + return (String) content.get(CLASS); + } + + public void setProxy(String proxy) { + this.content.put(CLASS, proxy); + } + + @Override + public String getId() { + return (String) content.get(ID); + } + + @Override + public void setId(String id) { + this.content.put(ID, id); + } + + @Override + @SuppressWarnings("unchecked") + public List getType() { + return (List) content.get(TYPE); + } + + @Override + public void setType(List type) { + this.content.put(TYPE, type); + } + + @Override + @SuppressWarnings("unchecked") + public List getSyncIds() { + return (List) content.get(SYNC_IDS); + } + + @Override + public void setSyncIds(List syncIds) { + this.content.put(SYNC_IDS, syncIds); + } + + public static Individual from(SolrDocument document) { + Map content = new HashMap<>(); + + String name = (String) normalize(document.getFieldValue(CLASS)); + + DiscoveryUtility.getDiscoveryDocumentTypeFields(name) + .entrySet() + .stream() + .filter(entry -> document.containsKey(entry.getKey())) + .forEach(entry -> { + String field = entry.getKey(); + if (Collection.class.isAssignableFrom(entry.getValue())) { + Collection values = document.getFieldValues(field) + .stream() + .map(Individual::normalize) + .collect(Collectors.toList()); + content.put(field, values); + } else { + content.put(field, normalize(document.getFirstValue(field))); + } + }); + + return Individual.from(content); + } + + public static Object normalize(Object value) { + if (StoredField.class.isAssignableFrom(value.getClass())) { + return ((StoredField) value).stringValue(); + } + return value; + } + + public static Individual from(Map content) { + return new Individual(content); } } diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/model/Organization.java b/src/main/java/edu/tamu/scholars/middleware/discovery/model/Organization.java index b3881cde7..aa88567cb 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/model/Organization.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/model/Organization.java @@ -1,347 +1,288 @@ package edu.tamu.scholars.middleware.discovery.model; import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; -import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.COLLECTION; import java.util.List; -import org.apache.solr.client.solrj.beans.Field; - import com.fasterxml.jackson.annotation.JsonInclude; import edu.tamu.scholars.middleware.discovery.annotation.CollectionSource; -import edu.tamu.scholars.middleware.discovery.annotation.CollectionTarget; -import edu.tamu.scholars.middleware.discovery.annotation.NestedObject; -import edu.tamu.scholars.middleware.discovery.annotation.NestedObject.Reference; import edu.tamu.scholars.middleware.discovery.annotation.FieldSource; import edu.tamu.scholars.middleware.discovery.annotation.FieldType; +import edu.tamu.scholars.middleware.discovery.annotation.NestedObject; +import edu.tamu.scholars.middleware.discovery.annotation.NestedObject.Reference; @JsonInclude(NON_EMPTY) -@CollectionTarget(name = COLLECTION) @CollectionSource(name = "organizations", predicate = "http://xmlns.com/foaf/0.1/Organization") public class Organization extends Common { - @Field @FieldType(type = "tokenized_string", copyTo = { "_text_", "name_sort" }) @FieldSource(template = "organization/name", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private String name; - @Field @FieldType(type = "tokenized_string", copyTo = "_text_") @FieldSource(template = "organization/overview", predicate = "http://vivoweb.org/ontology/core#overview") private String overview; - @Field @NestedObject @FieldType(type = "nested_whole_strings", copyTo = "_text_") @FieldSource(template = "organization/offersDegree", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List degrees; - @Field @FieldType(type = "whole_string", copyTo = "_text_") @FieldSource(template = "organization/abbreviation", predicate = "http://vivoweb.org/ontology/core#abbreviation") private String abbreviation; - @Field @FieldType(type = "pdate", searchable = false) @FieldSource(template = "organization/date", predicate = "http://vivoweb.org/ontology/core#dateTime") private String date; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/sponsorsAwardOrHonor", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List sponsorsAwardOrHonor; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/awardOrHonorGiven", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List awardOrHonorGiven; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/awardOrHonorReceived", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List awardOrHonorReceived; - @Field @FieldType(type = "whole_strings", copyTo = "_text_") @FieldSource(template = "organization/keyword", predicate = "http://vivoweb.org/ontology/core#freetextKeyword") private List keywords; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "organizationForTrainingTrainee", key = "trainee"), @Reference(value = "organizationForTrainingDegree", key = "degree"), @Reference(value = "organizationForTrainingStartDate", key = "startDate"), @Reference(value = "organizationForTrainingEndDate", key = "endDate") }) @FieldSource(template = "organization/organizationForTraining", predicate = "http://vivoweb.org/ontology/core#majorField") private List organizationForTraining; - @Field @NestedObject(root = false) @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/organizationForTrainingTrainee", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List organizationForTrainingTrainee; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/organizationForTrainingDegree", predicate = "http://vivoweb.org/ontology/core#abbreviation") private List organizationForTrainingDegree; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "organization/organizationForTrainingStartDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List organizationForTrainingStartDate; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "organization/organizationForTrainingEndDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List organizationForTrainingEndDate; - @Field @FieldType(type = "nested_whole_strings") @NestedObject(properties = { @Reference(value = "peopleType", key = "type"), @Reference(value = "peopleTitle", key = "title") }) @FieldSource(template = "organization/people", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List people; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/peopleType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List peopleType; - @Field @FieldType(type = "nested_whole_strings") @FieldSource(template = "organization/peopleTitle", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List peopleTitle; - @Field - @NestedObject + @NestedObject(properties = { @Reference(value = "hasSubOrganizationType", key = "type") }) @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/hasSubOrganization", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List hasSubOrganizations; - @Field + @FieldType(type = "nested_whole_strings", searchable = false) + @FieldSource(template = "organization/hasSubOrganizationType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) + private List hasSubOrganizationType; + @NestedObject @FieldType(type = "nested_whole_strings") @FieldSource(template = "organization/organizationWithin", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List organizationWithin; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/leadOrganizationOf", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List leadOrganizationOf; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/hasCollaboratingOrganizationOrGroup", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List hasCollaboratingOrganizationOrGroup; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/hasAffiliatedOrganization", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List hasAffiliatedOrganizations; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/memberOf", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List memberOf; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/clinicalActivity", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List clinicalActivities; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/convenerOfEvent", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List convenerOfEvents; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/attendedEvent", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List attendedEvents; - @Field @NestedObject @FieldType(type = "nested_tokenized_strings", copyTo = "_text_") @FieldSource(template = "organization/publication", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List publications; - @Field @NestedObject @FieldType(type = "nested_whole_strings") @FieldSource(template = "organization/publisherOf", predicate = "http://www.w3.org/2000/01/rdf-schema#label", unique = true) private List publisherOf; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/presentation", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List presentations; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/featuredIn", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List featuredIn; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/assigneeForPatent", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List assigneeForPatent; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/translatorOf", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List translatorOf; - @Field @FieldType(type = "nested_whole_strings") @NestedObject(properties = { @Reference(value = "awardsGrantDate", key = "date") }) @FieldSource(template = "organization/awardsGrant", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List awardsGrant; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "organization/awardsGrantDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List awardsGrantDate; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "administersGrantDate", key = "date") }) @FieldSource(template = "organization/administersGrant", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List administersGrant; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "organization/administersGrantDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List administersGrantDate; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "subcontractsGrantDate", key = "date") }) @FieldSource(template = "organization/subcontractsGrant", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List subcontractsGrant; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "organization/subcontractsGrantDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List subcontractsGrantDate; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/performsHumanStudy", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List performsHumanStudy; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/contractOrProviderForService", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List contractOrProviderForService; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/outreachAndCommunityServiceActivity", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List outreachAndCommunityServiceActivities; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/hasEquipment", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List hasEquipment; - @Field @NestedObject @FieldType(type = "nested_whole_strings") @FieldSource(template = "organization/offersCourse", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List courses; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "organization/phone", predicate = "http://www.w3.org/2006/vcard/ns#telephone") private String phone; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "organization/fax", predicate = "http://www.w3.org/2006/vcard/ns#fax") private String fax; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "organization/emailAddress", predicate = "http://www.w3.org/2006/vcard/ns#email") private String emailAddress; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "organization/streetAddress", predicate = "organization.streetAddress") private String streetAddress; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "organization/locality", predicate = "organization.locality") private String locality; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "organization/region", predicate = "organization.region") private String region; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "organization/postalCode", predicate = "organization.postalCode") private String postalCode; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "organization/country", predicate = "organization.country") private String country; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "organization/geographicLocation", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private String geographicLocation; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/locatedAtFacility", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List locatedAtFacilities; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/predecessorOrganization", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List predecessorOrganizations; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/successorOrganization", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List successorOrganizations; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "organization/governingAuthorityFor", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List governingAuthorityFor; - @Field @NestedObject @FieldType(type = "nested_whole_strings") @FieldSource(template = "organization/affiliatedResearchArea", predicate = "http://www.w3.org/2000/01/rdf-schema#label", unique = true) private List affiliatedResearchAreas; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "organization/orgId", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#OrgID") private String orgId; @@ -494,6 +435,14 @@ public void setHasSubOrganizations(List hasSubOrganizations) { this.hasSubOrganizations = hasSubOrganizations; } + public List getHasSubOrganizationType() { + return hasSubOrganizationType; + } + + public void setHasSubOrganizationType(List hasSubOrganizationType) { + this.hasSubOrganizationType = hasSubOrganizationType; + } + public List getOrganizationWithin() { return organizationWithin; } diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/model/Person.java b/src/main/java/edu/tamu/scholars/middleware/discovery/model/Person.java index 4a442ad14..32069db84 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/model/Person.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/model/Person.java @@ -1,882 +1,714 @@ package edu.tamu.scholars.middleware.discovery.model; import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; -import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.COLLECTION; import java.util.List; -import org.apache.solr.client.solrj.beans.Field; - import com.fasterxml.jackson.annotation.JsonInclude; import edu.tamu.scholars.middleware.discovery.annotation.CollectionSource; -import edu.tamu.scholars.middleware.discovery.annotation.CollectionTarget; +import edu.tamu.scholars.middleware.discovery.annotation.FieldSource; +import edu.tamu.scholars.middleware.discovery.annotation.FieldType; import edu.tamu.scholars.middleware.discovery.annotation.NestedMultiValuedProperty; import edu.tamu.scholars.middleware.discovery.annotation.NestedObject; import edu.tamu.scholars.middleware.discovery.annotation.NestedObject.Reference; -import edu.tamu.scholars.middleware.discovery.annotation.FieldSource; -import edu.tamu.scholars.middleware.discovery.annotation.FieldType; @JsonInclude(NON_EMPTY) -@CollectionTarget(name = COLLECTION) @CollectionSource(name = "persons", predicate = "http://xmlns.com/foaf/0.1/Person") public class Person extends Common { - @Field @FieldType(type = "tokenized_string", copyTo = { "_text_", "name_sort" }) @FieldSource(template = "person/name", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private String name; - @Field @FieldType(type = "whole_string") @FieldSource(template = "person/primaryEmail", predicate = "http://www.w3.org/2006/vcard/ns#email") private String primaryEmail; - @Field @FieldType(type = "whole_strings", searchable = false) @FieldSource(template = "person/additionalEmail", predicate = "http://www.w3.org/2006/vcard/ns#email") private List additionalEmails; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "person/phone", predicate = "http://www.w3.org/2006/vcard/ns#telephone") private String phone; - @Field @FieldType(type = "whole_string") @FieldSource(template = "person/orcidId", predicate = "http://vivoweb.org/ontology/core#orcidId", parse = true) private String orcidId; - @Field @FieldType(type = "tokenized_string") @FieldSource(template = "person/preferredTitle", predicate = "http://www.w3.org/2006/vcard/ns#title") private String preferredTitle; - @Field @FieldType(type = "nested_whole_strings") @NestedObject(properties = { @Reference(value = "positionType", key = "type"), @Reference(value = "positionOrganization", key = "organizations") }) @FieldSource(template = "person/position", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List positions; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/positionType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List positionType; - @Field @NestedMultiValuedProperty @FieldType(type = "nested_whole_strings") @NestedObject(root = false, properties = { @Reference(value = "positionOrganizationParent", key = "parent") }) @FieldSource(template = "person/positionOrganization", predicate = "http://www.w3.org/2000/01/rdf-schema#label", unique = true) private List positionOrganization; - @Field @NestedMultiValuedProperty @NestedObject(root = false) @FieldType(type = "nested_whole_strings") @FieldSource(template = "person/positionOrganizationParent", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List positionOrganizationParent; - @Field @FieldType(type = "tokenized_string", copyTo = "_text_") @FieldSource(template = "person/overview", predicate = "http://vivoweb.org/ontology/core#overview") private String overview; - @Field @NestedObject @FieldType(type = "nested_tokenized_strings", copyTo = { "_text_", "researchAreas_nested_facets" }) @FieldSource(template = "person/researchArea", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List researchAreas; - @Field @FieldType(type = "whole_string") @FieldSource(template = "person/hrJobTitle", predicate = "http://vivoweb.org/ontology/core#hrJobTitle") private String hrJobTitle; - @Field @FieldType(type = "whole_strings") @FieldSource(template = "person/keyword", predicate = "http://vivoweb.org/ontology/core#freetextKeyword") private List keywords; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "headOfType", key = "type"), @Reference(value = "headOfOrganization", key = "organization"), @Reference(value = "headOfStartDate", key = "startDate"), @Reference(value = "headOfEndDate", key = "endDate") }) @FieldSource(template = "person/headOf", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List headOf; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/headOfType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List headOfType; - @Field @NestedObject(root = false) @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/headOfOrganization", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List headOfOrganization; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/headOfStartDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List headOfStartDate; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/headOfEndDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List headOfEndDate; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "memberOfType", key = "type"), @Reference(value = "memberOfOrganization", key = "organization"), @Reference(value = "memberOfStartDate", key = "startDate"), @Reference(value = "memberOfEndDate", key = "endDate") }) @FieldSource(template = "person/memberOf", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List memberOf; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/memberOfType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List memberOfType; - @Field @NestedObject(root = false) @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/memberOfOrganization", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List memberOfOrganization; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/memberOfStartDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List memberOfStartDate; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/memberOfEndDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List memberOfEndDate; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/hasCollaborator", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List hasCollaborator; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "clinicalActivityType", key = "type"), @Reference(value = "clinicalActivityRole", key = "role"), @Reference(value = "clinicalActivityStartDate", key = "startDate"), @Reference(value = "clinicalActivityEndDate", key = "endDate") }) @FieldSource(template = "person/clinicalActivity", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List clinicalActivities; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/clinicalActivityType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List clinicalActivityType; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/clinicalActivityRole", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List clinicalActivityRole; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/clinicalActivityStartDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List clinicalActivityStartDate; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/clinicalActivityEndDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List clinicalActivityEndDate; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "attendedEventType", key = "type"), @Reference(value = "attendedEventStartDate", key = "startDate"), @Reference(value = "attendedEventEndDate", key = "endDate") }) @FieldSource(template = "person/attendedEvent", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List attendedEvents; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/attendedEventType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List attendedEventType; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/attendedEventStartDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List attendedEventStartDate; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/attendedEventEndDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List attendedEventEndDate; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "educationAndTrainingName", key = "name"), @Reference(value = "educationAndTrainingInfo", key = "info"), @Reference(value = "educationAndTrainingOrganization", key = "organization"), @Reference(value = "educationAndTrainingMajorField", key = "field"), @Reference(value = "educationAndTrainingDegreeAbbreviation", key = "abbreviation"), @Reference(value = "educationAndTrainingStartDate", key = "startDate"), @Reference(value = "educationAndTrainingEndDate", key = "endDate"), @Reference(value = "educationAndTrainingIsDateSuppressed", key = "isDateSuppressed") }) @FieldSource(template = "person/educationAndTraining", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List educationAndTraining; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/educationAndTrainingName", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List educationAndTrainingName; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/educationAndTrainingInfo", predicate = "http://vivoweb.org/ontology/core#supplementalInformation") private List educationAndTrainingInfo; - @Field @NestedObject(root = false) @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/educationAndTrainingOrganization", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List educationAndTrainingOrganization; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/educationAndTrainingMajorField", predicate = "http://vivoweb.org/ontology/core#majorField") private List educationAndTrainingMajorField; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/educationAndTrainingDegreeAbbreviation", predicate = "http://vivoweb.org/ontology/core#abbreviation") private List educationAndTrainingDegreeAbbreviation; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/educationAndTrainingStartDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List educationAndTrainingStartDate; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/educationAndTrainingEndDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List educationAndTrainingEndDate; - @Field @FieldType(type="nested_whole_string", searchable = false) @FieldSource(template= "person/educationAndTrainingIsDateSuppressed", predicate = "http://vivoweb.org/ontology/core#supplementalInformation") private List educationAndTrainingIsDateSuppressed; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/credentials", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List credentials; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "credentialEligibilityAttainedType", key = "type") }) @FieldSource(template = "person/credentialEligibilityAttained", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List credentialEligibilityAttained; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/credentialEligibilityAttainedType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List credentialEligibilityAttainedType; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/awardAndHonor", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List awardsAndHonors; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "adviseeOfType", key = "type"), @Reference(value = "adviseeOfCandidacy", key = "candidacy"), @Reference(value = "adviseeOfStartDate", key = "startDate"), @Reference(value = "adviseeOfEndDate", key = "endDate") }) @FieldSource(template = "person/adviseeOf", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List adviseeOf; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/adviseeOfType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List adviseeOfType; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/adviseeOfCandidacy", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List adviseeOfCandidacy; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/adviseeOfStartDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List adviseeOfStartDate; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/adviseeOfEndDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List adviseeOfEndDate; - @Field @FieldType(type = "nested_tokenized_strings", copyTo = "_text_") @NestedObject(properties = { @Reference(value = "selectedPublicationType", key = "type"), @Reference(value = "selectedPublicationDate", key = "publicationDate"), @Reference(value = "selectedPublicationPublisher", key = "publisher"), @Reference(value = "selectedPublicationVenue", key = "venue"), @Reference(value = "selectedPublicationTag", key = "tags") }) @FieldSource(template = "person/selectedPublications", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List publications; - @Field @FieldType(type = "pdates") @FieldSource(template = "person/publicationDates", predicate = "http://vivoweb.org/ontology/core#dateTime") private List publicationDates; // duplicate of selectedPublicationDate without encoded reference to publication - @Field @FieldType(type = "nested_whole_strings") @FieldSource(template = "person/selectedPublicationType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List selectedPublicationType; - @Field @FieldType(type = "nested_dates") @FieldSource(template = "person/selectedPublicationDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List selectedPublicationDate; - @Field @FieldType(type = "nested_whole_strings") @FieldSource(template = "person/selectedPublicationPublisher", predicate = "http://www.w3.org/2000/01/rdf-schema#label", unique = true) private List selectedPublicationPublisher; - @Field @FieldType(type = "nested_whole_strings") @FieldSource(template = "person/selectedPublicationVenue", predicate = "http://www.w3.org/2000/01/rdf-schema#label", unique = true) private List selectedPublicationVenue; - @Field @FieldType(type = "nested_whole_strings") @FieldSource(template = "person/selectedPublicationTag", predicate = "http://purl.obolibrary.org/obo/ARG_0000015") private List selectedPublicationTag; - @Field @FieldType(type = "nested_tokenized_strings", copyTo = "_text_") @NestedObject(properties = { @Reference(value = "creativeWorkType", key = "type") }) @FieldSource(template = "person/creativeWorks", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List creativeWorks; - @Field @FieldType(type = "nested_whole_strings") @FieldSource(template = "person/creativeWorkType", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#subtype") private List creativeWorkType; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "collectionOrSeriesEditorForType", key = "type"), @Reference(value = "collectionOrSeriesEditorForRole", key = "role"), @Reference(value = "collectionOrSeriesEditorForStartDate", key = "startDate"), @Reference(value = "collectionOrSeriesEditorForEndDate", key = "endDate") }) @FieldSource(template = "person/collectionOrSeriesEditorFor", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List collectionOrSeriesEditorFor; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/collectionOrSeriesEditorForType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List collectionOrSeriesEditorForType; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/collectionOrSeriesEditorForRole", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List collectionOrSeriesEditorForRole; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/collectionOrSeriesEditorForStartDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List collectionOrSeriesEditorForStartDate; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/collectionOrSeriesEditorForEndDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List collectionOrSeriesEditorForEndDate; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "editorOfType", key = "type"), @Reference(value = "editorOfPublisher", key = "publisher"), @Reference(value = "editorOfPageStart", key = "pageStart"), @Reference(value = "editorOfPageEnd", key = "pageEnd"), @Reference(value = "editorOfDate", key = "date") }) @FieldSource(template = "person/editorOf", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List editorOf; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/editorOfType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List editorOfType; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/editorOfPublisher", predicate = "http://www.w3.org/2000/01/rdf-schema#label", unique = true) private List editorOfPublisher; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/editorOfPageStart", predicate = "http://purl.org/ontology/bibo/pageStart") private List editorOfPageStart; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/editorOfPageEnd", predicate = "http://purl.org/ontology/bibo/pageEnd") private List editorOfPageEnd; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/editorOfDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List editorOfDate; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "presentationType", key = "type"), @Reference(value = "presentationRole", key = "role"), @Reference(value = "presentationEvent", key = "event"), @Reference(value = "presentationStartDate", key = "startDate"), @Reference(value = "presentationEndDate", key = "endDate") }) @FieldSource(template = "person/presentation", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List presentations; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/presentationType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List presentationType; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/presentationRole", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List presentationRole; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/presentationEvent", predicate = "http://www.w3.org/2000/01/rdf-schema#label", parse = true) private List presentationEvent; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/presentationStartDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List presentationStartDate; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/presentationEndDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List presentationEndDate; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/featuredIn", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List featuredIn; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/assigneeForPatent", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List assigneeForPatent; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/translatorOf", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List translatorOf; - @Field @FieldType(type = "tokenized_string") @FieldSource(template = "person/researchOverview", predicate = "http://vivoweb.org/ontology/core#researchOverview") private String researchOverview; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/principalInvestigatorOn", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List principalInvestigatorOn; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/coPrincipalInvestigatorOn", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List coPrincipalInvestigatorOn; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "researcherOnAwardedBy", key = "awardedBy"), @Reference(value = "researcherOnRole", key = "role"), @Reference(value = "researcherOnStartDate", key = "startDate"), @Reference(value = "researcherOnEndDate", key = "endDate") }) @FieldSource(template = "person/researcherOn", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List researcherOn; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(root = false, properties = { @Reference(value = "researcherOnAwardedByPreferredLabel", key = "preferredLabel") }) @FieldSource(template = "person/researcherOnAwardedBy", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List researcherOnAwardedBy; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/researcherOnAwardedByPreferredLabel", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#awardedBy_label") private List researcherOnAwardedByPreferredLabel; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/researcherOnRole", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List researcherOnRole; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/researcherOnStartDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List researcherOnStartDate; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/researcherOnEndDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List researcherOnEndDate; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "otherResearchActivityRole", key = "role"), @Reference(value = "otherResearchActivityStartDate", key = "startDate"), @Reference(value = "otherResearchActivityEndDate", key = "endDate") }) @FieldSource(template = "person/otherResearchActivity", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List otherResearchActivities; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/otherResearchActivityRole", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List otherResearchActivityRole; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/otherResearchActivityStartDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List otherResearchActivityStartDate; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/otherResearchActivityEndDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List otherResearchActivityEndDate; - @Field @FieldType(type = "tokenized_string") @FieldSource(template = "person/teachingOverview", predicate = "http://vivoweb.org/ontology/core#teachingOverview") private String teachingOverview; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "teachingActivityRole", key = "role") }) @FieldSource(template = "person/teachingActivity", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List teachingActivities; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/teachingActivityRole", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List teachingActivityRole; - @Field @NestedObject @FieldType(type = "nested_whole_strings") @FieldSource(template = "person/teachingMaterials", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List teachingMaterials; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "adviseeType", key = "type"), @Reference(value = "adviseeCandidacy", key = "candidacy"), @Reference(value = "adviseeStartDate", key = "startDate"), @Reference(value = "adviseeEndDate", key = "endDate") }) @FieldSource(template = "person/advisee", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List advisee; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/adviseeType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List adviseeType; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/adviseeCandidacy", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List adviseeCandidacy; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/adviseeStartDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List adviseeStartDate; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/adviseeEndDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List adviseeEndDate; - @Field @FieldType(type = "tokenized_string") @FieldSource(template = "person/outreachOverview", predicate = "http://vivoweb.org/ontology/core#outreachOverview") private String outreachOverview; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "reviewerOfType", key = "type"), @Reference(value = "reviewerOfStartDate", key = "startDate"), @Reference(value = "reviewerOfEndDate", key = "endDate") }) @FieldSource(template = "person/reviewerOf", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List reviewerOf; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/reviewerOfType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List reviewerOfType; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/reviewerOfStartDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List reviewerOfStartDate; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/reviewerOfEndDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List reviewerOfEndDate; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "contactOrProvidorForServiceType", key = "type") }) @FieldSource(template = "person/contactOrProvidorForService", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List contactOrProvidorForService; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/contactOrProvidorForServiceType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List contactOrProvidorForServiceType; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "organizerOfEventType", key = "type"), @Reference(value = "organizerOfEventStartDate", key = "startDate"), @Reference(value = "organizerOfEventEndDate", key = "endDate") }) @FieldSource(template = "person/organizerOfEvent", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List organizerOfEvent; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/organizerOfEventType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List organizerOfEventType; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/organizerOfEventStartDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List organizerOfEventStartDate; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/organizerOfEventEndDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List organizerOfEventEndDate; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "professionalServiceActivityType", key = "type"), @Reference(value = "professionalServiceActivityRole", key = "role"), @Reference(value = "professionalServiceActivityStartDate", key = "startDate"), @Reference(value = "professionalServiceActivityEndDate", key = "endDate") }) @FieldSource(template = "person/professionalServiceActivity", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List professionalServiceActivities; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/professionalServiceActivityRole", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List professionalServiceActivityRole; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/professionalServiceActivityType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List professionalServiceActivityType; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/professionalServiceActivityStartDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List professionalServiceActivityStartDate; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/professionalServiceActivityEndDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List professionalServiceActivityEndDate; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "outreachAndCommunityServiceActivityType", key = "type"), @Reference(value = "outreachAndCommunityServiceActivityRole", key = "role"), @Reference(value = "outreachAndCommunityServiceActivityStartDate", key = "startDate"), @Reference(value = "outreachAndCommunityServiceActivityEndDate", key = "endDate") }) @FieldSource(template = "person/outreachAndCommunityServiceActivity", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List outreachAndCommunityServiceActivities; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/professionalServiceActivityType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List outreachAndCommunityServiceActivityType; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/professionalServiceActivityRole", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List outreachAndCommunityServiceActivityRole; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/professionalServiceActivityStartDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List outreachAndCommunityServiceActivityStartDate; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/professionalServiceActivityEndDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List outreachAndCommunityServiceActivityEndDate; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "performsTechniqueType", key = "type") }) @FieldSource(template = "person/performsTechnique", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List performsTechnique; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/performsTechniqueType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List performsTechniqueType; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "hasExpertiseInTechniqueType", key = "type") }) @FieldSource(template = "person/hasExpertiseInTechnique", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List hasExpertiseInTechnique; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/hasExpertiseInTechniqueType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List hasExpertiseInTechniqueType; - @Field @FieldType(type = "whole_string") @FieldSource(template = "person/eraCommonsId", predicate = "http://vivoweb.org/ontology/core#eRACommonsId") private String eraCommonsId; - @Field @FieldType(type = "whole_string") @FieldSource(template = "person/isiResearcherId", predicate = "http://vivoweb.org/ontology/core#researcherId") private String isiResearcherId; - @Field @FieldType(type = "whole_string") @FieldSource(template = "person/scopusId", predicate = "http://vivoweb.org/ontology/core#scopusId") private String scopusId; - @Field @FieldType(type = "whole_string") @FieldSource(template = "person/healthCareProviderId", predicate = "http://purl.obolibrary.org/obo/ARG_0000197") private String healthCareProviderId; - @Field @FieldType(type = "whole_string") @FieldSource(template = "person/email", predicate = "http://www.w3.org/2006/vcard/ns#email") private String email; - @Field @FieldType(type = "tokenized_string") @FieldSource(template = "person/firstName", predicate = "http://www.w3.org/2006/vcard/ns#givenName") private String firstName; - @Field @FieldType(type = "tokenized_string") @FieldSource(template = "person/middleName", predicate = "http://www.w3.org/2006/vcard/ns#middleName") private String middleName; - @Field @FieldType(type = "tokenized_string") @FieldSource(template = "person/lastName", predicate = "http://www.w3.org/2006/vcard/ns#familyName") private String lastName; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "person/streetAddress", predicate = "http://www.w3.org/2006/vcard/ns#streetAddress") private String streetAddress; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "person/locality", predicate = "http://www.w3.org/2006/vcard/ns#locality") private String locality; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "person/region", predicate = "http://www.w3.org/2006/vcard/ns#region") private String region; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "person/postalCode", predicate = "http://www.w3.org/2006/vcard/ns#postalCode") private String postalCode; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "person/country", predicate = "http://www.w3.org/2006/vcard/ns#country") private String country; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "person/geographicLocation", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private String geographicLocation; - @Field @FieldType(type = "whole_strings", searchable = false) @FieldSource(template = "person/locatedInFacility", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List locatedInFacility; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "person/fax", predicate = "http://www.w3.org/2006/vcard/ns#fax") private String fax; - @Field @FieldType(type = "whole_strings") @FieldSource(template = "person/organization", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List organizations; - @Field @FieldType(type = "whole_strings") @FieldSource(template = "person/school", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List schools; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "person/isni", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#ISNI") private String isni; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "person/netid", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#NETID") private String netid; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "person/researcherId", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#ResearcherId") private String researcherId; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "person/twitter", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#twitterID") private String twitter; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "person/uid", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#UID") private String uid; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "person/uin", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#UIN") private String uin; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "person/youtube", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#youtube") private String youtube; - @Field @NestedObject @FieldType(type = "nested_whole_strings") @FieldSource(template = "person/inTheNews", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List inTheNews; - @Field @NestedObject @FieldType(type = "nested_whole_strings") @FieldSource(template = "person/futureResearchIdeas", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List futureResearchIdeas; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "etdChairOfURL", key = "url"), @Reference(value = "etdChairOfPublicationDate", key = "publicationDate") }) @FieldSource(template = "person/etdChairOf", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List etdChairOf; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "person/etdChairOfURL", predicate = "http://www.w3.org/2006/vcard/ns#url") private List etdChairOfURL; - @Field @FieldType(type = "nested_dates", searchable = false) @FieldSource(template = "person/etdChairOfPublicationDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List etdChairOfPublicationDate; - @Field @NestedObject(properties = { @Reference(value = "capstoneAdvisedOfURL", key = "url"), @Reference(value = "capstoneAdvisedOfPublicationDate", key = "publicationDate") }) @FieldType(type = "nested_whole_strings") @FieldSource(template = "person/capstoneAdvisedOf", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List capstoneAdvisedOf; - @Field @FieldType(type = "nested_whole_strings") @FieldSource(template = "person/capstoneAdvisedOfURL", predicate = "http://www.w3.org/2006/vcard/ns#url") private List capstoneAdvisedOfURL; - @Field @FieldType(type = "nested_dates") @FieldSource(template = "person/capstoneAdvisedOfPublicationDate", predicate = "http://vivoweb.org/ontology/core#dateTime") private List capstoneAdvisedOfPublicationDate; - @Field @FieldType(type = "whole_string") @FieldSource(template = "person/featuredProfileDisplay", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#FeaturedProfileDisplay") private String featuredProfileDisplay; - @Field @FieldType(type = "whole_string") @FieldSource(template = "person/publicationToInterfolio", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#PublicationToInterfolio") private String publicationToInterfolio; diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/model/Process.java b/src/main/java/edu/tamu/scholars/middleware/discovery/model/Process.java index d6109bb57..82b4fa1b8 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/model/Process.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/model/Process.java @@ -1,224 +1,184 @@ package edu.tamu.scholars.middleware.discovery.model; import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; -import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.COLLECTION; +import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.ABSTRACT; import java.util.List; -import org.apache.solr.client.solrj.beans.Field; - import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import edu.tamu.scholars.middleware.discovery.annotation.CollectionSource; -import edu.tamu.scholars.middleware.discovery.annotation.CollectionTarget; +import edu.tamu.scholars.middleware.discovery.annotation.FieldSource; +import edu.tamu.scholars.middleware.discovery.annotation.FieldType; import edu.tamu.scholars.middleware.discovery.annotation.NestedMultiValuedProperty; import edu.tamu.scholars.middleware.discovery.annotation.NestedObject; import edu.tamu.scholars.middleware.discovery.annotation.NestedObject.Reference; -import edu.tamu.scholars.middleware.discovery.annotation.FieldSource; -import edu.tamu.scholars.middleware.discovery.annotation.FieldType; @JsonInclude(NON_EMPTY) -@CollectionTarget(name = COLLECTION) @CollectionSource(name = "processes", predicate = "http://purl.obolibrary.org/obo/BFO_0000015") public class Process extends Common { - @Field @FieldType(type = "tokenized_string", copyTo = { "_text_", "title_sort" }) @FieldSource(template = "process/title", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private String title; - @Field("abstract") - @JsonProperty("abstract") - @FieldType(type = "tokenized_string", value = "abstract", copyTo = "_text_") + @JsonProperty(ABSTRACT) + @FieldType(type = "tokenized_string", value = ABSTRACT, copyTo = "_text_") @FieldSource(template = "process/abstract", predicate = "http://purl.org/ontology/bibo/abstract") private String abstractText; - @Field @FieldType(type = "nested_whole_strings", copyTo = "_text_") @NestedObject(properties = { @Reference(value = "authorOrganization", key = "organizations") }) @FieldSource(template = "process/author", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List authors; - @Field @NestedMultiValuedProperty @NestedObject(root = false) @FieldType(type = "nested_whole_strings") @FieldSource(template = "process/authorOrganization", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List authorOrganization; - @Field @FieldType(type = "whole_strings") @FieldSource(template = "process/authorList", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#fullAuthorList") private List authorList; - @Field @FieldType(type = "tokenized_string", copyTo = "_text_") @FieldSource(template = "process/description", predicate = "http://vivoweb.org/ontology/core#description") private String description; - @Field @NestedObject @FieldType(type = "nested_whole_strings") @FieldSource(template = "process/offeredBy", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List offeredBy; - @Field @FieldType(type = "nested_whole_string") @NestedObject(properties = { @Reference(value = "dateTimeIntervalStart", key = "start"), @Reference(value = "dateTimeIntervalEnd", key = "end") }) @FieldSource(template = "process/dateTimeInterval", predicate = "http://vivoweb.org/ontology/core#dateTimeInterval") private String dateTimeInterval; - @Field @FieldType(type = "nested_date") @NestedObject(properties = { @Reference(value = "dateTimePrecisionStart", key = "precision") }, root = false) @FieldSource(template = "process/dateTimeIntervalStart", predicate = "http://vivoweb.org/ontology/core#dateTime") private String dateTimeIntervalStart; - @Field @FieldType(type = "nested_date") @NestedObject(properties = { @Reference(value = "dateTimePrecisionEnd", key = "precision") }, root = false) @FieldSource(template = "process/dateTimeIntervalEnd", predicate = "http://vivoweb.org/ontology/core#dateTime") private String dateTimeIntervalEnd; - @Field @FieldType(type = "nested_whole_string") @FieldSource(template = "process/dateTimePrecisionStart", predicate = "http://vivoweb.org/ontology/core#dateTimePrecision", parse = true) private String dateTimePrecisionStart; - @Field @FieldType(type = "nested_whole_strings") @FieldSource(template = "process/dateTimePrecisionEnd", predicate = "http://vivoweb.org/ontology/core#dateTimePrecision", parse = true) private String dateTimePrecisionEnd; - @Field @FieldType(type = "whole_string") @FieldSource(template = "process/subtype", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#subtype") private String subtype; - @Field @FieldType(type = "whole_string") @FieldSource(template = "process/venue", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#venue") private String venue; - @Field @FieldType(type = "whole_string") @FieldSource(template = "process/location", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#location") private String location; - @Field @FieldType(type = "whole_string") @FieldSource(template = "process/url", predicate = "http://www.w3.org/2006/vcard/ns#url") private String url; - @Field @FieldType(type = "whole_string") @FieldSource(template = "process/note", predicate = "http://www.w3.org/2006/vcard/ns#note") private String note; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "process/occursWithinEvent", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List occursWithinEvent; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "process/includesEvent", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List includesEvent; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "process/inEventSeries", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List inEventSeries; - @Field @FieldType(type = "nested_tokenized_strings", copyTo = { "_text_", "participants_nested_facets" }) @NestedObject(properties = { @Reference(value = "participantId", key = "personId"), @Reference(value = "participantRole", key = "role"), @Reference(value = "participantDateTimeIntervalStart", key = "startDate"), @Reference(value = "participantDateTimeIntervalEnd", key = "endDate") }) @FieldSource(template = "process/participant", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List participants; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "process/participantId", predicate = "http://purl.obolibrary.org/obo/RO_0000052", parse = true) private List participantId; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "process/participantRole", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List participantRole; - @Field @FieldType(type = "nested_dates") @FieldSource(template = "process/participantDateTimeIntervalStart", predicate = "http://vivoweb.org/ontology/core#dateTime") private List participantDateTimeIntervalStart; - @Field @FieldType(type = "nested_dates") @FieldSource(template = "process/participantDateTimeIntervalEnd", predicate = "http://vivoweb.org/ontology/core#dateTime") private List participantDateTimeIntervalEnd; - @Field @NestedObject @FieldType(type = "nested_whole_strings") @FieldSource(template = "process/hasSubjectArea", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List subjectAreas; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "process/hasPrerequisite", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List hasPrerequisite; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "process/prerequisiteFor", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List prerequisiteFor; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "process/credits", predicate = "http://vivoweb.org/ontology/core#courseCredits") private String credits; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "process/outputPublicationOrOtherWork", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List outputPublicationOrOtherWork; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "process/relatedDocument", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List relatedDocuments; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "process/contactInformation", predicate = "http://vivoweb.org/ontology/core#contactInformation") private String contactInformation; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "process/heldInFacility", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List heldInFacility; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "process/heldInGeographicLocation", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List heldInGeographicLocation; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "process/hasOutput", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List hasOutput; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "process/hasParticipant", predicate = "http://www.w3.org/2000/01/rdf-schema#label") diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/model/Relationship.java b/src/main/java/edu/tamu/scholars/middleware/discovery/model/Relationship.java index d06f7710c..31578dc2a 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/model/Relationship.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/model/Relationship.java @@ -1,237 +1,194 @@ package edu.tamu.scholars.middleware.discovery.model; import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; -import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.COLLECTION; +import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.ABSTRACT; import java.util.List; -import org.apache.solr.client.solrj.beans.Field; - import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import edu.tamu.scholars.middleware.discovery.annotation.CollectionSource; -import edu.tamu.scholars.middleware.discovery.annotation.CollectionTarget; -import edu.tamu.scholars.middleware.discovery.annotation.NestedObject; -import edu.tamu.scholars.middleware.discovery.annotation.NestedObject.Reference; import edu.tamu.scholars.middleware.discovery.annotation.FieldSource; import edu.tamu.scholars.middleware.discovery.annotation.FieldType; +import edu.tamu.scholars.middleware.discovery.annotation.NestedObject; +import edu.tamu.scholars.middleware.discovery.annotation.NestedObject.Reference; @JsonInclude(NON_EMPTY) -@CollectionTarget(name = COLLECTION) @CollectionSource(name = "relationships", predicate = "http://vivoweb.org/ontology/core#Relationship") public class Relationship extends Common { - @Field @FieldType(type = "tokenized_string", copyTo = { "_text_", "title_sort" }) @FieldSource(template = "relationship/title", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private String title; - @Field("abstract") - @JsonProperty("abstract") - @FieldType(type = "whole_string", value = "abstract", copyTo = "_text_") + @JsonProperty(ABSTRACT) + @FieldType(type = "whole_string", value = ABSTRACT, copyTo = "_text_") @FieldSource(template = "relationship/abstract", predicate = "http://purl.org/ontology/bibo/abstract") private String abstractText; - @Field @FieldType(type = "whole_string") @FieldSource(template = "relationship/description", predicate = "http://vivoweb.org/ontology/core#description") private String description; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "relationship/organization", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List organization; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "relationship/receiptOf", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List receiptOf; - @Field @FieldType(type = "nested_whole_strings") @NestedObject(properties = { @Reference(value = "awardOrHonorForType", key = "type") }) @FieldSource(template = "relationship/awardOrHonorFor", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List awardOrHonorFor; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "relationship/awardOrHonorForType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List awardOrHonorForType; - @Field @FieldType(type = "nested_whole_strings", copyTo = "_text_") @NestedObject(properties = { @Reference(value = "awardConferredByType", key = "type"), @Reference(value = "awardConferredByAbbreviation", key = "abbreviation"), @Reference(value = "awardConferredByPreferredLabel", key = "preferredLabel") }) @FieldSource(template = "relationship/awardConferredBy", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List awardConferredBy; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "relationship/awardConferredByType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List awardConferredByType; - @Field @FieldType(type = "nested_whole_strings", copyTo = "_text_") @FieldSource(template = "relationship/awardConferredByAbbreviation", predicate = "http://vivoweb.org/ontology/core#abbreviation") private List awardConferredByAbbreviation; - @Field @FieldType(type = "nested_whole_strings", copyTo = "_text_") @FieldSource(template = "relationship/awardConferredByPreferredLabel", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#awardConferredBy_label") private List awardConferredByPreferredLabel; - @Field @FieldType(type = "nested_tokenized_strings", copyTo = { "_text_", "awardedBy_nested_facets" }) @NestedObject(properties = { @Reference(value = "awardedByType", key = "type"), @Reference(value = "awardedByAbbreviation", key = "abbreviation"), @Reference(value = "awardedByPreferredLabel", key = "preferredLabel") }) @FieldSource(template = "relationship/awardedBy", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List awardedBy; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "relationship/awardedByType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List awardedByType; - @Field @FieldType(type = "nested_whole_strings", copyTo = "_text_") @FieldSource(template = "relationship/awardedByAbbreviation", predicate = "http://vivoweb.org/ontology/core#abbreviation") private List awardedByAbbreviation; - @Field @FieldType(type = "nested_whole_strings", copyTo = "_text_") @FieldSource(template = "relationship/awardedByPreferredLabel", predicate = "http://vivo.library.tamu.edu/ontology/TAMU#awardedBy_label") private List awardedByPreferredLabel; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @NestedObject(properties = { @Reference(value = "grantSubcontractedThroughType", key = "type") }) @FieldSource(template = "relationship/grantSubcontractedThrough", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List grantSubcontractedThrough; - @Field @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "relationship/grantSubcontractedThroughType", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List grantSubcontractedThroughType; - @Field @NestedObject @FieldType(type = "nested_whole_strings") @FieldSource(template = "relationship/administeredBy", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List administeredBy; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "relationship/subGrant", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List subGrant; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "relationship/subGrantOf", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List subGrantOf; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "relationship/providesFundingFor", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List providesFundingFor; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "relationship/totalAwardAmount", predicate = "http://vivoweb.org/ontology/core#totalAwardAmount") private String totalAwardAmount; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "relationship/directCosts", predicate = "http://vivoweb.org/ontology/core#directCosts") private String directCosts; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "relationship/sponsorAwardId", predicate = "http://vivoweb.org/ontology/core#sponsorAwardId") private String sponsorAwardId; - @Field @FieldType(type = "whole_string", searchable = false) @FieldSource(template = "relationship/localAwardId", predicate = "http://vivoweb.org/ontology/core#localAwardId") private String localAwardId; - @Field @FieldType(type = "nested_tokenized_strings", copyTo = "_text_") - @NestedObject(properties = { @Reference(value = "contributorRole", key = "role"), @Reference(value = "contributorOrganization", key = "organization") }) + @NestedObject(properties = { @Reference(value = "contributorRole", key = "role"), @Reference(value = "contributorOrganization", key = "organizations") }) @FieldSource(template = "relationship/contributor", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List contributors; - @Field @FieldType(type = "nested_whole_strings") @FieldSource(template = "relationship/contributorRole", predicate = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType", parse = true) private List contributorRole; - @Field @FieldType(type = "nested_whole_strings") @FieldSource(template = "relationship/contributorOrganization", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List contributorOrganization; - @Field @NestedObject @FieldType(type = "nested_whole_strings", copyTo = "_text_") @FieldSource(template = "relationship/principalInvestigator", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List principalInvestigators; - @Field @NestedObject @FieldType(type = "nested_whole_strings", copyTo = "_text_") @FieldSource(template = "relationship/coPrincipalInvestigator", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List coPrincipalInvestigators; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "relationship/supportedPublicationOrOtherWork", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List supportedPublicationOrOtherWork; - @Field @FieldType(type = "pdate") - @FieldSource(template = "relationship/dateTimeIntervalStart", predicate = "http://vivoweb.org/ontology/core#dateTime") - private String dateTimeIntervalStart; + @FieldSource(template = "relationship/startDateTime", predicate = "http://vivoweb.org/ontology/core#dateTime") + private String startDateTime; - @Field @FieldType(type = "pdate") - @FieldSource(template = "relationship/dateTimeIntervalEnd", predicate = "http://vivoweb.org/ontology/core#dateTime") - private String dateTimeIntervalEnd; + @FieldSource(template = "relationship/endDateTime", predicate = "http://vivoweb.org/ontology/core#dateTime") + private String endDateTime; - @Field @NestedObject @FieldType(type = "nested_whole_strings") @FieldSource(template = "relationship/hasSubjectArea", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List subjectAreas; - @Field @FieldType(type = "pdate") @FieldSource(template = "relationship/yearAwarded", predicate = "http://vivoweb.org/ontology/core#dateTime") private String yearAwarded; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "relationship/inheresIn", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List inheresIn; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "relationship/isSpecifiedOutputOf", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List specifiedOutputOf; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "relationship/outputOf", predicate = "http://www.w3.org/2000/01/rdf-schema#label") private List outputOf; - @Field @NestedObject @FieldType(type = "nested_whole_strings", searchable = false) @FieldSource(template = "relationship/participatesIn", predicate = "http://www.w3.org/2000/01/rdf-schema#label") @@ -489,20 +446,20 @@ public void setSupportedPublicationOrOtherWork(List supportedPublication this.supportedPublicationOrOtherWork = supportedPublicationOrOtherWork; } - public String getDateTimeIntervalStart() { - return dateTimeIntervalStart; + public String getStartDateTime() { + return startDateTime; } - public void setDateTimeIntervalStart(String dateTimeIntervalStart) { - this.dateTimeIntervalStart = dateTimeIntervalStart; + public void setStartDateTime(String startDateTime) { + this.startDateTime = startDateTime; } - public String getDateTimeIntervalEnd() { - return dateTimeIntervalEnd; + public String getEndDateTime() { + return endDateTime; } - public void setDateTimeIntervalEnd(String dateTimeIntervalEnd) { - this.dateTimeIntervalEnd = dateTimeIntervalEnd; + public void setEndDateTime(String endDateTime) { + this.endDateTime = endDateTime; } public List getSubjectAreas() { diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/model/helper/ContentMapper.java b/src/main/java/edu/tamu/scholars/middleware/discovery/model/helper/ContentMapper.java deleted file mode 100644 index b8f3cd077..000000000 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/model/helper/ContentMapper.java +++ /dev/null @@ -1,33 +0,0 @@ -package edu.tamu.scholars.middleware.discovery.model.helper; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import edu.tamu.scholars.middleware.discovery.model.Individual; - -public class ContentMapper { - private final Map> content; - - private ContentMapper(Map> content) { - this.content = content; - } - - public String getValue(String property) { - List values = new ArrayList<>(this.content.get(property)); - - StringBuilder value = new StringBuilder(); - - if (!values.isEmpty()) { - value.append(String.valueOf(values.get(0))); - } - - return value.toString(); - } - - public static ContentMapper from(Individual individual) { - return new ContentMapper(individual.getContent()); - } - -} diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/model/helper/IndividualHelper.java b/src/main/java/edu/tamu/scholars/middleware/discovery/model/helper/IndividualHelper.java deleted file mode 100644 index ae8ed2597..000000000 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/model/helper/IndividualHelper.java +++ /dev/null @@ -1,43 +0,0 @@ -package edu.tamu.scholars.middleware.discovery.model.helper; - -import edu.tamu.scholars.middleware.discovery.model.Individual; -import edu.tamu.scholars.middleware.discovery.model.Organization; -import edu.tamu.scholars.middleware.discovery.model.Person; - -/** - * Helper class to get individual label. - */ -public class IndividualHelper { - - public final Individual individual; - - public IndividualHelper(Individual individual) { - this.individual = individual; - } - - public String getLabel() { - ContentMapper cm = ContentMapper.from(individual); - StringBuilder label = new StringBuilder(); - - String clazz = individual.getClazz(); - - if (clazz.equals(Organization.class.getSimpleName())) { - label.append(cm.getValue("name")) - .append("_"); - } else if (clazz.equals(Person.class.getSimpleName())) { - label.append(cm.getValue("lastName")) - .append("_") - .append(cm.getValue("firstName")) - .append("_"); - } - - return label - .append(individual.getId()) - .toString(); - } - - public static IndividualHelper as(Individual individual) { - return new IndividualHelper(individual); - } - -} diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/model/repo/IndexDocumentRepo.java b/src/main/java/edu/tamu/scholars/middleware/discovery/model/repo/IndexDocumentRepo.java index abb9927b0..18cabf3fd 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/model/repo/IndexDocumentRepo.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/model/repo/IndexDocumentRepo.java @@ -10,7 +10,7 @@ import edu.tamu.scholars.middleware.discovery.argument.BoostArg; import edu.tamu.scholars.middleware.discovery.argument.DiscoveryNetworkDescriptor; import edu.tamu.scholars.middleware.discovery.argument.DiscoveryQuantityDistributionDescriptor; -import edu.tamu.scholars.middleware.discovery.argument.DiscoveryResearchAgeDescriptor; +import edu.tamu.scholars.middleware.discovery.argument.DiscoveryAcademicAgeDescriptor; import edu.tamu.scholars.middleware.discovery.argument.FacetArg; import edu.tamu.scholars.middleware.discovery.argument.FilterArg; import edu.tamu.scholars.middleware.discovery.argument.HighlightArg; @@ -19,7 +19,7 @@ import edu.tamu.scholars.middleware.discovery.response.DiscoveryFacetAndHighlightPage; import edu.tamu.scholars.middleware.discovery.response.DiscoveryNetwork; import edu.tamu.scholars.middleware.discovery.response.DiscoveryQuantityDistribution; -import edu.tamu.scholars.middleware.discovery.response.DiscoveryResearchAge; +import edu.tamu.scholars.middleware.discovery.response.DiscoveryAcademicAge; import reactor.core.publisher.Flux; public interface IndexDocumentRepo { @@ -46,7 +46,7 @@ public interface IndexDocumentRepo { public DiscoveryNetwork network(DiscoveryNetworkDescriptor dataNetworkDescriptor); - public DiscoveryResearchAge researcherAge(DiscoveryResearchAgeDescriptor researcherAgeDescriptor, QueryArg query, List filters); + public DiscoveryAcademicAge academicAge(DiscoveryAcademicAgeDescriptor academicAgeDescriptor, QueryArg query, List filters); public DiscoveryQuantityDistribution quantityDistribution(DiscoveryQuantityDistributionDescriptor quantityDistributionDescriptor, QueryArg query, List filters); diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/model/repo/IndividualRepo.java b/src/main/java/edu/tamu/scholars/middleware/discovery/model/repo/IndividualRepo.java index e2a92a231..5d1af93a6 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/model/repo/IndividualRepo.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/model/repo/IndividualRepo.java @@ -1,7 +1,6 @@ package edu.tamu.scholars.middleware.discovery.model.repo; import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.CLASS; -import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.COLLECTION; import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.DEFAULT_QUERY; import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.ID; import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.MOD_TIME; @@ -15,7 +14,6 @@ import java.util.Calendar; import java.util.Date; import java.util.List; -import java.util.Objects; import java.util.Optional; import java.util.concurrent.atomic.AtomicLong; import java.util.regex.Matcher; @@ -47,19 +45,19 @@ import org.springframework.stereotype.Service; import edu.tamu.scholars.middleware.discovery.argument.BoostArg; +import edu.tamu.scholars.middleware.discovery.argument.DiscoveryAcademicAgeDescriptor; import edu.tamu.scholars.middleware.discovery.argument.DiscoveryNetworkDescriptor; import edu.tamu.scholars.middleware.discovery.argument.DiscoveryQuantityDistributionDescriptor; -import edu.tamu.scholars.middleware.discovery.argument.DiscoveryResearchAgeDescriptor; import edu.tamu.scholars.middleware.discovery.argument.FacetArg; import edu.tamu.scholars.middleware.discovery.argument.FilterArg; import edu.tamu.scholars.middleware.discovery.argument.HighlightArg; import edu.tamu.scholars.middleware.discovery.argument.QueryArg; import edu.tamu.scholars.middleware.discovery.exception.SolrRequestException; import edu.tamu.scholars.middleware.discovery.model.Individual; +import edu.tamu.scholars.middleware.discovery.response.DiscoveryAcademicAge; import edu.tamu.scholars.middleware.discovery.response.DiscoveryFacetAndHighlightPage; import edu.tamu.scholars.middleware.discovery.response.DiscoveryNetwork; import edu.tamu.scholars.middleware.discovery.response.DiscoveryQuantityDistribution; -import edu.tamu.scholars.middleware.discovery.response.DiscoveryResearchAge; import edu.tamu.scholars.middleware.utility.DateFormatUtility; import reactor.core.publisher.Flux; @@ -70,6 +68,9 @@ public class IndividualRepo implements IndexDocumentRepo { private static final Pattern RANGE_PATTERN = Pattern.compile("^\\[(.*?) TO (.*?)\\]$"); + @Value("${middleware.index.name}") + private String collectionName; + @Value("${spring.data.solr.parser:edismax}") private String defType; @@ -135,9 +136,12 @@ public List findByIdIn(List ids, List filters, So JsonQueryRequest jsonRequest = builder.jsonQuery(ids); - QueryResponse queryResponse = jsonRequest.process(solrClient, COLLECTION); + QueryResponse response = jsonRequest.process(solrClient, collectionName); - return queryResponse.getBeans(Individual.class); + return response.getResults() + .stream() + .map(Individual::from) + .collect(Collectors.toList()); } catch (IOException | SolrServerException e) { throw new SolrRequestException("Failed to find documents from ids", e); } @@ -171,9 +175,14 @@ public DiscoveryFacetAndHighlightPage search( .withPage(page); try { - QueryResponse response = solrClient.query(COLLECTION, builder.query()); + QueryResponse response = solrClient.query(collectionName, builder.query()); + + List individuals = response.getResults() + .stream() + .map(Individual::from) + .collect(Collectors.toList()); - return DiscoveryFacetAndHighlightPage.from(response, page, facets, highlight, Individual.class); + return DiscoveryFacetAndHighlightPage.from(individuals, response, page, facets, highlight, Individual.class); } catch (IOException | SolrServerException e) { throw new SolrRequestException("Failed to search documents", e); } @@ -190,21 +199,12 @@ public Flux export(QueryArg query, List filters, List { try { - solrClient.queryAndStreamResponse(COLLECTION, builder.query(), new StreamingResponseCallback() { + solrClient.queryAndStreamResponse(collectionName, builder.query(), new StreamingResponseCallback() { private final AtomicLong remaining = new AtomicLong(0); @Override - public void streamSolrDocument(SolrDocument doc) { - Individual individual = new Individual(); - - individual.setContent(doc.getFieldValuesMap()); - individual.setId(doc.getFieldValue(ID).toString()); - individual.setClazz(doc.getFieldValue(CLASS).toString()); - if (Objects.nonNull(doc.getFieldValues(TYPE))) { - individual.setType(doc.getFieldValues(TYPE).stream().map(to -> to.toString()).collect(Collectors.toList())); - } - - emitter.next(individual); + public void streamSolrDocument(SolrDocument document) { + emitter.next(Individual.from(document)); if (remaining.decrementAndGet() == 0) { emitter.complete(); @@ -213,10 +213,10 @@ public void streamSolrDocument(SolrDocument doc) { @Override public void streamDocListInfo(long numFound, long start, Float maxScore) { - if (numFound == 0) { - emitter.complete(); - } else { + if (numFound > 0) { remaining.set(numFound); + } else { + emitter.complete(); } } @@ -235,7 +235,7 @@ public DiscoveryNetwork network(DiscoveryNetworkDescriptor dataNetworkDescriptor try { final SolrParams queryParams = dataNetworkDescriptor.getSolrParams(); - final QueryResponse response = solrClient.query(COLLECTION, queryParams); + final QueryResponse response = solrClient.query(collectionName, queryParams); final SolrDocumentList documents = response.getResults(); @@ -275,18 +275,16 @@ public DiscoveryNetwork network(DiscoveryNetworkDescriptor dataNetworkDescriptor } @Override - public DiscoveryResearchAge researcherAge(DiscoveryResearchAgeDescriptor researcherAgeDescriptor, QueryArg query, List filters) { - DiscoveryResearchAge researchAge = new DiscoveryResearchAge(researcherAgeDescriptor.getLabel(), researcherAgeDescriptor.getDateField()); + public DiscoveryAcademicAge academicAge(DiscoveryAcademicAgeDescriptor academicAgeDescriptor, QueryArg query, List filters) { + DiscoveryAcademicAge academicAge = new DiscoveryAcademicAge(academicAgeDescriptor.getLabel(), academicAgeDescriptor.getDateField()); - String dateField = researcherAgeDescriptor.getDateField(); - String ageField = researcherAgeDescriptor.getAgeField(); + String dateField = academicAgeDescriptor.getDateField(); + String ageField = academicAgeDescriptor.getAgeField(); try { - - // get count long count = this.count(query, filters); - String fields = researcherAgeDescriptor.getAccumulateMultivaluedDate() + String fields = academicAgeDescriptor.getAccumulateMultivaluedDate() ? String.format("%s,%s", dateField, ageField) : ageField; @@ -297,16 +295,16 @@ public DiscoveryResearchAge researcherAge(DiscoveryResearchAgeDescriptor researc .withSort(Sort.by(Direction.ASC, ageField)) .withRows((int) count); - QueryResponse response = solrClient.query(COLLECTION, builder.query()); + QueryResponse response = solrClient.query(collectionName, builder.query()); SolrDocumentList results = response.getResults(); - researchAge.from(researcherAgeDescriptor, results); + academicAge.from(academicAgeDescriptor, results); } catch (Exception e) { - logger.error("Failed to gather researcher age analytics!", e); + logger.error("Failed to gather academic age analytics!", e); } - return researchAge; + return academicAge; } @Override @@ -336,7 +334,7 @@ public DiscoveryQuantityDistribution quantityDistribution(DiscoveryQuantityDistr .withRows(0); try { - QueryResponse response = solrClient.query(COLLECTION, builder.query()); + QueryResponse response = solrClient.query(collectionName, builder.query()); quantityDistribution.parse(response); } catch (IOException | SolrServerException e) { @@ -375,7 +373,7 @@ private boolean validateAndCountDateField(DiscoveryNetwork dataNetwork, Object d private long count(SolrQuery query) { try { - return solrClient.query(COLLECTION, query) + return solrClient.query(collectionName, query) .getResults() .getNumFound(); } catch (IOException | SolrServerException e) { @@ -385,10 +383,9 @@ private long count(SolrQuery query) { private Individual getById(String id) { try { - SolrDocument document = solrClient.getById(COLLECTION, id); + SolrDocument document = solrClient.getById(collectionName, id); - return solrClient.getBinder() - .getBean(Individual.class, document); + return Individual.from(document); } catch (IOException | SolrServerException e) { throw new SolrRequestException("Failed to get document by id", e); } @@ -396,8 +393,10 @@ private Individual getById(String id) { private List findAll(SolrQuery query) { try { - return solrClient.query(COLLECTION, query) - .getBeans(Individual.class); + return solrClient.query(collectionName, query).getResults() + .stream() + .map(Individual::from) + .collect(Collectors.toList()); } catch (IOException | SolrServerException e) { throw new SolrRequestException("Failed to query documents", e); } @@ -405,8 +404,13 @@ private List findAll(SolrQuery query) { private Page findAll(SolrQuery query, Pageable pageable) { try { - SolrDocumentList documents = solrClient.query(COLLECTION, query).getResults(); - List individuals = solrClient.getBinder().getBeans(Individual.class, documents); + SolrDocumentList documents = solrClient.query(collectionName, query) + .getResults(); + List individuals = solrClient.query(collectionName, query) + .getResults() + .stream() + .map(Individual::from) + .collect(Collectors.toList()); return new PageImpl(individuals, pageable, documents.getNumFound()); } catch (IOException | SolrServerException e) { diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/response/DiscoveryResearchAge.java b/src/main/java/edu/tamu/scholars/middleware/discovery/response/DiscoveryAcademicAge.java similarity index 80% rename from src/main/java/edu/tamu/scholars/middleware/discovery/response/DiscoveryResearchAge.java rename to src/main/java/edu/tamu/scholars/middleware/discovery/response/DiscoveryAcademicAge.java index c6d86fa1d..af52644d6 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/response/DiscoveryResearchAge.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/response/DiscoveryAcademicAge.java @@ -1,163 +1,163 @@ -package edu.tamu.scholars.middleware.discovery.response; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.solr.common.SolrDocument; -import org.apache.solr.common.SolrDocumentList; - -import edu.tamu.scholars.middleware.discovery.argument.DiscoveryResearchAgeDescriptor; -import edu.tamu.scholars.middleware.discovery.argument.DiscoveryResearchAgeDescriptor.LabeledRange; -import edu.tamu.scholars.middleware.discovery.utility.DateUtility; - -public class DiscoveryResearchAge { - - private final String label; - - private final String dateField; - - private final Map ranges; - - private final List groups; - - private double mean; - - private int median; - - public DiscoveryResearchAge(String label, String dateField) { - this.label = label; - this.dateField = dateField; - this.ranges = new HashMap<>(); - this.groups = new ArrayList<>(); - } - - private synchronized void add(Integer index, String range, String label, Integer value) { - if (!ranges.containsKey(label)) { - ranges.put(label, range); - groups.add(new AgeGroup(index, label, value)); - } - } - - public void from(DiscoveryResearchAgeDescriptor researcherAgeDescriptor, SolrDocumentList results) { - String dateField = researcherAgeDescriptor.getDateField(); - String ageField = researcherAgeDescriptor.getAgeField(); - - List labeledRanges = researcherAgeDescriptor.getLabeledRanges(); - - AtomicInteger sum = new AtomicInteger(0); - AtomicInteger total = new AtomicInteger(0); - - labeledRanges.parallelStream().forEach(lr -> { - - int subtotal = 0; - - List set = new ArrayList<>(); - - for (SolrDocument solrDoc : results) { - long dateFromEpochInSeconds = (long) solrDoc.getFieldValue(ageField); - - int age = DateUtility.ageInYearsFromEpochSecond(dateFromEpochInSeconds); - - boolean inRange = false; - - if (lr.isFirst) { - sum.getAndAdd(age); - inRange = age < lr.to; - } else if (lr.isLast) { - inRange = age >= lr.from; - } else { - inRange = age >= lr.from && age < lr.to; - } - - if (inRange) { - if (researcherAgeDescriptor.getAccumulateMultivaluedDate() && solrDoc.containsKey(dateField)) { - Collection docs = solrDoc.getFieldValues(dateField); - subtotal += docs.size(); - - set.add(docs.size()); - } else { - subtotal++; - } - } - } - - total.addAndGet(subtotal); - - Integer value = researcherAgeDescriptor.getAverageOverInterval() && set.size() > 0 - ? subtotal / set.size() - : subtotal; - - add(lr.index, lr.range, lr.label, value); - - }); - - Collections.sort(groups, new AgeGroupComparator()); - - this.mean = results.size() > 0 ? sum.get() / results.size() : 0; - this.median = results.size() > 0 ? DateUtility.ageInYearsFromEpochSecond((long) results.get(results.size() / 2).getFieldValue(ageField)) : 0; - } - - public String getLabel() { - return label; - } - - public String getDateField() { - return dateField; - } - - public Map getRanges() { - return ranges; - } - - public List getGroups() { - return groups; - } - - public double getMean() { - return this.mean; - } - - public int getMedian() { - return this.median; - } - - public static DiscoveryResearchAge create(String label, String dateField) { - return new DiscoveryResearchAge(label, dateField); - } - - public class AgeGroup { - private final Integer index; - private final String label; - private final Integer value; - private AgeGroup(Integer index, String label, Integer value) { - this.index = index; - this.label = label; - this.value = value; - } - public Integer getIndex() { - return index; - } - public String getLabel() { - return label; - } - public Integer getValue() { - return value; - } - } - - private class AgeGroupComparator implements Comparator { - - @Override - public int compare(AgeGroup o1, AgeGroup o2) { - return o1.getIndex().compareTo(o2.getIndex()); - } - - } - -} +package edu.tamu.scholars.middleware.discovery.response; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.solr.common.SolrDocument; +import org.apache.solr.common.SolrDocumentList; + +import edu.tamu.scholars.middleware.discovery.argument.DiscoveryAcademicAgeDescriptor; +import edu.tamu.scholars.middleware.discovery.argument.DiscoveryAcademicAgeDescriptor.LabeledRange; +import edu.tamu.scholars.middleware.discovery.utility.DateUtility; + +public class DiscoveryAcademicAge { + + private final String label; + + private final String dateField; + + private final Map ranges; + + private final List groups; + + private double mean; + + private int median; + + public DiscoveryAcademicAge(String label, String dateField) { + this.label = label; + this.dateField = dateField; + this.ranges = new HashMap<>(); + this.groups = new ArrayList<>(); + } + + private synchronized void add(Integer index, String range, String label, Integer value) { + if (!ranges.containsKey(label)) { + ranges.put(label, range); + groups.add(new AgeGroup(index, label, value)); + } + } + + public void from(DiscoveryAcademicAgeDescriptor academicAgeDescriptor, SolrDocumentList results) { + String dateField = academicAgeDescriptor.getDateField(); + String ageField = academicAgeDescriptor.getAgeField(); + + List labeledRanges = academicAgeDescriptor.getLabeledRanges(); + + AtomicInteger sum = new AtomicInteger(0); + AtomicInteger total = new AtomicInteger(0); + + labeledRanges.parallelStream().forEach(lr -> { + + int subtotal = 0; + + List set = new ArrayList<>(); + + for (SolrDocument solrDoc : results) { + long dateFromEpochInSeconds = (long) solrDoc.getFieldValue(ageField); + + int age = DateUtility.ageInYearsFromEpochSecond(dateFromEpochInSeconds); + + boolean inRange = false; + + if (lr.isFirst) { + sum.getAndAdd(age); + inRange = age < lr.to; + } else if (lr.isLast) { + inRange = age >= lr.from; + } else { + inRange = age >= lr.from && age < lr.to; + } + + if (inRange) { + if (academicAgeDescriptor.getAccumulateMultivaluedDate() && solrDoc.containsKey(dateField)) { + Collection docs = solrDoc.getFieldValues(dateField); + subtotal += docs.size(); + + set.add(docs.size()); + } else { + subtotal++; + } + } + } + + total.addAndGet(subtotal); + + Integer value = academicAgeDescriptor.getAverageOverInterval() && set.size() > 0 + ? subtotal / set.size() + : subtotal; + + add(lr.index, lr.range, lr.label, value); + + }); + + Collections.sort(groups, new AgeGroupComparator()); + + this.mean = results.size() > 0 ? sum.get() / results.size() : 0; + this.median = results.size() > 0 ? DateUtility.ageInYearsFromEpochSecond((long) results.get(results.size() / 2).getFieldValue(ageField)) : 0; + } + + public String getLabel() { + return label; + } + + public String getDateField() { + return dateField; + } + + public Map getRanges() { + return ranges; + } + + public List getGroups() { + return groups; + } + + public double getMean() { + return this.mean; + } + + public int getMedian() { + return this.median; + } + + public static DiscoveryAcademicAge create(String label, String dateField) { + return new DiscoveryAcademicAge(label, dateField); + } + + public class AgeGroup { + private final Integer index; + private final String label; + private final Integer value; + private AgeGroup(Integer index, String label, Integer value) { + this.index = index; + this.label = label; + this.value = value; + } + public Integer getIndex() { + return index; + } + public String getLabel() { + return label; + } + public Integer getValue() { + return value; + } + } + + private class AgeGroupComparator implements Comparator { + + @Override + public int compare(AgeGroup o1, AgeGroup o2) { + return o1.getIndex().compareTo(o2.getIndex()); + } + + } + +} diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/response/DiscoveryFacetAndHighlightPage.java b/src/main/java/edu/tamu/scholars/middleware/discovery/response/DiscoveryFacetAndHighlightPage.java index 64475ce9a..742742915 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/response/DiscoveryFacetAndHighlightPage.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/response/DiscoveryFacetAndHighlightPage.java @@ -33,8 +33,7 @@ public DiscoveryFacetAndHighlightPage(List content, Pageable pageable, long t this.highlights = highlights; } - public static DiscoveryFacetAndHighlightPage from(QueryResponse response, Pageable pageable, List facetArguments, HighlightArg highlightArg, Class type) { - List documents = response.getBeans(type); + public static DiscoveryFacetAndHighlightPage from(List documents, QueryResponse response, Pageable pageable, List facetArguments, HighlightArg highlightArg, Class type) { List facets = buildFacets(response, facetArguments); List highlights = buildHighlights(response, highlightArg); SolrDocumentList results = response.getResults(); diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/response/DiscoveryFacetPage.java b/src/main/java/edu/tamu/scholars/middleware/discovery/response/DiscoveryFacetPage.java index 5bf809ea4..0076a559d 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/response/DiscoveryFacetPage.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/response/DiscoveryFacetPage.java @@ -35,8 +35,7 @@ public DiscoveryFacetPage(List content, Pageable pageable, long total, List DiscoveryFacetPage from(QueryResponse response, Pageable pageable, List facetArguments, Class type) { - List documents = response.getBeans(type); + public static DiscoveryFacetPage from(List documents, QueryResponse response, Pageable pageable, List facetArguments, Class type) { List facets = buildFacets(response, facetArguments); SolrDocumentList results = response.getResults(); diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/serializer/UnwrappingIndividualSerializer.java b/src/main/java/edu/tamu/scholars/middleware/discovery/serializer/UnwrappingIndividualSerializer.java index 110410c62..8451d9c5e 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/serializer/UnwrappingIndividualSerializer.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/serializer/UnwrappingIndividualSerializer.java @@ -3,11 +3,10 @@ import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.CLASS; import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.ID; import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.NESTED_DELIMITER; -import static edu.tamu.scholars.middleware.discovery.utility.DiscoveryUtility.getDiscoveryDocumentTypeByName; +import static edu.tamu.scholars.middleware.discovery.utility.DiscoveryUtility.getDiscoveryDocumentType; import java.io.IOException; import java.lang.reflect.Field; -import java.util.Collection; import java.util.EnumSet; import java.util.List; import java.util.Map; @@ -54,11 +53,11 @@ public boolean isUnwrappingSerializer() { } @Override - public void serialize(Individual document, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException { - Class type = getDiscoveryDocumentTypeByName(document.getClazz()); - Map> content = document.getContent(); - jsonGenerator.writeObjectField(nameTransformer.transform(ID), document.getId()); - jsonGenerator.writeObjectField(nameTransformer.transform(CLASS), document.getClazz()); + public void serialize(Individual individual, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException { + Class type = getDiscoveryDocumentType(individual.getProxy()); + Map content = individual.getContent(); + jsonGenerator.writeObjectField(nameTransformer.transform(ID), individual.getId()); + jsonGenerator.writeObjectField(nameTransformer.transform(CLASS), individual.getProxy()); for (Field field : FieldUtils.getFieldsListWithAnnotation(type, FieldSource.class)) { JsonProperty jsonProperty = field.getAnnotation(JsonProperty.class); String name = nameTransformer.transform(jsonProperty != null ? jsonProperty.value() : field.getName()); @@ -90,14 +89,13 @@ public void serialize(Individual document, JsonGenerator jsonGenerator, Serializ } } else { if (!value.toString().contains(NESTED_DELIMITER)) { - - @SuppressWarnings("unchecked") - List values = (List) value; - if (List.class.isAssignableFrom(field.getType())) { + @SuppressWarnings("unchecked") + List values = (List) value; + jsonGenerator.writeObjectField(name, values); } else { - jsonGenerator.writeObjectField(nameTransformer.transform(name), values.get(0)); + jsonGenerator.writeObjectField(nameTransformer.transform(name), value); } } } @@ -105,7 +103,7 @@ public void serialize(Individual document, JsonGenerator jsonGenerator, Serializ } } - private ObjectNode processValue(Map> content, Class type, Field field, String[] vParts, int index) { + private ObjectNode processValue(Map content, Class type, Field field, String[] vParts, int index) { ObjectNode node = JsonNodeFactory.instance.objectNode(); NestedObject nestedObject = field.getAnnotation(NestedObject.class); if (nestedObject != null) { @@ -116,7 +114,7 @@ private ObjectNode processValue(Map> content, Class> content, Class type, NestedObject nestedObject, ObjectNode node, String[] vParts, int depth) { + private void processNestedObject(Map content, Class type, NestedObject nestedObject, ObjectNode node, String[] vParts, int depth) { for (Reference reference : nestedObject.properties()) { String ref = reference.value(); Field nestedField = FieldUtils.getField(type, ref, true); diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/service/IndexService.java b/src/main/java/edu/tamu/scholars/middleware/discovery/service/IndexService.java index ccef03b48..2198a615e 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/service/IndexService.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/service/IndexService.java @@ -12,11 +12,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.stereotype.Service; +import edu.tamu.scholars.middleware.config.model.IndexConfig; import edu.tamu.scholars.middleware.discovery.component.Harvester; import edu.tamu.scholars.middleware.discovery.component.Indexer; import edu.tamu.scholars.middleware.service.Triplestore; @@ -30,14 +30,8 @@ public class IndexService { public static final List CREATED_FIELDS = new CopyOnWriteArrayList(); - @Value("${middleware.index.onStartup:false}") - private boolean indexOnStartup; - - @Value("${middleware.index.onStartupDelay:10000}") - private int indexOnStartupDelay; - - @Value("${middleware.index.batchSize:10000}") - private int indexBatchSize; + @Autowired + private IndexConfig index; @Autowired private List harvesters; @@ -57,12 +51,14 @@ public Boolean isIndexing() { @PostConstruct public void startup() { - logger.info("Initializing index fields..."); - indexers.stream().forEach(indexer -> { - logger.info(String.format("Initializing %s fields.", indexer.type().getSimpleName())); - indexer.init(); - }); - if (indexOnStartup) { + if (index.isSchematize()) { + logger.info("Initializing index fields..."); + indexers.stream().forEach(indexer -> { + logger.info("Initializing {} fields.", indexer.type().getSimpleName()); + indexer.init(); + }); + } + if (index.isOnStartup()) { threadPoolTaskScheduler.schedule(new Runnable() { @Override @@ -70,7 +66,7 @@ public void run() { index(); } - }, new Date(System.currentTimeMillis() + indexOnStartupDelay)); + }, new Date(System.currentTimeMillis() + index.getOnStartupDelay())); } } @@ -81,23 +77,23 @@ public void index() { Instant start = Instant.now(); logger.info("Indexing..."); harvesters.parallelStream().forEach(harvester -> { - logger.info(String.format("Indexing %s documents.", harvester.type().getSimpleName())); + logger.info("Indexing {} documents.", harvester.type().getSimpleName()); if (indexers.stream().anyMatch(indexer -> indexer.type().equals(harvester.type()))) { - harvester.harvest().buffer(indexBatchSize).subscribe(batch -> { + harvester.harvest().buffer(index.getBatchSize()).subscribe(batch -> { indexers.parallelStream().filter(indexer -> indexer.type().equals(harvester.type())).forEach(indexer -> { indexer.index(batch); }); }); } else { - logger.warn(String.format("No indexer found for %s documents!", harvester.type().getSimpleName())); + logger.warn("No indexer found for {} documents!", harvester.type().getSimpleName()); } - logger.info(String.format("Indexing %s documents finished.", harvester.type().getSimpleName())); + logger.info("Indexing {} documents finished.", harvester.type().getSimpleName()); }); indexers.stream().forEach(indexer -> { - logger.info(String.format("Optimizing %s index.", indexer.type().getSimpleName())); + logger.info("Optimizing {} index.", indexer.type().getSimpleName()); indexer.optimize(); }); - logger.info(String.format("Indexing finished. %s seconds.", Duration.between(start, Instant.now()).toMillis() / 1000.0)); + logger.info("Indexing finished. {} seconds.", Duration.between(start, Instant.now()).toMillis() / 1000.0); triplestore.destroy(); indexing.set(false); } else { diff --git a/src/main/java/edu/tamu/scholars/middleware/discovery/utility/DiscoveryUtility.java b/src/main/java/edu/tamu/scholars/middleware/discovery/utility/DiscoveryUtility.java index 1b63141ad..095841864 100644 --- a/src/main/java/edu/tamu/scholars/middleware/discovery/utility/DiscoveryUtility.java +++ b/src/main/java/edu/tamu/scholars/middleware/discovery/utility/DiscoveryUtility.java @@ -1,5 +1,6 @@ package edu.tamu.scholars.middleware.discovery.utility; +import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.CLASS; import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.DISCOVERY_MODEL_PACKAGE; import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.PATH_DELIMETER_REGEX; import static edu.tamu.scholars.middleware.discovery.DiscoveryConstants.REQUEST_PARAM_DELIMETER; @@ -7,8 +8,9 @@ import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashSet; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -22,14 +24,17 @@ import org.springframework.core.type.filter.AnnotationTypeFilter; import edu.tamu.scholars.middleware.discovery.annotation.CollectionSource; +import edu.tamu.scholars.middleware.discovery.annotation.FieldType; import edu.tamu.scholars.middleware.discovery.annotation.NestedObject; import edu.tamu.scholars.middleware.discovery.annotation.NestedObject.Reference; public class DiscoveryUtility { - private final static Set> DISCOVERY_DOCUMENT_TYPES = new HashSet<>(); + private final static Map> TYPES = new HashMap<>(); - private final static BidiMap DISCOVERY_DOCUMENT_PROPERTY_PATH_MAPPING = new DualHashBidiMap(); + private final static Map>> TYPE_FIELDS = new HashMap<>(); + + private final static BidiMap MAPPING = new DualHashBidiMap(); static { ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); @@ -37,28 +42,49 @@ public class DiscoveryUtility { Set beanDefinitions = provider.findCandidateComponents(DISCOVERY_MODEL_PACKAGE); for (BeanDefinition beanDefinition : beanDefinitions) { try { - DISCOVERY_DOCUMENT_TYPES.add(Class.forName(beanDefinition.getBeanClassName())); + Class type = Class.forName(beanDefinition.getBeanClassName()); + TYPES.put(type.getSimpleName(), type); + + Map> fields = FieldUtils.getFieldsListWithAnnotation(type, FieldType.class) + .stream() + .collect(Collectors.toMap(field -> { + FieldType fieldType = field.getAnnotation(FieldType.class); + return StringUtils.isNotEmpty(fieldType.value()) + ? fieldType.value() + : field.getName(); + }, field -> field.getType())); + + fields.put(CLASS, String.class); + TYPE_FIELDS.put(type.getSimpleName(), fields); + } catch (ClassNotFoundException e) { throw new RuntimeException("Unable to find class for " + beanDefinition.getBeanClassName(), e); } } } - public static Set> getDiscoveryDocumentTypes() { - return DISCOVERY_DOCUMENT_TYPES; - } - - public static Class getDiscoveryDocumentTypeByName(String name) { - String typeName = String.format("%s.%s", DISCOVERY_MODEL_PACKAGE, name); - Optional> documentType = DISCOVERY_DOCUMENT_TYPES.stream().filter(type -> type.getName().equals(typeName)).findAny(); + public static Class getDiscoveryDocumentType(String name) { + Optional> documentType = Optional.ofNullable(TYPES.get(name)); if (documentType.isPresent()) { return documentType.get(); } throw new RuntimeException("Unable to find class for " + name); } + public static Map> getDiscoveryDocumentTypeFields(String name) { + Optional>> documentTypeFields = Optional.ofNullable(TYPE_FIELDS.get(name)); + if (documentTypeFields.isPresent()) { + return documentTypeFields.get(); + } + throw new RuntimeException("Unable to find class for " + name); + } + public static String[] processFields(String[] fields) { - return Arrays.asList(fields).stream().map(DiscoveryUtility::findProperty).collect(Collectors.toList()).toArray(new String[fields.length]); + return Arrays.asList(fields) + .stream() + .map(DiscoveryUtility::findProperty) + .collect(Collectors.toList()) + .toArray(new String[fields.length]); } public static String processFields(String fields) { @@ -73,7 +99,7 @@ public static String processFields(String fields) { } public static String findPath(String property) { - String actualProperty = DISCOVERY_DOCUMENT_PROPERTY_PATH_MAPPING.getKey(property); + String actualProperty = MAPPING.getKey(property); if (StringUtils.isNoneEmpty(actualProperty)) { return actualProperty; } @@ -81,19 +107,19 @@ public static String findPath(String property) { } public static String findProperty(String path) { - String actualPath = DISCOVERY_DOCUMENT_PROPERTY_PATH_MAPPING.get(path); + String actualPath = MAPPING.get(path); if (StringUtils.isNotEmpty(actualPath)) { return actualPath; } List properties = new ArrayList(Arrays.asList(path.split(PATH_DELIMETER_REGEX))); - for (Class type : DISCOVERY_DOCUMENT_TYPES) { + for (Class type : TYPES.values()) { Optional property = findProperty(type, properties); if (property.isPresent()) { - DISCOVERY_DOCUMENT_PROPERTY_PATH_MAPPING.put(path, property.get()); + MAPPING.put(path, property.get()); return property.get(); } } - DISCOVERY_DOCUMENT_PROPERTY_PATH_MAPPING.put(path, path); + MAPPING.put(path, path); return path; } diff --git a/src/main/java/edu/tamu/scholars/middleware/export/advice/ExportControllerAdvice.java b/src/main/java/edu/tamu/scholars/middleware/export/advice/ExportControllerAdvice.java index b022ce998..aa762c020 100644 --- a/src/main/java/edu/tamu/scholars/middleware/export/advice/ExportControllerAdvice.java +++ b/src/main/java/edu/tamu/scholars/middleware/export/advice/ExportControllerAdvice.java @@ -12,6 +12,7 @@ import edu.tamu.scholars.middleware.export.exception.ExportException; import edu.tamu.scholars.middleware.export.exception.ExportQueryParameterRequiredException; +import edu.tamu.scholars.middleware.export.exception.UnauthorizedExportException; import edu.tamu.scholars.middleware.export.exception.UnknownExporterTypeException; import edu.tamu.scholars.middleware.export.exception.UnsupportedExporterTypeException; @@ -44,6 +45,12 @@ public class ExportControllerAdvice { return exception.getMessage(); } + @ResponseStatus(value = HttpStatus.UNAUTHORIZED) + @ExceptionHandler(value = UnauthorizedExportException.class) + public @ResponseBody String handleUnauthorizedExportException(UnauthorizedExportException exception) { + return exception.getMessage(); + } + @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR) @ExceptionHandler(value = ExportException.class) public @ResponseBody String handleExportException(ExportException exception) { diff --git a/src/main/java/edu/tamu/scholars/middleware/export/controller/IndividualExportController.java b/src/main/java/edu/tamu/scholars/middleware/export/controller/IndividualExportController.java index 6619a8446..e9480cc15 100644 --- a/src/main/java/edu/tamu/scholars/middleware/export/controller/IndividualExportController.java +++ b/src/main/java/edu/tamu/scholars/middleware/export/controller/IndividualExportController.java @@ -3,6 +3,7 @@ import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; +import java.util.Objects; import java.util.Optional; import javax.persistence.EntityNotFoundException; @@ -11,6 +12,8 @@ import org.springframework.hateoas.server.RepresentationModelProcessor; import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; @@ -19,7 +22,10 @@ import edu.tamu.scholars.middleware.discovery.assembler.model.IndividualModel; import edu.tamu.scholars.middleware.discovery.model.Individual; +import edu.tamu.scholars.middleware.discovery.model.Organization; +import edu.tamu.scholars.middleware.discovery.model.Person; import edu.tamu.scholars.middleware.discovery.model.repo.IndividualRepo; +import edu.tamu.scholars.middleware.export.exception.UnauthorizedExportException; import edu.tamu.scholars.middleware.export.exception.UnknownExporterTypeException; import edu.tamu.scholars.middleware.export.service.Exporter; import edu.tamu.scholars.middleware.export.service.ExporterRegistry; @@ -40,6 +46,14 @@ public ResponseEntity export( @RequestParam(value = "type", required = false, defaultValue = "docx") String type, @RequestParam(value = "name", required = true) String name ) throws UnknownExporterTypeException, IllegalArgumentException, IllegalAccessException { + + if (type.equals("zip")) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (Objects.isNull(authentication) || !this.isAdmin(authentication)) { + throw new UnauthorizedExportException("Must be administrator to use zip exporter."); + } + } + Optional individual = repo.findById(id); if (individual.isPresent()) { Individual document = individual.get(); @@ -54,16 +68,73 @@ public ResponseEntity export( @Override public IndividualModel process(IndividualModel resource) { + Individual individual = resource.getContent(); + if (individual != null) { + if (individual.getProxy().equals(Person.class.getSimpleName())) { + addResource(resource, new ResourceLink(individual, "docx", "Single Page Bio", "Individual single page bio export")); + addResource(resource, new ResourceLink(individual, "docx", "Profile Summary", "Individual profile summary export")); + addResource(resource, new ResourceLink(individual, "zip", "Last 5 Years", "Individual 5 year publications export")); + addResource(resource, new ResourceLink(individual, "zip", "Last 8 Years", "Individual 8 year publications export")); + } else if (individual.getProxy().equals(Organization.class.getSimpleName())) { + addResource(resource, new ResourceLink(individual, "zip", "Last 5 Years", "Organization 5 year publications export")); + addResource(resource, new ResourceLink(individual, "zip", "Last 8 Years", "Organization 8 year publications export")); + } + } + + return resource; + } + + private boolean isAdmin(Authentication authentication) { + return authentication.getAuthorities().stream() + .anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN") || a.getAuthority().equals("ROLE_SUPER_ADMIN")); + } + + private void addResource(IndividualModel resource, ResourceLink link) { try { resource.add(linkTo(methodOn(this.getClass()).export( - resource.getContent().getId(), - "docx", - "Profile Summary" - )).withRel("export").withTitle("Individual export")); + link.getIndividual().getId(), + link.getType(), + link.getName() + )).withRel(link.getName().toLowerCase().replace(" ", "_")).withTitle(link.getTitle())); } catch (NullPointerException | UnknownExporterTypeException | IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } - return resource; + } + + private class ResourceLink { + private final Individual individual; + private final String type; + private final String name; + private final String title; + + private ResourceLink( + Individual individual, + String type, + String name, + String title + ) { + this.individual = individual; + this.type = type; + this.name = name; + this.title = title; + } + + public Individual getIndividual() { + return individual; + } + + public String getType() { + return type; + } + + public String getName() { + return name; + } + + public String getTitle() { + return title; + } + } } diff --git a/src/main/java/edu/tamu/scholars/middleware/export/exception/ExportException.java b/src/main/java/edu/tamu/scholars/middleware/export/exception/ExportException.java index 175f62838..6b1dcb771 100644 --- a/src/main/java/edu/tamu/scholars/middleware/export/exception/ExportException.java +++ b/src/main/java/edu/tamu/scholars/middleware/export/exception/ExportException.java @@ -8,4 +8,4 @@ public ExportException(String message) { super(message); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/tamu/scholars/middleware/export/exception/ExportQueryParameterRequiredException.java b/src/main/java/edu/tamu/scholars/middleware/export/exception/ExportQueryParameterRequiredException.java index 4b7a9ee4f..bd28cd59c 100644 --- a/src/main/java/edu/tamu/scholars/middleware/export/exception/ExportQueryParameterRequiredException.java +++ b/src/main/java/edu/tamu/scholars/middleware/export/exception/ExportQueryParameterRequiredException.java @@ -8,4 +8,4 @@ public ExportQueryParameterRequiredException(String message) { super(message); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/tamu/scholars/middleware/export/exception/UnauthorizedExportException.java b/src/main/java/edu/tamu/scholars/middleware/export/exception/UnauthorizedExportException.java new file mode 100644 index 000000000..1c390d515 --- /dev/null +++ b/src/main/java/edu/tamu/scholars/middleware/export/exception/UnauthorizedExportException.java @@ -0,0 +1,11 @@ +package edu.tamu.scholars.middleware.export.exception; + +public class UnauthorizedExportException extends RuntimeException { + + private static final long serialVersionUID = -928374692174698721L; + + public UnauthorizedExportException(String message) { + super(message); + } + +} diff --git a/src/main/java/edu/tamu/scholars/middleware/export/service/CsvExporter.java b/src/main/java/edu/tamu/scholars/middleware/export/service/CsvExporter.java index e2207486d..eb53cf9ba 100644 --- a/src/main/java/edu/tamu/scholars/middleware/export/service/CsvExporter.java +++ b/src/main/java/edu/tamu/scholars/middleware/export/service/CsvExporter.java @@ -5,7 +5,6 @@ import java.io.IOException; import java.io.OutputStreamWriter; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -61,12 +60,12 @@ public StreamingResponseBody streamIndividuals(Flux individuals, Lis .create() .setHeader(headers) .build(); + List properties = export.stream() + .map(e -> e.getField()) + .collect(Collectors.toList()); try (CSVPrinter printer = new CSVPrinter(outputStreamWriter, format)) { individuals.subscribe( individual -> { - List properties = export.stream() - .map(e -> e.getField()) - .collect(Collectors.toList()); try { List row = getRow(individual, properties); printer.printRecord(row.toArray(new Object[row.size()])); @@ -101,27 +100,42 @@ private String[] getColumnHeaders(List export) { } private List getRow(Individual individual, List properties) throws InvalidValuePathException, IllegalArgumentException, IllegalAccessException { - Map> content = individual.getContent(); + Map content = individual.getContent(); List row = new ArrayList(); for (String property : properties) { if (property.equals(config.getIndividualKey())) { row.add(String.format("%s/%s", config.getIndividualBaseUri(), individual.getId())); continue; } - String value = StringUtils.EMPTY; + + String data = StringUtils.EMPTY; + if (content.containsKey(property)) { - Collection values = content.get(property); - if (values.size() > 0) { - value = String.join(DELIMITER, values.stream().map(this::serialize).collect(Collectors.toList())); + + Object value = content.get(property); + + if (List.class.isAssignableFrom(value.getClass())) { + + @SuppressWarnings("unchecked") + List values = (List) value; + + if (values.size() > 0) { + data = String.join(DELIMITER, values.stream() + .map(v -> (String) v) + .map(this::serialize) + .collect(Collectors.toList())); + } + + } else { + data = (String) value; } } - row.add(serialize(value)); + row.add(serialize(data)); } return row; } - private String serialize(Object obj) { - String value = String.valueOf(obj); + private String serialize(String value) { return value.contains(NESTED_DELIMITER) ? value.substring(0, value.indexOf(NESTED_DELIMITER)) : value; diff --git a/src/main/java/edu/tamu/scholars/middleware/export/service/DocxExporter.java b/src/main/java/edu/tamu/scholars/middleware/export/service/DocxExporter.java index 82fdc816f..05c7466b9 100644 --- a/src/main/java/edu/tamu/scholars/middleware/export/service/DocxExporter.java +++ b/src/main/java/edu/tamu/scholars/middleware/export/service/DocxExporter.java @@ -43,8 +43,8 @@ public String contentType() { } @Override - public StreamingResponseBody streamIndividual(Individual document, String name) { - final List type = document.getType(); + public StreamingResponseBody streamIndividual(Individual individual, String name) { + final List type = individual.getType(); Optional displayView = displayViewRepo.findByTypesIn(type); @@ -64,7 +64,7 @@ public StreamingResponseBody streamIndividual(Individual document, String name) return outputStream -> { try { - final ObjectNode node = mapper.valueToTree(document); + final ObjectNode node = mapper.valueToTree(individual); final WordprocessingMLPackage pkg = createDocx(node, exportView.get()); pkg.save(outputStream); diff --git a/src/main/java/edu/tamu/scholars/middleware/export/service/ZipDocxExporter.java b/src/main/java/edu/tamu/scholars/middleware/export/service/ZipDocxExporter.java index 35cb4b43a..a789033db 100644 --- a/src/main/java/edu/tamu/scholars/middleware/export/service/ZipDocxExporter.java +++ b/src/main/java/edu/tamu/scholars/middleware/export/service/ZipDocxExporter.java @@ -53,8 +53,8 @@ public String contentType() { } @Override - public StreamingResponseBody streamIndividual(Individual document, String name) { - final List type = document.getType(); + public StreamingResponseBody streamIndividual(Individual individual, String name) { + final List type = individual.getType(); Optional displayView = displayViewRepo.findByTypesIn(type); @@ -74,7 +74,7 @@ public StreamingResponseBody streamIndividual(Individual document, String name) return outputStream -> { - final ObjectNode node = mapper.valueToTree(document); + final ObjectNode node = mapper.valueToTree(individual); Optional multipleReference = Optional.ofNullable(exportView.get().getMultipleReference()); @@ -85,10 +85,10 @@ public StreamingResponseBody streamIndividual(Individual document, String name) List ids = extractIds(reference); referenceDocuments.addAll(fetchLazyReference(multipleReference.get(), ids)); } else { - referenceDocuments.add(document); + referenceDocuments.add(individual); } - File zipFile = File.createTempFile(document.getId(), ".zip"); + File zipFile = File.createTempFile(individual.getId(), ".zip"); try ( FileOutputStream fos = new FileOutputStream(zipFile.getAbsolutePath()); diff --git a/src/main/java/edu/tamu/scholars/middleware/export/utility/FilenameUtility.java b/src/main/java/edu/tamu/scholars/middleware/export/utility/FilenameUtility.java index 1d5a2bca4..72933818f 100644 --- a/src/main/java/edu/tamu/scholars/middleware/export/utility/FilenameUtility.java +++ b/src/main/java/edu/tamu/scholars/middleware/export/utility/FilenameUtility.java @@ -2,17 +2,22 @@ import java.util.Date; import java.util.Locale; +import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.springframework.context.i18n.LocaleContextHolder; import edu.tamu.scholars.middleware.discovery.model.AbstractIndexDocument; import edu.tamu.scholars.middleware.discovery.model.Individual; -import edu.tamu.scholars.middleware.discovery.model.helper.IndividualHelper; +import edu.tamu.scholars.middleware.discovery.model.Organization; +import edu.tamu.scholars.middleware.discovery.model.Person; public class FilenameUtility { private final static String UNDERSCORE = "_"; + private final static String NAME = "name"; + private final static String LAST_NAME = "lastName"; + private final static String FIRST_NAME = "firstName"; private FilenameUtility() { @@ -27,7 +32,27 @@ public static String normalizeExportFilename(AbstractIndexDocument refDoc) { } public static String normalizeExportFilename(Individual individual) { - return localizeWhileUnderscoreReplaceSpaceWithUnderscore(IndividualHelper.as(individual).getLabel()); + Map content = individual.getContent(); + StringBuilder label = new StringBuilder(); + + String proxy = individual.getProxy(); + + if (proxy.equals(Organization.class.getSimpleName()) && content.containsKey(NAME)) { + label.append((String) content.get(NAME)) + .append(UNDERSCORE); + } else if (proxy.equals(Person.class.getSimpleName()) && content.containsKey(LAST_NAME)) { + label.append((String) content.get(LAST_NAME)) + .append(UNDERSCORE); + + if (content.containsKey(FIRST_NAME)) { + label.append((String) content.get(FIRST_NAME)) + .append(UNDERSCORE); + } + } + + label.append(individual.getId()); + + return localizeWhileUnderscoreReplaceSpaceWithUnderscore(label.toString()); } private static String localizeWhileUnderscoreReplaceSpaceWithUnderscore(String value) { diff --git a/src/main/java/edu/tamu/scholars/middleware/service/SparqlHttpTriplestore.java b/src/main/java/edu/tamu/scholars/middleware/service/HttpTriplestore.java similarity index 75% rename from src/main/java/edu/tamu/scholars/middleware/service/SparqlHttpTriplestore.java rename to src/main/java/edu/tamu/scholars/middleware/service/HttpTriplestore.java index 4031f9bf0..fd6dfd8c7 100644 --- a/src/main/java/edu/tamu/scholars/middleware/service/SparqlHttpTriplestore.java +++ b/src/main/java/edu/tamu/scholars/middleware/service/HttpTriplestore.java @@ -1,27 +1,27 @@ package edu.tamu.scholars.middleware.service; -import edu.tamu.scholars.middleware.config.model.TriplestoreConfig; +import java.time.Duration; +import java.time.Instant; + import org.apache.jena.query.QueryExecution; -import org.apache.jena.query.QueryExecutionFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.time.Duration; -import java.time.Instant; +import edu.tamu.scholars.middleware.config.model.TriplestoreConfig; -public class SparqlHttpTriplestore implements Triplestore { +public class HttpTriplestore implements Triplestore { - private final static Logger logger = LoggerFactory.getLogger(SparqlHttpTriplestore.class); + private final static Logger logger = LoggerFactory.getLogger(HttpTriplestore.class); private final TriplestoreConfig config; - public SparqlHttpTriplestore(TriplestoreConfig config) { + public HttpTriplestore(TriplestoreConfig config) { this.config = config; } @Override public QueryExecution createQueryExecution(String query) { - return QueryExecutionFactory.sparqlService(config.getDatasourceUrl(), query); + return QueryExecution.service(config.getDatasourceUrl()).query(query).build(); } @Override diff --git a/src/main/java/edu/tamu/scholars/middleware/service/SDBTriplestore.java b/src/main/java/edu/tamu/scholars/middleware/service/SDBTriplestore.java deleted file mode 100644 index 33636f3e1..000000000 --- a/src/main/java/edu/tamu/scholars/middleware/service/SDBTriplestore.java +++ /dev/null @@ -1,64 +0,0 @@ -package edu.tamu.scholars.middleware.service; - -import java.time.Duration; -import java.time.Instant; - -import org.apache.jena.query.Dataset; -import org.apache.jena.query.QueryExecution; -import org.apache.jena.query.QueryExecutionFactory; -import org.apache.jena.sdb.SDB; -import org.apache.jena.sdb.SDBFactory; -import org.apache.jena.sdb.Store; -import org.apache.jena.sdb.StoreDesc; -import org.apache.jena.sdb.sql.SDBConnection; -import org.apache.jena.sdb.store.DatabaseType; -import org.apache.jena.sdb.store.LayoutType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import edu.tamu.scholars.middleware.config.model.TriplestoreConfig; - -public class SDBTriplestore implements Triplestore { - - private final static Logger logger = LoggerFactory.getLogger(SDBTriplestore.class); - - private final TriplestoreConfig config; - - private Store store; - - private Dataset dataset; - - public SDBTriplestore(TriplestoreConfig config) { - this.config = config; - } - - @Override - public QueryExecution createQueryExecution(String query) { - return QueryExecutionFactory.create(query, dataset); - } - - @Override - public void init() { - Instant start = Instant.now(); - logger.info(String.format("Intializing %s", config.getType().getSimpleName())); - // TODO: handle missing configurations - SDB.getContext().setTrue(SDB.unionDefaultGraph); - SDB.getContext().set(SDB.jdbcStream, config.isJdbcStream()); - SDB.getContext().set(SDB.jdbcFetchSize, config.getJdbcFetchSize()); - SDB.getContext().set(SDB.streamGraphAPI, config.isStreamGraphAPI()); - SDB.getContext().set(SDB.annotateGeneratedSQL, config.isAnnotateGeneratedSQL()); - StoreDesc storeDesc = new StoreDesc(LayoutType.fetch(config.getLayoutType()), DatabaseType.fetch(config.getDatabaseType())); - SDBConnection conn = new SDBConnection(config.getDatasourceUrl(), config.getUsername(), config.getPassword()); - store = SDBFactory.connectStore(conn, storeDesc); - dataset = SDBFactory.connectDataset(store); - logger.info(String.format("%s ready. %s seconds", config.getType().getSimpleName(), Duration.between(start, Instant.now()).toMillis() / 1000.0)); - } - - @Override - public void destroy() { - store.getConnection().close(); - store.close(); - dataset.close(); - } - -} diff --git a/src/main/java/edu/tamu/scholars/middleware/theme/model/Theme.java b/src/main/java/edu/tamu/scholars/middleware/theme/model/Theme.java index a444e2785..0dedad470 100644 --- a/src/main/java/edu/tamu/scholars/middleware/theme/model/Theme.java +++ b/src/main/java/edu/tamu/scholars/middleware/theme/model/Theme.java @@ -20,6 +20,9 @@ public class Theme extends Named { @Column(nullable = false) private String organization; + @Column(nullable = false) + private String organizationId; + @Column(nullable = false) private boolean active; @@ -52,10 +55,11 @@ public Theme() { this.variables = new ArrayList