From 3240448d2fd1b56cedb10d63d321a800190b7bef Mon Sep 17 00:00:00 2001 From: qqmyers Date: Wed, 7 Jan 2026 09:25:41 -0500 Subject: [PATCH 1/5] remove logging --- .../java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java index e6b2711b443..99fa2b092ea 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java @@ -648,8 +648,6 @@ private JsonObject filterResponse(JsonObject cvocEntry, JsonObject readObject, S JsonObjectBuilder job = Json.createObjectBuilder(); JsonObject filtering = cvocEntry.getJsonObject("retrieval-filtering"); logger.fine("RF: " + filtering.toString()); - JsonObject managedFields = cvocEntry.getJsonObject("managed-fields"); - logger.fine("MF: " + managedFields.toString()); int nrOfNotFound = 0; for (String filterKey : filtering.keySet()) { if (!filterKey.equals("@context")) { From 06b130e71443546335719772e322635185493960 Mon Sep 17 00:00:00 2001 From: qqmyers Date: Tue, 24 Feb 2026 14:48:16 -0500 Subject: [PATCH 2/5] per vocab retrieval filtering --- .../iq/dataverse/DatasetFieldServiceBean.java | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java index 99fa2b092ea..1b25c34249a 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java @@ -406,10 +406,24 @@ public void registerExternalVocabValues(DatasetField df) { public Set getIndexableStringsByTermUri(String termUri, JsonObject cvocEntry, String indexingField) { Set strings = new HashSet<>(); JsonObject jo = getExternalVocabularyValue(termUri); - JsonObject filtering = cvocEntry.getJsonObject("retrieval-filtering"); - String termUriField = cvocEntry.getJsonString("term-uri-field").getString(); if (jo != null) { + JsonObject filtering = cvocEntry.getJsonObject("retrieval-filtering"); + //Check for per-vocab filtering + JsonObject vocabs = cvocEntry.getJsonObject("vocabs"); + for (String key : vocabs.keySet()) { + JsonObject vocab = vocabs.getJsonObject(key); + if (vocab.containsKey("uriSpace")) { + if (termUri.startsWith(vocab.getString("uriSpace"))) { + if(vocab.containsKey("retrieval-filtering")) { + filtering = vocab.getJsonObject("retrieval-filtering"); + } + break; + } + } + } + String termUriField = cvocEntry.getJsonString("term-uri-field").getString(); + try { for (String key : jo.keySet()) { String indexIn = filtering.getJsonObject(key).getString("indexIn", null); @@ -514,6 +528,13 @@ public void registerExternalTerm(JsonObject cvocEntry, String term, List Date: Fri, 27 Mar 2026 17:03:08 -0400 Subject: [PATCH 3/5] allow null top-level retrieval-uri --- .../java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java index 1b25c34249a..88f02125aa8 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java @@ -513,7 +513,7 @@ public JsonObject getExternalVocabularyValue(String termUri) { * @param relatedDatasetFields - siblings or childs of the term */ public void registerExternalTerm(JsonObject cvocEntry, String term, List relatedDatasetFields) { - String retrievalUri = cvocEntry.getString("retrieval-uri"); + String retrievalUri = cvocEntry.getString("retrieval-uri", null); String termUriFieldName = cvocEntry.getString("term-uri-field"); String prefix = cvocEntry.getString("prefix", null); if(StringUtils.isBlank(term)) { From 375a1ee552fd92d161e2137fa5fd53a309b25fa6 Mon Sep 17 00:00:00 2001 From: qqmyers Date: Wed, 15 Apr 2026 12:07:58 -0400 Subject: [PATCH 4/5] release note --- doc/release-notes/12331-multi-PID-support-in-external-vocabs.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 doc/release-notes/12331-multi-PID-support-in-external-vocabs.md diff --git a/doc/release-notes/12331-multi-PID-support-in-external-vocabs.md b/doc/release-notes/12331-multi-PID-support-in-external-vocabs.md new file mode 100644 index 00000000000..fb528197d59 --- /dev/null +++ b/doc/release-notes/12331-multi-PID-support-in-external-vocabs.md @@ -0,0 +1,2 @@ +Dataverse now allows use of multiple PIDs/PID services per field when using external vocabulary scripts. +One example of this is allowing ORCID and ROR values in the author or contact field. \ No newline at end of file From 8908851459834236bf3ec273c9822dd5a1514ada Mon Sep 17 00:00:00 2001 From: qqmyers Date: Mon, 4 May 2026 16:23:45 -0400 Subject: [PATCH 5/5] fix multi-vocab retrieval filtering --- .../iq/dataverse/DatasetFieldServiceBean.java | 188 +++++++++--------- 1 file changed, 96 insertions(+), 92 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java index 88f02125aa8..04eb8079e98 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java @@ -408,20 +408,7 @@ public Set getIndexableStringsByTermUri(String termUri, JsonObject cvocE JsonObject jo = getExternalVocabularyValue(termUri); if (jo != null) { - JsonObject filtering = cvocEntry.getJsonObject("retrieval-filtering"); - //Check for per-vocab filtering - JsonObject vocabs = cvocEntry.getJsonObject("vocabs"); - for (String key : vocabs.keySet()) { - JsonObject vocab = vocabs.getJsonObject(key); - if (vocab.containsKey("uriSpace")) { - if (termUri.startsWith(vocab.getString("uriSpace"))) { - if(vocab.containsKey("retrieval-filtering")) { - filtering = vocab.getJsonObject("retrieval-filtering"); - } - break; - } - } - } + JsonObject filtering = getRetrievalFilteringObject(cvocEntry, termUri); String termUriField = cvocEntry.getJsonString("term-uri-field").getString(); try { @@ -481,6 +468,24 @@ public Set getIndexableStringsByTermUri(String termUri, JsonObject cvocE return strings; } + private JsonObject getRetrievalFilteringObject(JsonObject cvocEntry, String termUri) { + JsonObject filtering = cvocEntry.getJsonObject("retrieval-filtering"); + //Check for per-vocab filtering + JsonObject vocabs = cvocEntry.getJsonObject("vocabs"); + for (String key : vocabs.keySet()) { + JsonObject vocab = vocabs.getJsonObject(key); + if (vocab.containsKey("uriSpace")) { + if (termUri.startsWith(vocab.getString("uriSpace"))) { + if (vocab.containsKey("retrieval-filtering")) { + filtering = vocab.getJsonObject("retrieval-filtering"); + } + break; + } + } + } + return filtering; + } + /** * Perform a query to retrieve a cached value from the externalvocabularvalue table * @param termUri @@ -672,94 +677,93 @@ private String tryToReplaceRetrievalUriParam(String retrievalUri, String paramNa private JsonObject filterResponse(JsonObject cvocEntry, JsonObject readObject, String termUri) { JsonObjectBuilder job = Json.createObjectBuilder(); - JsonObject filtering = cvocEntry.getJsonObject("retrieval-filtering"); - logger.fine("RF: " + filtering.toString()); - int nrOfNotFound = 0; - for (String filterKey : filtering.keySet()) { - if (!filterKey.equals("@context")) { - try { - JsonObject filter = filtering.getJsonObject(filterKey); - logger.fine("F: " + filter.toString()); - JsonArray params = filter.getJsonArray("params"); - if (params == null) { - params = Json.createArrayBuilder().build(); - } - logger.fine("Params: " + params.toString()); - List vals = new ArrayList(); - for (int i = 0; i < params.size(); i++) { - String param = params.getString(i); - if (param.startsWith("/")) { - // Remove leading / - param = param.substring(1); - String[] pathParts = param.split("/"); - logger.fine("PP: " + String.join(", ", pathParts)); - var foundPart = processPathSegment(0, pathParts, readObject, termUri); - if (foundPart == null) { - nrOfNotFound ++ ; - logger.warning("External Vocabulary: no value found for %s - %s".formatted(filterKey, param)); - } else { - vals.add(i, foundPart); - logger.fine("Added param value: " + i + ": " + vals.get(i)); - } - } else { - logger.fine("Param is: " + param); - // param is not a path - either a reference to the term URI - if (param.equals("@id")) { - logger.fine("Adding id param: " + termUri); - vals.add(i, termUri); - } else { - // or a hardcoded value - logger.fine("Adding hardcoded param: " + param); - vals.add(i, param); - } + JsonObject filtering = getRetrievalFilteringObject(cvocEntry, termUri); + if(filtering != null) { + logger.fine("RF: " + filtering.toString()); + int nrOfNotFound = 0; + for (String filterKey : filtering.keySet()) { + if (!filterKey.equals("@context")) { + try { + JsonObject filter = filtering.getJsonObject(filterKey); + logger.fine("F: " + filter.toString()); + JsonArray params = filter.getJsonArray("params"); + if (params == null) { + params = Json.createArrayBuilder().build(); } - } - // Shortcut: nominally using a pattern of {0} and a param that is @id or - // hardcoded value allows the same options as letting the pattern itself be @id - // or a hardcoded value - String pattern = filter.getString("pattern"); - logger.fine("Pattern: " + pattern); - if (pattern.equals("@id")) { - logger.fine("Added #id pattern: " + filterKey + ": " + termUri); - job.add(filterKey, termUri); - } else if (pattern.contains("{")) { - if (vals.isEmpty()) { - if (nrOfNotFound == 0) { - logger.warning("External Vocabulary: " + termUri + " - No value found for " + filterKey); + logger.fine("Params: " + params.toString()); + List vals = new ArrayList(); + for (int i = 0; i < params.size(); i++) { + String param = params.getString(i); + if (param.startsWith("/")) { + // Remove leading / + param = param.substring(1); + String[] pathParts = param.split("/"); + logger.fine("PP: " + String.join(", ", pathParts)); + var foundPart = processPathSegment(0, pathParts, readObject, termUri); + if (foundPart == null) { + nrOfNotFound++; + logger.warning("External Vocabulary: no value found for %s - %s".formatted(filterKey, param)); + } else { + vals.add(i, foundPart); + logger.fine("Added param value: " + i + ": " + vals.get(i)); + } + } else { + logger.fine("Param is: " + param); + // param is not a path - either a reference to the term URI + if (param.equals("@id")) { + logger.fine("Adding id param: " + termUri); + vals.add(i, termUri); + } else { + // or a hardcoded value + logger.fine("Adding hardcoded param: " + param); + vals.add(i, param); + } } } - else { - if (pattern.equals("{0}")) { - if (vals.get(0) instanceof JsonArray) { - job.add(filterKey, (JsonArray) vals.get(0)); + // Shortcut: nominally using a pattern of {0} and a param that is @id or + // hardcoded value allows the same options as letting the pattern itself be @id + // or a hardcoded value + String pattern = filter.getString("pattern"); + logger.fine("Pattern: " + pattern); + if (pattern.equals("@id")) { + logger.fine("Added #id pattern: " + filterKey + ": " + termUri); + job.add(filterKey, termUri); + } else if (pattern.contains("{")) { + if (vals.isEmpty()) { + if (nrOfNotFound == 0) { + logger.warning("External Vocabulary: " + termUri + " - No value found for " + filterKey); } - else if (vals.get(0) instanceof JsonObject) { - job.add(filterKey, (JsonObject) vals.get(0)); - } - else { - job.add(filterKey, (String) vals.get(0)); + } else { + if (pattern.equals("{0}")) { + if (vals.get(0) instanceof JsonArray) { + job.add(filterKey, (JsonArray) vals.get(0)); + } else if (vals.get(0) instanceof JsonObject) { + job.add(filterKey, (JsonObject) vals.get(0)); + } else { + job.add(filterKey, (String) vals.get(0)); + } + } else { + String result = MessageFormat.format(pattern, vals.toArray()); + logger.fine("Result: " + result); + job.add(filterKey, result); + logger.fine("Added : " + filterKey + ": " + result); } } - else { - String result = MessageFormat.format(pattern, vals.toArray()); - logger.fine("Result: " + result); - job.add(filterKey, result); - logger.fine("Added : " + filterKey + ": " + result); - } + } else { + logger.fine("Added hardcoded pattern: " + filterKey + ": " + pattern); + job.add(filterKey, pattern); } - } else { - logger.fine("Added hardcoded pattern: " + filterKey + ": " + pattern); - job.add(filterKey, pattern); + } catch (Exception e) { + logger.warning("External Vocabulary: " + termUri + " - Failed to find value for " + filterKey + ": " + + e.getMessage()); + e.printStackTrace(); } - } catch (Exception e) { - logger.warning("External Vocabulary: " + termUri + " - Failed to find value for " + filterKey + ": " - + e.getMessage()); - e.printStackTrace(); } } - } - if(nrOfNotFound>0) { - logger.warning("External Vocabulary: " + termUri + " - Failed to find value(s) reported above in " +readObject); + + if (nrOfNotFound > 0) { + logger.warning("External Vocabulary: " + termUri + " - Failed to find value(s) reported above in " + readObject); + } } JsonObject filteredResponse = job.build(); if(filteredResponse.isEmpty()) {