updates for label management

This commit is contained in:
hudajkhan 2013-10-01 11:24:15 -04:00
parent cba46c4f72
commit 9fae5d7c3e
10 changed files with 453 additions and 82 deletions

View file

@ -77,6 +77,7 @@ public class SimplePermission extends Permission {
public static final SimplePermission USE_SPARQL_QUERY_PAGE = new SimplePermission(
NAMESPACE + "UseSparqlQueryPage");
// ----------------------------------------------------------------------
// These instances are "catch all" permissions to cover poorly defined
// groups of actions until better definitions were found. Don't add usages

View file

@ -0,0 +1,246 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.vocabulary.RDFS;
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.beans.Property;
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.edit.n3editing.VTwo.EditConfigurationVTwo;
import edu.cornell.mannlib.vitro.webapp.i18n.selection.SelectedLocale;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.DataPropertyStatementTemplateModel;
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
/*Servlet to view all labels in various languages for individual*/
public class ViewLabelsServlet extends FreemarkerHttpServlet{
private static final Log log = LogFactory.getLog(ViewLabelsServlet.class.getName());
@Override
protected ResponseValues processRequest(VitroRequest vreq) {
Map<String, Object> body = new HashMap<String, Object>();
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<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
ArrayList<Literal> existingLabels = this.getExistingLabels(subjectUri, vreq);
//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);
//Get available locales for the drop down for adding a new label, also sorted by language name
HashSet<String> existingLanguageNames = new HashSet<String>(existingLabelsByLanguageName.keySet());
body.put("labelsSortedByLanguageName", existingLabelsByLanguageName);
Individual subject = vreq.getWebappDaoFactory().getIndividualDao().getIndividualByURI(subjectUri);
if( subject != null && subject.getName() != null ){
body.put("subjectName", subject.getName());
}else{
body.put("subjectName", null);
}
} catch (Throwable e) {
log.error(e, e);
return new ExceptionResponseValues(e);
}
String template = "viewLabelsForIndividual.ftl";
return new TemplateResponseValues(template, body);
}
//Languages sorted by language name
private HashMap<String, List<LabelInformation>> getLabelsSortedByLanguageName(List<Literal> labels, Map<String, String> localeCodeToNameMap,
VitroRequest vreq, String subjectUri) {
//Iterate through the labels and create a hashmap
HashMap<String, List<LabelInformation>> labelsHash= new HashMap<String, List<LabelInformation>>();
for(Literal l: labels) {
String languageTag = l.getLanguage();
String languageName = "";
if(languageTag == "") {
languageName = "untyped";
}
else if(localeCodeToNameMap.containsKey(languageTag)) {
languageName = localeCodeToNameMap.get(languageTag);
} else {
log.warn("This language tag " + languageTag + " does not have corresponding name in the system and was not processed");
}
if(languageName != "") {
if(!labelsHash.containsKey(languageName)) {
labelsHash.put(languageName, new ArrayList<LabelInformation>());
}
ArrayList<LabelInformation> labelsList = (ArrayList<LabelInformation>)labelsHash.get(languageName);
//This should put the label in the list
//Create label information instance with the required information
//To generate link
labelsList.add(new LabelInformation(
l, languageTag, languageName));
}
}
//Sort each label list
LabelInformationComparator lic = new LabelInformationComparator();
for(String languageName: labelsHash.keySet()) {
List<LabelInformation> labelInfo = labelsHash.get(languageName);
Collections.sort(labelInfo, lic);
}
return labelsHash;
}
public static class LabelInformationComparator implements Comparator<LabelInformation> {
public int compare(LabelInformation l1, LabelInformation l2) {
return l1.getLabelStringValue().compareTo(l2.getLabelStringValue());
}
}
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
//get locales
public List<HashMap<String, String>> getLocales(VitroRequest vreq) {
List<Locale> selectables = SelectedLocale.getSelectableLocales(vreq);
if (selectables.isEmpty()) {
return Collections.emptyList();
}
List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
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;
}
//copied from locale selection data getter but don't need all this information
private HashMap<String, String> buildLocaleMap(Locale locale,
Locale currentLocale) throws FileNotFoundException {
HashMap<String, String> map = new HashMap<String, String>();
//Replacing the underscore with a hyphen because that is what is represented in the actual literals
map.put("code", locale.toString().replace("_", "-"));
map.put("label", locale.getDisplayName(currentLocale));
return map;
}
public HashMap<String, String> getFullCodeToLanguageNameMap(List<HashMap<String, String>> localesList) {
HashMap<String, String> codeToLanguageMap = new HashMap<String, String>();
for(Map<String, String> locale: localesList) {
String code = (String) locale.get("code");
String label = (String) locale.get("label");
if(!codeToLanguageMap.containsKey(code)) {
codeToLanguageMap.put(code, label);
}
else {
log.warn("Language code " + code + " for " + label + " was not associated in map becayse label already exists");
}
}
return codeToLanguageMap;
}
private ArrayList<Literal> getExistingLabels(String subjectUri, VitroRequest vreq) {
String queryStr = QueryUtils.subUriForQueryVar(LABEL_QUERY, "subject", subjectUri);
log.debug("queryStr = " + queryStr);
ArrayList<Literal> labels = new ArrayList<Literal>();
try {
//We want to get the labels for all the languages, not just the display language
ResultSet results = QueryUtils.getLanguageNeutralQueryResults(queryStr, vreq);
while (results.hasNext()) {
QuerySolution soln = results.nextSolution();
Literal nodeLiteral = soln.get("label").asLiteral();
labels.add(nodeLiteral);
}
} catch (Exception e) {
log.error(e, e);
}
return labels;
}
//Class used to store the information needed for the template, such as the labels, their languages, their edit links
public class LabelInformation {
private Literal labelLiteral = null;
private String languageCode; //languageCode
private String languageName;
public LabelInformation(Literal inputLiteral, String inputLanguageCode, String inputLanguageName) {
this.labelLiteral = inputLiteral;
this.languageCode = inputLanguageCode;
this.languageName = inputLanguageName;
}
public Literal getLabelLiteral() {
return this.labelLiteral;
}
public String getLabelStringValue() {
return this.labelLiteral.getString();
}
public String getLanguageCode() {
return this.languageCode;
}
public String getLanguageName() {
return this.languageName;
}
}
private static String LABEL_QUERY = ""
+ "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n"
+ "SELECT DISTINCT ?label WHERE { \n"
+ " ?subject rdfs:label ?label \n"
+ "} ORDER BY ?label";
}

View file

@ -4,63 +4,118 @@ package edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocess
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.QuerySolutionMap;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.query.Syntax;
import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.ResIterator;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.ResourceFactory;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.shared.Lock;
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
public class FoafNameToRdfsLabelPreprocessor implements ModelChangePreprocessor {
private static final String FOAF = "http://xmlns.com/foaf/0.1/";
private Log log = LogFactory.getLog(FoafNameToRdfsLabelPreprocessor.class);
@Override
public void preprocess(Model retractionsModel, Model additionsModel,
HttpServletRequest request) {
Property firstNameP = additionsModel.getProperty(FOAF+"firstName");
Property lastNameP = additionsModel.getProperty(FOAF+"lastName");
//middle name is optional
Property middleNameP = additionsModel.getProperty(FOAF+"middleName");
updateModelWithLabel(additionsModel);
}
private String getSparqlQuery() {
String queryStr = "SELECT ?subject ?firstName ?middleName ?lastName where {" +
"?subject <http://purl.obolibrary.org/obo/ARG_2000028> ?individualVcard ." +
"?individualVcard <http://www.w3.org/2006/vcard/ns#hasName> ?fullName ." +
"?fullName <http://www.w3.org/2006/vcard/ns#givenName> ?firstName ." +
"?fullName <http://www.w3.org/2006/vcard/ns#familyName> ?lastName ." +
"OPTIONAL {?fullName <http://www.w3.org/2006/vcard/ns#middleName> ?middleName .}" +
"}";
return queryStr;
}
private void updateModelWithLabel(Model additionsModel) {
Model changesModel = ModelFactory.createDefaultModel();
String queryStr = getSparqlQuery();
Property rdfsLabelP = additionsModel.getProperty(VitroVocabulary.LABEL);
ResIterator subs =
additionsModel.listSubjectsWithProperty(firstNameP);
while( subs.hasNext() ){
Resource sub = subs.nextResource();
Statement fname = sub.getProperty( firstNameP );
Statement lname = sub.getProperty( lastNameP );
Statement mname = sub.getProperty(middleNameP);
if( fname != null && lname != null && fname.getString() != null && lname.getString() != null ){
//Check if there are languages associated with first name and last name and add the language
//attribute to the label
//This preprocessor is used in multiple places, including for managing labels
Literal firstNameLiteral = fname.getLiteral();
Literal lastNameLiteral = lname.getLiteral();
Query query = null;
QueryExecution qe = null;
additionsModel.getLock().enterCriticalSection(Lock.READ);
try {
query = QueryFactory.create(queryStr);
qe = QueryExecutionFactory.create(
query, additionsModel);
ResultSet res = qe.execSelect();
while( res.hasNext() ){
String newLabel = "";
Resource subject = null;
QuerySolution qs = res.nextSolution();
subject = qs.getResource("subject");
//Get first and last names, and middle names if they exist
if(qs.getLiteral("firstName") != null && qs.getLiteral("lastName") != null) {
Literal firstNameLiteral = qs.getLiteral("firstName");
Literal lastNameLiteral = qs.getLiteral("lastName");
String firstNameLanguage = firstNameLiteral.getLanguage();
String lastNameLanguage = lastNameLiteral.getLanguage();
//Start creating string for new label
String newLabel = lname.getString() + ", " + fname.getString();
newLabel = lastNameLiteral.getString() + ", " + firstNameLiteral.getString();
//Middle name handling
if(mname != null && mname.getString() != null) {
newLabel += " " + mname.getString();
if(qs.getLiteral("middleName") != null) {
Literal middleNameLiteral = qs.getLiteral("middleName");
newLabel += " " + middleNameLiteral.getString();
}
if(firstNameLanguage != null && lastNameLanguage != null && firstNameLanguage.equals(lastNameLanguage)) {
if(subject != null &&
firstNameLanguage != null && lastNameLanguage != null
&& firstNameLanguage.equals(lastNameLanguage)) {
//create a literal with the appropriate value and the language
Literal labelWithLanguage = additionsModel.createLiteral(newLabel, firstNameLanguage);
additionsModel.add(sub, rdfsLabelP, labelWithLanguage);
Literal labelWithLanguage = changesModel.createLiteral(newLabel, firstNameLanguage);
changesModel.add(subject, rdfsLabelP, labelWithLanguage);
} else {
additionsModel.add(sub, rdfsLabelP, newLabel );
changesModel.add(subject, rdfsLabelP, newLabel );
}
}
}
} catch(Throwable th){
log.error("An error occurred in executing query:" + queryStr);
} finally {
if (qe != null) {
qe.close();
}
additionsModel.getLock().leaveCriticalSection();
}
//Write changes model to additions model
additionsModel.getLock().enterCriticalSection(Lock.WRITE);
try {
additionsModel.add(changesModel);
}catch(Throwable th){
log.error("An error occurred in writing model", th);
} finally {
additionsModel.getLock().leaveCriticalSection();
}
}
}

View file

@ -625,12 +625,12 @@
</servlet-mapping>
<servlet>
<servlet-name>ManageLabelsForIndividualController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.freemarker.ManageLabelsForIndividualController</servlet-class>
<servlet-name>ViewLabelsServlet</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.freemarker.ViewLabelsServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ManageLabelsForIndividualController</servlet-name>
<url-pattern>/manageLabels</url-pattern>
<servlet-name>ViewLabelsServlet</servlet-name>
<url-pattern>/viewLabels</url-pattern>
</servlet-mapping>
<servlet>

View file

@ -873,3 +873,5 @@ manage_labels_capitalized = Manage Labels
manage_labels_intro = In the case where multiple labels exist in the same language, please use the remove link to delete the labels you do not want displayed on the profile page for a given language.
processing_icon = processing
selection_in_process = Your selection is being processed.
view_labels_capitalized = View Labels
view_labels_for = View Labels for

View file

@ -24,6 +24,8 @@ var manageLabels = {
this.addLabelForm = $('#addLabelForm');
this.showFormButtonWrapper = $('#showAddForm');
this.showFormButton = $("#showAddFormButton");
//button to return to profile - div with only cancel
this.showCancelOnlyButton = $("#showCancelOnly");
this.addLabelCancel = this.addLabelForm.find(".cancel");
this.submit = this.addLabelForm.find('input#submit');
this.labelLanguage = this.addLabelForm.find("#newLabelLanguage");
@ -37,14 +39,20 @@ var manageLabels = {
if(this.submissionErrorsExist == "false") {
//hide the form to add label
this.addLabelForm.hide();
//If the number of available locales is zero, then hide the ability to show the form as well
if(this.numberAvailableLocales == 0) {
manageLabels.showFormButtonWrapper.hide();
this.showCancelOnlyButton.show();
} else {
//if the add label button is visible, don't need cancel only link
this.showCancelOnlyButton.hide();
}
} else {
//Display the form
this.onShowAddForm();
//Also make sure the save button is enabled in case there is a value selected for the drop down
if(this.labelLanguage.val() != "") {
disableSubmit = false;
@ -52,6 +60,8 @@ var manageLabels = {
}
if(disableSubmit) {
//disable submit until user selects a language
this.submit.attr('disabled', 'disabled');
@ -235,6 +245,8 @@ var manageLabels = {
//Re-show the add button and the form if they were hidden before
if(availableLocalesList.length > 0 && manageLabels.showFormButtonWrapper.is(":hidden")) {
manageLabels.showFormButtonWrapper.show();
//hide the cancel only button
manageLabels.showCancelOnlyButton.hide();
}
//Now replace dropdown with this new list

View file

@ -1,6 +1,7 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<#include "manageLabelsForIndividualTerms.ftl" >
<#-- Custom form for managing labels for individuals -->
<#--This is used both for editing and for viewLabelsServlet-->
<#import "manageLabelsForIndividualMacros.ftl" as m >
<#assign requiredHint = "<span class='requiredHint'> *</span>" />
<#assign subjectUri = editConfiguration.subjectUri/>
@ -66,7 +67,9 @@
<input type="submit" value="${i18n().add_label}" id="showAddFormButton" name="showAddFormButton"> ${i18n().or}
<a class="cancel" href="${cancelUrl}&url=/individual" title="${returnText}">${returnText}</a>
</div>
<div id="showCancelOnly">
<a class="cancel" href="${cancelUrl}&url=/individual" title="${returnText}">${returnText}</a>
</div>
<#include "manageLabelsForIndividualAddForm.ftl" >
</#if>

View file

@ -1,7 +1,8 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<#--LabelsSorted is a hash keyed by language name where the value is a list of LabelInformation class objects-->
<#macro displayExistingLabelsForLanguage lang labelsSorted editable editGenerator displayRemoveLink=true>
<#macro displayExistingLabelsForLanguage lang labelsSorted editable editGenerator="" displayRemoveLink=true>
<#--get label information for this language-->
<#if labelsSorted?keys?seq_contains(lang) >
<#assign labelList = labelsSorted[lang] />
<#--Reset for every language-->
<#assign labelSeq = []/>
@ -30,10 +31,11 @@
<#assign labelSeq = labelSeq + [labelStr]>
</#list>
</#if>
</#macro>
<#--ignore 'untyped' and display everything-->
<#macro displayExistingTypedLabels langList labelsSorted editable editGenerator displayRemoveLink=true>
<#macro displayExistingTypedLabels langList labelsSorted editable editGenerator="" displayRemoveLink=true>
<#list langList as lang>

View file

@ -0,0 +1,46 @@
<#-- $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$ -->
<#include "manageLabelsForIndividualTerms.ftl" >
<#-- Custom form for managing labels for individuals -->
<#--This is used both for editing and for viewLabelsServlet-->
<#import "manageLabelsForIndividualMacros.ftl" as m >
<#assign requiredHint = "<span class='requiredHint'> *</span>" />
<#assign labelStr = "" >
<#assign languageTag = "" >
<#assign labelSeq = [] >
<#assign editable = "false"/>
<#assign displayRemoveLink = "false"/>
<#if subjectName?? >
<h2>${i18n().view_labels_for} ${editConfiguration.pageData.subjectName}</h2>
<#else>
<h2>${i18n().view_labels_capitalized}</h2>
</#if>
<section id="rdfsLabels" role="container">
<ul id="existingLabelsList" name="existingLabelsList">
<#if editConfiguration.pageData.labelsSortedByLanguageName?has_content>
<#--List of labelInformation objects as value where key = language name -->
<#assign labelsSorted = editConfiguration.pageData.labelsSortedByLanguageName />
<#--Keys would be the actual names of languages-->
<#assign labelLanguages = labelsSorted?keys?sort />
<#--What we need here is printing out the labels by the language Name and not language code, starting with untyped first-->
<@m.displayExistingLabelsForLanguage "untyped" labelsSorted editable ""/>
<@m.displayExistingTypedLabels labelLanguages labelsSorted editable ""/>
</#if>
</ul>
</section>
${stylesheets.add('<link rel="stylesheet" href="${urls.base}/js/jquery-ui/css/smoothness/jquery-ui-1.8.9.custom.css" />')}
${scripts.add('<script type="text/javascript" src="${urls.base}/js/utils.js"></script>',
'<script type="text/javascript" src="${urls.base}/js/jquery-ui/js/jquery-ui-1.8.9.custom.min.js"></script>')}

View file

@ -233,18 +233,22 @@ name will be used as the label. -->
<@editingLinks "label" "" label editable />
<#elseif editable || (labelCount > 1)>
<#--We display the link even when the user is not logged in case of multiple labels-->
<#if editable>
<#assign imageAlt = "${i18n().manage}" />
<#assign linkTitle = "${i18n().manage_list_of_labels}">
<#else>
<#assign linkTitle = "${i18n().view_list_of_labels}">
<#assign imageAlt = "${i18n().view}" />
</#if>
<#assign labelLink = ""/>
<#-- Manage labels now goes to generator -->
<#assign individualUri = individual.uri!""/>
<#assign individualUri = (individualUri?url)/>
<#if editable>
<#assign imageAlt = "${i18n().manage}" />
<#assign linkTitle = "${i18n().manage_list_of_labels}">
<#assign labelLink= "${urls.base}/editRequestDispatch?subjectUri=${individualUri}&editForm=edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.ManageLabelsGenerator&predicateUri=${labelPropertyUri}">
<#else>
<#assign linkTitle = "${i18n().view_list_of_labels}">
<#assign imageAlt = "${i18n().view}" />
<#assign labelLink= "${urls.base}/viewLabels?subjectUri=${individualUri}">
</#if>
<span class="inline">
<a class="add-label" href="${urls.base}/editRequestDispatch?subjectUri=${individualUri}&editForm=edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.ManageLabelsForIndividualGenerator&predicateUri=${labelPropertyUri}"
<a class="add-label" href="${labelLink}"
title="${linkTitle}">
<img class="add-individual" src="${urls.images}/individual/manage-icon.png" alt="${imageAlt}" /></a>
</span>