diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ViewLabelsServlet.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ViewLabelsServlet.java index 1425b10f7..f68db8d56 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ViewLabelsServlet.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ViewLabelsServlet.java @@ -11,28 +11,29 @@ import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.commons.lang3.LocaleUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.apache.jena.query.QuerySolution; import org.apache.jena.query.ResultSet; import org.apache.jena.rdf.model.Literal; import edu.cornell.mannlib.vitro.webapp.beans.Individual; 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.ResponseValues; 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.i18n.selection.SelectedLocale; +import edu.cornell.mannlib.vitro.webapp.rdfservice.filter.LanguageFilteringUtils; /*Servlet to view all labels in various languages for individual*/ @@ -47,12 +48,13 @@ public class ViewLabelsServlet extends FreemarkerHttpServlet{ String subjectUri = vreq.getParameter("subjectUri"); body.put("subjectUri", subjectUri); try { - //Get all language codes/labels in the system, and this list is sorted by language name - List> locales = this.getLocales(vreq); + //the labels already added by the user + ArrayList existingLabels = this.getExistingLabels(subjectUri, vreq); + //Get all language codes/labels used in the list of existing labels + List> 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 localeCodeToNameMap = this.getFullCodeToLanguageNameMap(locales); - //the labels already added by the user - ArrayList existingLabels = this.getExistingLabels(subjectUri, vreq); + //existing labels keyed by language name and each of the list of labels is sorted by language name HashMap> existingLabelsByLanguageName = this.getLabelsSortedByLanguageName(existingLabels, localeCodeToNameMap, vreq, subjectUri); //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); } - //get locales - public List> getLocales(VitroRequest vreq) { - List selectables = SelectedLocale.getSelectableLocales(vreq); - if (selectables.isEmpty()) { + //get locales present in list of literals + public List> getLocales(VitroRequest vreq, + List existingLiterals) { + Set locales = new HashSet(); + for(Literal literal : existingLiterals) { + String language = literal.getLanguage(); + if(!StringUtils.isEmpty(language)) { + locales.add(LanguageFilteringUtils.languageToLocale(language)); + } + } + if (locales.isEmpty()) { return Collections.emptyList(); } List> list = new ArrayList>(); Locale currentLocale = SelectedLocale.getCurrentLocale(vreq); - for (Locale locale : selectables) { + for (Locale locale : locales) { try { list.add(buildLocaleMap(locale, currentLocale)); } catch (FileNotFoundException e) { - log.warn("Can't show the Locale selector for '" + locale - + "': " + e); + log.warn("Can't show locale '" + locale + "': " + e); } } @@ -188,8 +196,8 @@ public class ViewLabelsServlet extends FreemarkerHttpServlet{ ArrayList labels = new ArrayList(); try { - //We want to get the labels for all the languages, not just the display language - ResultSet results = QueryUtils.getLanguageNeutralQueryResults(queryStr, vreq); + // Show only labels with current language filtering + ResultSet results = QueryUtils.getQueryResults(queryStr, vreq); while (results.hasNext()) { QuerySolution soln = results.nextSolution(); Literal nodeLiteral = soln.get("label").asLiteral(); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualResponseBuilder.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualResponseBuilder.java index c89119f5a..0f7154c88 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualResponseBuilder.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualResponseBuilder.java @@ -6,14 +6,13 @@ import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; 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.LogFactory; - import org.apache.jena.query.QuerySolution; 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.web.beanswrappers.ReadOnlyBeansWrapper; 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 freemarker.ext.beans.BeansWrapper; import freemarker.template.TemplateModel; @@ -123,8 +123,10 @@ class IndividualResponseBuilder { * into the data model: no real data can be modified. */ // body.put("individual", wrap(itm, BeansWrapper.EXPOSE_SAFE)); - body.put("labelCount", getLabelCount(itm.getUri(), vreq)); - body.put("languageCount", getLanguagesRepresentedCount(itm.getUri(), vreq)); + LabelAndLanguageCount labelAndLanguageCount = getLabelAndLanguageCount( + itm.getUri(), vreq); + body.put("labelCount", labelAndLanguageCount.getLabelCount()); + body.put("languageCount", labelAndLanguageCount.getLanguageCount()); //We also need to know the number of available locales body.put("localesCount", SelectedLocale.getSelectableLocales(vreq).size()); body.put("profileType", getProfileType(itm.getUri(), vreq)); @@ -282,61 +284,103 @@ class IndividualResponseBuilder { return map; } - private static String LABEL_COUNT_QUERY = "" - + "PREFIX rdfs: \n" - + "SELECT ( str(COUNT(?label)) AS ?labelCount ) WHERE { \n" - + " ?subject rdfs:label ?label \n" - + " FILTER isLiteral(?label) \n" - + "}" ; - - private static String DISTINCT_LANGUAGE_QUERY = "" + private static String LABEL_QUERY = "" + "PREFIX rdfs: \n" - + "SELECT ( str(COUNT(DISTINCT lang(?label))) AS ?languageCount ) WHERE { \n" + + "SELECT ?label WHERE { \n" + " ?subject rdfs:label ?label \n" + " FILTER isLiteral(?label) \n" + "}" ; + +// Queries that were previously used for counts via RDFService that didn't +// filter results by language. With language filtering, aggregate +// functions like COUNT() cannot be used. + +// private static String LABEL_COUNT_QUERY = "" +// + "PREFIX rdfs: \n" +// + "SELECT ( str(COUNT(?label)) AS ?labelCount ) WHERE { \n" +// + " ?subject rdfs:label ?label \n" +// + " FILTER isLiteral(?label) \n" +// + "}" ; - private static Integer getLabelCount(String subjectUri, VitroRequest vreq) { - String queryStr = QueryUtils.subUriForQueryVar(LABEL_COUNT_QUERY, "subject", subjectUri); +// private static String DISTINCT_LANGUAGE_QUERY = "" +// + "PREFIX rdfs: \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 distinctLanguages = new HashSet(); + String queryStr = QueryUtils.subUriForQueryVar(LABEL_QUERY, "subject", subjectUri); log.debug("queryStr = " + queryStr); - int theCount = 0; - try { - //ResultSet results = QueryUtils.getQueryResults(queryStr, vreq); - //Get query results across all languages in order for template to show manage labels link correctly - ResultSet results = QueryUtils.getLanguageNeutralQueryResults(queryStr, vreq); - if (results.hasNext()) { - QuerySolution soln = results.nextSolution(); - RDFNode labelCount = soln.get("labelCount"); - if (labelCount != null && labelCount.isLiteral()) { - theCount = labelCount.asLiteral().getInt(); + int labelCount = 0; + try { + ResultSet results = QueryUtils.getQueryResults(queryStr, vreq); + while(results.hasNext()) { + QuerySolution qsoln = results.next(); + labelCount++; + String lang = qsoln.getLiteral("label").getLanguage(); + if(lang == null) { + lang = ""; } + distinctLanguages.add(lang); } } catch (Exception 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 - private static Integer getLanguagesRepresentedCount(String subjectUri, VitroRequest vreq) { - String queryStr = QueryUtils.subUriForQueryVar(DISTINCT_LANGUAGE_QUERY, "subject", subjectUri); - log.debug("queryStr = " + queryStr); - int theCount = 0; - try { - - ResultSet results = QueryUtils.getLanguageNeutralQueryResults(queryStr, vreq); - if (results.hasNext()) { - QuerySolution soln = results.nextSolution(); - RDFNode languageCount = soln.get("languageCount"); - if (languageCount != null && languageCount.isLiteral()) { - theCount = languageCount.asLiteral().getInt(); - } - } - } catch (Exception e) { - log.error(e, e); - } - return theCount; - } + // This version not compatible with language-filtering RDF services +// private static Integer getLanguagesRepresentedCount(String subjectUri, VitroRequest vreq) { +// String queryStr = QueryUtils.subUriForQueryVar(DISTINCT_LANGUAGE_QUERY, "subject", subjectUri); +// log.debug("queryStr = " + queryStr); +// int theCount = 0; +// try { +// +// ResultSet results = QueryUtils.getLanguageNeutralQueryResults(queryStr, vreq); +// if (results.hasNext()) { +// QuerySolution soln = results.nextSolution(); +// RDFNode languageCount = soln.get("languageCount"); +// if (languageCount != null && languageCount.isLiteral()) { +// theCount = languageCount.asLiteral().getInt(); +// log.info("Language count is " + theCount); +// } +// } +// } catch (Exception e) { +// log.error(e, e); +// } +// log.info("Returning language count " + theCount); +// return theCount; +// } private static String PROFILE_TYPE_QUERY = "" + "PREFIX display: \n" diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManageLabelsForIndividualGenerator.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManageLabelsForIndividualGenerator.java index d2a109895..3f7e912bb 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManageLabelsForIndividualGenerator.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManageLabelsForIndividualGenerator.java @@ -15,6 +15,7 @@ import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; 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.ManageLabelsForIndividualPreprocessor; 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; /** @@ -202,12 +204,12 @@ public class ManageLabelsForIndividualGenerator extends BaseEditConfigurationGen private void addFormSpecificData(EditConfigurationVTwo config, VitroRequest vreq) { - //Get all language codes/labels in the system, and this list is sorted by language name - List> locales = this.getLocales(vreq); + //the labels already added by the user + ArrayList existingLabels = this.getExistingLabels(config.getSubjectUri(), vreq); + //Get language codes/labels for languages present in the existing labels + List> 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 localeCodeToNameMap = this.getFullCodeToLanguageNameMap(locales); - //the labels already added by the user - ArrayList existingLabels = this.getExistingLabels(config.getSubjectUri(), vreq); + HashMap localeCodeToNameMap = this.getFullCodeToLanguageNameMap(locales); int numberExistingLabels = existingLabels.size(); //existing labels keyed by language name and each of the list of labels is sorted by language name HashMap> existingLabelsByLanguageName = this.getLabelsSortedByLanguageName(existingLabels, localeCodeToNameMap, config, vreq); @@ -373,8 +375,9 @@ public class ManageLabelsForIndividualGenerator extends BaseEditConfigurationGen ArrayList labels = new ArrayList(); try { - //We want to get the labels for all the languages, not just the display language - ResultSet results = QueryUtils.getLanguageNeutralQueryResults(queryStr, vreq); + // Get results filtered to current locale so as to be consistent + // with other editing forms. + ResultSet results = QueryUtils.getQueryResults(queryStr, vreq); while (results.hasNext()) { QuerySolution soln = results.nextSolution(); Literal nodeLiteral = soln.get("label").asLiteral(); @@ -401,30 +404,32 @@ public class ManageLabelsForIndividualGenerator extends BaseEditConfigurationGen return template; } + //get locales present in list of literals + public List> getLocales(VitroRequest vreq, + List existingLiterals) { + Set locales = new HashSet(); + for(Literal literal : existingLiterals) { + String language = literal.getLanguage(); + if(!StringUtils.isEmpty(language)) { + locales.add(LanguageFilteringUtils.languageToLocale(language)); + } + } + if (locales.isEmpty()) { + return Collections.emptyList(); + } + List> list = new ArrayList>(); + Locale currentLocale = SelectedLocale.getCurrentLocale(vreq); + for (Locale locale : locales) { + try { + list.add(buildLocaleMap(locale, currentLocale)); + } catch (FileNotFoundException e) { + log.warn("Can't show locale '" + locale + "': " + e); + } + } - - //get locales - public List> getLocales(VitroRequest vreq) { - List selectables = SelectedLocale.getSelectableLocales(vreq); - if (selectables.isEmpty()) { - return Collections.emptyList(); - } - List> list = new ArrayList>(); - Locale currentLocale = SelectedLocale.getCurrentLocale(vreq); - for (Locale locale : selectables) { - try { - list.add(buildLocaleMap(locale, currentLocale)); - } catch (FileNotFoundException e) { - log.warn("Can't show the Locale selector for '" + locale - + "': " + e); - } - } - - return list; + return list; } - - public HashMap getFullCodeToLanguageNameMap(List> localesList) { HashMap codeToLanguageMap = new HashMap(); for(Map locale: localesList) {