updates for concept search service, adding LCSH search capability

This commit is contained in:
hudajkhan 2013-09-16 14:02:47 -04:00
parent e032ceeca4
commit ba1c6c7075
10 changed files with 1009 additions and 135 deletions

View file

@ -1,6 +1,6 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> <#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<#import "lib-vivo-form.ftl" as lvf> <#import "lib-vivo-form.ftl" as lvf>
<#include "addAssociatedConceptVocabSpecificDisplay.ftl" >
<#assign existingConcepts = editConfiguration.pageData.existingConcepts/> <#assign existingConcepts = editConfiguration.pageData.existingConcepts/>
<#assign userDefinedConceptUrl = editConfiguration.pageData.userDefinedConceptUrl/> <#assign userDefinedConceptUrl = editConfiguration.pageData.userDefinedConceptUrl/>
<#assign sources = editConfiguration.pageData.searchServices/> <#assign sources = editConfiguration.pageData.searchServices/>
@ -35,29 +35,44 @@
<ul id="existingConcepts" > <ul id="existingConcepts">
<script type="text/javascript"> <script type="text/javascript">
var existingConceptsData = []; var existingConceptsData = [];
</script> </script>
<#if (existingConcepts?size > 0)>
<li class="conceptHeadings conceptsListContainer">
<div class="row">
<div class="column conceptLabelInfo">
<h4>Concept (Type)</h4>
</div>
<div class="column conceptVocabSource">
<h4>Vocabulary Source</h4>
</div>
<div class="column">&nbsp;
</div>
</div>
</li>
</#if>
<#list existingConcepts as existingConcept> <#list existingConcepts as existingConcept>
<li class="existingConcept"> <li class="existingConcept conceptsListContainer">
<div class="row">
<span class="concept"> <div class="column conceptLabelInfo"> ${existingConcept.conceptLabel}
<span class="conceptWrapper">
<span class="conceptLabel"> ${existingConcept.conceptLabel}
<#if existingConcept.vocabURI?has_content && existingConcept.vocabLabel?has_content>
(${existingConcept.vocabLabel})
</#if>
<#if existingConcept.conceptSemanticTypeLabel?has_content> <#if existingConcept.conceptSemanticTypeLabel?has_content>
${existingConcept.conceptSemanticTypeLabel} (${existingConcept.conceptSemanticTypeLabel})
</#if> </#if>
</span> </div>
</span> <div class="column conceptVocabSource">
&nbsp;<a href="${urls.base}/edit/primitiveRdfEdit" class="remove" title="${i18n().remove_capitalized}">${i18n().remove_capitalized}</a> <#if existingConcept.vocabURI?has_content && existingConcept.vocabLabel?has_content>
</span> ${existingConcept.vocabLabel}
</#if>
</div>
<div class="column">
<a href="${urls.base}/edit/primitiveRdfEdit" class="remove" title="${i18n().remove_capitalized}">${i18n().remove_capitalized}</a>
</div>
</div>
</li> </li>
<script type="text/javascript"> <script type="text/javascript">
@ -86,7 +101,7 @@
<form id="addConceptForm" class="customForm" action="${submitUrl}"> <form id="addConceptForm" class="customForm" action="${submitUrl}">
<#assign checkedSource = false /> <#assign checkedSource = false />
<h4 class="services">${i18n().external_vocabulary_services}</h4> <h4 class="services">${i18n().external_vocabulary_services}</h4>
<#list sources?keys as sourceUri> <#list sources?keys?sort as sourceUri>
<#assign thisSource = sources[sourceUri]/> <#assign thisSource = sources[sourceUri]/>
<input type="radio" name="source" value="${sourceUri}" role="radio" <#if checkedSource = false><#assign checkedSource = true/>checked="checked"</#if>> <input type="radio" name="source" value="${sourceUri}" role="radio" <#if checkedSource = false><#assign checkedSource = true/>checked="checked"</#if>>
<label class="inline" for="${thisSource.label}"> <a href="${thisSource.url}">${thisSource.label}</a> &nbsp;(${thisSource.description})</label> <label class="inline" for="${thisSource.label}"> <a href="${thisSource.url}">${thisSource.label}</a> &nbsp;(${thisSource.description})</label>
@ -101,12 +116,21 @@
<input type="hidden" id="conceptSource" name="conceptSource" value="" /> <!-- Field value populated by JavaScript --> <input type="hidden" id="conceptSource" name="conceptSource" value="" /> <!-- Field value populated by JavaScript -->
<input type="hidden" id="conceptSemanticTypeURI" name="conceptSemanticTypeURI" value="" /> <!-- Field value populated by JavaScript --> <input type="hidden" id="conceptSemanticTypeURI" name="conceptSemanticTypeURI" value="" /> <!-- Field value populated by JavaScript -->
<input type="hidden" id="conceptSemanticTypeLabel" name="conceptSemanticTypeLabel" value="" /> <!-- Field value populated by JavaScript --> <input type="hidden" id="conceptSemanticTypeLabel" name="conceptSemanticTypeLabel" value="" /> <!-- Field value populated by JavaScript -->
<input type="hidden" id="conceptBroaderURI" name="conceptBroaderURI" value=""/><!-- Field value populated by JavaScript -->
<input type="hidden" id="conceptNarrowerURI" name="conceptNarrowerURI" value=""/><!-- Field value populated by JavaScript -->
<div id="indicator" class="hidden">
<img id="loadingIndicator" class="indicator" src="${urls.base}/images/indicatorWhite.gif" alt="${i18n().processing_indicator}"/>
</div>
<div id="selectedConcept" name="selectedConcept" class="acSelection"> <div id="selectedConcept" name="selectedConcept" class="acSelection">
<p class="inline"> <p class="inline">
</p> </p>
<!-- Search results populated by JavaScript --> <!-- Search results populated by JavaScript -->
</div> </div>
<div id="showHideResults" name="showHideResults">
<a href="#" id="showHideLink">Results</a>
</div>
<div id="errors" name="errors"></div> <div id="errors" name="errors"></div>
<input type="hidden" name="editKey" id="editKey" value="${editKey}"/> <input type="hidden" name="editKey" id="editKey" value="${editKey}"/>
@ -133,16 +157,21 @@ var customFormData = {
predicateUri: '${editConfiguration.predicateUri}', predicateUri: '${editConfiguration.predicateUri}',
inversePredicateUri: '${inversePredicate}' inversePredicateUri: '${inversePredicate}'
}; };
var vocabSpecificDisplay = {};
<#list vocabSpecificDisplay?keys as vocab>
vocabSpecificDisplay["${vocab}"] = "${vocabSpecificDisplay[vocab]}";
</#list>
var i18nStrings = { var i18nStrings = {
vocServiceUnavailable: '${i18n().vocabulary_service_unavailable}', vocServiceUnavailable: '${i18n().vocabulary_service_unavailable}',
noResultsFound: '${i18n().no_serch_results_found}', noResultsFound: '${i18n().no_serch_results_found}',
labelTypeString: '${i18n().label_type}', defaultLabelTypeString: '${i18n().label_type}',
definitionString: '${i18n().definition_capitalized}', definitionString: '${i18n().definition_capitalized}',
bestMatchString: '${i18n().best_match}', bestMatchString: '${i18n().best_match}',
selectTermFromResults: '${i18n().select_term_from_results}', selectTermFromResults: '${i18n().select_term_from_results}',
selectVocSource: '${i18n().select_vocabulary_source_to_search}', selectVocSource: '${i18n().select_vocabulary_source_to_search}',
confirmTermDelete: '${i18n().confirm_term_deletion}', confirmTermDelete: '${i18n().confirm_term_deletion}',
errorTernNotRemoved: '${i18n().error_term_not_deleted}' errorTernNotRemoved: '${i18n().error_term_not_deleted}',
vocabSpecificLabels: vocabSpecificDisplay
}; };
</script> </script>

View file

@ -0,0 +1,14 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<#--The original concept javascript is service independent, i.e. all vocabulary service information is returned from the servlet
and the template itself generates the same display for all the services. Right now we would like to show a different label
in the search results based on the service. I am storing that information here and later we can consider how the display
can return to being independent of vocabulary service-specific display options.
These values will be passed to the javascript-->
<#assign vocabSpecificDisplay = {
"http://link.informatics.stonybrook.edu/umls":"${i18n().label_type}",
"http://aims.fao.org/aos/agrovoc/agrovocScheme":"${i18n().label_altLabels}",
"http://www.eionet.europa.eu/gemet/gemetThesaurus":"${i18n().label_type}",
"http://id.loc.gov/authorities/subjects":"${i18n().label_altLabels}"
}/>

View file

@ -1,5 +1,9 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */ /* $This file is distributed under the terms of the license in /doc/license.txt$ */
.conceptsListContainer {
overflow:hidden;
width:100%;
}
.concepts .column { .concepts .column {
float:left; float:left;
padding-right:3px; padding-right:3px;
@ -45,3 +49,28 @@ form#addConceptForm span#createOwnOne{
float:left; float:left;
margin-top:24px margin-top:24px
} }
/*For existing concepts, display will also be tabular with columns*/
.existingConcept .row, .conceptHeadings .row {
clear:both;
float:left;
}
.existingConcept .column , .conceptHeadings .column {
float:left;
padding-right:3px;
clear:none !important; /*Overriding customFor div's clearing*/
}
/*label and semantic type if it exists*/
.existingConcept .conceptLabelInfo, .conceptHeadings .conceptLabelInfo {
width:220px;
}
.existingConcept .conceptVocabSource, .conceptHeadings .conceptVocabSource {
width:220px;
}
.conceptHeadings .row {
border-bottom: 1px solid #5F6464;
}

View file

@ -55,12 +55,19 @@ var addConceptForm = {
this.externalConceptLabel = $('#conceptLabel'); this.externalConceptLabel = $('#conceptLabel');
this.externalConceptSource = $('#conceptSource'); this.externalConceptSource = $('#conceptSource');
this.externalConceptSemanticTypeLabel = $("#conceptSemanticTypeLabel"); this.externalConceptSemanticTypeLabel = $("#conceptSemanticTypeLabel");
this.externalConceptBroaderUris = $("#conceptBroaderURI");
this.externalConceptNarrowerUris = $("#conceptNarrowerURI");
//remove links //remove links
this.removeConceptLinks = $('a.remove'); this.removeConceptLinks = $('a.remove');
this.errors = $('#errors'); this.errors = $('#errors');
this.createOwn1 = $('#createOwnOne'); this.createOwn1 = $('#createOwnOne');
this.createOwn2 = $('#createOwnTwo'); this.createOwn2 = $('#createOwnTwo');
this.orSpan = $('span.or') this.orSpan = $('span.or')
this.loadingIndicator = $("#indicator");
this.showHideSearchResults = $("#showHideResults");
//Value we are setting to cut off length of alternate labels string
this.maxNumberAlternateLabels = 4;
this.numberOfMaxInitialSearchResults = 7;
}, },
initPage: function() { initPage: function() {
@ -87,6 +94,10 @@ var addConceptForm = {
addConceptForm.removeExistingConcept(this); addConceptForm.removeExistingConcept(this);
return false; return false;
}); });
this.showHideSearchResults.find("a#showHideLink").click(function() {
addConceptForm.showHideMultipleSearchResults(this);
return false;
});
}, },
initForm: function() { initForm: function() {
// Hide the button that shows the form // Hide the button that shows the form
@ -99,7 +110,9 @@ var addConceptForm = {
//Also clear the search input //Also clear the search input
this.searchTerm.val(""); this.searchTerm.val("");
this.cancel.unbind('click'); this.cancel.unbind('click');
//make sure results loading indicator is hidden
this.loadingIndicator.addClass("hidden");
this.showHideSearchResults.hide();
// Show the form // Show the form
this.form.show(); this.form.show();
}, },
@ -114,6 +127,8 @@ var addConceptForm = {
}, },
clearSearchResults:function() { clearSearchResults:function() {
$('#selectedConcept').empty(); $('#selectedConcept').empty();
//Hide the indicator icon if still there
$("#indicator").addClass("hidden");
}, },
clearErrors:function() { clearErrors:function() {
addConceptForm.errors.empty(); addConceptForm.errors.empty();
@ -134,6 +149,25 @@ var addConceptForm = {
this.hideForm(); this.hideForm();
this.showFormButtonWrapper.show(); this.showFormButtonWrapper.show();
}, },
showHideMultipleSearchResults: function(link) {
if($(link).hasClass("showmore")) {
//if clicking and already says show more then need to show the rest of the results
$("li.concepts").show(); //show everything
$(link).html("Show fewer results");
$(link).removeClass("showmore");
} else {
//if clicking and does not say show more than need to show less
$("li.concepts").slice(addConceptForm.numberOfMaxInitialSearchResults).hide();
$(link).html("Show more results");
$(link).addClass("showmore");
}
},
//reset this to default, which is hidden with show more link
resetShowHideMultipleSearchResults: function() {
addConceptForm.showHideSearchResults.hide();
addConceptForm.showHideSearchResults.find("a#showHideLink").html("Show more results");
addConceptForm.showHideSearchResults.find("a#showHideLink").addClass("showmore");
},
submitSearchTerm: function() { submitSearchTerm: function() {
//Get value of search term //Get value of search term
var searchValue = this.searchTerm.val(); var searchValue = this.searchTerm.val();
@ -145,7 +179,11 @@ var addConceptForm = {
} }
var vocabSourceValue = checkedVocabSource.val(); var vocabSourceValue = checkedVocabSource.val();
var dataServiceUrl = addConceptForm.dataServiceUrl + "?searchTerm=" + encodeURIComponent(searchValue) + "&source=" + encodeURIComponent(vocabSourceValue); var dataServiceUrl = addConceptForm.dataServiceUrl + "?searchTerm=" + encodeURIComponent(searchValue) + "&source=" + encodeURIComponent(vocabSourceValue);
//This should return an object including the concept list or any errors if there are any //Show the loading icon until the results appear
addConceptForm.loadingIndicator.removeClass("hidden");
//Hide and reset the show more button
addConceptForm.resetShowHideMultipleSearchResults();
//This should return an object including the concept list or any errors if there are any
$.getJSON(dataServiceUrl, function(results) { $.getJSON(dataServiceUrl, function(results) {
var htmlAdd = ""; var htmlAdd = "";
var vocabUnavailable = "<p>" + addConceptForm.vocServiceUnavailable + "</p>"; var vocabUnavailable = "<p>" + addConceptForm.vocServiceUnavailable + "</p>";
@ -166,7 +204,7 @@ var addConceptForm = {
//For each result, display //For each result, display
if(numberTotalMatches > 0) { if(numberTotalMatches > 0) {
htmlAdd = "<ul class='dd' id='concepts' name='concepts'>"; htmlAdd = "<ul class='dd' id='concepts' name='concepts'>";
htmlAdd+= addConceptForm.addResultsHeader(); htmlAdd+= addConceptForm.addResultsHeader(vocabSourceValue);
//Show best matches first //Show best matches first
for(i = 0; i < numberBestMatches; i++) { for(i = 0; i < numberBestMatches; i++) {
var conceptResult = bestMatchResults[i]; var conceptResult = bestMatchResults[i];
@ -184,6 +222,8 @@ var addConceptForm = {
} }
if(htmlAdd.length) { if(htmlAdd.length) {
//hide the loading icon again
addConceptForm.loadingIndicator.addClass("hidden");
$('#selectedConcept').html(htmlAdd); $('#selectedConcept').html(htmlAdd);
if (htmlAdd.indexOf("No search results") >= 0) { if (htmlAdd.indexOf("No search results") >= 0) {
addConceptForm.showHiddenElements(hasResults); addConceptForm.showHiddenElements(hasResults);
@ -191,6 +231,8 @@ var addConceptForm = {
else { else {
hasResults = true; hasResults = true;
addConceptForm.showHiddenElements(hasResults); addConceptForm.showHiddenElements(hasResults);
//Here, tweak the display based on the number of results
addConceptForm.displayUptoMaxResults();
} }
} }
}); });
@ -203,9 +245,12 @@ var addConceptForm = {
var definedBy = conceptResult.definedBy; var definedBy = conceptResult.definedBy;
var type = conceptResult.type; var type = conceptResult.type;
var uri = conceptResult.uri; var uri = conceptResult.uri;
//also adding broader and narrower uris wherever they exist
var broaderUris = conceptResult.broaderURIList;
var narrowerUris = conceptResult.narrowerURIList;
//this will be null if there are no alternate labels //this will be null if there are no alternate labels
var altLabels = conceptResult.altLabelList; var altLabels = conceptResult.altLabelList;
return addConceptForm.generateIndividualConceptDisplay(uri, label, altLabels, definition, type, definedBy, isBestMatch); return addConceptForm.generateIndividualConceptDisplay(uri, label, altLabels, definition, type, definedBy, isBestMatch, broaderUris, narrowerUris);
}, },
//This should now return all best matches in one array and other results in another //This should now return all best matches in one array and other results in another
parseResults:function(resultsArray) { parseResults:function(resultsArray) {
@ -225,10 +270,19 @@ var addConceptForm = {
} }
return {"bestMatch":bestMatchResults, "alternate":alternateResults}; return {"bestMatch":bestMatchResults, "alternate":alternateResults};
}, },
addResultsHeader:function() { addResultsHeader:function(vocabSourceValue) {
var htmlAdd = "<li class='concepts'><div class='row'><span class='column conceptLabel'>" + addConceptForm.labelTypeString + " </span><span class='column conceptDefinition'>" + addConceptForm.definitionString + "</span><span class='column'>" + addConceptForm.bestMatchString + "</span></div></li>"; var htmlAdd = "<li class='concepts'><div class='row'><span class='column conceptLabel'>" +
addConceptForm.getVocabSpecificColumnLabel(vocabSourceValue) + " </span><span class='column conceptDefinition'>" + addConceptForm.definitionString + "</span><span class='column'>" + addConceptForm.bestMatchString + "</span></div></li>";
return htmlAdd; return htmlAdd;
}, },
//currently just the first column label depends on which service has been utilized
getVocabSpecificColumnLabel: function(vocabSourceValue) {
var columnLabel = addConceptForm.vocabSpecificLabels[vocabSourceValue];
if(columnLabel == undefined) {
columnLabel = addConceptForm.defaultLabelTypeString;
}
return columnLabel;
},
hideSearchResults:function() { hideSearchResults:function() {
this.selectedConcept.hide(); this.selectedConcept.hide();
}, },
@ -239,11 +293,14 @@ var addConceptForm = {
} }
var i; var i;
var len = checkedElements.length; var len = checkedElements.length;
var checkedConcept, checkedConceptElement, conceptLabel, conceptSource, conceptSemanticType; var checkedConcept, checkedConceptElement, conceptLabel, conceptSource, conceptSemanticType,
conceptBroaderUri, conceptNarrowerUri;
var conceptNodes = []; var conceptNodes = [];
var conceptLabels = []; var conceptLabels = [];
var conceptSources = []; var conceptSources = [];
var conceptSemanticTypes = []; var conceptSemanticTypes = [];
var conceptBroaderUris = []; //each array element can be a string which is comma delimited for multiple uris
var conceptNarrowerUris = [];//same as above
checkedElements.each(function() { checkedElements.each(function() {
checkedConceptElement = $(this); checkedConceptElement = $(this);
@ -251,22 +308,29 @@ var addConceptForm = {
conceptLabel = checkedConceptElement.attr("label"); conceptLabel = checkedConceptElement.attr("label");
conceptSource = checkedConceptElement.attr("conceptDefinedBy"); conceptSource = checkedConceptElement.attr("conceptDefinedBy");
conceptSemanticType = checkedConceptElement.attr("conceptType"); conceptSemanticType = checkedConceptElement.attr("conceptType");
conceptBroaderUri = checkedConceptElement.attr("broaderUris");
conceptNarrowerUri = checkedConceptElement.attr("narrowerUris");
conceptNodes.push(checkedConcept); conceptNodes.push(checkedConcept);
conceptLabels.push(conceptLabel); conceptLabels.push(conceptLabel);
conceptSources.push(conceptSource); conceptSources.push(conceptSource);
conceptSemanticTypes.push(conceptSemanticType); conceptSemanticTypes.push(conceptSemanticType);
conceptBroaderUris.push(conceptBroaderUri);
conceptNarrowerUris.push(conceptNarrowerUri);
}); });
this.externalConceptURI.val(conceptNodes); this.externalConceptURI.val(conceptNodes);
this.externalConceptLabel.val(conceptLabels); this.externalConceptLabel.val(conceptLabels);
this.externalConceptSource.val(conceptSources); this.externalConceptSource.val(conceptSources);
this.externalConceptSemanticTypeLabel.val(conceptSemanticTypes); this.externalConceptSemanticTypeLabel.val(conceptSemanticTypes);
this.externalConceptBroaderUris.val(conceptBroaderUris);
this.externalConceptNarrowerUris.val(conceptNarrowerUris);
return true; return true;
}, },
generateIndividualConceptDisplay: function(cuiURI, label, altLabels, definition, type, definedBy, isBestMatch) { generateIndividualConceptDisplay: function(cuiURI, label, altLabels, definition, type, definedBy, isBestMatch, broaderUris, narrowerUris) {
var htmlAdd = "<li class='concepts'>" + var htmlAdd = "<li class='concepts'>" +
"<div class='row'>" + "<div class='row'>" +
"<div class='column conceptLabel'>" + "<div class='column conceptLabel'>" +
addConceptForm.generateIndividualCUIInput(cuiURI, label, type, definedBy) + addConceptForm.generateIndividualCUIInput(cuiURI, label, type, definedBy, broaderUris, narrowerUris) +
addConceptForm.generateIndividualLabelsDisplay(label, altLabels) + addConceptForm.generateIndividualTypeDisplay(type) + "</div>" + addConceptForm.generateIndividualLabelsDisplay(label, altLabels) + addConceptForm.generateIndividualTypeDisplay(type) + "</div>" +
addConceptForm.generateIndividualDefinitionDisplay(definition) + addConceptForm.generateIndividualDefinitionDisplay(definition) +
addConceptForm.generateBestOrAlternate(isBestMatch) + addConceptForm.generateBestOrAlternate(isBestMatch) +
@ -274,14 +338,23 @@ var addConceptForm = {
"</li>"; "</li>";
return htmlAdd; return htmlAdd;
}, },
generateIndividualCUIInput:function(cuiURI, label, type, definedBy) { generateIndividualCUIInput:function(cuiURI, label, type, definedBy, broaderUris, narrowerUris) {
return "<input type='checkbox' name='CUI' value='" + cuiURI + "' label='" + label + "' conceptType='" + type + "' conceptDefinedBy='" + definedBy + "'/>"; return "<input type='checkbox' name='CUI' value='" + cuiURI + "' label='" +
label + "' conceptType='" + type + "' conceptDefinedBy='" + definedBy + "' " +
"broaderUris='" + broaderUris + "' narrowerUris='" + narrowerUris + "'/>";
}, },
//In case there are multiple labels display those //In case there are multiple labels display those
generateIndividualLabelsDisplay:function(label, altLabels) { generateIndividualLabelsDisplay:function(label, altLabels) {
var labelDisplay = label; var labelDisplay = label;
var displayAltLabels = altLabels;
if(altLabels != null && altLabels.length > 0) { if(altLabels != null && altLabels.length > 0) {
labelDisplay += "<br> [" + altLabels + "]"; //Certain vocabulary services might return a long list of alternate labels, in which case we will show fewer
//display only upto a certain number of alternate labels and use an ellipsis to signify there
//are additional terms
if(altLabels.length > addConceptForm.maxNumberAlternateLabels) {
displayAltLabels = altLabels.slice(0, addConceptForm.maxNumberAlternateLabels) + ",...";
}
labelDisplay += "<br> (" + displayAltLabels + ")";
} }
return labelDisplay; return labelDisplay;
}, },
@ -307,6 +380,18 @@ var addConceptForm = {
} }
return "<div class='column'><div class='" + className + "'>&nbsp;</div></div>"; return "<div class='column'><div class='" + className + "'>&nbsp;</div></div>";
}, },
//Certain vocabulary services return a great number of results, we would like the ability to show more or less of those results
displayUptoMaxResults:function() {
var numberConcepts = $("li.concepts").length;
if(numberConcepts > addConceptForm.numberOfMaxInitialSearchResults) {
$("li.concepts").slice(addConceptForm.numberOfMaxInitialSearchResults).hide();
//Hide the link for showing/hiding search results
addConceptForm.showHideSearchResults.show();
addConceptForm.showHideSearchResults.find("a#showHideLink").html("Show more results");
addConceptForm.showHideSearchResults.find("a#showHideLink").addClass("showmore");
}
},
validateConceptSelection:function(checkedElements) { validateConceptSelection:function(checkedElements) {
var numberElements = checkedElements.length; var numberElements = checkedElements.length;
if(numberElements < 1) { if(numberElements < 1) {

View file

@ -4,3 +4,5 @@
<http://link.informatics.stonybrook.edu/umls> <http://www.w3.org/2000/01/rdf-schema#label> "UMLS"^^<http://www.w3.org/2001/XMLSchema#string> . <http://link.informatics.stonybrook.edu/umls> <http://www.w3.org/2000/01/rdf-schema#label> "UMLS"^^<http://www.w3.org/2001/XMLSchema#string> .
<http://aims.fao.org/aos/agrovoc/agrovocScheme> <http://www.w3.org/2000/01/rdf-schema#label> "AGROVOC"^^<http://www.w3.org/2001/XMLSchema#string> . <http://aims.fao.org/aos/agrovoc/agrovocScheme> <http://www.w3.org/2000/01/rdf-schema#label> "AGROVOC"^^<http://www.w3.org/2001/XMLSchema#string> .
<http://www.eionet.europa.eu/gemet/gemetThesaurus> <http://www.w3.org/2000/01/rdf-schema#label> "GEMET"^^<http://www.w3.org/2001/XMLSchema#string> . <http://www.eionet.europa.eu/gemet/gemetThesaurus> <http://www.w3.org/2000/01/rdf-schema#label> "GEMET"^^<http://www.w3.org/2001/XMLSchema#string> .
<http://id.loc.gov/authorities/subjects> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Thing> .
<http://id.loc.gov/authorities/subjects> <http://www.w3.org/2000/01/rdf-schema#label> "LCSH"^^<http://www.w3.org/2001/XMLSchema#string> .

View file

@ -0,0 +1,510 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.semservices.service.impl;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLEncoder;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.rpc.ServiceException;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.fao.www.webservices.AgrovocWS.ACSWWebService;
import org.fao.www.webservices.AgrovocWS.ACSWWebServiceServiceLocator;
import org.semanticweb.skos.SKOSAnnotation;
import org.semanticweb.skos.SKOSConcept;
import org.semanticweb.skos.SKOSDataFactory;
import org.semanticweb.skos.SKOSDataProperty;
import org.semanticweb.skos.SKOSDataRelationAssertion;
import org.semanticweb.skos.SKOSDataset;
import org.semanticweb.skos.SKOSEntity;
import org.semanticweb.skos.SKOSLiteral;
import org.semanticweb.skos.SKOSObjectRelationAssertion;
import org.semanticweb.skos.SKOSUntypedLiteral;
import org.semanticweb.skos.properties.*;
import org.semanticweb.skosapibinding.SKOSManager;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import edu.cornell.mannlib.semservices.bo.Concept;
import edu.cornell.mannlib.semservices.exceptions.ConceptsNotFoundException;
import edu.cornell.mannlib.semservices.service.ExternalConceptService;
import edu.cornell.mannlib.semservices.util.XMLUtils;
public class LCSHService implements ExternalConceptService {
protected final Log log = LogFactory.getLog(getClass());
private final String skosSuffix = ".skos.rdf";
private final String hostUri = "http://id.loc.gov";
private java.lang.String LCSHWS_address = hostUri + "/authorities/subjects";
private final String schemeUri = hostUri + "/authorities/subjects";
private final String baseUri = hostUri + "/search/";
private final String ontologyName = "LCSH";
private final String format = "SKOS";
private final String lang = "en";
private final String codeName = "hasCodeAgrovoc";
private final String searchMode = "Exact Match";
protected final String dbpedia_endpoint = " http://dbpedia.org/sparql";
//Property uris used for SKOS
protected final String SKOSNotePropertyURI = "http://www.w3.org/2004/02/skos/core#note";
protected final String SKOSPrefLabelURI = "http://www.w3.org/2004/02/skos/core#prefLabel";
protected final String SKOSAltLabelURI = "http://www.w3.org/2008/05/skos-xl#altLabel";
protected final String SKOSBroaderURI = "http://www.w3.org/2004/02/skos/core#broader";
protected final String SKOSNarrowerURI = "http://www.w3.org/2004/02/skos/core#narrower";
protected final String SKOSExactMatchURI = "http://www.w3.org/2004/02/skos/core#exactMatch";
protected final String SKOSCloseMatchURI = "http://www.w3.org/2004/02/skos/core#closeMatch";
@Override
public List<Concept> getConcepts(String term) throws Exception {
List<Concept> conceptList = new ArrayList<Concept>();
String results = null;
String dataUrl = baseUri + "?q=" + URLEncoder.encode(term, "UTF-8")
+ "&q=cs%3Ahttp%3A%2F%2Fid.loc.gov%2Fauthorities%2Fsubjects"
+ "&format=XML";
log.debug("dataURL " + dataUrl);
try {
StringWriter sw = new StringWriter();
URL rss = new URL(dataUrl);
BufferedReader in = new BufferedReader(new InputStreamReader(
rss.openStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
sw.write(inputLine);
}
in.close();
results = sw.toString();
log.debug(results);
} catch (Exception ex) {
log.error("error occurred in servlet", ex);
return null;
}
if (StringUtils.isEmpty(results)) {
return conceptList;
}
conceptList = processOutput(results);
return conceptList;
}
// Results are in json format (atom) - atom entries need to be extracted
// retrieve the URIs and get the SKOS version of the entry, getting broader
// and narrower terms as applicable as well as any description (skos:note)
// that might exist
private List<Concept> processOutput(String results) throws Exception {
List<Concept> conceptList = new ArrayList<Concept>();
SKOSManager manager = new SKOSManager();
// Get uris from the results
// Properties we will be querying for
SKOSDataFactory sdf = manager.getSKOSDataFactory();
List<String> uris = getConceptURIFromXML(results);
String bestMatch = "true";
int i = 0;
for (String uri : uris) {
if(i > 0) {
bestMatch = "false";
}
log.debug("-" + uri + "-");
String conceptUriString = getSKOSURI(uri);
URI conceptURI = null;
try {
conceptURI = new URI(conceptUriString);
} catch (URISyntaxException e) {
log.error("URI syntax exception in trying to get concept uri " + conceptUriString, e);
return conceptList;
}
log.debug("loading concept uri " + conceptUriString);
SKOSDataset dataset = manager.loadDataset(conceptURI);
Set<SKOSConcept> skosConcepts = dataset.getSKOSConcepts();
log.debug("Number of skos concepts " + skosConcepts.size());
for (SKOSConcept skosConcept : skosConcepts) {
Concept c = this.createConcept(sdf, bestMatch, skosConcept, dataset);
if(c != null) {
conceptList.add(c);
}
}
i++;
}
return conceptList;
}
//Will use skos if does not encounter error from skos api, otherwise will use regular XML parsing techniques
public Concept createConcept(SKOSDataFactory skosDataFactory, String bestMatch, SKOSConcept skosConcept, SKOSDataset dataset) {
Concept concept = new Concept();
String skosConceptURI = skosConcept.getURI().toString();
log.debug("SKOSConceptURI is " + skosConceptURI);
// get skos version of uri
concept.setUri(skosConceptURI);
concept.setConceptId(stripConceptId(skosConceptURI));
concept.setBestMatch(bestMatch);
concept.setDefinedBy(schemeUri);
concept.setSchemeURI(schemeUri);
concept.setType("");
//Get the skos annotations first to see if there is an error triggered, if so try and see if we can instead utilize XML
//For some of the SKOS concepts, a null pointer exception occurs while XML processing still works
//I do not yet know the reasons, hjk54
try {
Set<SKOSAnnotation> skosAnnots = skosConcept
.getSKOSAnnotations(dataset);
} catch(NullPointerException ex) {
concept = createConceptUsingXML(concept, bestMatch, skosConcept);
return concept;
} catch(Exception ex) {
log.debug("Error occurred for annotation retrieval for skos concept " + skosConceptURI, ex);
return null;
}
concept = this.createConceptUsingSKOS(skosDataFactory, concept, skosConcept, dataset);
return concept;
}
private Concept createConceptUsingSKOS(SKOSDataFactory skosDataFactory, Concept concept, SKOSConcept skosConcept, SKOSDataset dataset) {
SKOSPrefLabelProperty prefLabelProperty = skosDataFactory.getSKOSPrefLabelProperty();
SKOSAltLabelProperty altLabelProperty = skosDataFactory.getSKOSAltLabelProperty();
try {
List<String> labelLiterals = this.getSKOSLiteralValues(skosConcept
.getSKOSRelatedConstantByProperty(dataset,
prefLabelProperty));
if(labelLiterals.size() > 0) {
concept.setLabel(labelLiterals.get(0));
} else {
//This is an error because there should be at least one label returned
log.debug("The number of preferred labels is not greater than zero");
}
// get altLabels
List<String> altLabelList = this.getSKOSLiteralValues(skosConcept
.getSKOSRelatedConstantByProperty(dataset, altLabelProperty));
concept.setAltLabelList(altLabelList);
// See if we can get a description as well
List<String> notes = this.getSKOSAnnotationValues(skosConcept
.getSKOSAnnotationsByURI(dataset, new URI(this.SKOSNotePropertyURI)));
concept.setDefinition(StringUtils.join(notes, ","));
// get the broader property URI
List<String> broaderURIList = this.getSKOSAnnotationValues(skosConcept
.getSKOSAnnotationsByURI(dataset, new URI(this.SKOSBroaderURI)));
concept.setBroaderURIList(broaderURIList);
// get the narrower property URI
List<String> narrowerURIList = this.getSKOSAnnotationValues(skosConcept
.getSKOSAnnotationsByURI(dataset, new URI(this.SKOSNarrowerURI)));
concept.setNarrowerURIList(narrowerURIList);
// exact match
List<String> exactMatchURIList = this.getSKOSAnnotationValues(skosConcept
.getSKOSAnnotationsByURI(dataset,
new URI(this.SKOSExactMatchURI)));
concept.setExactMatchURIList(exactMatchURIList);
// close match
List<String> closeMatchURIList = this.getSKOSAnnotationValues(skosConcept
.getSKOSAnnotationsByURI(dataset,
new URI(this.SKOSCloseMatchURI)));
concept.setCloseMatchURIList(closeMatchURIList);
log.debug("add concept to list");
} catch (Exception ex) {
log.debug("Exception occurred for -" + skosConcept.getURI()
+ "- " + ex.getMessage(), ex);
return null;
}
return concept;
}
private List<String> getSKOSLiteralValues(Set<SKOSLiteral> skosLiterals) {
String lang = "";
List<String> literalValues = new ArrayList<String>();
for (SKOSLiteral literal : skosLiterals) {
if (!literal.isTyped()) {
// if it has language
SKOSUntypedLiteral untypedLiteral = literal
.getAsSKOSUntypedLiteral();
if (untypedLiteral.hasLang()) {
lang = untypedLiteral.getLang();
} else {
lang = "";
}
}
// log.debug("literal: "+ literal.getLiteral());
if (lang.equals("en")) {
log.debug("literal value: " + literal.getLiteral());
literalValues.add(literal.getLiteral());
}
}
return literalValues;
}
//For a given set of annotations (for example, for a specific property)
private List<String> getSKOSAnnotationValues(Set<SKOSAnnotation> skosAnnotations) {
List<String> valuesList = new ArrayList<String>();
for (SKOSAnnotation annotation : skosAnnotations) {
String value = this.getSKOSAnnotationStringValue(annotation);
valuesList.add(value);
}
return valuesList;
}
//Get string value for annotation
private String getSKOSAnnotationStringValue(SKOSAnnotation annotation) {
String value = new String();
if (annotation.isAnnotationByConstant()) {
SKOSLiteral literal = annotation
.getAnnotationValueAsConstant();
value = literal.getLiteral();
log.debug("broder uri: " + value);
} else {
// annotation is some resource
SKOSEntity entity = annotation.getAnnotationValue();
value = entity.getURI().toString();
}
return value;
}
//this method relies on the XML of the single SKOS rdf concept in case the SKOS api throws a null pointer exception
private Concept createConceptUsingXML(Concept concept, String bestMatch,
SKOSConcept skosConcept) {
String conceptUriString = skosConcept.getURI().toString() + this.skosSuffix;;
URL conceptURL = null;
try {
conceptURL = new URL(conceptUriString);
} catch (Exception e) {
log.error("Exception occurred in instantiating URL for " + conceptUriString, e);
//If the url is having trouble, just return null for the concept
return null;
}
log.debug("loading concept uri " + conceptUriString);
String results = null;
try {
StringWriter sw = new StringWriter();
BufferedReader in = new BufferedReader(new InputStreamReader(
conceptURL.openStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
sw.write(inputLine);
}
in.close();
results = sw.toString();
log.debug(results);
} catch (Exception ex) {
log.error("Error occurred in getting concept from the URL " + conceptUriString, ex);
return null;
}
try {
Document doc = XMLUtils.parse(results);
List<String> labelLiterals = this.getValuesFromXMLNodes(doc, "skos:prefLabel", null);
if(labelLiterals.size() > 0) {
concept.setLabel(labelLiterals.get(0));
} else {
//This is an error because there should be at least one label returned
log.debug("The number of preferred labels is not greater than zero");
}
List<String> altLabelList = this.getValuesFromXMLNodes(doc, "skos:altLabel", null);
concept.setAltLabelList(altLabelList);
List<String> broaderURIList = this.getValuesFromXMLNodes(doc, "skos:broader", "rdf:resource");
concept.setBroaderURIList(broaderURIList);
List<String> narrowerURIList = this.getValuesFromXMLNodes(doc, "skos:narrower", "rdf:resource");
concept.setNarrowerURIList(narrowerURIList);
List<String> exactMatchURIList = this.getValuesFromXMLNodes(doc, "skos:exactMatch", "rdf:resource");
concept.setExactMatchURIList(exactMatchURIList);
List<String> closeMatchURIList = this.getValuesFromXMLNodes(doc, "skos:closeMatch", "rdf:resource");
concept.setCloseMatchURIList(closeMatchURIList);
} catch (IOException e) {
log.error("error occurred in parsing " + results, e);
} catch (SAXException e) {
log.error("error occurred in parsing " + results, e);
} catch (ParserConfigurationException e) {
log.error("error occurred in parsing " + results, e);
}
return concept;
}
private String getSKOSURI(String uri) {
// Strip .xml at the end and replace with .skos.rdf
String skosURI = uri;
if (uri.endsWith(".xml")) {
skosURI = uri.substring(0, uri.length() - 4);
skosURI += skosSuffix;
}
return hostUri + skosURI;
}
public List<String> getConceptURISFromJSON(String results) {
List<String> uris = new ArrayList<String>();
try {
JSONObject json = (JSONObject) JSONSerializer.toJSON(results);
log.debug(json.toString());
// Get atom entry elements
} catch (Exception ex) {
log.error("Could not get concepts", ex);
throw ex;
}
return uris;
}
protected List<String> getConceptURIFromXML(String rdf) {
List<String> uris = new ArrayList<String>();
String conceptUri = new String();
try {
Document doc = XMLUtils.parse(rdf);
NodeList nodes = doc.getElementsByTagName("search:result");
int len = nodes.getLength();
int i;
for (i = 0; i < len; i++) {
Node node = nodes.item(i);
NamedNodeMap attrs = node.getAttributes();
Attr idAttr = (Attr) attrs.getNamedItem("uri");
conceptUri = idAttr.getTextContent();
log.debug("concept uri is " + conceptUri);
uris.add(conceptUri);
}
} catch (IOException e) {
log.error("error occurred in parsing " +rdf, e);
} catch (SAXException e) {
log.error("error occurred in parsing " +rdf, e);
} catch (ParserConfigurationException e) {
log.error("error occurred in parsing " +rdf, e);
}
return uris;
}
public List<Concept> processResults(String term) throws Exception {
return getConcepts(term);
}
/**
* @param uri
* @return
*/
protected String stripConceptId(String uri) {
String conceptId = new String();
int lastslash = uri.lastIndexOf('/');
conceptId = uri.substring(lastslash + 1, uri.length());
return conceptId;
}
/**
* @param str
* @return
*/
protected String extractConceptId(String str) {
try {
return str.substring(1, str.length() - 1);
} catch (Exception ex) {
log.error("Exception occurred in extracting concept id for " + str, ex);
return "";
}
}
@Override
public List<Concept> getConceptsByURIWithSparql(String uri)
throws Exception {
// TODO Auto-generated method stub
return null;
}
public List<String> getValuesFromXMLNodes(Document doc, String tagName, String attributeName) {
NodeList nodes = doc.getElementsByTagName(tagName);
return getValuesFromXML(nodes, attributeName);
}
//Returns list of values based on nodes and whether or not a specific attribute name should be used or just the text content
public List<String> getValuesFromXML(NodeList nodes, String attributeName) {
int len = nodes.getLength();
int i;
List<String> values = new ArrayList<String>();
for (i = 0; i < len; i++) {
Node node = nodes.item(i);
if(attributeName != null && !attributeName.isEmpty()) {
NamedNodeMap attrs = node.getAttributes();
Attr a = (Attr)attrs.getNamedItem(attributeName);
if(a != null) {
values.add(a.getTextContent());
}
} else {
values.add(node.getTextContent());
}
}
return values;
}
}

View file

@ -59,6 +59,8 @@ public class AddAssociatedConceptGenerator extends VivoBaseGenerator implements
//TODO: Set this to a dynamic mechanism //TODO: Set this to a dynamic mechanism
private static String VIVOCore = "http://vivoweb.org/ontology/core#"; private static String VIVOCore = "http://vivoweb.org/ontology/core#";
private static String SKOSConceptType = "http://www.w3.org/2004/02/skos/core#Concept"; private static String SKOSConceptType = "http://www.w3.org/2004/02/skos/core#Concept";
private static String SKOSBroaderURI = "http://www.w3.org/2004/02/skos/core#broader";
private static String SKOSNarrowerURI = "http://www.w3.org/2004/02/skos/core#narrower";
@Override @Override
public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq, HttpSession session) { public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq, HttpSession session) {
EditConfigurationVTwo editConfiguration = new EditConfigurationVTwo(); EditConfigurationVTwo editConfiguration = new EditConfigurationVTwo();
@ -97,7 +99,8 @@ public class AddAssociatedConceptGenerator extends VivoBaseGenerator implements
// Add preprocessors // Add preprocessors
addPreprocessors(editConfiguration, addPreprocessors(editConfiguration,
ModelAccess.on(vreq).getJenaOntModel(), ModelAccess.on(vreq).getJenaOntModel(),
ModelAccess.on(vreq).getOntModelSelector().getTBoxModel()); ModelAccess.on(vreq).getOntModelSelector().getTBoxModel(),
vreq.getWebappDaoFactory());
// Adding additional data, specifically edit mode // Adding additional data, specifically edit mode
addFormSpecificData(editConfiguration, vreq); addFormSpecificData(editConfiguration, vreq);
// One override for basic functionality, changing url pattern // One override for basic functionality, changing url pattern
@ -189,7 +192,11 @@ public class AddAssociatedConceptGenerator extends VivoBaseGenerator implements
"?conceptNode <" + RDFS.isDefinedBy.getURI() + "> ?conceptSource .", "?conceptNode <" + RDFS.isDefinedBy.getURI() + "> ?conceptSource .",
"?conceptNode <" + RDF.type + "> ?conceptSemanticTypeURI ." + "?conceptNode <" + RDF.type + "> ?conceptSemanticTypeURI ." +
"?conceptSemanticTypeURI <" + RDFS.label.getURI() + "> ?conceptSemanticTypeLabel ." + "?conceptSemanticTypeURI <" + RDFS.label.getURI() + "> ?conceptSemanticTypeLabel ." +
"?conceptSemanticTypeURI <" + RDFS.subClassOf + "> <" + SKOSConceptType + "> ." "?conceptSemanticTypeURI <" + RDFS.subClassOf + "> <" + SKOSConceptType + "> .",
"?conceptNode <" + this.SKOSNarrowerURI + "> ?conceptNarrowerURI ." +
"?conceptNarrowerURI <" + this.SKOSBroaderURI + "> ?conceptNode .",
"?conceptNode <" + this.SKOSBroaderURI + "> ?conceptBroaderURI ." +
"?conceptBroaderURI <" + this.SKOSNarrowerURI + "> ?conceptNode ."
); );
} }
@ -254,6 +261,8 @@ public class AddAssociatedConceptGenerator extends VivoBaseGenerator implements
urisOnForm.add("conceptNode"); urisOnForm.add("conceptNode");
urisOnForm.add("conceptSource"); urisOnForm.add("conceptSource");
urisOnForm.add("conceptSemanticTypeURI"); urisOnForm.add("conceptSemanticTypeURI");
urisOnForm.add("conceptBroaderURI");
urisOnForm.add("conceptNarrowerURI");
editConfiguration.setUrisOnform(urisOnForm); editConfiguration.setUrisOnform(urisOnForm);
//Also need to add the label of the concept //Also need to add the label of the concept
literalsOnForm.add("conceptLabel"); literalsOnForm.add("conceptLabel");
@ -288,8 +297,23 @@ public class AddAssociatedConceptGenerator extends VivoBaseGenerator implements
setVocabURIField(editConfiguration, vreq); setVocabURIField(editConfiguration, vreq);
setConceptSemanticTypeURIField(editConfiguration,vreq); setConceptSemanticTypeURIField(editConfiguration,vreq);
setConceptSemanticTypeLabelField(editConfiguration,vreq); setConceptSemanticTypeLabelField(editConfiguration,vreq);
setConceptBroaderURIField(editConfiguration, vreq);
setConceptNarrowerURIField(editConfiguration, vreq);
} }
private void setConceptNarrowerURIField(
EditConfigurationVTwo editConfiguration, VitroRequest vreq) {
editConfiguration.addField(new FieldVTwo().
setName("conceptNarrowerURI"));
}
private void setConceptBroaderURIField(
EditConfigurationVTwo editConfiguration, VitroRequest vreq) {
editConfiguration.addField(new FieldVTwo().
setName("conceptBroaderURI"));
}
//this field will be hidden and include the concept node URI //this field will be hidden and include the concept node URI
private void setConceptNodeField(EditConfigurationVTwo editConfiguration, private void setConceptNodeField(EditConfigurationVTwo editConfiguration,
VitroRequest vreq) { VitroRequest vreq) {
@ -335,14 +359,17 @@ public class AddAssociatedConceptGenerator extends VivoBaseGenerator implements
//Add preprocessor //Add preprocessor
private void addPreprocessors(EditConfigurationVTwo editConfiguration, OntModel ontModel, OntModel modelChangeModel) { private void addPreprocessors(EditConfigurationVTwo editConfiguration,
OntModel ontModel,
OntModel modelChangeModel,
WebappDaoFactory wdf) {
//An Edit submission preprocessor for enabling addition of multiple terms for a single search //An Edit submission preprocessor for enabling addition of multiple terms for a single search
//TODO: Check if this is the appropriate way of getting model //TODO: Check if this is the appropriate way of getting model
//Passing model to check for any URIs that are present //Passing model to check for any URIs that are present
editConfiguration.addEditSubmissionPreprocessor( editConfiguration.addEditSubmissionPreprocessor(
new AddAssociatedConceptsPreprocessor(editConfiguration, ontModel)); new AddAssociatedConceptsPreprocessor(editConfiguration, ontModel, wdf));
editConfiguration.addModelChangePreprocessor(new ConceptSemanticTypesPreprocessor( editConfiguration.addModelChangePreprocessor(new ConceptSemanticTypesPreprocessor(
modelChangeModel)); modelChangeModel));

View file

@ -9,6 +9,7 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -27,6 +28,8 @@ import com.hp.hpl.jena.vocabulary.RDFS;
import com.hp.hpl.jena.vocabulary.XSD; import com.hp.hpl.jena.vocabulary.XSD;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.BaseEditSubmissionPreprocessorVTwo; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.BaseEditSubmissionPreprocessorVTwo;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUtils; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUtils;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo;
@ -38,8 +41,8 @@ public class AddAssociatedConceptsPreprocessor extends
protected static final Log log = LogFactory protected static final Log log = LogFactory
.getLog(AddAssociatedConceptsPreprocessor.class.getName()); .getLog(AddAssociatedConceptsPreprocessor.class.getName());
//TODO: Check if better way to do this?
protected OntModel ontModel = null; protected OntModel ontModel = null;
protected WebappDaoFactory wdf = null;
// Field names/variables names for n3 - these will have numbers added as // Field names/variables names for n3 - these will have numbers added as
// suffix if more than one term // suffix if more than one term
private static String conceptNodeBase = "conceptNode"; private static String conceptNodeBase = "conceptNode";
@ -47,6 +50,9 @@ public class AddAssociatedConceptsPreprocessor extends
private static String labelBase = "conceptLabel"; private static String labelBase = "conceptLabel";
private static String conceptSemanticTypeLabelBase = "conceptSemanticTypeLabel"; private static String conceptSemanticTypeLabelBase = "conceptSemanticTypeLabel";
private static String conceptSemanticTypeURIBase = "conceptSemanticTypeURI"; private static String conceptSemanticTypeURIBase = "conceptSemanticTypeURI";
private static String conceptBroaderURIBase = "conceptBroaderURI";
private static String conceptNarrowerURIBase = "conceptNarrowerURI";
//keyed off label variable, specifies which uri variable should be used, useful if same label repeated twice //keyed off label variable, specifies which uri variable should be used, useful if same label repeated twice
private HashMap<String, String> labelVarToUriVarHash = null; private HashMap<String, String> labelVarToUriVarHash = null;
private HashMap<String, List<String>> conceptSemanticTypeURIVarToValueMap = null; private HashMap<String, List<String>> conceptSemanticTypeURIVarToValueMap = null;
@ -56,15 +62,21 @@ public class AddAssociatedConceptsPreprocessor extends
private static String conceptSourceValues = null; private static String conceptSourceValues = null;
private static String conceptSemanticTypeLabelValues = null; private static String conceptSemanticTypeLabelValues = null;
private static String conceptSemanticTypeURIValues = null; private static String conceptSemanticTypeURIValues = null;
private static List<String> conceptBroaderURIValues = null;
private static List<String> conceptNarrowerURIValues = null;
private static MultiValueEditSubmission submission = null; private static MultiValueEditSubmission submission = null;
private static String SKOSBroaderURI = "http://www.w3.org/2004/02/skos/core#broader";
private static String SKOSNarrowerURI = "http://www.w3.org/2004/02/skos/core#narrower";
// String datatype // String datatype
// Will be editing the edit configuration as well as edit submission here // Will be editing the edit configuration as well as edit submission here
public AddAssociatedConceptsPreprocessor(EditConfigurationVTwo editConfig, OntModel ontModel) { public AddAssociatedConceptsPreprocessor(EditConfigurationVTwo editConfig, OntModel ontModel, WebappDaoFactory wadf) {
super(editConfig); super(editConfig);
this.ontModel = ontModel; this.ontModel = ontModel;
this.wdf = wadf;
this.labelVarToUriVarHash = new HashMap<String, String>(); this.labelVarToUriVarHash = new HashMap<String, String>();
//Saves values of concept type uris //Saves values of concept type uris
this.conceptSemanticTypeURIVarToValueMap = new HashMap<String, List<String>>(); this.conceptSemanticTypeURIVarToValueMap = new HashMap<String, List<String>>();
@ -86,6 +98,7 @@ public class AddAssociatedConceptsPreprocessor extends
processConceptSemanticValues(); processConceptSemanticValues();
//Also need to see if any broader or narrower uris for the concepts that already exist in the system //Also need to see if any broader or narrower uris for the concepts that already exist in the system
//and set up the appropriate relationships between this concept and the broader/narrower uri //and set up the appropriate relationships between this concept and the broader/narrower uri
getExistingConceptRelationships();
if (numberConcepts > 1) { if (numberConcepts > 1) {
processConceptNodes(numberConcepts); processConceptNodes(numberConcepts);
} }
@ -96,6 +109,8 @@ public class AddAssociatedConceptsPreprocessor extends
} }
//Since we will change the uris and literals from form, we should make copies //Since we will change the uris and literals from form, we should make copies
//of the original values and store them, this will also make iterations //of the original values and store them, this will also make iterations
//and updates to the submission independent from accessing the values //and updates to the submission independent from accessing the values
@ -103,11 +118,104 @@ public class AddAssociatedConceptsPreprocessor extends
conceptLabelValues = getConceptLabelValues(); conceptLabelValues = getConceptLabelValues();
conceptNodeValues = getConceptNodeValues(); conceptNodeValues = getConceptNodeValues();
conceptSourceValues = getConceptSourceValues(); conceptSourceValues = getConceptSourceValues();
conceptBroaderURIValues = getConceptBroaderURIValues();
conceptNarrowerURIValues = getConceptNarrowerURIValues();
log.debug("concept label values are " + conceptLabelValues); log.debug("concept label values are " + conceptLabelValues);
} }
//
//For broader and narrower relationships, we will be
//linking the concept to broader and narrower terms where those terms already
//exist in the system
//This method or approach may change later in which case this method should change
private void getExistingConceptRelationships() {
List<String> existingNarrowerURIs = getExistingNarrowerURIs(conceptNarrowerURIValues);
List<String> existingBroaderURIs = getExistingBroaderURIs(conceptBroaderURIValues);
//Now set the submission values to these, overwriting the original
Map<String, List<String>> urisFromForm = submission.getUrisFromForm();
if(existingNarrowerURIs.size() > 0) {
urisFromForm.put("conceptNarrowerURI", existingNarrowerURIs);
} else {
//The original code for submission wouldn't put in a key if the values were null or size 0
urisFromForm.remove("conceptNarrowerURI");
}
if(existingBroaderURIs.size() > 0) {
urisFromForm.put("conceptBroaderURI", existingBroaderURIs);
} else {
urisFromForm.remove("conceptBroaderURI");
}
}
//get the broader and narrower uri values that already exist in the system from the ones returned in the search
//and use those to populate relationships between the concept and other concepts already in the system
//We should also make sure to use bidirectional n3 so the graph has both sets of relationships represented
private List<String> getConceptNarrowerURIValues() {
Map<String, List<String>> urisFromForm = submission.getUrisFromForm();
List<String> narrowerURIs = urisFromForm.get("conceptNarrowerURI");
return narrowerURIs;
}
private List<String> getConceptBroaderURIValues() {
Map<String, List<String>> urisFromForm = submission.getUrisFromForm();
List<String> broaderURIs = urisFromForm.get("conceptBroaderURI");
return broaderURIs;
}
private List<String> getExistingBroaderURIs(List<String> broaderURIs) {
if(broaderURIs == null) {
return new ArrayList<String>();
}
List<String> existingBroaderURIs = this.getExistingURIs(broaderURIs);
return existingBroaderURIs;
}
private List<String> getExistingNarrowerURIs(List<String> narrowerURIs) {
if(narrowerURIs == null)
return new ArrayList<String>();
List<String> existingNarrowerURIs = this.getExistingURIs(narrowerURIs);
return existingNarrowerURIs;
}
//We need to keep the number of elements the same if there are any entries at all in the original
//So we will use an empty string or null
private List<String> getExistingURIs(List<String> uris) {
//Important to keep the same formatting as original, because a comma delimited string as an element in the array
//refers to a list of uris appropriate for a given concept, where each element in the array corresponds to a different
//concept
List<String> existingURIs = new ArrayList<String>();
for(String uri:uris) {
if(uri.indexOf(",") != -1) {
List<String> existingURISet = new ArrayList<String>();
String[] uriSet = uri.split(",");
for(String u: uriSet) {
if(u != null && !u.isEmpty() && this.wdf.hasExistingURI(u)) {
existingURISet.add(u);
}
}
//Now add the comma delimited version back to the array
if(existingURISet.size() > 0) {
existingURIs.add(StringUtils.join(existingURISet, ","));
} else {
//add empty string to indicate no value here
existingURIs.add("");
}
} else {
if(uri != null && !uri.isEmpty() && this.wdf.hasExistingURI(uri)) {
existingURIs.add(uri);
}
else
{
existingURIs.add("");
}
}
}
return existingURIs;
}
//Process the semantic type label and URI values for the concepts
private void processConceptSemanticValues() { private void processConceptSemanticValues() {
conceptSemanticTypeLabelValues = getConceptSemanticTypeLabelValues(); conceptSemanticTypeLabelValues = getConceptSemanticTypeLabelValues();
conceptSemanticTypeURIValues = getConceptSemanticTypeURIValues(); conceptSemanticTypeURIValues = getConceptSemanticTypeURIValues();
@ -183,10 +291,10 @@ public class AddAssociatedConceptsPreprocessor extends
addConceptSourceInputs(numberConcepts); addConceptSourceInputs(numberConcepts);
addConceptLabelInputs(numberConcepts); addConceptLabelInputs(numberConcepts);
//for concept semantic type labels and uris where they exist //for concept semantic type labels and uris where they exist
//TODO: Make into single method as URIs depend on labels
addConceptSemanticTypeLabelAndURIInputs(numberConcepts); addConceptSemanticTypeLabelAndURIInputs(numberConcepts);
//addConceptSemanticTypeURIInputs(numberConcepts); //For broader and narrower uris where they exist (this of course is in the case of multiple broader and narrower uris
addConceptBroaderURIInputs(numberConcepts);
addConceptNarrowerURIInputs(numberConcepts);
} }
private void addConceptNodeInputs(int numberConcepts) { private void addConceptNodeInputs(int numberConcepts) {
@ -301,28 +409,51 @@ public class AddAssociatedConceptsPreprocessor extends
String[] uriValuesArray = uriVals.toArray(new String[uriVals.size()]); String[] uriValuesArray = uriVals.toArray(new String[uriVals.size()]);
submission.addUriToForm(editConfiguration, uriInputName, uriValuesArray); submission.addUriToForm(editConfiguration, uriInputName, uriValuesArray);
} }
}
private void addConceptBroaderURIInputs(int numberConcepts) {
//the number of existing values may not match up, or at least existing populated ones int i;
/* //Add inputs based on if there are any broader uris to add
if(conceptSemanticTypeURIs != null && conceptSemanticTypeURIs.length == numberConcepts) { //Can't really compare number of existing broader uris to concepts
int i; //as each concept may or may not have a broader uri
if(this.conceptBroaderURIValues.size() > 0 && this.conceptBroaderURIValues.size() <= numberConcepts) {
for(i = 0; i < numberConcepts; i++) { for(i = 0; i < numberConcepts; i++) {
int suffix = i + 1; int suffix = i + 1;
String conceptInputName = conceptSemanticTypeURIBase + suffix; String conceptBroaderURIInputName = conceptBroaderURIBase + suffix;
String[] uriValues = new String[1]; String broaderURIs = this.conceptBroaderURIValues.get(i);
uriValues[0] = conceptSemanticTypeURIs[i]; if(broaderURIs != null && !broaderURIs.isEmpty()) {
//Add value for uri to form String[] broaderURISet = new String[1];
//TODO: Check if value is empty in which case don't add to submission if(broaderURIs.indexOf(",") != -1) {
submission.addUriToForm(editConfiguration, conceptInputName, uriValues); broaderURISet = broaderURIs.split(",");
} else {
broaderURISet[0] = broaderURIs;
}
//Add value for uri to form
submission.addUriToForm(editConfiguration, conceptBroaderURIInputName, broaderURISet);
}
} }
} else if(conceptSemanticTypeURIs != null && conceptSemanticTypeURIs.length != numberConcepts){
log.error("Number of concept nodes did not match the number of concepts to be added");
} else{
log.error("Concept nodes returned were null");
} }
*/ }
private void addConceptNarrowerURIInputs(int numberConcepts) {
int i;
if(this.conceptNarrowerURIValues.size() > 0 && this.conceptNarrowerURIValues.size() <= numberConcepts) {
for(i = 0; i < numberConcepts; i++) {
int suffix = i + 1;
String conceptNarrowerURIInputName = conceptNarrowerURIBase + suffix;
String narrowerURIs = this.conceptNarrowerURIValues.get(i);
if(narrowerURIs != null && !narrowerURIs.isEmpty()) {
String[] narrowerURISet = new String[1];
if(narrowerURIs.indexOf(",") != -1) {
narrowerURISet = narrowerURIs.split(",");
} else {
narrowerURISet[0] = narrowerURIs;
}
//Add value for uri to form
submission.addUriToForm(editConfiguration, conceptNarrowerURIInputName, narrowerURISet);
}
}
}
} }
//Fields //Fields
@ -340,7 +471,8 @@ public class AddAssociatedConceptsPreprocessor extends
String source = sourceBase + suffix; String source = sourceBase + suffix;
String conceptSemanticTypeLabel = conceptSemanticTypeLabelBase + suffix; String conceptSemanticTypeLabel = conceptSemanticTypeLabelBase + suffix;
String conceptSemanticTypeURI = this.getConceptSemanticTypeURIFieldName(conceptSemanticTypeLabel, suffix); String conceptSemanticTypeURI = this.getConceptSemanticTypeURIFieldName(conceptSemanticTypeLabel, suffix);
String conceptBroaderURI = conceptBroaderURIBase + suffix;
String conceptNarrowerURI = conceptNarrowerURIBase + suffix;
addConceptNodeField(conceptNode); addConceptNodeField(conceptNode);
addLabelField(label); addLabelField(label);
addSourceField(source); addSourceField(source);
@ -351,9 +483,15 @@ public class AddAssociatedConceptsPreprocessor extends
conceptSemanticTypeUris.add(conceptSemanticTypeURI); conceptSemanticTypeUris.add(conceptSemanticTypeURI);
addConceptSemanticTypeURIField(conceptSemanticTypeURI); addConceptSemanticTypeURIField(conceptSemanticTypeURI);
} }
//add fields for concept broader and narrower uris
addConceptBroaderURIField(conceptBroaderURI);
addConceptNarrowerURIField(conceptNarrowerURI);
} }
} }
private void addConceptNodeField(String conceptNode) { private void addConceptNodeField(String conceptNode) {
List<String> validators = new ArrayList<String>(); List<String> validators = new ArrayList<String>();
validators.add("nonempty"); validators.add("nonempty");
@ -394,6 +532,17 @@ public class AddAssociatedConceptsPreprocessor extends
} }
} }
private void addConceptNarrowerURIField(String conceptNarrowerURI) {
editConfiguration.addField(new FieldVTwo().
setName(conceptNarrowerURI));
}
private void addConceptBroaderURIField(String conceptBroaderURI) {
editConfiguration.addField(new FieldVTwo().
setName(conceptBroaderURI));
}
//original literals on form: label, uris on form: conceptNode and conceptSource //original literals on form: label, uris on form: conceptNode and conceptSource
//This will overwrite the original values in the edit configuration //This will overwrite the original values in the edit configuration
@ -412,12 +561,16 @@ public class AddAssociatedConceptsPreprocessor extends
String conceptSemanticTypeLabel = conceptSemanticTypeLabelBase + suffix; String conceptSemanticTypeLabel = conceptSemanticTypeLabelBase + suffix;
//String conceptSemanticTypeURI = conceptSemanticTypeURIBase + suffix; //String conceptSemanticTypeURI = conceptSemanticTypeURIBase + suffix;
String conceptSemanticTypeURI = this.getConceptSemanticTypeURIFieldName(conceptSemanticTypeLabel, suffix); String conceptSemanticTypeURI = this.getConceptSemanticTypeURIFieldName(conceptSemanticTypeLabel, suffix);
String conceptBroaderURI = conceptBroaderURIBase + suffix;
String conceptNarrowerURI = conceptNarrowerURIBase + suffix;
urisOnForm.add(conceptNode); urisOnForm.add(conceptNode);
urisOnForm.add(source); urisOnForm.add(source);
if(!conceptSemanticTypeURIs.contains(conceptSemanticTypeURI)) { if(!conceptSemanticTypeURIs.contains(conceptSemanticTypeURI)) {
conceptSemanticTypeURIs.add(conceptSemanticTypeURI); conceptSemanticTypeURIs.add(conceptSemanticTypeURI);
urisOnForm.add(conceptSemanticTypeURI); urisOnForm.add(conceptSemanticTypeURI);
} }
urisOnForm.add(conceptBroaderURI);
urisOnForm.add(conceptNarrowerURI);
literalsOnForm.add(label); literalsOnForm.add(label);
literalsOnForm.add(conceptSemanticTypeLabel); literalsOnForm.add(conceptSemanticTypeLabel);
} }
@ -456,10 +609,13 @@ public class AddAssociatedConceptsPreprocessor extends
String labelVar = "?" + labelBase; String labelVar = "?" + labelBase;
String sourceVar = "?" + sourceBase; String sourceVar = "?" + sourceBase;
String conceptSemanticTypeLabelVar = "?" + conceptSemanticTypeLabelBase; String conceptSemanticTypeLabelVar = "?" + conceptSemanticTypeLabelBase;
String conceptBroaderURIVar = "?" + conceptBroaderURIBase;
String conceptNarrowerURIVar = "?" + conceptNarrowerURIBase;
String prefixStr = "@prefix core: <http://vivoweb.org/ontology/core#> ."; String prefixStr = "@prefix core: <http://vivoweb.org/ontology/core#> .";
// First one already included so add new ones here // First one already included so add new ones here
//We already have a label var to uri var setup //We already have a label var to uri var setup
for (index = 1; index <= numberConcepts; index++) { for (index = 1; index <= numberConcepts; index++) {
//Set up the variables based on which concept node
int suffix = index; int suffix = index;
String node = nodeBase + suffix; String node = nodeBase + suffix;
String label = labelVar + suffix; String label = labelVar + suffix;
@ -467,7 +623,9 @@ public class AddAssociatedConceptsPreprocessor extends
String conceptSemanticTypeLabel = conceptSemanticTypeLabelVar + suffix; String conceptSemanticTypeLabel = conceptSemanticTypeLabelVar + suffix;
//get the URI appropriate for the concept semantic type label var //get the URI appropriate for the concept semantic type label var
String conceptSemanticTypeURI = getConceptSemanticTypeURIVar(conceptSemanticTypeLabelBase + suffix, suffix); String conceptSemanticTypeURI = getConceptSemanticTypeURIVar(conceptSemanticTypeLabelBase + suffix, suffix);
//onceptSemanticTypeURIVar + suffix; String conceptBroaderURI = conceptBroaderURIVar + suffix;
String conceptNarrowerURI = conceptNarrowerURIVar + suffix;
//Set up the n3 strings
String n3String = prefixStr; String n3String = prefixStr;
n3String += node + " <" + RDFS.label.getURI() + "> " + label + " .\n" + n3String += node + " <" + RDFS.label.getURI() + "> " + label + " .\n" +
node + " <" + RDFS.isDefinedBy.getURI() + "> " + source + " ."; node + " <" + RDFS.isDefinedBy.getURI() + "> " + source + " .";
@ -475,10 +633,17 @@ public class AddAssociatedConceptsPreprocessor extends
n3ConceptTypeString += node + " <" + RDF.type.getURI() + "> " + conceptSemanticTypeURI + " ." + n3ConceptTypeString += node + " <" + RDF.type.getURI() + "> " + conceptSemanticTypeURI + " ." +
conceptSemanticTypeURI + " <" + RDFS.label.getURI() + "> " + conceptSemanticTypeLabel + " .\n" + conceptSemanticTypeURI + " <" + RDFS.label.getURI() + "> " + conceptSemanticTypeLabel + " .\n" +
conceptSemanticTypeURI + " <" + RDFS.subClassOf.getURI() + "> <http://www.w3.org/2004/02/skos/core#Concept> .\n" ; conceptSemanticTypeURI + " <" + RDFS.subClassOf.getURI() + "> <http://www.w3.org/2004/02/skos/core#Concept> .\n" ;
//String representing the broader and narrower uri(s) for each of the concepts - these may or may not exist
String n3ConceptBroaderURI = prefixStr + node + " <" + this.SKOSNarrowerURI + "> " + conceptNarrowerURI + " ." +
conceptNarrowerURI + " <" + this.SKOSBroaderURI + "> " + node + " .";
String n3ConceptNarrowerURI = prefixStr + node + " <" + this.SKOSBroaderURI + "> " + conceptBroaderURI + " ." +
conceptBroaderURI + " <" + this.SKOSNarrowerURI + "> " + node + " .";
n3Optional.add(n3String); n3Optional.add(n3String);
//adding separately so their resolution does not depend on each other //adding separately so their resolution does not depend on each other
n3Optional.add(n3ConceptTypeString); n3Optional.add(n3ConceptTypeString);
n3Optional.add(n3ConceptBroaderURI);
n3Optional.add(n3ConceptNarrowerURI);
} }
//Already have n3 required so need to add to that //Already have n3 required so need to add to that
@ -536,86 +701,93 @@ public class AddAssociatedConceptsPreprocessor extends
private String getConceptSemanticTypeLabelValues() { private String getConceptSemanticTypeLabelValues() {
Map<String, List<Literal>> literalsFromForm = submission.getLiteralsFromForm(); Map<String, List<Literal>> literalsFromForm = submission.getLiteralsFromForm();
Map<String, List<String>> transformed = EditConfigurationUtils.transformLiteralMap(literalsFromForm); Map<String, List<String>> transformed = EditConfigurationUtils.transformLiteralMap(literalsFromForm);
return (String) getFirstElement(transformed.get("conceptSemanticTypeLabel")); String label = (String) getFirstElement(transformed.get("conceptSemanticTypeLabel"));
if(label == null) {
label = "";
}
return label;
} }
//This will either generate or retrieve URIs for the concept semantic type labels if they exist //This will either generate or retrieve URIs for the concept semantic type labels if they exist
//We will then update the submission to include this //We will then update the submission to include this
private String getConceptSemanticTypeURIValues() { private String getConceptSemanticTypeURIValues() {
String[] conceptSemanticTypeLabels = convertDelimitedStringToArray(conceptSemanticTypeLabelValues);
//keep track of what label values already exist and to which label variables they map
HashMap<String, List<Integer>> labelValueToVarSuffix = new HashMap<String, List<Integer>>();
int numberLabels = conceptSemanticTypeLabels.length;
String pseudoInputString = ""; String pseudoInputString = "";
if(conceptSemanticTypeLabelValues != null && !conceptSemanticTypeLabelValues.isEmpty()) {
String[] conceptSemanticTypeLabels = convertDelimitedStringToArray(conceptSemanticTypeLabelValues);
//keep track of what label values already exist and to which label variables they map
HashMap<String, List<Integer>> labelValueToVarSuffix = new HashMap<String, List<Integer>>();
int numberLabels = conceptSemanticTypeLabels.length;
//The rest of this code is really only relevant for multiple values, so we could break out the old code above //The rest of this code is really only relevant for multiple values, so we could break out the old code above
//as we don't need to set up hashes etc. if there is only one concept node being added //as we don't need to set up hashes etc. if there is only one concept node being added
if(numberLabels == 1) { if(numberLabels == 1) {
String label = conceptSemanticTypeLabels[0]; String label = conceptSemanticTypeLabels[0];
String uri = getURIForSemanticTypeLabel(label);
if(uri != "") {
String[] urisToAdd = new String[1];
urisToAdd[0] = uri;
pseudoInputString = uri;
log.debug("uris to add" + uri);
submission.addUriToForm(this.editConfiguration, "conceptSemanticTypeURI", urisToAdd);
}
}
//if there is more than one concept node, we may have duplicate semantic types
//which will need to be referred to by the same semantic type uri
else if (numberLabels > 1){
for(int i = 0; i < numberLabels; i++) {
int suffix = i + 1;
String label = conceptSemanticTypeLabels[i];
String labelVar = this.conceptSemanticTypeLabelBase + suffix;
//if label has not already been encountered, create entry for label value
//and list with the label variables that would refer to it
//for unique values, the uri variable will be the same as label
Integer thisSuffix = new Integer(suffix);
if(!labelValueToVarSuffix.containsKey(label)) {
labelValueToVarSuffix.put(label, new ArrayList<Integer>());
//Add suffix to list if not already there
labelValueToVarSuffix.get(label).add(thisSuffix);
} else {
//in this case, the label already exists, get the very first element in the list
//and use that as the uri variable
List<Integer> suffixList = labelValueToVarSuffix.get(label);
if(suffixList != null && suffixList.size() > 0) {
thisSuffix = suffixList.get(0);
}
}
//Now add the uri var to the hash mapping label variable to uri variable
String uriVar = this.conceptSemanticTypeURIBase + thisSuffix.intValue();
this.labelVarToUriVarHash.put(labelVar, uriVar);
//Make or retrieve URI for this label
//TODO: Do we create this string with empty inputs ?
String uri = getURIForSemanticTypeLabel(label); String uri = getURIForSemanticTypeLabel(label);
if(uri != "") { if(uri != "") {
//uri var shouldn't be repeated? String[] urisToAdd = new String[1];
if(!this.conceptSemanticTypeURIVarToValueMap.containsKey(uriVar)) { urisToAdd[0] = uri;
this.conceptSemanticTypeURIVarToValueMap.put(uriVar, new ArrayList<String>()); pseudoInputString = uri;
this.conceptSemanticTypeURIVarToValueMap.get(uriVar).add(uri); log.debug("uris to add" + uri);
} submission.addUriToForm(this.editConfiguration, "conceptSemanticTypeURI", urisToAdd);
} }
if(i != 0) {
pseudoInputString += ",";
}
pseudoInputString += uri;
} }
//if there is more than one concept node, we may have duplicate semantic types
//which will need to be referred to by the same semantic type uri
else if (numberLabels > 1){
//Add this string to the uris for the form for(int i = 0; i < numberLabels; i++) {
String[] urisToAdd = new String[1]; int suffix = i + 1;
urisToAdd[0] = pseudoInputString; String label = conceptSemanticTypeLabels[i];
log.debug("uris to add" + pseudoInputString); String labelVar = this.conceptSemanticTypeLabelBase + suffix;
submission.addUriToForm(this.editConfiguration, "conceptSemanticTypeURI", urisToAdd); //if label has not already been encountered, create entry for label value
//and list with the label variables that would refer to it
//for unique values, the uri variable will be the same as label
Integer thisSuffix = new Integer(suffix);
if(!labelValueToVarSuffix.containsKey(label)) {
labelValueToVarSuffix.put(label, new ArrayList<Integer>());
//Add suffix to list if not already there
labelValueToVarSuffix.get(label).add(thisSuffix);
} else {
//in this case, the label already exists, get the very first element in the list
//and use that as the uri variable
List<Integer> suffixList = labelValueToVarSuffix.get(label);
if(suffixList != null && suffixList.size() > 0) {
thisSuffix = suffixList.get(0);
}
}
//Now add the uri var to the hash mapping label variable to uri variable
String uriVar = this.conceptSemanticTypeURIBase + thisSuffix.intValue();
this.labelVarToUriVarHash.put(labelVar, uriVar);
//Make or retrieve URI for this label
//TODO: Do we create this string with empty inputs ?
String uri = getURIForSemanticTypeLabel(label);
if(uri != "") {
//uri var shouldn't be repeated?
if(!this.conceptSemanticTypeURIVarToValueMap.containsKey(uriVar)) {
this.conceptSemanticTypeURIVarToValueMap.put(uriVar, new ArrayList<String>());
this.conceptSemanticTypeURIVarToValueMap.get(uriVar).add(uri);
}
}
if(i != 0) {
pseudoInputString += ",";
}
pseudoInputString += uri;
}
//Add this string to the uris for the form
String[] urisToAdd = new String[1];
urisToAdd[0] = pseudoInputString;
log.debug("uris to add" + pseudoInputString);
submission.addUriToForm(this.editConfiguration, "conceptSemanticTypeURI", urisToAdd);
}
} }
return pseudoInputString; return pseudoInputString;
} }

View file

@ -23,6 +23,7 @@ public class ConceptSearchServiceUtils {
private static final String UMLSVocabSource = "http://link.informatics.stonybrook.edu/umls"; private static final String UMLSVocabSource = "http://link.informatics.stonybrook.edu/umls";
private static final String AgrovocVocabSource = "http://aims.fao.org/aos/agrovoc/agrovocScheme"; private static final String AgrovocVocabSource = "http://aims.fao.org/aos/agrovoc/agrovocScheme";
private static final String GemetVocabSource = "http://www.eionet.europa.eu/gemet/gemetThesaurus"; private static final String GemetVocabSource = "http://www.eionet.europa.eu/gemet/gemetThesaurus";
private static final String LCSHVocabSource = "http://id.loc.gov/authorities/subjects";
//Get the class that corresponds to the appropriate search //Get the class that corresponds to the appropriate search
public static String getConceptSearchServiceClassName(String searchServiceName) { public static String getConceptSearchServiceClassName(String searchServiceName) {
@ -41,6 +42,8 @@ public class ConceptSearchServiceUtils {
//Commenting out agrovoc for now until implementation is updated //Commenting out agrovoc for now until implementation is updated
map.put(AgrovocVocabSource, new VocabSourceDescription("AGROVOC", AgrovocVocabSource, "http://www.fao.org/agrovoc/", "Agricultural Vocabulary")); map.put(AgrovocVocabSource, new VocabSourceDescription("AGROVOC", AgrovocVocabSource, "http://www.fao.org/agrovoc/", "Agricultural Vocabulary"));
map.put(GemetVocabSource, new VocabSourceDescription("GEMET", GemetVocabSource, "http://www.eionet.europa.eu/gemet", "GEneral Multilingual Environmental Thesaurus")); map.put(GemetVocabSource, new VocabSourceDescription("GEMET", GemetVocabSource, "http://www.eionet.europa.eu/gemet", "GEneral Multilingual Environmental Thesaurus"));
map.put(LCSHVocabSource, new VocabSourceDescription("LCSH", LCSHVocabSource, "http://id.loc.gov/authorities/subjects/", "Library of Congress Subject Headings"));
return map; return map;
} }
@ -53,6 +56,8 @@ public class ConceptSearchServiceUtils {
map.put(UMLSVocabSource, "edu.cornell.mannlib.semservices.service.impl.UMLSService"); map.put(UMLSVocabSource, "edu.cornell.mannlib.semservices.service.impl.UMLSService");
map.put(AgrovocVocabSource, "edu.cornell.mannlib.semservices.service.impl.AgrovocService"); map.put(AgrovocVocabSource, "edu.cornell.mannlib.semservices.service.impl.AgrovocService");
map.put(GemetVocabSource, "edu.cornell.mannlib.semservices.service.impl.GemetService"); map.put(GemetVocabSource, "edu.cornell.mannlib.semservices.service.impl.GemetService");
map.put(LCSHVocabSource, "edu.cornell.mannlib.semservices.service.impl.LCSHService");
return map; return map;
} }

View file

@ -692,6 +692,7 @@ or_add_new_one = or add a new one.
vocabulary_service_unavailable = The vocabulary service is unavailable. Please try again later. vocabulary_service_unavailable = The vocabulary service is unavailable. Please try again later.
no_serch_results_found = No search results were found. no_serch_results_found = No search results were found.
label_type = Label (Type) label_type = Label (Type)
label_altLabels = Label (Alternate Labels)
definition_capitalized = Definition definition_capitalized = Definition
best_match = Best Match best_match = Best Match
select_term_from_results = Please select at least one term from the search search results. select_term_from_results = Please select at least one term from the search search results.