Merge pull request #232 from brianjlowe/issue/VIVO-1983

[VIVO-1983] Limit label management values to current locale
This commit is contained in:
Georgy Litvinov 2021-06-17 23:33:44 +02:00 committed by GitHub
commit 9565fbd925
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 146 additions and 89 deletions

View file

@ -11,28 +11,29 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet; import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.LocaleUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.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;
import org.apache.jena.query.QuerySolution; import org.apache.jena.query.QuerySolution;
import org.apache.jena.query.ResultSet; import org.apache.jena.query.ResultSet;
import org.apache.jena.rdf.model.Literal; import org.apache.jena.rdf.model.Literal;
import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ExceptionResponseValues; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ExceptionResponseValues;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
import edu.cornell.mannlib.vitro.webapp.dao.jena.QueryUtils; import edu.cornell.mannlib.vitro.webapp.dao.jena.QueryUtils;
import edu.cornell.mannlib.vitro.webapp.i18n.selection.SelectedLocale; import edu.cornell.mannlib.vitro.webapp.i18n.selection.SelectedLocale;
import edu.cornell.mannlib.vitro.webapp.rdfservice.filter.LanguageFilteringUtils;
/*Servlet to view all labels in various languages for individual*/ /*Servlet to view all labels in various languages for individual*/
@ -47,12 +48,13 @@ public class ViewLabelsServlet extends FreemarkerHttpServlet{
String subjectUri = vreq.getParameter("subjectUri"); String subjectUri = vreq.getParameter("subjectUri");
body.put("subjectUri", subjectUri); body.put("subjectUri", subjectUri);
try { try {
//Get all language codes/labels in the system, and this list is sorted by language name
List<HashMap<String, String>> locales = this.getLocales(vreq);
//Get code to label hashmap - we use this to get the language name for the language code returned in the rdf literal
HashMap<String, String> localeCodeToNameMap = this.getFullCodeToLanguageNameMap(locales);
//the labels already added by the user //the labels already added by the user
ArrayList<Literal> existingLabels = this.getExistingLabels(subjectUri, vreq); ArrayList<Literal> existingLabels = this.getExistingLabels(subjectUri, vreq);
//Get all language codes/labels used in the list of existing labels
List<HashMap<String, String>> locales = this.getLocales(vreq, existingLabels);
//Get code to label hashmap - we use this to get the language name for the language code returned in the rdf literal
HashMap<String, String> localeCodeToNameMap = this.getFullCodeToLanguageNameMap(locales);
//existing labels keyed by language name and each of the list of labels is sorted by language name //existing labels keyed by language name and each of the list of labels is sorted by language name
HashMap<String, List<LabelInformation>> existingLabelsByLanguageName = this.getLabelsSortedByLanguageName(existingLabels, localeCodeToNameMap, vreq, subjectUri); HashMap<String, List<LabelInformation>> existingLabelsByLanguageName = this.getLabelsSortedByLanguageName(existingLabels, localeCodeToNameMap, vreq, subjectUri);
//Get available locales for the drop down for adding a new label, also sorted by language name //Get available locales for the drop down for adding a new label, also sorted by language name
@ -137,20 +139,26 @@ public class ViewLabelsServlet extends FreemarkerHttpServlet{
doGet(request, response); doGet(request, response);
} }
//get locales //get locales present in list of literals
public List<HashMap<String, String>> getLocales(VitroRequest vreq) { public List<HashMap<String, String>> getLocales(VitroRequest vreq,
List<Locale> selectables = SelectedLocale.getSelectableLocales(vreq); List<Literal> existingLiterals) {
if (selectables.isEmpty()) { Set<Locale> locales = new HashSet<Locale>();
for(Literal literal : existingLiterals) {
String language = literal.getLanguage();
if(!StringUtils.isEmpty(language)) {
locales.add(LanguageFilteringUtils.languageToLocale(language));
}
}
if (locales.isEmpty()) {
return Collections.emptyList(); return Collections.emptyList();
} }
List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>(); List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
Locale currentLocale = SelectedLocale.getCurrentLocale(vreq); Locale currentLocale = SelectedLocale.getCurrentLocale(vreq);
for (Locale locale : selectables) { for (Locale locale : locales) {
try { try {
list.add(buildLocaleMap(locale, currentLocale)); list.add(buildLocaleMap(locale, currentLocale));
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
log.warn("Can't show the Locale selector for '" + locale log.warn("Can't show locale '" + locale + "': " + e);
+ "': " + e);
} }
} }
@ -188,8 +196,8 @@ public class ViewLabelsServlet extends FreemarkerHttpServlet{
ArrayList<Literal> labels = new ArrayList<Literal>(); ArrayList<Literal> labels = new ArrayList<Literal>();
try { try {
//We want to get the labels for all the languages, not just the display language // Show only labels with current language filtering
ResultSet results = QueryUtils.getLanguageNeutralQueryResults(queryStr, vreq); ResultSet results = QueryUtils.getQueryResults(queryStr, vreq);
while (results.hasNext()) { while (results.hasNext()) {
QuerySolution soln = results.nextSolution(); QuerySolution soln = results.nextSolution();
Literal nodeLiteral = soln.get("label").asLiteral(); Literal nodeLiteral = soln.get("label").asLiteral();

View file

@ -6,14 +6,13 @@ import java.io.IOException;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.apache.jena.rdf.model.RDFNode;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.IndividualTemplateModelBuilder;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.jena.query.QuerySolution; import org.apache.jena.query.QuerySolution;
import org.apache.jena.query.ResultSet; import org.apache.jena.query.ResultSet;
@ -36,6 +35,7 @@ import edu.cornell.mannlib.vitro.webapp.i18n.selection.SelectedLocale;
import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.ExecuteDataRetrieval; import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.ExecuteDataRetrieval;
import edu.cornell.mannlib.vitro.webapp.web.beanswrappers.ReadOnlyBeansWrapper; import edu.cornell.mannlib.vitro.webapp.web.beanswrappers.ReadOnlyBeansWrapper;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.IndividualTemplateModel; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.IndividualTemplateModel;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.IndividualTemplateModelBuilder;
import edu.ucsf.vitro.opensocial.OpenSocialManager; import edu.ucsf.vitro.opensocial.OpenSocialManager;
import freemarker.ext.beans.BeansWrapper; import freemarker.ext.beans.BeansWrapper;
import freemarker.template.TemplateModel; import freemarker.template.TemplateModel;
@ -123,8 +123,10 @@ class IndividualResponseBuilder {
* into the data model: no real data can be modified. * into the data model: no real data can be modified.
*/ */
// body.put("individual", wrap(itm, BeansWrapper.EXPOSE_SAFE)); // body.put("individual", wrap(itm, BeansWrapper.EXPOSE_SAFE));
body.put("labelCount", getLabelCount(itm.getUri(), vreq)); LabelAndLanguageCount labelAndLanguageCount = getLabelAndLanguageCount(
body.put("languageCount", getLanguagesRepresentedCount(itm.getUri(), vreq)); itm.getUri(), vreq);
body.put("labelCount", labelAndLanguageCount.getLabelCount());
body.put("languageCount", labelAndLanguageCount.getLanguageCount());
//We also need to know the number of available locales //We also need to know the number of available locales
body.put("localesCount", SelectedLocale.getSelectableLocales(vreq).size()); body.put("localesCount", SelectedLocale.getSelectableLocales(vreq).size());
body.put("profileType", getProfileType(itm.getUri(), vreq)); body.put("profileType", getProfileType(itm.getUri(), vreq));
@ -282,61 +284,103 @@ class IndividualResponseBuilder {
return map; return map;
} }
private static String LABEL_COUNT_QUERY = "" private static String LABEL_QUERY = ""
+ "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n" + "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n"
+ "SELECT ( str(COUNT(?label)) AS ?labelCount ) WHERE { \n" + "SELECT ?label WHERE { \n"
+ " ?subject rdfs:label ?label \n" + " ?subject rdfs:label ?label \n"
+ " FILTER isLiteral(?label) \n" + " FILTER isLiteral(?label) \n"
+ "}" ; + "}" ;
private static String DISTINCT_LANGUAGE_QUERY = "" // Queries that were previously used for counts via RDFService that didn't
+ "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n" // filter results by language. With language filtering, aggregate
+ "SELECT ( str(COUNT(DISTINCT lang(?label))) AS ?languageCount ) WHERE { \n" // functions like COUNT() cannot be used.
+ " ?subject rdfs:label ?label \n"
+ " FILTER isLiteral(?label) \n"
+ "}" ;
private static Integer getLabelCount(String subjectUri, VitroRequest vreq) { // private static String LABEL_COUNT_QUERY = ""
String queryStr = QueryUtils.subUriForQueryVar(LABEL_COUNT_QUERY, "subject", subjectUri); // + "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n"
// + "SELECT ( str(COUNT(?label)) AS ?labelCount ) WHERE { \n"
// + " ?subject rdfs:label ?label \n"
// + " FILTER isLiteral(?label) \n"
// + "}" ;
// private static String DISTINCT_LANGUAGE_QUERY = ""
// + "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n"
// + "SELECT ( str(COUNT(DISTINCT lang(?label))) AS ?languageCount ) WHERE { \n"
// + " ?subject rdfs:label ?label \n"
// + " FILTER isLiteral(?label) \n"
// + "}" ;
private static LabelAndLanguageCount getLabelAndLanguageCount(
String subjectUri, VitroRequest vreq) {
// 1.12.0 Now filtering to only the labels for the current locale so as
// to be consistent with other editing forms. Because the language
// filter can only act on a result set containing actual literals,
// we can't do the counting with a COUNT() in the query itself. So
// we will now use the LABEL_QUERY instead of LABEL_COUNT_QUERY and
// count the rows and the number of distinct languages represented.
Set<String> distinctLanguages = new HashSet<String>();
String queryStr = QueryUtils.subUriForQueryVar(LABEL_QUERY, "subject", subjectUri);
log.debug("queryStr = " + queryStr); log.debug("queryStr = " + queryStr);
int theCount = 0; int labelCount = 0;
try { try {
//ResultSet results = QueryUtils.getQueryResults(queryStr, vreq); ResultSet results = QueryUtils.getQueryResults(queryStr, vreq);
//Get query results across all languages in order for template to show manage labels link correctly while(results.hasNext()) {
ResultSet results = QueryUtils.getLanguageNeutralQueryResults(queryStr, vreq); QuerySolution qsoln = results.next();
if (results.hasNext()) { labelCount++;
QuerySolution soln = results.nextSolution(); String lang = qsoln.getLiteral("label").getLanguage();
RDFNode labelCount = soln.get("labelCount"); if(lang == null) {
if (labelCount != null && labelCount.isLiteral()) { lang = "";
theCount = labelCount.asLiteral().getInt();
} }
distinctLanguages.add(lang);
} }
} catch (Exception e) { } catch (Exception e) {
log.error(e, e); log.error(e, e);
} }
return theCount; return new LabelAndLanguageCount(labelCount, distinctLanguages.size());
}
private static class LabelAndLanguageCount {
private Integer labelCount;
private Integer languageCount;
public LabelAndLanguageCount(Integer labelCount, Integer languageCount) {
this.labelCount = labelCount;
this.languageCount = languageCount;
}
public Integer getLabelCount() {
return this.labelCount;
}
public Integer getLanguageCount() {
return this.languageCount;
}
} }
//what is the number of languages represented across the labels //what is the number of languages represented across the labels
private static Integer getLanguagesRepresentedCount(String subjectUri, VitroRequest vreq) { // This version not compatible with language-filtering RDF services
String queryStr = QueryUtils.subUriForQueryVar(DISTINCT_LANGUAGE_QUERY, "subject", subjectUri); // private static Integer getLanguagesRepresentedCount(String subjectUri, VitroRequest vreq) {
log.debug("queryStr = " + queryStr); // String queryStr = QueryUtils.subUriForQueryVar(DISTINCT_LANGUAGE_QUERY, "subject", subjectUri);
int theCount = 0; // log.debug("queryStr = " + queryStr);
try { // int theCount = 0;
// try {
ResultSet results = QueryUtils.getLanguageNeutralQueryResults(queryStr, vreq); //
if (results.hasNext()) { // ResultSet results = QueryUtils.getLanguageNeutralQueryResults(queryStr, vreq);
QuerySolution soln = results.nextSolution(); // if (results.hasNext()) {
RDFNode languageCount = soln.get("languageCount"); // QuerySolution soln = results.nextSolution();
if (languageCount != null && languageCount.isLiteral()) { // RDFNode languageCount = soln.get("languageCount");
theCount = languageCount.asLiteral().getInt(); // if (languageCount != null && languageCount.isLiteral()) {
} // theCount = languageCount.asLiteral().getInt();
} // log.info("Language count is " + theCount);
} catch (Exception e) { // }
log.error(e, e); // }
} // } catch (Exception e) {
return theCount; // log.error(e, e);
} // }
// log.info("Returning language count " + theCount);
// return theCount;
// }
private static String PROFILE_TYPE_QUERY = "" private static String PROFILE_TYPE_QUERY = ""
+ "PREFIX display: <http://vitro.mannlib.cornell.edu/ontologies/display/1.1#> \n" + "PREFIX display: <http://vitro.mannlib.cornell.edu/ontologies/display/1.1#> \n"

View file

@ -15,6 +15,7 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
@ -41,6 +42,7 @@ import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.FieldVTwo;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.FoafNameToRdfsLabelPreprocessor; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.FoafNameToRdfsLabelPreprocessor;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.ManageLabelsForIndividualPreprocessor; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.ManageLabelsForIndividualPreprocessor;
import edu.cornell.mannlib.vitro.webapp.i18n.selection.SelectedLocale; import edu.cornell.mannlib.vitro.webapp.i18n.selection.SelectedLocale;
import edu.cornell.mannlib.vitro.webapp.rdfservice.filter.LanguageFilteringUtils;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.DataPropertyStatementTemplateModel; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.DataPropertyStatementTemplateModel;
/** /**
@ -202,12 +204,12 @@ public class ManageLabelsForIndividualGenerator extends BaseEditConfigurationGen
private void addFormSpecificData(EditConfigurationVTwo config, private void addFormSpecificData(EditConfigurationVTwo config,
VitroRequest vreq) { VitroRequest vreq) {
//Get all language codes/labels in the system, and this list is sorted by language name
List<HashMap<String, String>> locales = this.getLocales(vreq);
//Get code to label hashmap - we use this to get the language name for the language code returned in the rdf literal
HashMap<String, String> localeCodeToNameMap = this.getFullCodeToLanguageNameMap(locales);
//the labels already added by the user //the labels already added by the user
ArrayList<Literal> existingLabels = this.getExistingLabels(config.getSubjectUri(), vreq); ArrayList<Literal> existingLabels = this.getExistingLabels(config.getSubjectUri(), vreq);
//Get language codes/labels for languages present in the existing labels
List<HashMap<String, String>> locales = this.getLocales(vreq, existingLabels);
//Get code to label hashmap - we use this to get the language name for the language code returned in the rdf literal
HashMap<String, String> localeCodeToNameMap = this.getFullCodeToLanguageNameMap(locales);
int numberExistingLabels = existingLabels.size(); int numberExistingLabels = existingLabels.size();
//existing labels keyed by language name and each of the list of labels is sorted by language name //existing labels keyed by language name and each of the list of labels is sorted by language name
HashMap<String, List<LabelInformation>> existingLabelsByLanguageName = this.getLabelsSortedByLanguageName(existingLabels, localeCodeToNameMap, config, vreq); HashMap<String, List<LabelInformation>> existingLabelsByLanguageName = this.getLabelsSortedByLanguageName(existingLabels, localeCodeToNameMap, config, vreq);
@ -373,8 +375,9 @@ public class ManageLabelsForIndividualGenerator extends BaseEditConfigurationGen
ArrayList<Literal> labels = new ArrayList<Literal>(); ArrayList<Literal> labels = new ArrayList<Literal>();
try { try {
//We want to get the labels for all the languages, not just the display language // Get results filtered to current locale so as to be consistent
ResultSet results = QueryUtils.getLanguageNeutralQueryResults(queryStr, vreq); // with other editing forms.
ResultSet results = QueryUtils.getQueryResults(queryStr, vreq);
while (results.hasNext()) { while (results.hasNext()) {
QuerySolution soln = results.nextSolution(); QuerySolution soln = results.nextSolution();
Literal nodeLiteral = soln.get("label").asLiteral(); Literal nodeLiteral = soln.get("label").asLiteral();
@ -401,30 +404,32 @@ public class ManageLabelsForIndividualGenerator extends BaseEditConfigurationGen
return template; return template;
} }
//get locales present in list of literals
public List<HashMap<String, String>> getLocales(VitroRequest vreq,
//get locales List<Literal> existingLiterals) {
public List<HashMap<String, String>> getLocales(VitroRequest vreq) { Set<Locale> locales = new HashSet<Locale>();
List<Locale> selectables = SelectedLocale.getSelectableLocales(vreq); for(Literal literal : existingLiterals) {
if (selectables.isEmpty()) { String language = literal.getLanguage();
if(!StringUtils.isEmpty(language)) {
locales.add(LanguageFilteringUtils.languageToLocale(language));
}
}
if (locales.isEmpty()) {
return Collections.emptyList(); return Collections.emptyList();
} }
List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>(); List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
Locale currentLocale = SelectedLocale.getCurrentLocale(vreq); Locale currentLocale = SelectedLocale.getCurrentLocale(vreq);
for (Locale locale : selectables) { for (Locale locale : locales) {
try { try {
list.add(buildLocaleMap(locale, currentLocale)); list.add(buildLocaleMap(locale, currentLocale));
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
log.warn("Can't show the Locale selector for '" + locale log.warn("Can't show locale '" + locale + "': " + e);
+ "': " + e);
} }
} }
return list; return list;
} }
public HashMap<String, String> getFullCodeToLanguageNameMap(List<HashMap<String, String>> localesList) { public HashMap<String, String> getFullCodeToLanguageNameMap(List<HashMap<String, String>> localesList) {
HashMap<String, String> codeToLanguageMap = new HashMap<String, String>(); HashMap<String, String> codeToLanguageMap = new HashMap<String, String>();
for(Map<String, String> locale: localesList) { for(Map<String, String> locale: localesList) {