Skip to content
Original file line number Diff line number Diff line change
@@ -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.
194 changes: 111 additions & 83 deletions src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java
Original file line number Diff line number Diff line change
Expand Up @@ -407,10 +407,11 @@ public void registerExternalVocabValues(DatasetField df) {
public Set<String> getIndexableStringsByTermUri(String termUri, JsonObject cvocEntry, String indexingField) {
Set<String> 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 = getRetrievalFilteringObject(cvocEntry, termUri);
String termUriField = cvocEntry.getJsonString("term-uri-field").getString();

try {
for (String key : jo.keySet()) {
String indexIn = filtering.getJsonObject(key).getString("indexIn", null);
Expand Down Expand Up @@ -468,6 +469,24 @@ public Set<String> 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
Expand Down Expand Up @@ -500,7 +519,7 @@ public JsonObject getExternalVocabularyValue(String termUri) {
* @param relatedDatasetFields - siblings or childs of the term
*/
public void registerExternalTerm(JsonObject cvocEntry, String term, List<DatasetField> 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)) {
Expand All @@ -515,6 +534,13 @@ public void registerExternalTerm(JsonObject cvocEntry, String term, List<Dataset
if (vocab.containsKey("uriSpace")) {
if (term.startsWith(vocab.getString("uriSpace"))) {
isExternal = true;
// A specific vocabulary can override the top-level retrieval-uri and prefix
if (vocab.containsKey("retrieval-uri")) {
retrievalUri = vocab.getString("retrieval-uri");
}
if (vocab.containsKey("prefix")) {
prefix = vocab.getString("prefix");
}
break;
}
}
Expand All @@ -523,6 +549,11 @@ public void registerExternalTerm(JsonObject cvocEntry, String term, List<Dataset
logger.fine("Ignoring free text entry: " + term);
return;
}
if (isExternal && (retrievalUri == null)) {
logger.warning("No retrieval-uri found for term " + term);
return;
}

logger.fine("Registering term: " + term);
try {
//Assure the term is in URI form - should be if the uriSpace entry was correct
Expand Down Expand Up @@ -647,96 +678,93 @@ private String tryToReplaceRetrievalUriParam(String retrievalUri, String paramNa
private JsonObject filterResponse(JsonObject cvocEntry, JsonObject readObject, String termUri) {

JsonObjectBuilder job = JsonUtil.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")) {
try {
JsonObject filter = filtering.getJsonObject(filterKey);
logger.fine("F: " + filter.toString());
JsonArray params = filter.getJsonArray("params");
if (params == null) {
params = JsonUtil.createArrayBuilder().build();
}
logger.fine("Params: " + params.toString());
List<Object> vals = new ArrayList<Object>();
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 = JsonUtil.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<Object> vals = new ArrayList<Object>();
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));
}
else if (vals.get(0) instanceof JsonObject) {
job.add(filterKey, (JsonObject) 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 {
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()) {
Expand Down
Loading