Merge branch 'develop' of https://github.com/vivo-project/Vitro into develop

This commit is contained in:
brianjlowe 2015-02-11 16:50:41 +02:00
commit 86d4ed6506
15 changed files with 178 additions and 91 deletions

View file

@ -25,12 +25,12 @@ auth:ADMIN
auth:hasPermission simplePermission:UseAdvancedDataToolsPages ; auth:hasPermission simplePermission:UseAdvancedDataToolsPages ;
auth:hasPermission simplePermission:UseMiscellaneousAdminPages ; auth:hasPermission simplePermission:UseMiscellaneousAdminPages ;
auth:hasPermission simplePermission:UseSparqlQueryPage ; auth:hasPermission simplePermission:UseSparqlQueryPage ;
auth:hasPermission simplePermission:PageViewableAdmin ; auth:hasPermission simplePermission:PageViewableAdmin ;
# Uncomment the following permission line to enable the SPARQL update API. # Uncomment the following permission line to enable the SPARQL update API.
# Before enabling, be sure that the URL api/sparqlUpdate is secured by SSH, # Before enabling, be sure that the URL api/sparqlUpdate is secured by HTTPS,
# so passwords will not be sent in clear text. # so passwords will not be sent in clear text.
# auth:hasPermission simplePermission:UseSparqlUpdateApi ; #auth:hasPermission simplePermission:UseSparqlUpdateApi ;
# permissions for CURATOR and above. # permissions for CURATOR and above.
auth:hasPermission simplePermission:EditOntology ; auth:hasPermission simplePermission:EditOntology ;

View file

@ -0,0 +1,25 @@
# $This file is distributed under the terms of the license in /doc/license.txt$
# All instances of a class can be excluded from the search index by adding a
# vitroDisplay:excludeClass property between vitroDisplay:SearchIndex and the
# URI of the class that you would like to exclude.
# .n3 or .rdf files can be created in this directory to configure the search
# exclusions. Each file must be a valid file in the format specified by its
# extension. Each file will be loaded individually and must be a complete
# stand alone example of its format. Each file must contain all the necessary
# prefixes, namespaces and preambles required by the format specified by its
# extension.
# If you would like to add classes to the exclusions, add a file to this
# directory ending in .n3 with N3 statements similar to this example.
#
# @prefix owl: <http://www.w3.org/2002/07/owl#> .
# @prefix vitroDisplay: <http://vitro.mannlib.cornell.edu/ontologies/display/1.1#> .
# @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
# @prefix example: <http://example/ns/> .
#
# vitroDisplay:SearchIndex
# rdf:type owl:Thing ;
# vitroDisplay:excludeClass example:classToExclude ;

View file

@ -16,6 +16,7 @@ public class Release18Migrator implements ServletContextListener {
ServletContext ctx = sce.getServletContext(); ServletContext ctx = sce.getServletContext();
new FauxPropertiesUpdater(ctx, this).migrate(); new FauxPropertiesUpdater(ctx, this).migrate();
new RemoveObsoleteMetadataGraphs(ctx, this).migrate();
} }
@Override @Override

View file

@ -0,0 +1,67 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.migration;
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess.WhichService.CONFIGURATION;
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess.WhichService.CONTENT;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextListener;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess.WhichService;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.jena.RDFServiceJena;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
/**
* The graphs http://vitro.mannlib.cornell.edu/ns/vitro/sdb/metadata were used
* in Content models through release 1.7 and in Configuration models in release
* 1.7
*
* In release 1.8, they area no longer used, and produce annoying warning
* messages.
*/
public class RemoveObsoleteMetadataGraphs {
private static final String OBSOLETE_METADATA_MODEL = "http://vitro.mannlib.cornell.edu/ns/vitro/sdb/metadata";
private final ServletContext ctx;
private final ServletContextListener parent;
public RemoveObsoleteMetadataGraphs(ServletContext ctx,
ServletContextListener parent) {
this.ctx = ctx;
this.parent = parent;
}
public void migrate() {
StartupStatus ss = StartupStatus.getBean(ctx);
removeMetadataModel(ctx, ss, CONTENT);
removeMetadataModel(ctx, ss, CONFIGURATION);
}
/**
* Ordinarily, RDFServiceJena will issue a warning when a single triple is
* removed from a blank node. In this case, however, that's exactly what we
* want, so stifle those warnings while we remove these models.
*/
private void removeMetadataModel(ServletContext ctx, StartupStatus ss,
WhichService which) {
Logger rdfServiceLogger = Logger.getLogger(RDFServiceJena.class);
Level rdfServiceLogLevel = rdfServiceLogger.getLevel();
rdfServiceLogger.setLevel(Level.ERROR);
try {
ModelAccess.on(ctx).getModelMaker(which)
.removeModel(OBSOLETE_METADATA_MODEL);
} catch (Exception e) {
ss.warning(parent, "Failed to remove '" + OBSOLETE_METADATA_MODEL
+ "' from " + which, e);
} finally {
rdfServiceLogger.setLevel(rdfServiceLogLevel);
}
}
}

View file

@ -374,7 +374,7 @@ public class SearchIndexerImpl implements SearchIndexer {
private final TaskQueue taskQueue; private final TaskQueue taskQueue;
private final List<Task> deferredQueue; private final List<Task> deferredQueue;
private volatile boolean started; private volatile boolean started;
private volatile boolean paused = true; private volatile boolean paused;
public Scheduler(TaskQueue taskQueue) { public Scheduler(TaskQueue taskQueue) {
this.taskQueue = taskQueue; this.taskQueue = taskQueue;

View file

@ -5,6 +5,7 @@ package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -139,39 +140,31 @@ public class CollatedObjectPropertyTemplateModel extends
// others will be removed // others will be removed
List<Map<String, String>> filteredList = new ArrayList<Map<String, String>>(); List<Map<String, String>> filteredList = new ArrayList<Map<String, String>>();
Set<String> processedObjects = new HashSet<String>(); Set<String> processedObjects = new HashSet<String>();
//Useful to keep track of objects where statement data may not match the most specific type
//returne for some reason, in which case useful to keep track
Set<String> filteredObjects = new HashSet<String>();
for (Map<String, String> outerMap : statementData) { for (Map<String, String> outerMap : statementData) {
String objectUri = outerMap.get(objectVariableName); String objectUri = outerMap.get(objectVariableName);
if (processedObjects.contains(objectUri)) { if (processedObjects.contains(objectUri)) {
continue; continue;
} }
processedObjects.add(objectUri); processedObjects.add(objectUri);
//Get most specific type for this particular List<Map<String, String>> dataForThisObject = new ArrayList<Map<String, String>>();
List<String> mostSpecificTypes = this.getSortedMostSpecificType(objectUri); //Retrieve the statements that are related to this specific object
//If more than one most specific type, will compare against both of them
//and if the first one matches, the object will be placed under that
//otherwise subclass will be checked against the other
for (Map<String, String> innerMap : statementData) { for (Map<String, String> innerMap : statementData) {
//Check both the object uri and that the subclass returned matches if (innerMap.get(objectVariableName).equals(objectUri)) {
//the most specific type // Subclass should at this point contain the most specific
if (innerMap.get(objectVariableName) == objectUri) { // type already
//At this point, the statement data will already have the most specific type dataForThisObject.add(innerMap);
//represented
String subclass = innerMap.get(SUBCLASS_VARIABLE_NAME);
if(mostSpecificTypes.contains(subclass)) {
filteredList.add(innerMap);
filteredObjects.add(objectUri);
} else {
if(log.isDebugEnabled()) {
log.debug("Iterating through statement data, Subclass does not match most specific type for Object URI - " + objectUri + " - subclass:" + subclass + " - most specific types=" + mostSpecificTypes.toString());
}
}
} }
} }
if(log.isDebugEnabled()) {
log.debug("Object URI " + objectUri + " has number of statements = " + dataForThisObject.size());
}
//Subclass variable should already reflect most specifick types but there may be more than one most specific type
Collections.sort(dataForThisObject, new DataComparatorBySubclass());
filteredList.add(dataForThisObject.get(0));
} }
statementData.retainAll(filteredList); statementData.retainAll(filteredList);
@ -179,31 +172,23 @@ public class CollatedObjectPropertyTemplateModel extends
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Data after subclass filtering"); log.debug("Data after subclass filtering");
logData(statementData); logData(statementData);
//check and see if filteredObjects and processedObjects not the same size
if(filteredObjects.size() < processedObjects.size()) {
log.debug("Certain objects not included in statements displayed for collated subclasses");
processedObjects.removeAll(filteredObjects);
log.debug("These object uris not represented" + processedObjects.toString());
}
} }
} }
//Get the most specific type //Subclass variable should already contain most specific type
//An alternative would be to ensure that the default form, or any form that utilizes collation //If there is more than one most specific type, then order alphabetically
//will return most specific type within the listview select/construct queries so the resulting private class DataComparatorBySubclass implements
//statement data has that value Comparator<Map<String, String>> {
List<String> getMostSpecificTypesForObject(String objectURI) {
WebappDaoFactory wadf = ModelAccess.on(vreq).getWebappDaoFactory();
return wadf.getIndividualDao().getIndividualByURI(objectURI).getMostSpecificTypeURIs();
}
//This will return a single most specific type for an object @Override
//If there are multiple most specific types, the list will be sorted alphabetically and public int compare(Map<String, String> map1, Map<String, String> map2) {
//the first one will be returned
List<String> getSortedMostSpecificType(String objectURI) { String subclass1 = map1.get(SUBCLASS_VARIABLE_NAME);
List<String> mostSpecificTypeURIs = this.getMostSpecificTypesForObject(objectURI); String subclass2 = map2.get(SUBCLASS_VARIABLE_NAME);
Collections.sort(mostSpecificTypeURIs);
return mostSpecificTypeURIs; return subclass1.compareTo(subclass2);
}
} }

View file

@ -65,6 +65,7 @@ public class DataPropertyTemplateModel extends PropertyTemplateModel {
private String objectKey; private String objectKey;
private String queryString; private String queryString;
private Set<String> constructQueries; private Set<String> constructQueries;
private int displayLimit;
DataPropertyTemplateModel(DataProperty dp, Individual subject, VitroRequest vreq, DataPropertyTemplateModel(DataProperty dp, Individual subject, VitroRequest vreq,
boolean editing, List<DataProperty> populatedDataPropertyList) { boolean editing, List<DataProperty> populatedDataPropertyList) {
@ -82,7 +83,7 @@ public class DataPropertyTemplateModel extends PropertyTemplateModel {
constructQueries = getConstructQueries(); constructQueries = getConstructQueries();
statements = new ArrayList<DataPropertyStatementTemplateModel>(); statements = new ArrayList<DataPropertyStatementTemplateModel>();
displayLimit = dp.getDisplayLimit();
// If the property is populated, get the data property statements via a sparql query // If the property is populated, get the data property statements via a sparql query
if (populatedDataPropertyList.contains(dp)) { if (populatedDataPropertyList.contains(dp)) {
log.debug("Getting data for populated data property " + getUri()); log.debug("Getting data for populated data property " + getUri());
@ -108,14 +109,22 @@ public class DataPropertyTemplateModel extends PropertyTemplateModel {
return; return;
} }
// If the display limit has already been reached, we can't add a new statement. /* If the display limit has already been reached, we can't add a new statement.
// NB This appears to be a misuse of a value called "display limit". Note that it's NB This appears to be a misuse of a value called "display limit". Note that it's
// not used to limit display, either, so should be renamed. not used to limit display, either, so should be renamed.
int displayLimit = dp.getDisplayLimit(); int displayLimit = dp.getDisplayLimit();
// Display limit of -1 (default value for new property) means no display limit Display limit of -1 (default value for new property) means no display limit
if ( displayLimit >= 0 && statements.size() >= displayLimit ) { if ( displayLimit >= 0 && statements.size() >= displayLimit ) {
return; return;
} }
*/
// Rewriting the above per jc55. If the data property is functional, there should only
// be 1 statement. The Display Limit is for determining how many statements to display
// before a "more..." link is used to hide statements exceeding the display limit. tlw72
boolean functional = dp.getFunctional();
if ( functional && statements.size() >= 1 ) {
return;
}
// Determine whether a new statement can be added // Determine whether a new statement can be added
RequestedAction action = new AddDataPropertyStatement( RequestedAction action = new AddDataPropertyStatement(
@ -147,6 +156,11 @@ public class DataPropertyTemplateModel extends PropertyTemplateModel {
return Route.DATA_PROPERTY_EDIT; return Route.DATA_PROPERTY_EDIT;
} }
@Override
public int getDisplayLimit() {
return displayLimit;
}
public ConfigError checkQuery(String queryString) { public ConfigError checkQuery(String queryString) {
if (StringUtils.isBlank(queryString)) { if (StringUtils.isBlank(queryString)) {
return ConfigError.NO_SELECT_QUERY; return ConfigError.NO_SELECT_QUERY;
@ -192,6 +206,7 @@ public class DataPropertyTemplateModel extends PropertyTemplateModel {
return getTemplateName(); return getTemplateName();
} }
/* Template methods */ /* Template methods */
public DataPropertyStatementTemplateModel first() { public DataPropertyStatementTemplateModel first() {

View file

@ -41,6 +41,7 @@ public abstract class PropertyTemplateModel extends BaseTemplateModel {
private String name; private String name;
private FauxProperty fauxProperty; private FauxProperty fauxProperty;
private int displayLimit;
PropertyTemplateModel(Property property, Individual subject, VitroRequest vreq, String name) { PropertyTemplateModel(Property property, Individual subject, VitroRequest vreq, String name) {
this.vreq = vreq; this.vreq = vreq;
@ -49,11 +50,13 @@ public abstract class PropertyTemplateModel extends BaseTemplateModel {
propertyUri = property.getURI(); propertyUri = property.getURI();
localName = property.getLocalName(); localName = property.getLocalName();
this.name = name; this.name = name;
this.displayLimit = displayLimit;
addUrl = ""; addUrl = "";
fauxProperty = isFauxProperty(property); fauxProperty = isFauxProperty(property);
if (fauxProperty != null) { if (fauxProperty != null) {
this.name = fauxProperty.getDisplayName(); this.name = fauxProperty.getDisplayName();
this.displayLimit = fauxProperty.getDisplayLimit();
} }
setVerboseDisplayValues(property); setVerboseDisplayValues(property);
@ -142,6 +145,10 @@ public abstract class PropertyTemplateModel extends BaseTemplateModel {
return name; return name;
} }
public int getDisplayLimit() {
return displayLimit;
}
public String getLocalName() { public String getLocalName() {
return localName; return localName;
} }

View file

@ -1,27 +0,0 @@
# $This file is distributed under the terms of the license in /doc/license.txt$
# All instances of a class can be excluded from the search index
# by adding a vitroDisplay:excludeClass property between
# vitroDisplay:SearchIndex and the URI of the class
# that you would like to exclude.
# All .n3 or .rdf files in this directory will be used to configure
# the search exclusions. Each file must be a valid file in the format
# specified by its extension. Each file will be loaded individually and
# must be a complete stand alone example of its format. Each file must contain all
# the necessary prefixes, namespaces and preambles required by the format
# specified by its extension.
# If you would like to add classes to the
# exclusions, add a file to this directory ending in .n3 with
# N3 statements similar to this example.
#
# @prefix owl: <http://www.w3.org/2002/07/owl#> .
# @prefix vitroDisplay: <http://vitro.mannlib.cornell.edu/ontologies/display/1.1#> .
# @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
# @prefix example: <http://example/ns/> .
#
# vitroDisplay:SearchIndex
# rdf:type owl:Thing ;
# vitroDisplay:excludeClass example:classToExclude ;

View file

@ -68,3 +68,6 @@ li.selectedGroupTab {
li.groupTabSpacer { li.groupTabSpacer {
float:left;border-bottom: 1px solid #DFE6E5;background-color:#fff;width:3px;height:37px float:left;border-bottom: 1px solid #DFE6E5;background-color:#fff;width:3px;height:37px
} }
div.additionalItems {
margin-top: 0 !important;
}

View file

@ -25,7 +25,7 @@
<section class="account-feedback"> <section class="account-feedback">
<p> <p>
${strings.updated_account_1} ${strings.updated_account_1}
<a href="${updatedUserAccount.editUrl}" title="${strings.updated_account_title}}">${updatedUserAccount.firstName} ${updatedUserAccount.lastName}</a> <a href="${updatedUserAccount.editUrl}" title="${strings.updated_account_title}">${updatedUserAccount.firstName} ${updatedUserAccount.lastName}</a>
${strings.updated_account_2} ${strings.updated_account_2}
<#if emailWasSent?? >${strings.updated_account_notification(updatedUserAccount.emailAddress)}</#if> <#if emailWasSent?? >${strings.updated_account_notification(updatedUserAccount.emailAddress)}</#if>
</p> </p>

View file

@ -1,4 +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-microformats.ftl" as mf>
<#--Number of labels present--> <#--Number of labels present-->
<#if !labelCount??> <#if !labelCount??>
<#assign labelCount = 0 > <#assign labelCount = 0 >
@ -14,7 +16,7 @@
<#-- Default individual profile page template --> <#-- Default individual profile page template -->
<#--@dumpAll /--> <#--@dumpAll /-->
<section id="individual-intro" class="vcard" role="region"> <section id="individual-intro" class="vcard" role="region" <@mf.sectionSchema individual/>>
<section id="share-contact" role="region"> <section id="share-contact" role="region">
<#-- Image --> <#-- Image -->
<#assign individualImage> <#assign individualImage>
@ -39,7 +41,7 @@
<h2>${relatedSubject.relatingPredicateDomainPublic} for ${relatedSubject.name}</h2> <h2>${relatedSubject.relatingPredicateDomainPublic} for ${relatedSubject.name}</h2>
<p><a href="${relatedSubject.url}" title="${i18n().return_to(relatedSubject.name)}">&larr; ${i18n().return_to(relatedSubject.name)}</a></p> <p><a href="${relatedSubject.url}" title="${i18n().return_to(relatedSubject.name)}">&larr; ${i18n().return_to(relatedSubject.name)}</a></p>
<#else> <#else>
<h1 class="fn"> <h1 class="fn" itemprop="name">
<#-- Label --> <#-- Label -->
<@p.label individual editable labelCount localesCount languageCount/> <@p.label individual editable labelCount localesCount languageCount/>

View file

@ -42,7 +42,11 @@
<h3 id="${property.localName}">${property.name} <@p.addLink property editable /> <@p.verboseDisplay property /> </h3> <h3 id="${property.localName}">${property.name} <@p.addLink property editable /> <@p.verboseDisplay property /> </h3>
</#if> </#if>
<#-- List the statements for each property --> <#-- List the statements for each property -->
<ul class="property-list" role="list" id="${property.localName}-${rangeClass}-List"> <#assign limit = property.getDisplayLimit()!5 />
<#if limit == -1 || limit == 0 >
<#assign limit = 5 />
</#if>
<ul class="property-list" role="list" id="${property.localName}-${rangeClass}-List" displayLimit="${limit}">
<#-- data property --> <#-- data property -->
<#if property.type == "data"> <#if property.type == "data">
<@p.dataPropertyList property editable /> <@p.dataPropertyList property editable />

View file

@ -9,11 +9,11 @@
<#if (individual.thumbUrl)??> <#if (individual.thumbUrl)??>
<img src="${individual.thumbUrl}" width="90" alt="${individual.name}" /> <img src="${individual.thumbUrl}" width="90" alt="${individual.name}" />
<h1 class="thumb"> <h1 class="thumb">
<a href="${individual.profileUrl}" title="${i18n().view_profile_page_for} ${individual.name}}">${individual.name}</a> <a href="${individual.profileUrl}" title="${i18n().view_profile_page_for} ${individual.name}">${individual.name}</a>
</h1> </h1>
<#else> <#else>
<h1> <h1>
<a href="${individual.profileUrl}" title="${i18n().view_profile_page_for} ${individual.name}}">${individual.name}</a> <a href="${individual.profileUrl}" title="${i18n().view_profile_page_for} ${individual.name}">${individual.name}</a>
</h1> </h1>
</#if> </#if>

View file

@ -0,0 +1,5 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<#macro sectionSchema individual>
<#-- Placeholder macro only. Will generate errors if this file is removed from the Vitro source. -->
</#macro>