Merge branch 'maint-rel-1.6' into develop
This commit is contained in:
commit
d8769df306
83 changed files with 2417 additions and 716 deletions
|
@ -745,6 +745,21 @@
|
|||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
Show only the most appropriate data values based on the Accept-Language
|
||||
header supplied by the browser. Default is false if not set.
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="odd_row">
|
||||
<td>
|
||||
RDFService.languageFilter
|
||||
</td>
|
||||
<td>
|
||||
false
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
Force VIVO to use a specific language or Locale instead of those
|
||||
|
@ -780,65 +795,6 @@
|
|||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<b>For developers only.</b>
|
||||
Defeat the Freemarker template cache, so each template
|
||||
is read from disk on each request. This permits developers to immediately
|
||||
see the effect of changes to the template. The default is <code>false</code>, which
|
||||
means that a cached copy of each template will be used for 60 seconds
|
||||
before the disk is checked for a new version.
|
||||
<br/><b>Setting this option to "true" slows down Vitro performance.</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="odd_row">
|
||||
<td>
|
||||
developer.defeatFreemarkerCache
|
||||
</td>
|
||||
<td>
|
||||
false
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<b>For developers only.</b>
|
||||
Defeat the cache of language-specific text strings,
|
||||
so the language file is read from disk on each request.
|
||||
This permits developers to immediately
|
||||
see the effect of changes to the text strings.
|
||||
The default is <code>false</code>, which means that the language file is
|
||||
read when VIVO starts up, or when a new theme is selected.
|
||||
<br/><b>Setting this option to "true" slows down Vitro performance.</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="odd_row">
|
||||
<td>
|
||||
developer.defeatI18nCache = true
|
||||
</td>
|
||||
<td>
|
||||
false
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<b>For developers only.</b>
|
||||
Add starting and ending delimiters to each Freemarker template, so you can see
|
||||
which template were invoked by viewing the generated HTML.
|
||||
The default is <code>false</code>.
|
||||
<br/><b>Setting this option to "true" slows down Vitro performance.</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="odd_row blue">
|
||||
<td>
|
||||
developer.insertFreemarkerDelimiters = true
|
||||
</td>
|
||||
<td>
|
||||
false
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
|
|
@ -263,7 +263,12 @@
|
|||
<target name="prepareVitroHomeDir" depends="prepare">
|
||||
<mkdir dir="${vitrohome.build.dir}" />
|
||||
<mkdir dir="${vitrohome.image.dir}" />
|
||||
<copy todir="${vitrohome.image.dir}" file="${appbase.dir}/config/example.runtime.properties" />
|
||||
<copy todir="${vitrohome.image.dir}" >
|
||||
<fileset dir="${appbase.dir}/config" >
|
||||
<include name="example.runtime.properties" />
|
||||
<include name="example.developer.properties" />
|
||||
</fileset>
|
||||
</copy>
|
||||
<copy todir="${vitrohome.image.dir}" >
|
||||
<fileset dir="${appbase.dir}" >
|
||||
<include name="rdf/**/*" />
|
||||
|
|
135
webapp/config/example.developer.properties
Normal file
135
webapp/config/example.developer.properties
Normal file
|
@ -0,0 +1,135 @@
|
|||
#
|
||||
# -----------------------------------------------------------------------------
|
||||
# Runtime properties for developer mode.
|
||||
#
|
||||
# If the developer.properties file is present in your VIVO home directory, it
|
||||
# will be loaded as VIVO starts up, taking effect immediately.
|
||||
#
|
||||
# Each of these properties can be set or changed while VIVO is running, but it
|
||||
# can be convenient to set them in advance.
|
||||
#
|
||||
# WARNING: Some of these options can seriously degrade performance. They should
|
||||
# not be enabled in a production instance of VIVO.
|
||||
#
|
||||
# -----------------------------------------------------------------------------
|
||||
#
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# General options
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
#
|
||||
# The "master switch" for developer mode. If this is not set to true, then none
|
||||
# of the other properties have any effect.
|
||||
#
|
||||
# developer.enabled = true
|
||||
|
||||
#
|
||||
# If developer mode is enabled, this will determine who can modify the
|
||||
# developer settings. If 'true', then any user can modify the settings. If
|
||||
# false, then only a site administrator (or root) can modify the settings.
|
||||
# The default is 'false'.
|
||||
#
|
||||
# developer.permitAnonymousControl
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Freemarker
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
#
|
||||
# Add HTML comments to each Freemarker template, so you can see what each
|
||||
# templates to the page, by viewing the source of the page in the browser.
|
||||
# The default is 'false'.
|
||||
#
|
||||
# developer.insertFreemarkerDelimiters = true
|
||||
|
||||
#
|
||||
# Defeat the Freemarker template cache, so each template is read from disk
|
||||
# on each request. This permits developers to immediately see the effect of
|
||||
# changes to the template. The default is 'false', which means that a cached
|
||||
# copy of each template will be used for 60 seconds before the disk is checked
|
||||
# for a new version.
|
||||
#
|
||||
# developer.defeatFreemarkerCache = true
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Page configuration
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
#
|
||||
# Turn on logging of custom list view configuration files. Each time a property
|
||||
# uses a list view other than the default, note it in the log. The default is
|
||||
# 'false'.
|
||||
#
|
||||
# developer.pageContents.logCustomListView = true
|
||||
|
||||
#
|
||||
# Turn on logging of custom short views. Each time an individual uses a short
|
||||
# view other than the default, note it in the log. The default is 'false'.
|
||||
#
|
||||
# developer.pageContents.logCustomShortView = true
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Internationalization
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
#
|
||||
# Defeat the cache of language-specific text strings, so the language file
|
||||
# is read from disk on each request. This permits developers to immediately
|
||||
# see the effect of changes to the text strings. The default is 'false', which
|
||||
# means that the language file is only read when VIVO starts up, or when a new
|
||||
# theme is selected.
|
||||
#
|
||||
# developer.i18n.defeatCache = true
|
||||
|
||||
#
|
||||
# Write a line to the log every time a template or a controller requests a
|
||||
# language-specific string from the properties files.
|
||||
#
|
||||
# developer.i18n.logStringRequests
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Logging SPARQL queries
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
#
|
||||
# Turn on logging of all SPARQL queries. The logging is at the INFO level.
|
||||
# Each entry includes:
|
||||
# - the elapsed time spent on the query, in seconds,
|
||||
# - the name of the method on RDFService that received the query,
|
||||
# - the format of the result stream from the RDFService method,
|
||||
# - the text of the query.
|
||||
# Note that all access to the content models is done through SPARQL queries,
|
||||
# but some go through translation layers before reaching the RDFService for
|
||||
# logging and execution. The default is 'false'.
|
||||
#
|
||||
# developer.loggingRDFService.enable = true
|
||||
|
||||
#
|
||||
# If SPARQL query logging is enabled, this will add a stack trace to each log
|
||||
# entry. The stack trace is abridged, so it starts after the
|
||||
# ApplicationFilterChain, omits any Jena classes, and ends at the RDFService.
|
||||
# The default is 'false'.
|
||||
#
|
||||
# developer.loggingRDFService.stackTrace = true
|
||||
|
||||
#
|
||||
# If SPARQL query logging is enabled, restrict the number of log entries by
|
||||
# matching a regular expression against the query string. If the expression
|
||||
# doesn't match the string, then no log entry is made. The default is "",
|
||||
# which means no restriction.
|
||||
#
|
||||
# developer.loggingRDFService.queryRestriction = .*
|
||||
|
||||
#
|
||||
# If SPARQL query logging is enabled, restrict the number of log entries by
|
||||
# matching a regular expression against the stack trace. The abridged stack
|
||||
# trace is concatenated into a single string of fully qualified class names
|
||||
# and method names. If the expression doesn't match the string, then no log
|
||||
# entry is made. The default is "", which means no restriction.
|
||||
#
|
||||
# developer.loggingRDFService.stackRestriction = .*
|
|
@ -116,9 +116,9 @@ proxy.eligibleTypeList = http://www.w3.org/2002/07/owl#Thing
|
|||
|
||||
#
|
||||
# Show only the most appropriate data values based on the Accept-Language
|
||||
# header supplied by the browser. Default is true if not set.
|
||||
# header supplied by the browser. Default is false if not set.
|
||||
#
|
||||
RDFService.languageFilter = true
|
||||
# RDFService.languageFilter = true
|
||||
|
||||
#
|
||||
# Tell VIVO to generate HTTP headers on its responses to facilitate caching the
|
||||
|
@ -152,35 +152,3 @@ RDFService.languageFilter = true
|
|||
# This should not be used with languages.forceLocale, which will override it.
|
||||
#
|
||||
# languages.selectableLocales = en, es, fr
|
||||
|
||||
#
|
||||
# For developers only: Setting this option to "true" slows down Vitro performance.
|
||||
#
|
||||
# Defeat the Freemarker template cache, so each template is read from disk
|
||||
# on each request. This permits developers to immediately see the effect of
|
||||
# changes to the template. The default is <code>false</code>, which means
|
||||
# that a cached copy of each template will be used for 60 seconds before
|
||||
# the disk is checked for a new version.
|
||||
#
|
||||
# developer.defeatFreemarkerCache = true
|
||||
|
||||
#
|
||||
# For developers only: Setting this option to "true" slows down Vitro performance.
|
||||
#
|
||||
# Defeat the cache of language-specific text strings, so the language file
|
||||
# is read from disk on each request. This permits developers to immediately
|
||||
# see the effect of changes to the text strings. The default is
|
||||
# <code>false</code>, which means that the language file is read when
|
||||
# VIVO starts up, or when a new theme is selected.
|
||||
#
|
||||
# developer.defeatI18nCache = true
|
||||
|
||||
#
|
||||
# For developers only: Setting this option to "true" slows down Vitro performance.
|
||||
#
|
||||
# Add starting and ending delimiters to each Freemarker template, so you can see
|
||||
# which template were invoked by viewing the generated HTML. The default is
|
||||
# <code>false</code>.
|
||||
#
|
||||
# developer.insertFreemarkerDelimiters = true
|
||||
|
||||
|
|
|
@ -444,7 +444,7 @@ please_create = Por favor, cree
|
|||
a_classgroup = un grupo de clase
|
||||
associate_classes_with_group = y las clases asociadas con el grupo creado.
|
||||
|
||||
refresh_content = Actualizar contenido
|
||||
site_maintenance = Mantenimiento del sitio
|
||||
rebuild_search_index = Reconstruir índice de búsqueda
|
||||
rebuild_vis_cache = Reconstruir caché de visualización
|
||||
recompute_inferences_mixed_caps = Inferencias Recompute
|
||||
|
@ -481,6 +481,9 @@ restrict_logins_mixed_caps = Restringir conexiones
|
|||
site_information = Información del sitio
|
||||
user_accounts = Las cuentas de usuario
|
||||
|
||||
activate_developer_panel = Activar el panel desarrollador
|
||||
activate_developer_panel_mixed_caps = Activar el panel desarrollador
|
||||
|
||||
#
|
||||
# search controller ( PagedSearchController.java )
|
||||
#
|
|
@ -24,6 +24,7 @@ auth:ADMIN
|
|||
auth:hasPermission simplePermission:UseMiscellaneousAdminPages ;
|
||||
auth:hasPermission simplePermission:UseSparqlQueryPage ;
|
||||
auth:hasPermission simplePermission:PageViewableAdmin ;
|
||||
auth:hasPermission simplePermission:EnableDeveloperPanel ;
|
||||
|
||||
# permissions for CURATOR and above.
|
||||
auth:hasPermission simplePermission:EditOntology ;
|
||||
|
|
|
@ -76,6 +76,8 @@ public class SimplePermission extends Permission {
|
|||
NAMESPACE + "UseAdvancedDataToolsPages");
|
||||
public static final SimplePermission USE_SPARQL_QUERY_PAGE = new SimplePermission(
|
||||
NAMESPACE + "UseSparqlQueryPage");
|
||||
public static final SimplePermission ENABLE_DEVELOPER_PANEL = new SimplePermission(
|
||||
NAMESPACE + "EnableDeveloperPanel");
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
|
|
@ -57,7 +57,7 @@ public class Classes2ClassesOperationController extends BaseEditController {
|
|||
return;
|
||||
}
|
||||
|
||||
VClassDao vcDao = request.getUnfilteredAssertionsWebappDaoFactory().getVClassDao();
|
||||
VClassDao vcDao = request.getLanguageNeutralWebappDaoFactory().getVClassDao();
|
||||
|
||||
String modeStr = request.getParameter("opMode");
|
||||
modeStr = (modeStr == null) ? "" : modeStr;
|
||||
|
|
|
@ -53,14 +53,14 @@ public class BaseSiteAdminController extends FreemarkerHttpServlet {
|
|||
|
||||
body.put("dataInput", getDataInputData(vreq));
|
||||
body.put("siteConfig", getSiteConfigData(vreq));
|
||||
body.put("indexCacheRebuild", getIndexCacheRebuildUrls(vreq));
|
||||
body.put("siteMaintenance", getSiteMaintenanceUrls(vreq));
|
||||
body.put("ontologyEditor", getOntologyEditorData(vreq));
|
||||
body.put("dataTools", getDataToolsUrls(vreq));
|
||||
|
||||
return new TemplateResponseValues(TEMPLATE_DEFAULT, body);
|
||||
}
|
||||
|
||||
protected Map<String, String> getIndexCacheRebuildUrls(VitroRequest vreq) {
|
||||
protected Map<String, String> getSiteMaintenanceUrls(VitroRequest vreq) {
|
||||
|
||||
Map<String, String> urls = new HashMap<String, String>();
|
||||
|
||||
|
@ -73,6 +73,14 @@ public class BaseSiteAdminController extends FreemarkerHttpServlet {
|
|||
urls.put("rebuildSearchIndex", UrlBuilder.getUrl("/SearchIndex"));
|
||||
}
|
||||
|
||||
if (PolicyHelper.isAuthorizedForActions(vreq, SimplePermission.LOGIN_DURING_MAINTENANCE.ACTIONS)) {
|
||||
urls.put("restrictLogins", UrlBuilder.getUrl("/admin/restrictLogins"));
|
||||
}
|
||||
|
||||
if (PolicyHelper.isAuthorizedForActions(vreq, SimplePermission.ENABLE_DEVELOPER_PANEL.ACTIONS)) {
|
||||
urls.put("activateDeveloperPanel", "javascript:new DeveloperPanel(developerAjaxUrl).setupDeveloperPanel({developerEnabled: true});");
|
||||
}
|
||||
|
||||
return urls;
|
||||
}
|
||||
|
||||
|
@ -143,10 +151,6 @@ public class BaseSiteAdminController extends FreemarkerHttpServlet {
|
|||
data.put("startupStatusAlert", !StartupStatus.getBean(getServletContext()).allClear());
|
||||
}
|
||||
|
||||
if (PolicyHelper.isAuthorizedForActions(vreq, SimplePermission.LOGIN_DURING_MAINTENANCE.ACTIONS)) {
|
||||
data.put("restrictLogins", UrlBuilder.getUrl("/admin/restrictLogins"));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
|
|
@ -167,21 +167,21 @@ public class DeletePropertyController extends FreemarkerHttpServlet {
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//process object property
|
||||
private void processObjectProperty(VitroRequest vreq) {
|
||||
ObjectProperty prop = EditConfigurationUtils.getObjectProperty(vreq);
|
||||
|
||||
//if this property is true, it means the object needs to be deleted along with statement
|
||||
if(prop.getStubObjectRelation())
|
||||
//while the second test is to see if a different object uri (i.e. not the direct objet of the predicate)
|
||||
//needs to be deleted
|
||||
if(prop.getStubObjectRelation() || hasDeleteObjectUri(vreq))
|
||||
{
|
||||
deleteObjectIndividual(vreq);
|
||||
}
|
||||
|
||||
deleteObjectPropertyStatement(vreq);
|
||||
if(!hasDeleteObjectUri(vreq)) {
|
||||
deleteObjectPropertyStatement(vreq);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -194,7 +194,7 @@ public class DeletePropertyController extends FreemarkerHttpServlet {
|
|||
wdf.getPropertyInstanceDao().deleteObjectPropertyStatement(subjectUri, predicateUri, objectUri);
|
||||
}
|
||||
|
||||
private Individual getObjectIndividualForStubRelation(VitroRequest vreq, String objectUri) {
|
||||
private Individual getObjectIndividualForDeletion(VitroRequest vreq, String objectUri) {
|
||||
|
||||
Individual object = EditConfigurationUtils.getIndividual(vreq, objectUri);
|
||||
if(object == null) {
|
||||
|
@ -208,9 +208,13 @@ public class DeletePropertyController extends FreemarkerHttpServlet {
|
|||
|
||||
private void deleteObjectIndividual(VitroRequest vreq) {
|
||||
String objectUri = EditConfigurationUtils.getObjectUri(vreq);
|
||||
Individual object = getObjectIndividualForStubRelation(vreq, objectUri);
|
||||
if(hasDeleteObjectUri(vreq)) {
|
||||
//if a different individual needs to be deleted, get that uri instead
|
||||
objectUri = getDeleteObjectUri(vreq);
|
||||
}
|
||||
Individual object = getObjectIndividualForDeletion(vreq, objectUri);
|
||||
if(object != null) {
|
||||
log.warn("Deleting individual " + object.getName() + "since property has been set to force range object deletion");
|
||||
log.warn("Deleting individual " + object.getName() + "since property has been set to force range object deletion or has been set to delete a specific object");
|
||||
WebappDaoFactory wdf = vreq.getWebappDaoFactory();
|
||||
wdf.getIndividualDao().deleteIndividual(object);
|
||||
} else {
|
||||
|
@ -218,6 +222,16 @@ public class DeletePropertyController extends FreemarkerHttpServlet {
|
|||
log.error("could not find object as request attribute or in model " + objectUri);
|
||||
}
|
||||
}
|
||||
|
||||
//This checks if the object uri is not the individual to be deleted but another individual connected
|
||||
private String getDeleteObjectUri(VitroRequest vreq) {
|
||||
return (String) vreq.getParameter("deleteObjectUri");
|
||||
}
|
||||
|
||||
private boolean hasDeleteObjectUri(VitroRequest vreq) {
|
||||
String deleteObjectUri = getDeleteObjectUri(vreq);
|
||||
return (deleteObjectUri != null && !deleteObjectUri.isEmpty());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ public class DelimitingTemplateLoader implements TemplateLoader {
|
|||
@Override
|
||||
public Object findTemplateSource(String name) throws IOException {
|
||||
Object innerTS = innerLoader.findTemplateSource(name);
|
||||
log.debug("template source for '" + name + "' is '" + innerTS + "'");
|
||||
if (innerTS == null) {
|
||||
return null;
|
||||
} else {
|
||||
|
|
|
@ -1,162 +0,0 @@
|
|||
/* $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.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import freemarker.cache.TemplateLoader;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A {@link TemplateLoader} that treats a directory and its sub-directories as a
|
||||
* flat namespace.
|
||||
* </p>
|
||||
* <p>
|
||||
* When a request is made to find a template source, the loader will search its
|
||||
* base directory and any sub-directories for a file with a matching name. So a
|
||||
* request for <code>myFile.ftl</code> might return a reference to a file at
|
||||
* <code>base/myFile.ftl</code> or at <code>base/this/myFile.ftl</code>
|
||||
* </p>
|
||||
* <p>
|
||||
* The order in which the sub-directories are searched is unspecified. The first
|
||||
* matching file will be returned.
|
||||
* </p>
|
||||
* <p>
|
||||
* A path (absolute or relative) on the source name would be meaningless, so any
|
||||
* such path will be stripped before the search is made. That is, a request for
|
||||
* <code>path/file.ftl</code> or <code>/absolute/path/file.ftl</code>is
|
||||
* functionally identical to a request for <code>file.ftl</code>
|
||||
* </p>
|
||||
* <p>
|
||||
* </p>
|
||||
*/
|
||||
public class FlatteningTemplateLoader implements TemplateLoader {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(FlatteningTemplateLoader.class);
|
||||
|
||||
private final File baseDir;
|
||||
|
||||
public FlatteningTemplateLoader(File baseDir) {
|
||||
if (baseDir == null) {
|
||||
throw new NullPointerException("baseDir may not be null.");
|
||||
}
|
||||
if (!baseDir.exists()) {
|
||||
throw new IllegalArgumentException("Template directory '"
|
||||
+ baseDir.getAbsolutePath() + "' does not exist");
|
||||
}
|
||||
if (!baseDir.isDirectory()) {
|
||||
throw new IllegalArgumentException("Template directory '"
|
||||
+ baseDir.getAbsolutePath() + "' is not a directory");
|
||||
}
|
||||
if (!baseDir.canRead()) {
|
||||
throw new IllegalArgumentException("Can't read template "
|
||||
+ "directory '" + baseDir.getAbsolutePath() + "'");
|
||||
}
|
||||
|
||||
log.debug("Created template loader - baseDir is '"
|
||||
+ baseDir.getAbsolutePath() + "'");
|
||||
this.baseDir = baseDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for a file by this name in the base directory, or its
|
||||
* subdirectories, disregarding any path information.
|
||||
*
|
||||
* @return a {@link File} that can be used in subsequent calls the template
|
||||
* loader methods, or <code>null</code> if no template is found.
|
||||
*/
|
||||
@Override
|
||||
public Object findTemplateSource(String name) throws IOException {
|
||||
if (name == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int lastSlashHere = name.indexOf('/');
|
||||
String trimmedName = (lastSlashHere == -1) ? name : name
|
||||
.substring(lastSlashHere + 1);
|
||||
|
||||
// start the recursive search.
|
||||
File source = findFile(trimmedName, baseDir);
|
||||
if (source == null) {
|
||||
log.debug("For template name '" + name
|
||||
+ "', found no template file.");
|
||||
} else {
|
||||
log.debug("For template name '" + name + "', template file is "
|
||||
+ source.getAbsolutePath());
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively search for a file of this name.
|
||||
*/
|
||||
private File findFile(String name, File dir) {
|
||||
for (File child : dir.listFiles()) {
|
||||
if (child.isDirectory()) {
|
||||
File file = findFile(name, child);
|
||||
if (file != null) {
|
||||
return file;
|
||||
}
|
||||
} else {
|
||||
if (child.getName().equals(name)) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask the file when it was last modified.
|
||||
*
|
||||
* @param templateSource
|
||||
* a {@link File} that was obtained earlier from
|
||||
* {@link #findTemplateSource(String)}.
|
||||
*/
|
||||
@Override
|
||||
public long getLastModified(Object templateSource) {
|
||||
if (!(templateSource instanceof File)) {
|
||||
throw new IllegalArgumentException("templateSource is not a File: "
|
||||
+ templateSource);
|
||||
}
|
||||
|
||||
return ((File) templateSource).lastModified();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@link Reader} on this {@link File}. The framework will see that
|
||||
* the {@link Reader} is closed when it has been read.
|
||||
*
|
||||
* @param templateSource
|
||||
* a {@link File} that was obtained earlier from
|
||||
* {@link #findTemplateSource(String)}.
|
||||
*/
|
||||
@Override
|
||||
public Reader getReader(Object templateSource, String encoding)
|
||||
throws IOException {
|
||||
if (!(templateSource instanceof File)) {
|
||||
throw new IllegalArgumentException("templateSource is not a File: "
|
||||
+ templateSource);
|
||||
}
|
||||
|
||||
return new FileReader(((File) templateSource));
|
||||
}
|
||||
|
||||
/**
|
||||
* Nothing to do here. No resources to free up.
|
||||
*
|
||||
* @param templateSource
|
||||
* a {@link File} that was obtained earlier from
|
||||
* {@link #findTemplateSource(String)}.
|
||||
*/
|
||||
@Override
|
||||
public void closeTemplateSource(Object templateSource) throws IOException {
|
||||
}
|
||||
|
||||
}
|
|
@ -56,7 +56,7 @@ public class SimpleReasonerRecomputeController extends FreemarkerHttpServlet {
|
|||
"SimpleReasonerRecomputController.Recomputer");
|
||||
thread.setWorkLevel(WORKING);
|
||||
thread.start();
|
||||
messageStr = "Recompute of inferences started. See vivo log for further details.";
|
||||
messageStr = "Recompute of inferences started. See log for further details.";
|
||||
} else {
|
||||
body.put("formAction", UrlBuilder.getUrl("/RecomputeInferences"));
|
||||
}
|
||||
|
|
|
@ -71,8 +71,7 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp
|
|||
}
|
||||
|
||||
public void deleteObjectProperty(String propertyURI) {
|
||||
ObjectProperty op = new ObjectProperty();
|
||||
op.setURI(propertyURI);
|
||||
ObjectProperty op = getObjectPropertyByURI(propertyURI);
|
||||
deleteObjectProperty(op);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import java.util.HashMap;
|
|||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
|
@ -116,7 +117,11 @@ public class QueryUtils {
|
|||
return getQueryResults(queryStr, vreq.getRDFService());
|
||||
}
|
||||
|
||||
public static ResultSet getLanguageNeutralQueryResults(String queryStr, VitroRequest vreq) {
|
||||
public static ResultSet getQueryResults(String queryStr, QuerySolution initialBindings, RDFService rdfService) {
|
||||
return getQueryResults(bindVariables(queryStr, initialBindings), rdfService);
|
||||
}
|
||||
|
||||
public static ResultSet getLanguageNeutralQueryResults(String queryStr, VitroRequest vreq) {
|
||||
return getQueryResults(queryStr, vreq.getUnfilteredRDFService());
|
||||
}
|
||||
|
||||
|
@ -130,4 +135,38 @@ public class QueryUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The RDFService interface doesn't support initial bindings, so do text
|
||||
* substitutions instead.
|
||||
*/
|
||||
public static String bindVariables(String queryStr,
|
||||
QuerySolution initialBindings) {
|
||||
String bound = queryStr;
|
||||
for (Iterator<String> it = initialBindings.varNames(); it.hasNext();) {
|
||||
String name = it.next();
|
||||
RDFNode node = initialBindings.get(name);
|
||||
if (node.isLiteral()) {
|
||||
bound = bound.replace('?' + name, literalToString(node.asLiteral()));
|
||||
} else if (node.isURIResource()) {
|
||||
bound = bound.replace('?' + name, '<'+node.asResource().getURI()+ '>');
|
||||
}else {
|
||||
log.warn("Failed to bind anonymous resource variable '" + name
|
||||
+ "' to query '" + bound + "'");
|
||||
}
|
||||
}
|
||||
return bound;
|
||||
}
|
||||
|
||||
private static String literalToString(Literal l) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append('"').append(l.getLexicalForm()).append('"');
|
||||
if (l.getDatatypeURI() != null) {
|
||||
buffer.append("^^<").append(l.getDatatypeURI()).append(">");
|
||||
} else if (StringUtils.isNotEmpty(l.getLanguage())) {
|
||||
buffer.append("@").append(l.getLanguage());
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1048,11 +1048,20 @@ public class VClassDaoJena extends JenaBaseDao implements VClassDao {
|
|||
try {
|
||||
OntResource subclass = getOntClass(ontModel,c2c.getSubclassURI());
|
||||
OntResource superclass = getOntClass(ontModel,c2c.getSuperclassURI());
|
||||
if(subclass == null || superclass == null) {
|
||||
log.warn("unable to delete " + c2c.getSubclassURI() +
|
||||
" rdfs:subClassOf " + c2c.getSuperclassURI());
|
||||
if (subclass == null) {
|
||||
log.warn(c2c.getSubclassURI() + " not found in the model.");
|
||||
}
|
||||
if (superclass == null) {
|
||||
log.warn(c2c.getSuperclassURI() + " not found in the model.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
Model removal = ModelFactory.createDefaultModel();
|
||||
Model additions = ModelFactory.createDefaultModel(); // to repair any rdf:Lists
|
||||
if ((subclass != null) && (superclass != null)) {
|
||||
removal.add(ontModel.listStatements(subclass, RDFS.subClassOf, superclass));
|
||||
}
|
||||
removal.add(ontModel.listStatements(subclass, RDFS.subClassOf, superclass));
|
||||
if (subclass.isAnon()) {
|
||||
Model[] changeSet = getSmartRemoval(subclass, getOntModel());
|
||||
removal.add(changeSet[0]);
|
||||
|
|
|
@ -56,7 +56,10 @@ public class DefaultAddMissingIndividualFormGenerator implements EditConfigurati
|
|||
public static boolean isCreateNewIndividual(VitroRequest vreq, HttpSession session) {
|
||||
String command = vreq.getParameter("cmd");
|
||||
String predicateUri = EditConfigurationUtils.getPredicateUri(vreq);
|
||||
ObjectProperty objProp = vreq.getWebappDaoFactory().getObjectPropertyDao().getObjectPropertyByURI(predicateUri);
|
||||
//This method also looks at domain and range uris and so is different than just getting the
|
||||
//object property based on predicate uri alone
|
||||
ObjectProperty objProp = EditConfigurationUtils.getObjectPropertyForPredicate(vreq,
|
||||
predicateUri);
|
||||
if(objProp != null) {
|
||||
return(objProp.getOfferCreateNewOption() &&
|
||||
(
|
||||
|
|
|
@ -336,11 +336,11 @@ public class RequestModelsPrep implements Filter {
|
|||
}
|
||||
|
||||
/**
|
||||
* Language awareness is enabled unless they explicitly disable it.
|
||||
* Language awareness is disabled unless they explicitly enable it.
|
||||
*/
|
||||
private Boolean isLanguageAwarenessEnabled() {
|
||||
return Boolean.valueOf(props.getProperty("RDFService.languageFilter",
|
||||
"true"));
|
||||
"false"));
|
||||
}
|
||||
|
||||
private RDFService addLanguageAwareness(HttpServletRequest req,
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
package edu.cornell.mannlib.vitro.webapp.freemarker.config;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -18,15 +17,16 @@ import org.apache.commons.lang.StringUtils;
|
|||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
||||
import edu.cornell.mannlib.vitro.webapp.config.RevisionInfoBean;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.DelimitingTemplateLoader;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FlatteningTemplateLoader;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
|
||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.EditConfigurationConstants;
|
||||
import edu.cornell.mannlib.vitro.webapp.freemarker.loader.FreemarkerTemplateLoader;
|
||||
import edu.cornell.mannlib.vitro.webapp.i18n.freemarker.I18nMethodModel;
|
||||
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings.Keys;
|
||||
import edu.cornell.mannlib.vitro.webapp.web.directives.IndividualShortViewDirective;
|
||||
import edu.cornell.mannlib.vitro.webapp.web.directives.UrlDirective;
|
||||
import edu.cornell.mannlib.vitro.webapp.web.directives.WidgetDirective;
|
||||
|
@ -34,7 +34,6 @@ import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualLocalNameMethod;
|
|||
import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualPlaceholderImageUrlMethod;
|
||||
import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualProfileUrlMethod;
|
||||
import freemarker.cache.ClassTemplateLoader;
|
||||
import freemarker.cache.FileTemplateLoader;
|
||||
import freemarker.cache.MultiTemplateLoader;
|
||||
import freemarker.cache.TemplateLoader;
|
||||
import freemarker.ext.beans.BeansWrapper;
|
||||
|
@ -55,18 +54,17 @@ import freemarker.template.TemplateModelException;
|
|||
* own locale, etc.
|
||||
*
|
||||
* Each time a request asks for the configuration, check to see whether the
|
||||
* cache is still valid, and whether the theme has changed (needs a new
|
||||
* TemplateLoader). Store the request info to the ThreadLocal.
|
||||
* cache is still valid, whether the theme has changed (needs a new
|
||||
* TemplateLoader), and whether the DeveloperSettings have changed (might need a
|
||||
* new TemplateLoader). Store the request info to the ThreadLocal.
|
||||
*/
|
||||
public abstract class FreemarkerConfiguration {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(FreemarkerConfiguration.class);
|
||||
|
||||
private static final String PROPERTY_DEFEAT_CACHE = "developer.defeatFreemarkerCache";
|
||||
private static final String PROPERTY_INSERT_DELIMITERS = "developer.insertFreemarkerDelimiters";
|
||||
|
||||
private static volatile FreemarkerConfigurationImpl instance;
|
||||
private static volatile String previousThemeDir;
|
||||
private static volatile Map<String, Object> previousSettingsMap;
|
||||
|
||||
public static Configuration getConfig(HttpServletRequest req) {
|
||||
confirmInstanceIsSet();
|
||||
|
@ -92,14 +90,12 @@ public abstract class FreemarkerConfiguration {
|
|||
}
|
||||
}
|
||||
|
||||
/** If the developer doesn't want the cache, it's invalid. */
|
||||
private static boolean isTemplateCacheInvalid(HttpServletRequest req) {
|
||||
ConfigurationProperties props = ConfigurationProperties.getBean(req);
|
||||
|
||||
// If the developer doesn't want the cache, it's invalid.
|
||||
if (Boolean.valueOf(props.getProperty(PROPERTY_DEFEAT_CACHE))) {
|
||||
DeveloperSettings settings = DeveloperSettings.getBean(req);
|
||||
if (settings.getBoolean(Keys.DEFEAT_FREEMARKER_CACHE)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -113,7 +109,8 @@ public abstract class FreemarkerConfiguration {
|
|||
private static void keepTemplateLoaderCurrentWithThemeDirectory(
|
||||
HttpServletRequest req) {
|
||||
String themeDir = getThemeDirectory(req);
|
||||
if (hasThemeDirectoryChanged(themeDir)) {
|
||||
if (hasThemeDirectoryChanged(themeDir)
|
||||
|| haveDeveloperSettingsChanged(req)) {
|
||||
TemplateLoader tl = createTemplateLoader(req, themeDir);
|
||||
instance.setTemplateLoader(tl);
|
||||
}
|
||||
|
@ -134,44 +131,48 @@ public abstract class FreemarkerConfiguration {
|
|||
}
|
||||
}
|
||||
|
||||
private static boolean haveDeveloperSettingsChanged(HttpServletRequest req) {
|
||||
Map<String, Object> settingsMap = DeveloperSettings.getBean(req)
|
||||
.getSettingsMap();
|
||||
if (settingsMap.equals(previousSettingsMap)) {
|
||||
return false;
|
||||
} else {
|
||||
previousSettingsMap = settingsMap;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static TemplateLoader createTemplateLoader(HttpServletRequest req,
|
||||
String themeDir) {
|
||||
ServletContext ctx = req.getSession().getServletContext();
|
||||
ConfigurationProperties props = ConfigurationProperties.getBean(ctx);
|
||||
|
||||
List<TemplateLoader> loaders = new ArrayList<TemplateLoader>();
|
||||
|
||||
// Theme template loader
|
||||
// Theme template loader - only if the theme has a template directory.
|
||||
String themeTemplatePath = ctx.getRealPath(themeDir) + "/templates";
|
||||
File themeTemplateDir = new File(themeTemplatePath);
|
||||
// A theme need not contain a template directory.
|
||||
if (themeTemplateDir.exists()) {
|
||||
try {
|
||||
FileTemplateLoader themeFtl = new FileTemplateLoader(
|
||||
themeTemplateDir);
|
||||
loaders.add(themeFtl);
|
||||
} catch (IOException e) {
|
||||
log.error("Error creating theme template loader", e);
|
||||
}
|
||||
loaders.add(new FreemarkerTemplateLoader(themeTemplateDir));
|
||||
}
|
||||
|
||||
// Vitro template loader
|
||||
String vitroTemplatePath = ctx.getRealPath("/templates/freemarker");
|
||||
loaders.add(new FlatteningTemplateLoader(new File(vitroTemplatePath)));
|
||||
loaders.add(new FreemarkerTemplateLoader(new File(vitroTemplatePath)));
|
||||
|
||||
// TODO VIVO-243 Why is this here?
|
||||
loaders.add(new ClassTemplateLoader(FreemarkerConfiguration.class, ""));
|
||||
|
||||
|
||||
TemplateLoader[] loaderArray = loaders
|
||||
.toArray(new TemplateLoader[loaders.size()]);
|
||||
MultiTemplateLoader mtl = new MultiTemplateLoader(loaderArray);
|
||||
TemplateLoader tl = new MultiTemplateLoader(loaderArray);
|
||||
|
||||
// If requested, add delimiters to the templates.
|
||||
if (Boolean.valueOf(props.getProperty(PROPERTY_INSERT_DELIMITERS))) {
|
||||
return new DelimitingTemplateLoader(mtl);
|
||||
} else {
|
||||
return mtl;
|
||||
DeveloperSettings settings = DeveloperSettings.getBean(req);
|
||||
if (settings.getBoolean(Keys.INSERT_FREEMARKER_DELIMITERS)) {
|
||||
tl = new DelimitingTemplateLoader(tl);
|
||||
}
|
||||
|
||||
return tl;
|
||||
}
|
||||
|
||||
private static void setThreadLocalsForRequest(HttpServletRequest req) {
|
||||
|
|
|
@ -287,6 +287,7 @@ public class FreemarkerConfigurationImpl extends Configuration {
|
|||
urls.put("images", UrlBuilder.getUrl("/images"));
|
||||
urls.put("theme", UrlBuilder.getUrl(themeDir));
|
||||
urls.put("index", UrlBuilder.getUrl("/browse"));
|
||||
urls.put("developerAjax", UrlBuilder.getUrl("/admin/developerAjax"));
|
||||
|
||||
return urls;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,323 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.freemarker.loader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.Comparator;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import freemarker.cache.TemplateLoader;
|
||||
|
||||
/**
|
||||
* Loads Freemarker templates from a given directory.
|
||||
*
|
||||
* Different from a file loader in two ways:
|
||||
*
|
||||
* 1) Flattens the directory. When it searches for a template, it will look in
|
||||
* the base directory and in any sub-directories. While doing this, it ignores
|
||||
* any path that is attached to the template name.
|
||||
*
|
||||
* So if you were to ask for 'admin/silly.ftl', it would search for 'silly.ftl'
|
||||
* in the base directory, and in any sub-directories, until it finds one.
|
||||
*
|
||||
* 2) Accepts approximate matches on locales. When asked for a template, it will
|
||||
* accepts an approximate match that matches the basename and extension, and
|
||||
* language or region if specifed. So a search for a template with no language
|
||||
* or region will prefer an exact match, but will accept one with language or
|
||||
* both language and region.
|
||||
*
|
||||
* <pre>
|
||||
* "this_es_MX.ftl" matches "this_es_MX.ftl"
|
||||
* "this_es.ftl" matches "this_es.ftl" or "this_es_MX.ftl"
|
||||
* "this.ftl" matches "this.ftl" or "this_es.ftl" or "this_es_MX.ftl"
|
||||
* </pre>
|
||||
*
|
||||
* This allows Freemarker to mimic the behavior of the language filtering RDF
|
||||
* service, because if Freemarker does not find a match for "this_es_MX.ftl", it
|
||||
* will try again with "this_es.ftl" and "this.ftl". So the net effect is that a
|
||||
* search for "silly_es_MX.ftl" would eventually return any of these, in order
|
||||
* of preference:
|
||||
*
|
||||
* <pre>
|
||||
* silly_es_MX.ftl
|
||||
* silly_es.ftl
|
||||
* silly_es_*.ftl
|
||||
* silly.ftl
|
||||
* silly_*.ftl
|
||||
* </pre>
|
||||
*
|
||||
* If more than one template file qualifies, we choose by best fit, shortest
|
||||
* path, and alphabetical order, to insure that identical requests produce
|
||||
* identical results.
|
||||
*/
|
||||
public class FreemarkerTemplateLoader implements TemplateLoader {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(FreemarkerTemplateLoader.class);
|
||||
|
||||
private final File baseDir;
|
||||
|
||||
public FreemarkerTemplateLoader(File baseDir) {
|
||||
if (baseDir == null) {
|
||||
throw new NullPointerException("baseDir may not be null.");
|
||||
}
|
||||
|
||||
String path = baseDir.getAbsolutePath();
|
||||
if (!baseDir.exists()) {
|
||||
throw new IllegalArgumentException("Template directory '" + path
|
||||
+ "' does not exist");
|
||||
}
|
||||
if (!baseDir.isDirectory()) {
|
||||
throw new IllegalArgumentException("Template directory '" + path
|
||||
+ "' is not a directory");
|
||||
}
|
||||
if (!baseDir.canRead()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't read template directory '" + path + "'");
|
||||
}
|
||||
|
||||
log.debug("Created template loader - baseDir is '" + path + "'");
|
||||
this.baseDir = baseDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the best template for this name. Walk the tree finding all possible
|
||||
* matches, then choose our favorite.
|
||||
*/
|
||||
@Override
|
||||
public Object findTemplateSource(String name) throws IOException {
|
||||
if (StringUtils.isBlank(name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
SortedSet<PathPieces> matches = findAllMatches(new PathPieces(name));
|
||||
|
||||
if (matches.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return matches.last().path.toFile();
|
||||
}
|
||||
}
|
||||
|
||||
private SortedSet<PathPieces> findAllMatches(PathPieces searchTerm) {
|
||||
PathPiecesFileVisitor visitor = new PathPiecesFileVisitor(searchTerm);
|
||||
try {
|
||||
Files.walkFileTree(baseDir.toPath(), visitor);
|
||||
} catch (IOException e) {
|
||||
log.error(e);
|
||||
}
|
||||
return visitor.getMatches();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask the file when it was last modified.
|
||||
*
|
||||
* @param templateSource
|
||||
* a File that was obtained earlier from findTemplateSource().
|
||||
*/
|
||||
@Override
|
||||
public long getLastModified(Object templateSource) {
|
||||
return asFile(templateSource).lastModified();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Reader on this File. The framework will close the Reader after
|
||||
* reading it.
|
||||
*
|
||||
* @param templateSource
|
||||
* a File that was obtained earlier from findTemplateSource().
|
||||
*/
|
||||
@Override
|
||||
public Reader getReader(Object templateSource, String encoding)
|
||||
throws IOException {
|
||||
return new FileReader(asFile(templateSource));
|
||||
}
|
||||
|
||||
/**
|
||||
* Nothing to do here. No resources to free up.
|
||||
*
|
||||
* @param templateSource
|
||||
* a File that was obtained earlier from findTemplateSource().
|
||||
*/
|
||||
@Override
|
||||
public void closeTemplateSource(Object templateSource) throws IOException {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
/**
|
||||
* That templateSource is a File, right?
|
||||
*/
|
||||
private File asFile(Object templateSource) {
|
||||
if (templateSource instanceof File) {
|
||||
return (File) templateSource;
|
||||
} else {
|
||||
throw new IllegalArgumentException("templateSource is not a File: "
|
||||
+ templateSource);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Helper classes
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Break a path into handy segments, so we can see whether they match the
|
||||
* search term, and how well they match.
|
||||
*/
|
||||
static class PathPieces {
|
||||
static final Pattern PATTERN = Pattern.compile("(.+?)" // base name
|
||||
+ "(_[a-z]{2})?" // optional language
|
||||
+ "(_[A-Z]{2})?" // optional country
|
||||
+ "(\\.\\w+)?" // optional extension
|
||||
);
|
||||
|
||||
final Path path;
|
||||
final String base;
|
||||
final String language;
|
||||
final String region;
|
||||
final String extension;
|
||||
|
||||
public PathPieces(String pathString) {
|
||||
this(Paths.get(pathString));
|
||||
}
|
||||
|
||||
public PathPieces(Path path) {
|
||||
this.path = path;
|
||||
|
||||
String filename = path.getFileName().toString();
|
||||
|
||||
Matcher m = PATTERN.matcher(filename);
|
||||
if (m.matches()) {
|
||||
base = getGroup(m, 1);
|
||||
language = getGroup(m, 2);
|
||||
region = getGroup(m, 3);
|
||||
extension = getGroup(m, 4);
|
||||
} else {
|
||||
base = filename;
|
||||
language = "";
|
||||
region = "";
|
||||
extension = "";
|
||||
}
|
||||
}
|
||||
|
||||
private String getGroup(Matcher m, int i) {
|
||||
return (m.start(i) == -1) ? "" : m.group(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* If I'm searching for this, is that an acceptable match?
|
||||
*
|
||||
* Note that this is asymetrical -- a search term without a region will
|
||||
* match a candidate with a region, but not vice versa. Same with
|
||||
* language.
|
||||
*/
|
||||
public boolean matches(PathPieces that) {
|
||||
return base.equals(that.base) && extension.equals(that.extension)
|
||||
&& (language.isEmpty() || language.equals(that.language))
|
||||
&& (region.isEmpty() || region.equals(that.region));
|
||||
}
|
||||
|
||||
/**
|
||||
* How good a match is that to this?
|
||||
*/
|
||||
public int score(PathPieces that) {
|
||||
if (matches(that)) {
|
||||
if (that.language.equals(language)) {
|
||||
if (that.region.equals(region)) {
|
||||
return 3; // exact match.
|
||||
} else {
|
||||
return 2; // same language, approximate region.
|
||||
}
|
||||
} else {
|
||||
return 1; // approximate language.
|
||||
}
|
||||
} else {
|
||||
return -1; // doesn't match.
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PathPieces[" + base + ", " + language + ", " + region
|
||||
+ ", " + extension + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* While walking the file tree, collect all files that match the search
|
||||
* term, as a sorted set of PathPieces.
|
||||
*/
|
||||
static class PathPiecesFileVisitor extends SimpleFileVisitor<Path> {
|
||||
private final PathPieces searchTerm;
|
||||
private final SortedSet<PathPieces> matches;
|
||||
|
||||
public PathPiecesFileVisitor(PathPieces searchTerm) {
|
||||
this.searchTerm = searchTerm;
|
||||
this.matches = new TreeSet<>(new PathPiecesComparator(searchTerm));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path path, BasicFileAttributes attrs)
|
||||
throws IOException {
|
||||
if (fileQualifies(path)) {
|
||||
PathPieces found = new PathPieces(path);
|
||||
if (searchTerm.matches(found)) {
|
||||
matches.add(found);
|
||||
}
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
public boolean fileQualifies(Path path) {
|
||||
return Files.isRegularFile(path) && Files.isReadable(path);
|
||||
}
|
||||
|
||||
public SortedSet<PathPieces> getMatches() {
|
||||
return matches;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce an ordering of paths by desirability. Best match, then shortest
|
||||
* directory path, and finally alphabetical order.
|
||||
*/
|
||||
static class PathPiecesComparator implements Comparator<PathPieces> {
|
||||
private final PathPieces searchFor;
|
||||
|
||||
public PathPiecesComparator(PathPieces searchFor) {
|
||||
this.searchFor = searchFor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(PathPieces p1, PathPieces p2) {
|
||||
int scoring = searchFor.score(p1) - searchFor.score(p2);
|
||||
if (scoring != 0) {
|
||||
return scoring; // prefer matches to region and language
|
||||
}
|
||||
|
||||
int pathLength = p1.path.getNameCount() - p2.path.getNameCount();
|
||||
if (pathLength != 0) {
|
||||
return -pathLength; // shorter is better
|
||||
}
|
||||
|
||||
return -p1.path.compareTo(p2.path); // early in alphabet is better
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -3,10 +3,14 @@
|
|||
package edu.cornell.mannlib.vitro.webapp.i18n;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
@ -15,8 +19,10 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.i18n.selection.SelectedLocale;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings.Keys;
|
||||
|
||||
/**
|
||||
* Provides access to a bundle of text strings, based on the name of the bundle,
|
||||
|
@ -31,7 +37,6 @@ public class I18n {
|
|||
private static final Log log = LogFactory.getLog(I18n.class);
|
||||
|
||||
public static final String DEFAULT_BUNDLE_NAME = "all";
|
||||
private static final String PROPERTY_DEVELOPER_DEFEAT_CACHE = "developer.defeatI18nCache";
|
||||
|
||||
/**
|
||||
* If this attribute is present on the request, then the cache has already
|
||||
|
@ -103,6 +108,7 @@ public class I18n {
|
|||
protected I18nBundle getBundle(String bundleName, HttpServletRequest req) {
|
||||
log.debug("Getting bundle '" + bundleName + "'");
|
||||
|
||||
I18nLogger i18nLogger = new I18nLogger(req);
|
||||
try {
|
||||
checkDevelopmentMode(req);
|
||||
checkForChangeInThemeDirectory(req);
|
||||
|
@ -113,13 +119,13 @@ public class I18n {
|
|||
ResourceBundle.Control control = new ThemeBasedControl(ctx, dir);
|
||||
ResourceBundle rb = ResourceBundle.getBundle(bundleName,
|
||||
req.getLocale(), control);
|
||||
return new I18nBundle(bundleName, rb);
|
||||
return new I18nBundle(bundleName, rb, i18nLogger);
|
||||
} catch (MissingResourceException e) {
|
||||
log.warn("Didn't find text bundle '" + bundleName + "'");
|
||||
return I18nBundle.emptyBundle(bundleName);
|
||||
return I18nBundle.emptyBundle(bundleName, i18nLogger);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to create text bundle '" + bundleName + "'", e);
|
||||
return I18nBundle.emptyBundle(bundleName);
|
||||
return I18nBundle.emptyBundle(bundleName, i18nLogger);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,11 +133,7 @@ public class I18n {
|
|||
* If we are in development mode, clear the cache on each request.
|
||||
*/
|
||||
private void checkDevelopmentMode(HttpServletRequest req) {
|
||||
ConfigurationProperties bean = ConfigurationProperties.getBean(req);
|
||||
|
||||
String flag = bean
|
||||
.getProperty(PROPERTY_DEVELOPER_DEFEAT_CACHE, "false");
|
||||
if (Boolean.valueOf(flag.trim())) {
|
||||
if (DeveloperSettings.getBean(req).getBoolean(Keys.I18N_DEFEAT_CACHE)) {
|
||||
log.debug("In development mode - clearing the cache.");
|
||||
clearCacheOnRequest(req);
|
||||
}
|
||||
|
@ -170,7 +172,7 @@ public class I18n {
|
|||
* Instead of looking in the classpath, look in the theme i18n directory and
|
||||
* the application i18n directory.
|
||||
*/
|
||||
private static class ThemeBasedControl extends ResourceBundle.Control {
|
||||
static class ThemeBasedControl extends ResourceBundle.Control {
|
||||
private static final String BUNDLE_DIRECTORY = "i18n/";
|
||||
private final ServletContext ctx;
|
||||
private final String themeDirectory;
|
||||
|
@ -218,6 +220,52 @@ public class I18n {
|
|||
themeI18nPath, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* When creating the chain of acceptable Locales, include approximate
|
||||
* matches before giving up and using the root Locale.
|
||||
*
|
||||
* Check the list of supported Locales to see if any have the same
|
||||
* language but different region. If we find any, sort them and insert
|
||||
* them into the usual result list, just before the root Locale.
|
||||
*/
|
||||
@Override
|
||||
public List<Locale> getCandidateLocales(String baseName, Locale locale) {
|
||||
// Find the list of Locales that would normally be returned.
|
||||
List<Locale> usualList = super
|
||||
.getCandidateLocales(baseName, locale);
|
||||
|
||||
// If our "selectable locales" include no approximate matches that
|
||||
// are not already in the list, we're done.
|
||||
SortedSet<Locale> approximateMatches = findApproximateMatches(locale);
|
||||
approximateMatches.removeAll(usualList);
|
||||
if (approximateMatches.isEmpty()) {
|
||||
return usualList;
|
||||
}
|
||||
|
||||
// Otherwise, insert those approximate matches into the list just
|
||||
// before the ROOT locale.
|
||||
List<Locale> mergedList = new LinkedList<>(usualList);
|
||||
int rootLocaleHere = mergedList.indexOf(Locale.ROOT);
|
||||
if (rootLocaleHere == -1) {
|
||||
mergedList.addAll(approximateMatches);
|
||||
} else {
|
||||
mergedList.addAll(rootLocaleHere, approximateMatches);
|
||||
}
|
||||
return mergedList;
|
||||
}
|
||||
|
||||
private SortedSet<Locale> findApproximateMatches(Locale locale) {
|
||||
SortedSet<Locale> set = new TreeSet<>(new LocaleComparator());
|
||||
|
||||
for (Locale l : SelectedLocale.getSelectableLocales(ctx)) {
|
||||
if (locale.getLanguage().equals(l.getLanguage())) {
|
||||
set.add(l);
|
||||
}
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* The documentation for ResourceBundle.Control.newBundle() says I
|
||||
* should throw these exceptions.
|
||||
|
@ -238,5 +286,20 @@ public class I18n {
|
|||
"format must be one of these: " + FORMAT_DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class LocaleComparator implements Comparator<Locale> {
|
||||
@Override
|
||||
public int compare(Locale o1, Locale o2) {
|
||||
int c = o1.getLanguage().compareTo(o2.getLanguage());
|
||||
if (c == 0) {
|
||||
c = o1.getCountry().compareTo(o2.getCountry());
|
||||
if (c == 0) {
|
||||
c = o1.getVariant().compareTo(o2.getVariant());
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,24 +24,28 @@ public class I18nBundle {
|
|||
private static final String MESSAGE_BUNDLE_NOT_FOUND = "Text bundle ''{0}'' not found.";
|
||||
private static final String MESSAGE_KEY_NOT_FOUND = "Text bundle ''{0}'' has no text for ''{1}''";
|
||||
|
||||
public static I18nBundle emptyBundle(String bundleName) {
|
||||
return new I18nBundle(bundleName);
|
||||
public static I18nBundle emptyBundle(String bundleName,
|
||||
I18nLogger i18nLogger) {
|
||||
return new I18nBundle(bundleName, i18nLogger);
|
||||
}
|
||||
|
||||
private final String bundleName;
|
||||
private final ResourceBundle resources;
|
||||
private final String notFoundMessage;
|
||||
private final I18nLogger i18nLogger;
|
||||
|
||||
private I18nBundle(String bundleName) {
|
||||
this(bundleName, new EmptyResourceBundle(), MESSAGE_BUNDLE_NOT_FOUND);
|
||||
private I18nBundle(String bundleName, I18nLogger i18nLogger) {
|
||||
this(bundleName, new EmptyResourceBundle(), MESSAGE_BUNDLE_NOT_FOUND,
|
||||
i18nLogger);
|
||||
}
|
||||
|
||||
public I18nBundle(String bundleName, ResourceBundle resources) {
|
||||
this(bundleName, resources, MESSAGE_KEY_NOT_FOUND);
|
||||
public I18nBundle(String bundleName, ResourceBundle resources,
|
||||
I18nLogger i18nLogger) {
|
||||
this(bundleName, resources, MESSAGE_KEY_NOT_FOUND, i18nLogger);
|
||||
}
|
||||
|
||||
private I18nBundle(String bundleName, ResourceBundle resources,
|
||||
String notFoundMessage) {
|
||||
String notFoundMessage, I18nLogger i18nLogger) {
|
||||
if (bundleName == null) {
|
||||
throw new IllegalArgumentException("bundleName may not be null");
|
||||
}
|
||||
|
@ -57,22 +61,27 @@ public class I18nBundle {
|
|||
this.bundleName = bundleName;
|
||||
this.resources = resources;
|
||||
this.notFoundMessage = notFoundMessage;
|
||||
this.i18nLogger = i18nLogger;
|
||||
}
|
||||
|
||||
public String text(String key, Object... parameters) {
|
||||
|
||||
String textString;
|
||||
if (resources.containsKey(key)) {
|
||||
textString = resources.getString(key);
|
||||
log.debug("In '" + bundleName + "', " + key + "='" + textString
|
||||
+ "')");
|
||||
return formatString(textString, parameters);
|
||||
} else {
|
||||
String message = MessageFormat.format(notFoundMessage, bundleName,
|
||||
key);
|
||||
log.warn(message);
|
||||
return "ERROR: " + message;
|
||||
textString = "ERROR: " + message;
|
||||
}
|
||||
String result = formatString(textString, parameters);
|
||||
|
||||
if (i18nLogger != null) {
|
||||
i18nLogger.log(bundleName, key, parameters, textString, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String formatString(String textString, Object... parameters) {
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.i18n;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings.Keys;
|
||||
|
||||
/**
|
||||
* If enabled in developer mode, write a message to the log each time someone
|
||||
* asks for a language string.
|
||||
*
|
||||
* The I18nBundle has a life span of one HTTP request, and so does this.
|
||||
*/
|
||||
public class I18nLogger {
|
||||
private static final Log log = LogFactory.getLog(I18nLogger.class);
|
||||
|
||||
private final boolean isLogging;
|
||||
|
||||
public I18nLogger(HttpServletRequest req) {
|
||||
DeveloperSettings settings = DeveloperSettings.getBean(req);
|
||||
this.isLogging = settings.getBoolean(Keys.ENABLED)
|
||||
&& settings.getBoolean(Keys.I18N_LOG_STRINGS)
|
||||
&& log.isInfoEnabled();
|
||||
}
|
||||
|
||||
public void log(String bundleName, String key, Object[] parameters,
|
||||
String rawText, String formattedText) {
|
||||
if (isLogging) {
|
||||
String message = String.format(
|
||||
"Retrieved from %s.%s with %s: '%s'", bundleName, key,
|
||||
Arrays.toString(parameters), rawText);
|
||||
|
||||
if (!rawText.equals(formattedText)) {
|
||||
message += String.format(" --> '%s'", formattedText);
|
||||
}
|
||||
|
||||
log.info(message);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -134,7 +134,8 @@ public class LocaleSelectionSetup implements ServletContextListener {
|
|||
throws IllegalArgumentException {
|
||||
Locale locale = LocaleUtils.toLocale(localeString);
|
||||
|
||||
if (!LocaleUtils.isAvailableLocale(locale)) {
|
||||
if (!"es_GO".equals(localeString) && // No complaint about bogus locale
|
||||
!LocaleUtils.isAvailableLocale(locale)) {
|
||||
ssWarning("'" + locale + "' is not a recognized locale.");
|
||||
}
|
||||
return locale;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
package edu.cornell.mannlib.vitro.webapp.i18n.selection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
@ -124,7 +125,14 @@ public abstract class SelectedLocale {
|
|||
* an empty list, but never returns null.
|
||||
*/
|
||||
public static List<Locale> getSelectableLocales(HttpServletRequest req) {
|
||||
ServletContext ctx = req.getSession().getServletContext();
|
||||
return getSelectableLocales(req.getSession().getServletContext());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of selectable Locales from the servlet context. May return
|
||||
* an empty list, but never returns null.
|
||||
*/
|
||||
public static List<Locale> getSelectableLocales(ServletContext ctx) {
|
||||
Object ctxInfo = ctx.getAttribute(ATTRIBUTE_NAME);
|
||||
if (ctxInfo instanceof ContextSelectedLocale) {
|
||||
List<Locale> selectableLocales = ((ContextSelectedLocale) ctxInfo)
|
||||
|
@ -164,7 +172,8 @@ public abstract class SelectedLocale {
|
|||
}
|
||||
|
||||
this.forcedLocale = null;
|
||||
this.selectableLocales = selectableLocales;
|
||||
this.selectableLocales = Collections
|
||||
.unmodifiableList(new ArrayList<>(selectableLocales));
|
||||
}
|
||||
|
||||
public Locale getForcedLocale() {
|
||||
|
|
|
@ -207,6 +207,14 @@ public class KnowledgeBaseUpdater {
|
|||
StmtIterator sit = anonModel.listStatements();
|
||||
while (sit.hasNext()) {
|
||||
Statement stmt = sit.nextStatement();
|
||||
// Skip statements with blank nodes (unsupported) to avoid
|
||||
// excessive deletion. In the future, the whole updater
|
||||
// could be modified to change whole graphs at once through
|
||||
// the RDFService, but right now this whole thing is statement
|
||||
// based.
|
||||
if (stmt.getSubject().isAnon() || stmt.getObject().isAnon()) {
|
||||
continue;
|
||||
}
|
||||
Iterator<String> graphIt = dataset.listNames();
|
||||
while(graphIt.hasNext()) {
|
||||
String graph = graphIt.next();
|
||||
|
@ -223,8 +231,9 @@ public class KnowledgeBaseUpdater {
|
|||
//log.info("removed " + anonModel.size() + " statements from SPARQL CONSTRUCTs");
|
||||
} else {
|
||||
Model writeModel = dataset.getNamedModel(JenaDataSourceSetupBase.JENA_DB_MODEL);
|
||||
Model dedupeModel = dataset.getDefaultModel();
|
||||
Model additions = jiu.renameBNodes(
|
||||
anonModel, settings.getDefaultNamespace() + "n", writeModel);
|
||||
anonModel, settings.getDefaultNamespace() + "n", dedupeModel);
|
||||
Model actualAdditions = ModelFactory.createDefaultModel();
|
||||
StmtIterator stmtIt = additions.listStatements();
|
||||
while (stmtIt.hasNext()) {
|
||||
|
@ -346,7 +355,9 @@ public class KnowledgeBaseUpdater {
|
|||
}
|
||||
|
||||
public static boolean isUpdatableABoxGraph(String graphName) {
|
||||
return (!graphName.contains("tbox") && !graphName.contains("filegraph"));
|
||||
return (graphName != null && !graphName.contains("tbox")
|
||||
&& !graphName.contains("filegraph")
|
||||
&& !graphName.contains("x-arq:UnionGraph"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -217,6 +217,9 @@ public abstract class RDFServiceJena extends RDFServiceImpl implements RDFServic
|
|||
private List<Statement> sort(List<Statement> stmts) {
|
||||
List<Statement> output = new ArrayList<Statement>();
|
||||
int originalSize = stmts.size();
|
||||
if(originalSize == 1) {
|
||||
return stmts;
|
||||
}
|
||||
List <Statement> remaining = stmts;
|
||||
ConcurrentLinkedQueue<Resource> subjQueue = new ConcurrentLinkedQueue<Resource>();
|
||||
for(Statement stmt : remaining) {
|
||||
|
|
|
@ -15,16 +15,20 @@ import org.apache.commons.lang.StringUtils;
|
|||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings.Keys;
|
||||
|
||||
/**
|
||||
* Writes the log message for the LoggingRDFService.
|
||||
*
|
||||
* If not enabled, or if the logging level is insufficient, this does nothing.
|
||||
*
|
||||
* If enabled, it checks for restrictions. If there is a restriction pattern
|
||||
* (regular expression), the a log message will only be printed if one of the
|
||||
* fully-qualified class names in the stack trace matches that pattern.
|
||||
* If enabled, it checks for restrictions. If there is a restriction on the call
|
||||
* stack (regular expression), then a log message will only be printed if the
|
||||
* pattern is found in the concatenated call stack (fully-qualified class names
|
||||
* and method names). If there is a restriction on the query string (regular
|
||||
* expression) then a log message will only be printed if the pattern is found
|
||||
* in the query string.
|
||||
*
|
||||
* If everything passes muster, the constructor will record the time that the
|
||||
* instance was created.
|
||||
|
@ -41,16 +45,13 @@ import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
|||
public class RDFServiceLogger implements AutoCloseable {
|
||||
private static final Log log = LogFactory.getLog(RDFServiceLogger.class);
|
||||
|
||||
private static final String PROPERTY_ENABLED = "developer.loggingRDFService.enable";
|
||||
private static final String PROPERTY_STACK_TRACE = "developer.loggingRDFService.stackTrace";
|
||||
private static final String PROPERTY_RESTRICTION = "developer.loggingRDFService.restriction";
|
||||
|
||||
private final ServletContext ctx;
|
||||
private final Object[] args;
|
||||
|
||||
private boolean isEnabled;
|
||||
private boolean traceRequested;
|
||||
private Pattern restriction;
|
||||
private Pattern queryStringRestriction;
|
||||
private Pattern callStackRestriction;
|
||||
|
||||
private String methodName;
|
||||
private List<StackTraceElement> trace = Collections.emptyList();
|
||||
|
@ -65,27 +66,33 @@ public class RDFServiceLogger implements AutoCloseable {
|
|||
|
||||
if (isEnabled && log.isInfoEnabled()) {
|
||||
loadStackTrace();
|
||||
if (passesRestrictions()) {
|
||||
if (passesQueryRestriction() && passesStackRestriction()) {
|
||||
this.startTime = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void getProperties() {
|
||||
ConfigurationProperties props = ConfigurationProperties.getBean(ctx);
|
||||
isEnabled = Boolean.valueOf(props.getProperty(PROPERTY_ENABLED));
|
||||
traceRequested = Boolean.valueOf(props
|
||||
.getProperty(PROPERTY_STACK_TRACE));
|
||||
DeveloperSettings settings = DeveloperSettings.getBean(ctx);
|
||||
isEnabled = settings.getBoolean(Keys.LOGGING_RDF_ENABLE);
|
||||
traceRequested = settings.getBoolean(Keys.LOGGING_RDF_STACK_TRACE);
|
||||
queryStringRestriction = patternFromSettings(settings,
|
||||
Keys.LOGGING_RDF_QUERY_RESTRICTION);
|
||||
callStackRestriction = patternFromSettings(settings,
|
||||
Keys.LOGGING_RDF_STACK_RESTRICTION);
|
||||
}
|
||||
|
||||
String restrictionString = props.getProperty(PROPERTY_RESTRICTION);
|
||||
if (StringUtils.isNotBlank(restrictionString)) {
|
||||
try {
|
||||
restriction = Pattern.compile(restrictionString);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to compile the pattern for "
|
||||
+ PROPERTY_RESTRICTION + " = " + restriction + " " + e);
|
||||
isEnabled = false;
|
||||
}
|
||||
private Pattern patternFromSettings(DeveloperSettings settings, Keys key) {
|
||||
String patternString = settings.getString(key);
|
||||
if (StringUtils.isBlank(patternString)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return Pattern.compile(patternString);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to compile the pattern for " + key + " = "
|
||||
+ patternString + " " + e);
|
||||
return Pattern.compile("^_____NEVER MATCH_____$");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,16 +151,39 @@ public class RDFServiceLogger implements AutoCloseable {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean passesRestrictions() {
|
||||
if (restriction == null) {
|
||||
private boolean passesQueryRestriction() {
|
||||
if (queryStringRestriction == null) {
|
||||
return true;
|
||||
}
|
||||
for (StackTraceElement ste : trace) {
|
||||
if (restriction.matcher(ste.getClassName()).find()) {
|
||||
return true;
|
||||
String q = assembleQueryString();
|
||||
return queryStringRestriction.matcher(q).find();
|
||||
}
|
||||
|
||||
private String assembleQueryString() {
|
||||
StringBuilder query = new StringBuilder();
|
||||
for (Object arg : args) {
|
||||
if (arg instanceof String) {
|
||||
query.append((String) arg).append(" ");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return query.deleteCharAt(query.length() - 1).toString();
|
||||
}
|
||||
|
||||
private boolean passesStackRestriction() {
|
||||
if (callStackRestriction == null) {
|
||||
return true;
|
||||
}
|
||||
String q = assembleCallStackString();
|
||||
return callStackRestriction.matcher(q).find();
|
||||
}
|
||||
|
||||
private String assembleCallStackString() {
|
||||
StringBuilder stack = new StringBuilder();
|
||||
for (StackTraceElement ste : trace) {
|
||||
stack.append(ste.getClassName()).append(" ")
|
||||
.append(ste.getMethodName()).append(" ");
|
||||
}
|
||||
return stack.deleteCharAt(stack.length() - 1).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -4,6 +4,7 @@ package edu.cornell.mannlib.vitro.webapp.rdfservice.impl.sparql;
|
|||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
|
@ -14,7 +15,9 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
|||
import org.apache.commons.httpclient.HttpClient;
|
||||
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
|
||||
import org.apache.commons.httpclient.NameValuePair;
|
||||
import org.apache.commons.httpclient.methods.GetMethod;
|
||||
import org.apache.commons.httpclient.methods.PostMethod;
|
||||
import org.apache.commons.httpclient.params.HttpMethodParams;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
@ -38,6 +41,7 @@ import com.hp.hpl.jena.rdf.model.ModelFactory;
|
|||
import com.hp.hpl.jena.rdf.model.RDFNode;
|
||||
import com.hp.hpl.jena.rdf.model.Statement;
|
||||
import com.hp.hpl.jena.rdf.model.StmtIterator;
|
||||
import com.hp.hpl.jena.sparql.engine.http.QueryEngineHTTP;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.SparqlGraph;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeListener;
|
||||
|
@ -84,11 +88,11 @@ public class RDFServiceSparql extends RDFServiceImpl implements RDFService {
|
|||
this.readRepository = new HTTPRepository(readEndpointURI);
|
||||
this.updateRepository = new HTTPRepository(updateEndpointURI);
|
||||
|
||||
testConnection();
|
||||
|
||||
MultiThreadedHttpConnectionManager mgr = new MultiThreadedHttpConnectionManager();
|
||||
mgr.getParams().setDefaultMaxConnectionsPerHost(10);
|
||||
mgr.getParams().setDefaultMaxConnectionsPerHost(50);
|
||||
this.httpClient = new HttpClient(mgr);
|
||||
|
||||
testConnection();
|
||||
}
|
||||
|
||||
private void testConnection() {
|
||||
|
@ -278,13 +282,28 @@ public class RDFServiceSparql extends RDFServiceImpl implements RDFService {
|
|||
*/
|
||||
@Override
|
||||
public InputStream sparqlSelectQuery(String queryStr, RDFService.ResultFormat resultFormat) throws RDFServiceException {
|
||||
|
||||
Query query = createQuery(queryStr);
|
||||
QueryExecution qe = QueryExecutionFactory.sparqlService(readEndpointURI, query);
|
||||
|
||||
|
||||
//QueryEngineHTTP qh = new QueryEngineHTTP(readEndpointURI, queryStr);
|
||||
|
||||
GetMethod meth = new GetMethod(readEndpointURI);
|
||||
try {
|
||||
ResultSet resultSet = qe.execSelect();
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
meth.addRequestHeader("Accept", "application/sparql-results+xml");
|
||||
NameValuePair param = new NameValuePair();
|
||||
param.setName("query");
|
||||
param.setValue(queryStr);
|
||||
NameValuePair[] params = new NameValuePair[1];
|
||||
params[0] = param;
|
||||
meth.setQueryString(params);
|
||||
int response = httpClient.executeMethod(meth);
|
||||
if (response > 399) {
|
||||
log.error("response " + response + " to query. \n");
|
||||
log.debug("update string: \n" + queryStr);
|
||||
throw new RDFServiceException("Unable to perform SPARQL UPDATE");
|
||||
}
|
||||
|
||||
InputStream in = meth.getResponseBodyAsStream();
|
||||
ResultSet resultSet = ResultSetFactory.fromXML(in);
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
|
||||
switch (resultFormat) {
|
||||
case CSV:
|
||||
|
@ -301,12 +320,14 @@ public class RDFServiceSparql extends RDFServiceImpl implements RDFService {
|
|||
break;
|
||||
default:
|
||||
throw new RDFServiceException("unrecognized result format");
|
||||
}
|
||||
|
||||
}
|
||||
InputStream result = new ByteArrayInputStream(outputStream.toByteArray());
|
||||
return result;
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException(ioe);
|
||||
} finally {
|
||||
qe.close();
|
||||
//qh.close();
|
||||
meth.releaseConnection();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -474,7 +495,7 @@ public class RDFServiceSparql extends RDFServiceImpl implements RDFService {
|
|||
int response = httpClient.executeMethod(meth);
|
||||
if (response > 399) {
|
||||
log.error("response " + response + " to update. \n");
|
||||
log.debug("update string: \n" + updateString);
|
||||
//log.debug("update string: \n" + updateString);
|
||||
throw new RDFServiceException("Unable to perform SPARQL UPDATE");
|
||||
}
|
||||
} finally {
|
||||
|
@ -744,6 +765,8 @@ public class RDFServiceSparql extends RDFServiceImpl implements RDFService {
|
|||
private List<Statement> sort(List<Statement> stmts) {
|
||||
List<Statement> output = new ArrayList<Statement>();
|
||||
int originalSize = stmts.size();
|
||||
if (originalSize == 1)
|
||||
return stmts;
|
||||
List <Statement> remaining = stmts;
|
||||
ConcurrentLinkedQueue<com.hp.hpl.jena.rdf.model.Resource> subjQueue =
|
||||
new ConcurrentLinkedQueue<com.hp.hpl.jena.rdf.model.Resource>();
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
package edu.cornell.mannlib.vitro.webapp.reasoner;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
@ -295,14 +296,35 @@ public class ABoxRecomputer {
|
|||
*/
|
||||
protected Collection<String> getAllIndividualURIs() {
|
||||
|
||||
String queryString = "SELECT DISTINCT ?s WHERE { GRAPH ?g { ?s a ?type } " +
|
||||
" FILTER (!bound(?g) || !regex(str(?g),\"tbox\")) } ORDER BY ?s";
|
||||
return getIndividualURIs(queryString);
|
||||
HashSet<String> individualURIs = new HashSet<String>();
|
||||
|
||||
List<String> classList = new ArrayList<String>();
|
||||
|
||||
tboxModel.enterCriticalSection(Lock.READ);
|
||||
try {
|
||||
StmtIterator classIt = tboxModel.listStatements(
|
||||
(Resource) null, RDF.type, OWL.Class);
|
||||
while(classIt.hasNext()) {
|
||||
Statement stmt = classIt.nextStatement();
|
||||
if(stmt.getSubject().isURIResource()
|
||||
&& stmt.getSubject().getURI() != null
|
||||
&& !stmt.getSubject().getURI().isEmpty()) {
|
||||
classList.add(stmt.getSubject().getURI());
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
tboxModel.leaveCriticalSection();
|
||||
}
|
||||
|
||||
for (String classURI : classList) {
|
||||
String queryString = "SELECT ?s WHERE { ?s a <" + classURI + "> } ";
|
||||
getIndividualURIs(queryString, individualURIs);
|
||||
}
|
||||
|
||||
return individualURIs;
|
||||
}
|
||||
|
||||
protected Collection<String> getIndividualURIs(String queryString) {
|
||||
|
||||
Set<String> individuals = new HashSet<String>();
|
||||
protected void getIndividualURIs(String queryString, Set<String> individuals) {
|
||||
|
||||
int batchSize = 50000;
|
||||
int offset = 0;
|
||||
|
@ -342,7 +364,6 @@ public class ABoxRecomputer {
|
|||
offset += batchSize;
|
||||
}
|
||||
|
||||
return individuals;
|
||||
}
|
||||
|
||||
protected void addedABoxTypeAssertion(Resource individual, Model inferenceModel, HashSet<String> unknownTypes) {
|
||||
|
@ -410,6 +431,11 @@ public class ABoxRecomputer {
|
|||
while (iter.hasNext()) {
|
||||
Statement stmt = iter.next();
|
||||
|
||||
// skip statements with blank nodes to avoid excessive deletion
|
||||
if (stmt.getSubject().isAnon() || stmt.getObject().isAnon()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
inferenceModel.enterCriticalSection(Lock.WRITE);
|
||||
try {
|
||||
inferenceModel.remove(stmt);
|
||||
|
|
|
@ -10,22 +10,17 @@ import java.util.List;
|
|||
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.Model;
|
||||
import com.hp.hpl.jena.rdf.model.RDFNode;
|
||||
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 com.hp.hpl.jena.vocabulary.RDFS;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.QueryUtils;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.StatementToURIsToUpdate;
|
||||
|
||||
/**
|
||||
|
@ -38,13 +33,13 @@ import edu.cornell.mannlib.vitro.webapp.search.beans.StatementToURIsToUpdate;
|
|||
public class AdditionalURIsForObjectProperties implements StatementToURIsToUpdate {
|
||||
protected static final Log log = LogFactory.getLog(AdditionalURIsForObjectProperties.class);
|
||||
|
||||
protected Model model;
|
||||
protected final RDFService rdfService;
|
||||
|
||||
public AdditionalURIsForObjectProperties( Model model){
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdditionalURIsForObjectProperties(RDFService rdfService) {
|
||||
this.rdfService = rdfService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> findAdditionalURIsToIndex(Statement stmt) {
|
||||
if( stmt == null )
|
||||
return Collections.emptyList();
|
||||
|
@ -102,37 +97,27 @@ public class AdditionalURIsForObjectProperties implements StatementToURIsToUpdat
|
|||
Resource uriResource = ResourceFactory.createResource(uri);
|
||||
initialBinding.add("uri", uriResource);
|
||||
|
||||
Query sparqlQuery = QueryFactory.create( QUERY_FOR_RELATED );
|
||||
model.getLock().enterCriticalSection(Lock.READ);
|
||||
try{
|
||||
QueryExecution qExec = QueryExecutionFactory.create(sparqlQuery, model, initialBinding);
|
||||
try{
|
||||
ResultSet results = qExec.execSelect();
|
||||
while(results.hasNext()){
|
||||
QuerySolution soln = results.nextSolution();
|
||||
Iterator<String> iter = soln.varNames() ;
|
||||
while( iter.hasNext()){
|
||||
String name = iter.next();
|
||||
RDFNode node = soln.get( name );
|
||||
if( node != null ){
|
||||
if( node.isURIResource() ){
|
||||
additionalUris.add( node.as( Resource.class ).getURI() );
|
||||
}else{
|
||||
log.warn( "value from query for var " + name + " was not a URIResource, it was " + node);
|
||||
}
|
||||
}else{
|
||||
log.warn("value for query for var " + name + " was null");
|
||||
}
|
||||
ResultSet results = QueryUtils.getQueryResults(QUERY_FOR_RELATED,
|
||||
initialBinding, rdfService);
|
||||
|
||||
while(results.hasNext()){
|
||||
QuerySolution soln = results.nextSolution();
|
||||
Iterator<String> iter = soln.varNames() ;
|
||||
while( iter.hasNext()){
|
||||
String name = iter.next();
|
||||
RDFNode node = soln.get( name );
|
||||
if( node != null ){
|
||||
if( node.isURIResource() ){
|
||||
additionalUris.add( node.as( Resource.class ).getURI() );
|
||||
}else{
|
||||
log.warn( "value from query for var " + name + " was not a URIResource, it was " + node);
|
||||
}
|
||||
}
|
||||
}catch(Throwable t){
|
||||
log.error(t,t);
|
||||
} finally{
|
||||
qExec.close();
|
||||
}
|
||||
}finally{
|
||||
model.getLock().leaveCriticalSection();
|
||||
}else{
|
||||
log.warn("value for query for var " + name + " was null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return additionalUris;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,9 +5,8 @@ package edu.cornell.mannlib.vitro.webapp.search.indexing;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.hp.hpl.jena.ontology.OntModel;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.StatementToURIsToUpdate;
|
||||
|
||||
/**
|
||||
|
@ -16,12 +15,12 @@ import edu.cornell.mannlib.vitro.webapp.search.beans.StatementToURIsToUpdate;
|
|||
*/
|
||||
public class AdditionalUriFinders {
|
||||
|
||||
public static List<StatementToURIsToUpdate> getList(OntModel jenaOntModel,
|
||||
public static List<StatementToURIsToUpdate> getList(RDFService rdfService,
|
||||
IndividualDao indDao) {
|
||||
// TODO How many of these are only relevant to VIVO?
|
||||
List<StatementToURIsToUpdate> uriFinders = new ArrayList<>();
|
||||
uriFinders.add(new AdditionalURIsForDataProperties());
|
||||
uriFinders.add(new AdditionalURIsForObjectProperties(jenaOntModel));
|
||||
uriFinders.add(new AdditionalURIsForObjectProperties(rdfService));
|
||||
uriFinders.add(new AdditionalURIsForTypeStatements());
|
||||
uriFinders.add(new URIsForClassGroupChange(indDao));
|
||||
return uriFinders;
|
||||
|
|
|
@ -23,6 +23,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.filtering.WebappDaoFactoryFiltering;
|
|||
import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilterUtils;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilters;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.ModelContext;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.StatementToURIsToUpdate;
|
||||
|
@ -133,7 +134,8 @@ public class SolrSetup implements javax.servlet.ServletContextListener{
|
|||
wadf = new WebappDaoFactoryFiltering(wadf, vf);
|
||||
|
||||
// make objects that will find additional URIs for context nodes etc
|
||||
List<StatementToURIsToUpdate> uriFinders = AdditionalUriFinders.getList(jenaOntModel,wadf.getIndividualDao());
|
||||
RDFService rdfService = RDFServiceUtils.getRDFServiceFactory(context).getRDFService();
|
||||
List<StatementToURIsToUpdate> uriFinders = AdditionalUriFinders.getList(rdfService,wadf.getIndividualDao());
|
||||
|
||||
// Make the IndexBuilder
|
||||
IndexBuilder builder = new IndexBuilder( solrIndexer, wadf, uriFinders );
|
||||
|
|
|
@ -1,44 +1,57 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
package edu.cornell.mannlib.vitro.webapp.search.solr.documentBuilding;
|
||||
|
||||
import static edu.cornell.mannlib.vitro.webapp.search.solr.documentBuilding.IndividualToSolrDocument.DONT_EXCLUDE;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.solr.common.SolrInputDocument;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.VClass;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||
|
||||
/**
|
||||
* Exclude individuals with types from the Vitro namespace from the
|
||||
* search index. (Other than old vitro Flag types).
|
||||
* Exclude individuals with most specific types from the Vitro namespace from
|
||||
* the search index. (Other than old vitro Flag types).
|
||||
*/
|
||||
public class ExcludeNonFlagVitro implements SearchIndexExcluder {
|
||||
private static final Log log = LogFactory.getLog(ExcludeNonFlagVitro.class);
|
||||
|
||||
@Override
|
||||
public String checkForExclusion(Individual ind) {
|
||||
if( ind != null && ind.getVClasses() != null ) {
|
||||
String excludeMsg = skipIfVitro(ind, ind.getVClasses() );
|
||||
if( excludeMsg != null)
|
||||
return excludeMsg;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String checkForExclusion(Individual ind) {
|
||||
if (ind == null) {
|
||||
return DONT_EXCLUDE;
|
||||
}
|
||||
|
||||
List<String> mostSpecificTypeUris = ind.getMostSpecificTypeURIs();
|
||||
if (mostSpecificTypeUris == null) {
|
||||
return DONT_EXCLUDE;
|
||||
}
|
||||
|
||||
String message = skipIfVitro(ind, mostSpecificTypeUris);
|
||||
if (!StringUtils.equals(DONT_EXCLUDE, message)) {
|
||||
log.debug("msg=" + message + ", individual=" + ind.getURI() + " ("
|
||||
+ ind.getLabel() + "), types=" + mostSpecificTypeUris);
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
String skipIfVitro(Individual ind, List<String> mostSpecificTypeUris) {
|
||||
for (String typeUri : mostSpecificTypeUris) {
|
||||
if (typeUri == null) {
|
||||
continue;
|
||||
}
|
||||
if (typeUri.startsWith(VitroVocabulary.vitroURI + "Flag")) {
|
||||
continue;
|
||||
}
|
||||
if (typeUri.startsWith(VitroVocabulary.vitroURI)) {
|
||||
return "Skipped " + ind.getURI() + " because in "
|
||||
+ VitroVocabulary.vitroURI + " namespace";
|
||||
}
|
||||
}
|
||||
return DONT_EXCLUDE;
|
||||
}
|
||||
|
||||
String skipIfVitro(Individual ind, List<VClass> vclasses) {
|
||||
for( VClass type: vclasses ){
|
||||
if( type != null && type.getURI() != null ){
|
||||
String typeURI = type.getURI();
|
||||
|
||||
if(typeURI.startsWith( VitroVocabulary.vitroURI )
|
||||
&& ! typeURI.startsWith(VitroVocabulary.vitroURI + "Flag") ){
|
||||
|
||||
return "Skipped " + ind.getURI()+" because in "
|
||||
+ VitroVocabulary.vitroURI + " namespace";
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -110,6 +110,9 @@ public class IndividualToSolrDocument {
|
|||
for( SearchIndexExcluder excluder : excludes){
|
||||
try{
|
||||
String msg = excluder.checkForExclusion(ind);
|
||||
log.debug("individual=" + ind.getURI() + " (" + ind.getLabel()
|
||||
+ "), excluder=" + excluder + ", types="
|
||||
+ ind.getMostSpecificTypeURIs() + ", msg=" + msg);
|
||||
if( msg != DONT_EXCLUDE)
|
||||
return msg;
|
||||
}catch (Exception e) {
|
||||
|
|
|
@ -380,6 +380,12 @@ public class FakeApplicationOntologyService {
|
|||
return dataGetters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[template=" + templateName + ", dataGetters=" + dataGetters
|
||||
+ "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** The view specifications that we read from the config file. */
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.services.shortview;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.services.shortview.FakeApplicationOntologyService.TemplateAndDataGetters;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings.Keys;
|
||||
|
||||
/**
|
||||
* When we use a short view other than the default, log it.
|
||||
*/
|
||||
public class ShortViewLogger {
|
||||
private static final Log log = LogFactory.getLog(ShortViewLogger.class);
|
||||
|
||||
public static void log(VitroRequest vreq, String contextName,
|
||||
Individual individual, String classUri, TemplateAndDataGetters tdg) {
|
||||
if (isLogging(vreq)) {
|
||||
log.info("Using custom short view in " + contextName + " because '"
|
||||
+ individual.getURI() + "' (" + individual.getLabel()
|
||||
+ ") has type '" + classUri + "': " + tdg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void log(VitroRequest vreq, String contextName,
|
||||
Individual individual) {
|
||||
if (isLogging(vreq)) {
|
||||
log.info("Using default short view in " + contextName + " for '"
|
||||
+ individual.getURI() + "' (" + individual.getLabel() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isLogging(VitroRequest vreq) {
|
||||
if (!log.isInfoEnabled()) {
|
||||
return false;
|
||||
}
|
||||
DeveloperSettings settings = DeveloperSettings.getBean(vreq);
|
||||
return settings.getBoolean(Keys.ENABLED)
|
||||
&& settings
|
||||
.getBoolean(Keys.PAGE_CONTENTS_LOG_CUSTOM_SHORT_VIEW);
|
||||
}
|
||||
|
||||
}
|
|
@ -15,9 +15,7 @@ import org.apache.commons.logging.Log;
|
|||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||
import edu.cornell.mannlib.vitro.webapp.services.freemarker.FreemarkerProcessingService;
|
||||
import edu.cornell.mannlib.vitro.webapp.services.freemarker.FreemarkerProcessingService.TemplateParsingException;
|
||||
import edu.cornell.mannlib.vitro.webapp.services.freemarker.FreemarkerProcessingService.TemplateProcessingException;
|
||||
|
@ -116,11 +114,13 @@ public class ShortViewServiceImpl implements ShortViewService {
|
|||
TemplateAndDataGetters tdg = faker.getShortViewProperties(vreq,
|
||||
individual, classUri, svContext.name());
|
||||
if (tdg != null) {
|
||||
ShortViewLogger.log(vreq, svContext.name(), individual, classUri, tdg);
|
||||
return tdg;
|
||||
}
|
||||
}
|
||||
|
||||
// Didn't find one? Use the default values.
|
||||
ShortViewLogger.log(vreq, svContext.name(), individual);
|
||||
return new TemplateAndDataGetters(svContext.getDefaultTemplateName());
|
||||
}
|
||||
|
||||
|
|
|
@ -187,8 +187,7 @@ public class FileGraphSetup implements ServletContextListener {
|
|||
} else {
|
||||
baseModel.add(model);
|
||||
}
|
||||
log.info("Attached file graph as " + type + " submodel " + p.getFileName());
|
||||
|
||||
log.debug("Attached file graph as " + type + " submodel " + p.getFileName());
|
||||
}
|
||||
|
||||
modelChanged = modelChanged | updateGraphInDB(dataset, model, type, p);
|
||||
|
|
|
@ -221,7 +221,7 @@ public class JenaDataSourceSetupBase extends JenaBaseDaoCon {
|
|||
int[] maxActiveAndIdle = getMaxActiveAndIdle(ctx);
|
||||
cpds.setMaxPoolSize(maxActiveAndIdle[0]);
|
||||
cpds.setMinPoolSize(maxActiveAndIdle[1]);
|
||||
cpds.setMaxIdleTime(3600); // ms
|
||||
cpds.setMaxIdleTime(43200); // s
|
||||
cpds.setMaxIdleTimeExcessConnections(300);
|
||||
cpds.setAcquireIncrement(5);
|
||||
cpds.setNumHelperThreads(6);
|
||||
|
|
|
@ -141,7 +141,7 @@ public class UpdateKnowledgeBase implements ServletContextListener {
|
|||
KnowledgeBaseUpdater ontologyUpdater = new KnowledgeBaseUpdater(settings);
|
||||
boolean requiredUpdate = ontologyUpdater.updateRequired(ctx);
|
||||
|
||||
if(!JenaDataSourceSetupBase.isFirstStartup()) {
|
||||
if(requiredUpdate && !JenaDataSourceSetupBase.isFirstStartup()) {
|
||||
try {
|
||||
ctx.setAttribute(KBM_REQURIED_AT_STARTUP, Boolean.TRUE);
|
||||
migrationChangesMade = ontologyUpdater.update(ctx);
|
||||
|
|
|
@ -0,0 +1,325 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.utils.developer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Hold the global developer settings. Render to JSON when requested.
|
||||
*
|
||||
* On first request, the "developer.properties" file is loaded from the Vitro
|
||||
* home directory. If the file doesn't exist, or doesn't contain values for
|
||||
* certain properties, those propertiew will keep their default values.
|
||||
*
|
||||
* An AJAX request can be used to update the properties. If the request has
|
||||
* multiple values for a property, the first value will be used. If the request
|
||||
* does not contain a value for a property, that property will keep its current
|
||||
* value.
|
||||
*/
|
||||
public class DeveloperSettings {
|
||||
private static final Log log = LogFactory.getLog(DeveloperSettings.class);
|
||||
|
||||
public enum Keys {
|
||||
/**
|
||||
* Developer mode and developer panel is enabled.
|
||||
*/
|
||||
ENABLED("developer.enabled", true),
|
||||
|
||||
/**
|
||||
* Users don't need authority to use the developer panel. But they still
|
||||
* can't enable it without authority.
|
||||
*/
|
||||
PERMIT_ANONYMOUS_CONTROL("developer.permitAnonymousControl", true),
|
||||
|
||||
/**
|
||||
* Load Freemarker templates every time they are requested.
|
||||
*/
|
||||
DEFEAT_FREEMARKER_CACHE("developer.defeatFreemarkerCache", true),
|
||||
|
||||
/**
|
||||
* Show where each Freemarker template starts and stops.
|
||||
*/
|
||||
INSERT_FREEMARKER_DELIMITERS("developer.insertFreemarkerDelimiters",
|
||||
true),
|
||||
|
||||
/**
|
||||
* Load language property files every time they are requested.
|
||||
*/
|
||||
I18N_DEFEAT_CACHE("developer.i18n.defeatCache", true),
|
||||
|
||||
/**
|
||||
* Enable the I18nLogger to log each string request.
|
||||
*/
|
||||
I18N_LOG_STRINGS("developer.i18n.logStringRequests", true),
|
||||
|
||||
/**
|
||||
* Enable the LoggingRDFService
|
||||
*/
|
||||
LOGGING_RDF_ENABLE("developer.loggingRDFService.enable", true),
|
||||
|
||||
/**
|
||||
* When logging with the LoggingRDFService, include a stack trace
|
||||
*/
|
||||
LOGGING_RDF_STACK_TRACE("developer.loggingRDFService.stackTrace", true),
|
||||
|
||||
/**
|
||||
* Don't log with the LoggingRDFService unless the calling stack meets
|
||||
* this restriction.
|
||||
*/
|
||||
LOGGING_RDF_QUERY_RESTRICTION(
|
||||
"developer.loggingRDFService.queryRestriction", false),
|
||||
|
||||
/**
|
||||
* Don't log with the LoggingRDFService unless the calling stack meets
|
||||
* this restriction.
|
||||
*/
|
||||
LOGGING_RDF_STACK_RESTRICTION(
|
||||
"developer.loggingRDFService.stackRestriction", false),
|
||||
|
||||
/**
|
||||
* Tell the CustomListViewLogger to note the use of non-default custom
|
||||
* list views.
|
||||
*/
|
||||
PAGE_CONTENTS_LOG_CUSTOM_LIST_VIEW(
|
||||
"developer.pageContents.logCustomListView", true),
|
||||
|
||||
/**
|
||||
* Tell the ShortViewLogger to note the use of non-default short views.
|
||||
*/
|
||||
PAGE_CONTENTS_LOG_CUSTOM_SHORT_VIEW(
|
||||
"developer.pageContents.logCustomShortView", true);
|
||||
|
||||
private final String propertyName;
|
||||
private final String elementId;
|
||||
private final boolean bool;
|
||||
|
||||
private Keys(String propertyName, boolean bool) {
|
||||
this.propertyName = propertyName;
|
||||
this.elementId = produceElementId();
|
||||
this.bool = bool;
|
||||
}
|
||||
|
||||
public String propertyName() {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
public String elementId() {
|
||||
return elementId;
|
||||
}
|
||||
|
||||
boolean isBoolean() {
|
||||
return bool;
|
||||
}
|
||||
|
||||
/**
|
||||
* The element ID is camel-case instead of period-delimited. So
|
||||
* "developer.enabled" becomes "developerEnabled".
|
||||
*/
|
||||
String produceElementId() {
|
||||
StringBuilder id = new StringBuilder(propertyName.length());
|
||||
boolean capitalize = false;
|
||||
for (int i = 0; i < propertyName.length(); i++) {
|
||||
char c = propertyName.charAt(i);
|
||||
if (c == '.') {
|
||||
capitalize = true;
|
||||
} else if (capitalize) {
|
||||
id.append(Character.toUpperCase(c));
|
||||
capitalize = false;
|
||||
} else {
|
||||
id.append(c);
|
||||
}
|
||||
}
|
||||
return id.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
static Keys fromElementId(String id) {
|
||||
for (Keys k : Keys.values()) {
|
||||
if (k.elementId.equals(id)) {
|
||||
return k;
|
||||
}
|
||||
}
|
||||
log.error("Can't find key for element id: '" + id + "'");
|
||||
return null;
|
||||
}
|
||||
|
||||
static Keys fromPropertyName(String name) {
|
||||
for (Keys k : Keys.values()) {
|
||||
if (k.propertyName.equals(name)) {
|
||||
return k;
|
||||
}
|
||||
}
|
||||
log.error("Can't find key for property name: '" + name + "'");
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// The factory
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
private static final String ATTRIBUTE_NAME = DeveloperSettings.class
|
||||
.getName();
|
||||
|
||||
public static DeveloperSettings getBean(HttpServletRequest req) {
|
||||
return getBean(req.getSession().getServletContext());
|
||||
}
|
||||
|
||||
public static DeveloperSettings getBean(ServletContext ctx) {
|
||||
Object o = ctx.getAttribute(ATTRIBUTE_NAME);
|
||||
if (o instanceof DeveloperSettings) {
|
||||
return (DeveloperSettings) o;
|
||||
} else {
|
||||
DeveloperSettings ds = new DeveloperSettings(ctx);
|
||||
ctx.setAttribute(ATTRIBUTE_NAME, ds);
|
||||
return ds;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// The instance
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
private final Map<Keys, Object> settings = new EnumMap<>(Keys.class);
|
||||
|
||||
private DeveloperSettings(ServletContext ctx) {
|
||||
updateFromFile(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the initial settings from "developer.properties" in the Vitro home
|
||||
* directory.
|
||||
*
|
||||
* This method is "protected" so we can override it for unit tests.
|
||||
*/
|
||||
protected void updateFromFile(ServletContext ctx) {
|
||||
Map<Keys, String> fromFile = new HashMap<>();
|
||||
|
||||
ConfigurationProperties props = ConfigurationProperties.getBean(ctx);
|
||||
String home = props.getProperty("vitro.home");
|
||||
File dsFile = Paths.get(home, "developer.properties").toFile();
|
||||
|
||||
if (dsFile.isFile()) {
|
||||
try (FileReader reader = new FileReader(dsFile)) {
|
||||
Properties dsProps = new Properties();
|
||||
dsProps.load(reader);
|
||||
for (String key : dsProps.stringPropertyNames()) {
|
||||
fromFile.put(Keys.fromPropertyName(key),
|
||||
dsProps.getProperty(key));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to load 'developer.properties' file.", e);
|
||||
}
|
||||
} else {
|
||||
log.debug("No developer.properties file.");
|
||||
}
|
||||
|
||||
log.debug("Properties from file: " + fromFile);
|
||||
update(fromFile);
|
||||
}
|
||||
|
||||
/** Provide the parameter map from the HttpServletRequest */
|
||||
public void updateFromRequest(Map<String, String[]> parameterMap) {
|
||||
if (log.isDebugEnabled()) {
|
||||
dumpParameterMap(parameterMap);
|
||||
}
|
||||
|
||||
Map<Keys, String> fromRequest = new HashMap<>();
|
||||
for (String key : parameterMap.keySet()) {
|
||||
fromRequest.put(Keys.fromElementId(key), parameterMap.get(key)[0]);
|
||||
}
|
||||
update(fromRequest);
|
||||
}
|
||||
|
||||
private void update(Map<Keys, String> changedSettings) {
|
||||
for (Keys key : Keys.values()) {
|
||||
String s = changedSettings.get(key);
|
||||
if (s != null) {
|
||||
if (key.isBoolean()) {
|
||||
settings.put(key, Boolean.valueOf(s));
|
||||
} else {
|
||||
settings.put(key, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
log.debug("DeveloperSettings: " + this);
|
||||
}
|
||||
|
||||
public Object get(Keys key) {
|
||||
if (key.isBoolean()) {
|
||||
return getBoolean(key);
|
||||
} else {
|
||||
return getString(key);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getBoolean(Keys key) {
|
||||
if (!key.isBoolean()) {
|
||||
throw new IllegalArgumentException("Key '" + key
|
||||
+ "' does not take a boolean value.");
|
||||
}
|
||||
if (settings.containsKey(key)) {
|
||||
if (Boolean.TRUE.equals(settings.get(Keys.ENABLED))) {
|
||||
return (Boolean) settings.get(key);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getString(Keys key) {
|
||||
if (key.isBoolean()) {
|
||||
throw new IllegalArgumentException("Key '" + key
|
||||
+ "' takes a boolean value.");
|
||||
}
|
||||
if (settings.containsKey(key)) {
|
||||
if (Boolean.TRUE.equals(settings.get(Keys.ENABLED))) {
|
||||
return (String) settings.get(key);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public Map<String, Object> getSettingsMap() {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
for (Keys key : Keys.values()) {
|
||||
map.put(key.elementId(), get(key));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DeveloperSettings" + settings;
|
||||
}
|
||||
|
||||
/* For debugging. */
|
||||
private void dumpParameterMap(Map<String, String[]> parameterMap) {
|
||||
Map<String, List<String>> map = new HashMap<>();
|
||||
for (String key : parameterMap.keySet()) {
|
||||
map.put(key, Arrays.asList(parameterMap.get(key)));
|
||||
}
|
||||
log.debug("Parameter map: " + map);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.utils.developer;
|
||||
|
||||
import static edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings.Keys.PERMIT_ANONYMOUS_CONTROL;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.ajax.VitroAjaxController;
|
||||
import edu.cornell.mannlib.vitro.webapp.services.freemarker.FreemarkerProcessingService.TemplateProcessingException;
|
||||
import edu.cornell.mannlib.vitro.webapp.services.freemarker.FreemarkerProcessingServiceSetup;
|
||||
|
||||
/**
|
||||
* Accept an AJAX request to update the developer settings. Return an HTML
|
||||
* representation of the developer panel from the settings and a Freemarker
|
||||
* template.
|
||||
*
|
||||
* If developer mode is not enabled, the HTML response is empty.
|
||||
*
|
||||
* You may only control the panel if you are logged in with sufficient
|
||||
* authorization, or if anonymous control is permitted by the settings.
|
||||
*
|
||||
* If you are not allowed to control the panel, then the HTML response
|
||||
* is only a statement that developer mode is enabled. Otherwise, it
|
||||
* is a full panel (collapsed at first).
|
||||
*/
|
||||
public class DeveloperSettingsServlet extends VitroAjaxController {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(DeveloperSettingsServlet.class);
|
||||
|
||||
@Override
|
||||
protected void doRequest(VitroRequest vreq, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
DeveloperSettings settings = DeveloperSettings.getBean(vreq);
|
||||
|
||||
/*
|
||||
* Are they allowed to control the panel?
|
||||
*/
|
||||
if (isAuthorized(vreq)) {
|
||||
// Update the settings.
|
||||
settings.updateFromRequest(vreq.getParameterMap());
|
||||
} else {
|
||||
log.debug("Not authorized to update settings.");
|
||||
}
|
||||
|
||||
/*
|
||||
* Build the response.
|
||||
*/
|
||||
try {
|
||||
Map<String, Object> bodyMap = buildBodyMap(isAuthorized(vreq),
|
||||
settings);
|
||||
String rendered = renderTemplate(vreq, bodyMap);
|
||||
resp.getWriter().write(rendered);
|
||||
} catch (Exception e) {
|
||||
doError(resp, e.toString(), 500);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Object> buildBodyMap(boolean authorized,
|
||||
DeveloperSettings settings) {
|
||||
Map<String, Object> settingsMap = new HashMap<>();
|
||||
settingsMap.putAll(settings.getSettingsMap());
|
||||
settingsMap.put("mayControl", authorized);
|
||||
Map<String, Object> bodyMap = new HashMap<>();
|
||||
bodyMap.put("settings", settingsMap);
|
||||
return bodyMap;
|
||||
}
|
||||
|
||||
private String renderTemplate(VitroRequest vreq, Map<String, Object> bodyMap)
|
||||
throws TemplateProcessingException {
|
||||
return FreemarkerProcessingServiceSetup.getService(getServletContext())
|
||||
.renderTemplate("developerPanel.ftl", bodyMap, vreq);
|
||||
}
|
||||
|
||||
private boolean isAuthorized(VitroRequest vreq) {
|
||||
boolean authBySetting = DeveloperSettings.getBean(vreq).getBoolean(
|
||||
PERMIT_ANONYMOUS_CONTROL);
|
||||
boolean authByPolicy = PolicyHelper.isAuthorizedForActions(vreq,
|
||||
SimplePermission.ENABLE_DEVELOPER_PANEL.ACTION);
|
||||
return authBySetting || authByPolicy;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings.Keys;
|
||||
|
||||
/**
|
||||
* If enabled in the developer settings (and log levels), log every non-default
|
||||
* custom list view.
|
||||
*/
|
||||
public class CustomListViewLogger {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(CustomListViewLogger.class);
|
||||
|
||||
public static void log(VitroRequest vreq, ObjectProperty op,
|
||||
String configFileName) {
|
||||
if (isLogging(vreq)) {
|
||||
log.info("Using list view: '" + configFileName + "' for "
|
||||
+ op.getURI() + " (" + op.getLabel() + ")");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isLogging(VitroRequest vreq) {
|
||||
if (!log.isInfoEnabled()) {
|
||||
return false;
|
||||
}
|
||||
DeveloperSettings settings = DeveloperSettings.getBean(vreq);
|
||||
return settings.getBoolean(Keys.ENABLED)
|
||||
&& settings.getBoolean(Keys.PAGE_CONTENTS_LOG_CUSTOM_LIST_VIEW);
|
||||
}
|
||||
}
|
|
@ -61,6 +61,8 @@ public class PropertyListConfig {
|
|||
String configFileName = wadf.getObjectPropertyDao().getCustomListViewConfigFileName(op);
|
||||
if (configFileName == null) { // no custom config; use default config
|
||||
configFileName = DEFAULT_CONFIG_FILE_NAME;
|
||||
} else {
|
||||
CustomListViewLogger.log(vreq, op, configFileName);
|
||||
}
|
||||
log.debug("Using list view config file " + configFileName + " for object property " + op.getURI());
|
||||
|
||||
|
|
|
@ -491,6 +491,10 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel {
|
|||
return getDataLiteralValuesFromParameter();
|
||||
}
|
||||
|
||||
//Get a custom object uri for deletion if one exists, i.e. not the object uri for the property
|
||||
public String getCustomDeleteObjectUri() {
|
||||
return (String) vreq.getParameter("deleteObjectUri");
|
||||
}
|
||||
//Used for deletion in case there's a specific template to be employed
|
||||
public String getDeleteTemplate() {
|
||||
String templateName = vreq.getParameter("templateName");
|
||||
|
@ -544,7 +548,7 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel {
|
|||
}
|
||||
for(VClass rangeVClass : rangeVClasses) {
|
||||
vclasses.add(rangeVClass);
|
||||
List<String> subURIs = wdf.getVClassDao().getSubClassURIs(rangeVClass.getURI());
|
||||
List<String> subURIs = wdf.getVClassDao().getAllSubClassURIs(rangeVClass.getURI());
|
||||
for (String subClassURI : subURIs) {
|
||||
VClass subClass = wdf.getVClassDao().getVClassByURI(subClassURI);
|
||||
if (subClass != null) {
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.apache.commons.logging.Log;
|
|||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.display.DisplayDataProperty;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.display.DisplayObjectProperty;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAction;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.DataProperty;
|
||||
|
@ -50,8 +51,15 @@ public class PropertyGroupTemplateModel extends BaseTemplateModel {
|
|||
properties.add(tm);
|
||||
}
|
||||
|
||||
} else if (p instanceof DataProperty){
|
||||
DataProperty dp = (DataProperty) p;
|
||||
RequestedAction dop = new DisplayDataProperty(dp);
|
||||
if (!PolicyHelper.isAuthorizedForActions(vreq, dop)) {
|
||||
continue;
|
||||
}
|
||||
properties.add(new DataPropertyTemplateModel(dp, subject, vreq, editing, populatedDataPropertyList));
|
||||
} else {
|
||||
properties.add(new DataPropertyTemplateModel((DataProperty)p, subject, vreq, editing, populatedDataPropertyList));
|
||||
log.debug(p.getURI() + " is neither an ObjectProperty nor a DataProperty; skipping display");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,11 +11,14 @@ import org.apache.commons.logging.LogFactory;
|
|||
import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.DataProperty;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.Property;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.BaseTemplateModel;
|
||||
|
||||
|
@ -94,6 +97,27 @@ public abstract class PropertyTemplateModel extends BaseTemplateModel {
|
|||
|
||||
String editUrl = UrlBuilder.getUrl(getPropertyEditRoute(), "uri", property.getURI());
|
||||
verboseDisplay.put("propertyEditUrl", editUrl);
|
||||
|
||||
if(isFauxProperty(property)) {
|
||||
verboseDisplay.put("fauxProperty", "true");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isFauxProperty(Property prop) {
|
||||
if(!(prop instanceof ObjectProperty)) {
|
||||
return false;
|
||||
}
|
||||
ObjectPropertyDao opDao = vreq.getWebappDaoFactory().getObjectPropertyDao();
|
||||
ObjectProperty baseProp = opDao.getObjectPropertyByURI(prop.getURI());
|
||||
if(baseProp == null) {
|
||||
return false;
|
||||
}
|
||||
ObjectProperty possibleFaux = (ObjectProperty) prop;
|
||||
if (possibleFaux.getDomainPublic() == null) {
|
||||
return (baseProp.getDomainPublic() != null);
|
||||
} else {
|
||||
return !possibleFaux.getDomainPublic().equals(baseProp.getDomainPublic());
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract int getPropertyDisplayTier(Property p);
|
||||
|
|
|
@ -1,183 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
|
||||
|
||||
/**
|
||||
* Test the methods of {@link FlatteningTemplateLoader}.
|
||||
*/
|
||||
public class FlatteningTemplateLoaderTest extends AbstractTestClass {
|
||||
/**
|
||||
* TODO test plan
|
||||
*
|
||||
* <pre>
|
||||
* findTemplateSource
|
||||
* null arg
|
||||
* not found
|
||||
* found in top level
|
||||
* found in lower level
|
||||
* with path
|
||||
*
|
||||
* getReader
|
||||
* get it, read it, check it, close it.
|
||||
*
|
||||
* getLastModified
|
||||
* check the create date within a range
|
||||
* modify it and check again.
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
// ----------------------------------------------------------------------
|
||||
// setup and teardown
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
private static final String SUBDIRECTORY_NAME = "sub";
|
||||
|
||||
private static final String TEMPLATE_NAME_UPPER = "template.ftl";
|
||||
private static final String TEMPLATE_NAME_UPPER_WITH_PATH = "path/template.ftl";
|
||||
private static final String TEMPLATE_UPPER_CONTENTS = "The contents of the file.";
|
||||
|
||||
private static final String TEMPLATE_NAME_LOWER = "another.ftl";
|
||||
private static final String TEMPLATE_LOWER_CONTENTS = "Another template file.";
|
||||
|
||||
private static File tempDir;
|
||||
private static File notADirectory;
|
||||
private static File upperTemplate;
|
||||
private static File lowerTemplate;
|
||||
|
||||
private FlatteningTemplateLoader loader;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpFiles() throws IOException {
|
||||
notADirectory = File.createTempFile(
|
||||
FlatteningTemplateLoader.class.getSimpleName(), "");
|
||||
|
||||
tempDir = createTempDirectory(FlatteningTemplateLoader.class
|
||||
.getSimpleName());
|
||||
upperTemplate = createFile(tempDir, TEMPLATE_NAME_UPPER,
|
||||
TEMPLATE_UPPER_CONTENTS);
|
||||
|
||||
File subdirectory = new File(tempDir, SUBDIRECTORY_NAME);
|
||||
subdirectory.mkdir();
|
||||
lowerTemplate = createFile(subdirectory, TEMPLATE_NAME_LOWER,
|
||||
TEMPLATE_LOWER_CONTENTS);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void initializeLoader() {
|
||||
loader = new FlatteningTemplateLoader(tempDir);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void cleanUpFiles() throws IOException {
|
||||
purgeDirectoryRecursively(tempDir);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// the tests
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void constructorNull() {
|
||||
new FlatteningTemplateLoader(null);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorNonExistent() {
|
||||
new FlatteningTemplateLoader(new File("bogusDirName"));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorNotADirectory() {
|
||||
new FlatteningTemplateLoader(notADirectory);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findNull() throws IOException {
|
||||
Object source = loader.findTemplateSource(null);
|
||||
assertNull("find null", source);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findNotFound() throws IOException {
|
||||
Object source = loader.findTemplateSource("bogus");
|
||||
assertNull("not found", source);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findInTopLevel() throws IOException {
|
||||
Object source = loader.findTemplateSource(TEMPLATE_NAME_UPPER);
|
||||
assertEquals("top level", upperTemplate, source);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findInLowerLevel() throws IOException {
|
||||
Object source = loader.findTemplateSource(TEMPLATE_NAME_LOWER);
|
||||
assertEquals("lower level", lowerTemplate, source);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findIgnoringPath() throws IOException {
|
||||
Object source = loader
|
||||
.findTemplateSource(TEMPLATE_NAME_UPPER_WITH_PATH);
|
||||
assertEquals("top level", upperTemplate, source);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkTheReader() throws IOException {
|
||||
Object source = loader.findTemplateSource(TEMPLATE_NAME_UPPER);
|
||||
Reader reader = loader.getReader(source, "UTF-8");
|
||||
String contents = readAll(reader);
|
||||
assertEquals("read the contents", contents, TEMPLATE_UPPER_CONTENTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Some systems only record last-modified times to the nearest second, so we
|
||||
* can't rely on them changing during the course of the test. Force the
|
||||
* change, and test for it.
|
||||
*/
|
||||
@Test
|
||||
public void teplateLastModified() throws IOException {
|
||||
Object source = loader.findTemplateSource(TEMPLATE_NAME_UPPER);
|
||||
long modified = loader.getLastModified(source);
|
||||
long now = System.currentTimeMillis();
|
||||
assertTrue("near to now: modified=" + formatTimeStamp(modified)
|
||||
+ ", now=" + formatTimeStamp(now),
|
||||
2000 > Math.abs(modified - now));
|
||||
|
||||
upperTemplate.setLastModified(5000);
|
||||
assertEquals("modified modified", 5000, loader.getLastModified(source));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void closeDoesntCrash() throws IOException {
|
||||
Object source = loader.findTemplateSource(TEMPLATE_NAME_UPPER);
|
||||
loader.closeTemplateSource(source);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// helper methods
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
private String formatTimeStamp(long time) {
|
||||
SimpleDateFormat formatter = new SimpleDateFormat(
|
||||
"yyyy-MM-dd HH:mm:ss.SSS");
|
||||
return formatter.format(time);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.dao.jena;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.hp.hpl.jena.query.QuerySolutionMap;
|
||||
import com.hp.hpl.jena.rdf.model.Literal;
|
||||
import com.hp.hpl.jena.rdf.model.ModelFactory;
|
||||
import com.hp.hpl.jena.rdf.model.ResourceFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
public class QueryUtilsTest extends AbstractTestClass {
|
||||
private QuerySolutionMap bindings = new QuerySolutionMap();
|
||||
|
||||
@Test
|
||||
public void bindResource() {
|
||||
bindings.add("uri", ResourceFactory.createResource("http://my.uri"));
|
||||
assertBoundQueryEquals("a resource ?uri", "a resource <http://my.uri>");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindPlainLiteral() {
|
||||
bindings.add("plain", ResourceFactory.createPlainLiteral("too easy"));
|
||||
assertBoundQueryEquals("This is ?plain ?plain",
|
||||
"This is \"too easy\" \"too easy\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindTypedLiteral() {
|
||||
bindings.add("typed", ResourceFactory.createTypedLiteral(100L));
|
||||
assertBoundQueryEquals("take this ?typed number",
|
||||
"take this \"100\"^^<http://www.w3.org/2001/XMLSchema#long> number");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindLanguageLiteral() {
|
||||
Literal l = ModelFactory.createDefaultModel().createLiteral("Spanish",
|
||||
"es-ES");
|
||||
bindings.add("lang", l);
|
||||
assertBoundQueryEquals("speak my ?lang?", "speak my \"Spanish\"@es-ES?");
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void bindAnon() {
|
||||
fail("bindAnon not implemented");
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Helper methods
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
private void assertBoundQueryEquals(String template, String expected) {
|
||||
String actual = QueryUtils.bindVariables(template, bindings);
|
||||
assertEquals("bounding results", expected, actual);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,360 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.freemarker.loader;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.freemarker.loader.FreemarkerTemplateLoader.PathPieces;
|
||||
import edu.cornell.mannlib.vitro.webapp.freemarker.loader.FreemarkerTemplateLoader.PathPiecesFileVisitor;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
public class FreemarkerTemplateLoaderTest {
|
||||
private PathPiecesFileVisitor visitor;
|
||||
private String[] paths;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// PathPieces tests
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@Test
|
||||
public void ppLanguageRegionExtension() {
|
||||
assertPathPieces("this_en_US.ftl", "this", "_en", "_US", ".ftl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ppLanguageRegion() {
|
||||
assertPathPieces("this_en_US", "this", "_en", "_US", "");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ppLanguageExtension() {
|
||||
assertPathPieces("this_en.ftl", "this", "_en", "", ".ftl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ppLanguage() {
|
||||
assertPathPieces("this_en", "this", "_en", "", "");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ppDefaultExtension() {
|
||||
assertPathPieces("this.ftl", "this", "", "", ".ftl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ppDefault() {
|
||||
assertPathPieces("this", "this", "", "", "");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ppExtraUnderscoreExtension() {
|
||||
assertPathPieces("woo_hoo_en_US.ftl", "woo_hoo", "_en", "_US", ".ftl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ppExtraUnderscore() {
|
||||
assertPathPieces("woo_hoo_en_US", "woo_hoo", "_en", "_US", "");
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Specific function tests
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@Test
|
||||
public void baseAndExtensionMatch() {
|
||||
paths("match-me.ftl");
|
||||
assertMatches("match-me.ftl", 1, "match-me.ftl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void baseAndExtensionDontMatch() {
|
||||
paths("match-me.ftl");
|
||||
assertMatches("fail.ftl", 0, null);
|
||||
assertMatches("match-me", 0, null);
|
||||
assertMatches("match-me.FTL", 0, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchRegardlessOfDepth() {
|
||||
paths("short-path.ftl", "long/long-path.ftl");
|
||||
assertMatches("long/short-path.ftl", 1, "short-path.ftl");
|
||||
assertMatches("long-path.ftl", 1, "long/long-path.ftl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferShorterPath() {
|
||||
paths("shorter-is-better", "long/shorter-is-better");
|
||||
assertMatches("shorter-is-better", 2, "shorter-is-better");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferShorterPathToExactPath() {
|
||||
paths("shorter-is-better", "long/shorter-is-better");
|
||||
assertMatches("long/shorter-is-better", 2, "shorter-is-better");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void languageAndRegionMustMatchExactly() {
|
||||
paths("this_es_MX.ftl", "this_es_ES.ftl", "this_es.ftl");
|
||||
assertMatches("this_es_ES.ftl", 1, "this_es_ES.ftl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void languageAndRegionNoMatch() {
|
||||
paths("this_es_MX.ftl", "this_es_ES.ftl", "this_es.ftl");
|
||||
assertMatches("this_es_GO.ftl", 0, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void languagePrefersExactMatch() {
|
||||
paths("this_es_MX.ftl", "this_es.ftl", "this_es_ES.ftl");
|
||||
assertMatches("this_es.ftl", 3, "this_es.ftl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void languageAcceptsApproximateMatch() {
|
||||
paths("this_es_MX.ftl");
|
||||
assertMatches("this_es.ftl", 1, "this_es_MX.ftl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void languagePrefersApproximateAlphabetical() {
|
||||
paths("this_es_MX.ftl", "this_es_ES.ftl");
|
||||
assertMatches("this_es.ftl", 2, "this_es_ES.ftl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultPrefersExactMatch() {
|
||||
paths("this_fr.ftl", "this.ftl", "this_fr_BE.ftl");
|
||||
assertMatches("this.ftl", 3, "this.ftl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultPrefersDefaultRegion() {
|
||||
paths("this_fr_BE.ftl", "this_fr.ftl", "this_fr_CA.ftl");
|
||||
assertMatches("this.ftl", 3, "this_fr.ftl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultPrefersLanguageAlphabetical() {
|
||||
paths("this_es.ftl", "this_fr.ftl");
|
||||
assertMatches("this.ftl", 2, "this_es.ftl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultPrefersRegionAlphabetical() {
|
||||
paths("this_fr_BE.ftl", "this_fr_CA.ftl");
|
||||
assertMatches("this.ftl", 2, "this_fr_BE.ftl");
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Freemarker simulation tests
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
public static final String[] FREEMARKER_TEST_PATHS = {
|
||||
"long/this_fr_BE.ftl", "language_fr.ftl", "default.ftl",
|
||||
"language-approx_en_US.ftl" };
|
||||
|
||||
@Test
|
||||
public void freemarkerLangAndRegionExact() {
|
||||
paths = FREEMARKER_TEST_PATHS;
|
||||
assertFM("this_fr_BE.ftl", 1, "long/this_fr_BE.ftl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void freemarkerLangAndRegionMatchLang() {
|
||||
paths = FREEMARKER_TEST_PATHS;
|
||||
assertFM("language_fr_CA.ftl", 2, "language_fr.ftl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void freemarkerLangAndRegionMatchDefault() {
|
||||
paths = FREEMARKER_TEST_PATHS;
|
||||
assertFM("default_es_ES.ftl", 3, "default.ftl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void freemarkerLangAndRegionNoMatch() {
|
||||
paths = FREEMARKER_TEST_PATHS;
|
||||
assertFM("bogus_en_US.ftl", 3, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void freemarkerLangExact() {
|
||||
paths = FREEMARKER_TEST_PATHS;
|
||||
assertFM("language_fr.ftl", 1, "language_fr.ftl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void freemarkerLangMatchLangAndRegion() {
|
||||
paths = FREEMARKER_TEST_PATHS;
|
||||
assertFM("language-approx_en.ftl", 1, "language-approx_en_US.ftl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void freemarkerLangMatchDefault() {
|
||||
paths = FREEMARKER_TEST_PATHS;
|
||||
assertFM("default_en.ftl", 2, "default.ftl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void freemarkerLangNoMatch() {
|
||||
paths = FREEMARKER_TEST_PATHS;
|
||||
assertFM("bogus_it.ftl", 2, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void freemarkerDefaultExact() {
|
||||
paths = FREEMARKER_TEST_PATHS;
|
||||
assertFM("default.ftl", 1, "default.ftl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void freemarkerDefaultMatchLang() {
|
||||
paths = FREEMARKER_TEST_PATHS;
|
||||
assertFM("language.ftl", 1, "language_fr.ftl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void freemarkerDefaultMatchLangAndRegion() {
|
||||
paths = FREEMARKER_TEST_PATHS;
|
||||
assertFM("this.ftl", 1, "long/this_fr_BE.ftl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void freemarkerDefaultNoMatch() {
|
||||
paths = FREEMARKER_TEST_PATHS;
|
||||
assertFM("bogus.ftl", 1, null);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Helper methods
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
private void paths(String... p) {
|
||||
this.paths = p;
|
||||
}
|
||||
|
||||
private void assertPathPieces(String path, String base, String language,
|
||||
String region, String extension) {
|
||||
PathPieces pp = new PathPieces(path);
|
||||
String[] expected = new String[] { base, language, region, extension };
|
||||
String[] actual = new String[] { pp.base, pp.language, pp.region,
|
||||
pp.extension };
|
||||
assertEquals("pieces", Arrays.asList(expected), Arrays.asList(actual));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param searchTerm
|
||||
* template we are looking for
|
||||
* @param expectedHowMany
|
||||
* How many matches do we expect?
|
||||
* @param expectedBestFit
|
||||
* What should the best match turn out to be?
|
||||
* @throws IOException
|
||||
*/
|
||||
private void assertMatches(String searchTerm, int expectedHowMany,
|
||||
String expectedBestFitString) {
|
||||
Path expectedBestFit = (expectedBestFitString == null) ? null : Paths
|
||||
.get(expectedBestFitString);
|
||||
|
||||
SortedSet<PathPieces> matches = runTheVisitor(searchTerm);
|
||||
int actualHowMany = matches.size();
|
||||
Path actualBestFit = matches.isEmpty() ? null : matches.last().path;
|
||||
|
||||
if (expectedHowMany != actualHowMany) {
|
||||
fail("How many results: expected " + expectedHowMany
|
||||
+ ", but was " + actualHowMany + ": " + matches);
|
||||
}
|
||||
assertEquals("Best result", expectedBestFit, actualBestFit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try for exact match, then pare down if needed, just like Freemarker
|
||||
* would.
|
||||
*/
|
||||
private void assertFM(String searchTerm, int expectedNumberOfTries,
|
||||
String expectedBestString) {
|
||||
Path expectedBestFit = expectedBestString == null ? null : Paths
|
||||
.get(expectedBestString);
|
||||
PathPieces stPp = new PathPieces(searchTerm);
|
||||
|
||||
int actualNumberOfTries = 0;
|
||||
Path actualBestFit = null;
|
||||
|
||||
if (StringUtils.isNotBlank(stPp.region)) {
|
||||
actualNumberOfTries++;
|
||||
SortedSet<PathPieces> matches = runTheVisitor(stPp.base
|
||||
+ stPp.language + stPp.region + stPp.extension);
|
||||
if (!matches.isEmpty()) {
|
||||
actualBestFit = matches.last().path;
|
||||
}
|
||||
}
|
||||
if (actualBestFit == null && StringUtils.isNotBlank(stPp.language)) {
|
||||
actualNumberOfTries++;
|
||||
SortedSet<PathPieces> matches = runTheVisitor(stPp.base
|
||||
+ stPp.language + stPp.extension);
|
||||
if (!matches.isEmpty()) {
|
||||
actualBestFit = matches.last().path;
|
||||
}
|
||||
}
|
||||
if (actualBestFit == null) {
|
||||
actualNumberOfTries++;
|
||||
SortedSet<PathPieces> matches = runTheVisitor(stPp.base
|
||||
+ stPp.extension);
|
||||
if (!matches.isEmpty()) {
|
||||
actualBestFit = matches.last().path;
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("How many tries", expectedNumberOfTries,
|
||||
actualNumberOfTries);
|
||||
assertEquals("best fit", expectedBestFit, actualBestFit);
|
||||
}
|
||||
|
||||
private SortedSet<PathPieces> runTheVisitor(String searchTerm) {
|
||||
try {
|
||||
visitor = new PathPiecesFileVisitorStub(new PathPieces(searchTerm));
|
||||
for (String p : this.paths) {
|
||||
visitor.visitFile(Paths.get(p), null);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
fail("Failed: " + e);
|
||||
}
|
||||
|
||||
return visitor.getMatches();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Helper classes
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* We want to test the PathPiecesFileVisitor, but we can't have it checking
|
||||
* to see whether the files actually exist.
|
||||
*/
|
||||
private static class PathPiecesFileVisitorStub extends
|
||||
PathPiecesFileVisitor {
|
||||
public PathPiecesFileVisitorStub(PathPieces searchTerm) {
|
||||
super(searchTerm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fileQualifies(Path path) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package edu.cornell.mannlib.vitro.webapp.i18n;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import stubs.javax.servlet.ServletContextStub;
|
||||
import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
|
||||
import edu.cornell.mannlib.vitro.webapp.i18n.selection.SelectedLocale;
|
||||
|
||||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
/**
|
||||
* Test the I18N functionality.
|
||||
*
|
||||
* Start by checking the logic that finds approximate matches for
|
||||
* language-specific property files.
|
||||
*/
|
||||
public class I18nTest extends AbstractTestClass {
|
||||
private static final List<Locale> SELECTABLE_LOCALES = locales("es_MX",
|
||||
"en_US");
|
||||
|
||||
ServletContextStub ctx;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
ctx = new ServletContextStub();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noMatchOnLanguageRegion() {
|
||||
assertLocales("fr_CA", SELECTABLE_LOCALES, "fr_CA", "fr", "");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noMatchOnLanguage() {
|
||||
assertLocales("fr", SELECTABLE_LOCALES, "fr", "");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noMatchOnRoot() {
|
||||
assertLocales("", SELECTABLE_LOCALES, "");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchOnLanguageRegion() {
|
||||
assertLocales("es_ES", SELECTABLE_LOCALES, "es_ES", "es", "es_MX", "");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchOnLanguage() {
|
||||
assertLocales("es", SELECTABLE_LOCALES, "es", "es_MX", "");
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Helper methods
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
private void assertLocales(String requested, List<Locale> selectable,
|
||||
String... expected) {
|
||||
SelectedLocale.setSelectableLocales(ctx, selectable);
|
||||
List<Locale> expectedLocales = locales(expected);
|
||||
|
||||
I18n.ThemeBasedControl control = new I18n.ThemeBasedControl(ctx,
|
||||
"bogusThemeDirectory");
|
||||
List<Locale> actualLocales = control.getCandidateLocales(
|
||||
"bogusBaseName", locale(requested));
|
||||
|
||||
assertEquals("Expected locales", expectedLocales, actualLocales);
|
||||
}
|
||||
|
||||
private static List<Locale> locales(String... strings) {
|
||||
List<Locale> locales = new ArrayList<>();
|
||||
for (String s : strings) {
|
||||
locales.add(locale(s));
|
||||
}
|
||||
return locales;
|
||||
}
|
||||
|
||||
private static Locale locale(String s) {
|
||||
String[] parts = s.split("_");
|
||||
String language = (parts.length > 0) ? parts[0] : "";
|
||||
String country = (parts.length > 1) ? parts[1] : "";
|
||||
String variant = (parts.length > 2) ? parts[2] : "";
|
||||
return new Locale(language, country, variant);
|
||||
}
|
||||
|
||||
}
|
|
@ -15,9 +15,13 @@ import com.hp.hpl.jena.rdf.model.ResourceFactory;
|
|||
import com.hp.hpl.jena.vocabulary.OWL;
|
||||
import com.hp.hpl.jena.vocabulary.RDFS;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.jena.model.RDFServiceModel;
|
||||
|
||||
public class AdditionalURIsForObjectPropertiesTest {
|
||||
|
||||
Model model;
|
||||
RDFService rdfService;
|
||||
|
||||
String testNS = "http://example.com/test#";
|
||||
String n3 = "" +
|
||||
|
@ -39,11 +43,12 @@ public class AdditionalURIsForObjectPropertiesTest {
|
|||
public void setUp() throws Exception {
|
||||
model = ModelFactory.createDefaultModel();
|
||||
model.read(new StringReader(n3 ), null , "N3");
|
||||
rdfService = new RDFServiceModel(model);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChangeOfRdfsLabel() {
|
||||
AdditionalURIsForObjectProperties aufop = new AdditionalURIsForObjectProperties(model);
|
||||
AdditionalURIsForObjectProperties aufop = new AdditionalURIsForObjectProperties(rdfService);
|
||||
List<String> uris = aufop.findAdditionalURIsToIndex(
|
||||
ResourceFactory.createStatement(
|
||||
ResourceFactory.createResource(testNS + "bob"),
|
||||
|
@ -66,7 +71,7 @@ public class AdditionalURIsForObjectPropertiesTest {
|
|||
@Test
|
||||
public void testChangeOfObjPropStmt() {
|
||||
|
||||
AdditionalURIsForObjectProperties aufop = new AdditionalURIsForObjectProperties(model);
|
||||
AdditionalURIsForObjectProperties aufop = new AdditionalURIsForObjectProperties(rdfService);
|
||||
List<String> uris = aufop.findAdditionalURIsToIndex(
|
||||
ResourceFactory.createStatement(
|
||||
ResourceFactory.createResource(testNS + "bob"),
|
||||
|
@ -88,7 +93,7 @@ public class AdditionalURIsForObjectPropertiesTest {
|
|||
|
||||
@Test
|
||||
public void testOfDataPropChange() {
|
||||
AdditionalURIsForObjectProperties aufop = new AdditionalURIsForObjectProperties(model);
|
||||
AdditionalURIsForObjectProperties aufop = new AdditionalURIsForObjectProperties(rdfService);
|
||||
List<String> uris = aufop.findAdditionalURIsToIndex(
|
||||
ResourceFactory.createStatement(
|
||||
ResourceFactory.createResource(testNS + "bob"),
|
||||
|
@ -107,8 +112,9 @@ public class AdditionalURIsForObjectPropertiesTest {
|
|||
|
||||
Model model = ModelFactory.createDefaultModel();
|
||||
model.read(new StringReader( n3ForNIHVIVO_2902 ), null , "N3");
|
||||
|
||||
AdditionalURIsForObjectProperties aufop = new AdditionalURIsForObjectProperties(model);
|
||||
RDFService rdfService = new RDFServiceModel(model);
|
||||
|
||||
AdditionalURIsForObjectProperties aufop = new AdditionalURIsForObjectProperties(rdfService);
|
||||
List<String> uris = aufop.findAdditionalURIsToIndex(
|
||||
ResourceFactory.createStatement(
|
||||
ResourceFactory.createResource("http://caruso-laptop.mannlib.cornell.edu:8090/vivo/individual/n2241"),
|
||||
|
|
|
@ -51,7 +51,7 @@ public class I18nStub extends I18n {
|
|||
|
||||
private class I18nBundleStub extends I18nBundle {
|
||||
public I18nBundleStub(String bundleName) {
|
||||
super(bundleName, new DummyResourceBundle());
|
||||
super(bundleName, new DummyResourceBundle(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
</header>
|
||||
|
||||
<#include "developer.ftl">
|
||||
|
||||
<nav role="navigation">
|
||||
<ul id="main-nav" role="list">
|
||||
<#list menu.items as item>
|
||||
|
|
|
@ -814,6 +814,15 @@
|
|||
<url-pattern>/searchHelp</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>DeveloperAjax</servlet-name>
|
||||
<servlet-class>edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettingsServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>DeveloperAjax</servlet-name>
|
||||
<url-pattern>/admin/developerAjax</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- for now, need to make sure the links on CALS' site doesn't break -->
|
||||
<servlet-mapping>
|
||||
<servlet-name>SearchController</servlet-name>
|
||||
|
|
48
webapp/web/css/developer/developerPanel.css
Normal file
48
webapp/web/css/developer/developerPanel.css
Normal file
|
@ -0,0 +1,48 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
/* Styles for the developer panel. */
|
||||
|
||||
div.developer {
|
||||
background-color: #f7dd8a;
|
||||
padding: 0px 10px 0px 10px;
|
||||
font-variant: small-caps;
|
||||
}
|
||||
|
||||
div.developer #developerPanelBody {
|
||||
display: none;
|
||||
line-height: 1em;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
div.developer div.devleft {
|
||||
width: 49%
|
||||
}
|
||||
|
||||
div.developer div.devright {
|
||||
float: right;
|
||||
width: 49%
|
||||
}
|
||||
|
||||
div.developer div.container {
|
||||
border: thin groove black;
|
||||
padding: 3px 10px 3px 10px;
|
||||
margin: 3px 0px 3px 0px;
|
||||
}
|
||||
|
||||
div.developer div.within {
|
||||
padding-left: 1.5em;
|
||||
}
|
||||
|
||||
div.developer input[type="text"] {
|
||||
padding: 2px 10px 2px 10px;
|
||||
line-height: 1em;
|
||||
margin: 2px 2px 2px 2px;
|
||||
}
|
||||
|
||||
div.developer input[type="text"]:disabled {
|
||||
background-color: #f8eeae;
|
||||
}
|
||||
|
||||
div.developer a {
|
||||
margin: 3px;
|
||||
}
|
|
@ -456,7 +456,7 @@ please_create = Please create
|
|||
a_classgroup = a class group
|
||||
associate_classes_with_group = and associate classes with the group created.
|
||||
|
||||
refresh_content = Refresh Content
|
||||
site_maintenance = Site Maintenance
|
||||
rebuild_search_index = Rebuild search index
|
||||
rebuild_vis_cache = Rebuild visualization cache
|
||||
recompute_inferences_mixed_caps = Recompute inferences
|
||||
|
@ -493,6 +493,9 @@ restrict_logins_mixed_caps = Restrict logins
|
|||
site_information = Site information
|
||||
user_accounts = User accounts
|
||||
|
||||
activate_developer_panel = Activate developer panel
|
||||
activate_developer_panel_mixed_caps = Activate developer panel
|
||||
|
||||
#
|
||||
# search controller ( PagedSearchController.java )
|
||||
#
|
||||
|
|
88
webapp/web/js/developer/developerPanel.js
Normal file
88
webapp/web/js/developer/developerPanel.js
Normal file
|
@ -0,0 +1,88 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
function DeveloperPanel(developerAjaxUrl) {
|
||||
this.setupDeveloperPanel = updateDeveloperPanel;
|
||||
|
||||
function updateDeveloperPanel(data) {
|
||||
$.ajax({
|
||||
url: developerAjaxUrl,
|
||||
dataType: "json",
|
||||
data: data,
|
||||
complete: function(xhr, status) {
|
||||
updatePanelContents(xhr.responseText);
|
||||
if (document.getElementById("developerPanelSaveButton")) {
|
||||
enablePanelOpener();
|
||||
addBehaviorToElements();
|
||||
updateDisabledFields();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updatePanelContents(contents) {
|
||||
document.getElementById("developerPanel").innerHTML = contents;
|
||||
}
|
||||
|
||||
function enablePanelOpener() {
|
||||
document.getElementById("developerPanelClickMe").onclick = function() {
|
||||
document.getElementById("developerPanelClickText").style.display = "none";
|
||||
document.getElementById("developerPanelBody").style.display = "block";
|
||||
};
|
||||
}
|
||||
|
||||
function addBehaviorToElements() {
|
||||
document.getElementById("developerPanelSaveButton").onclick = function() {
|
||||
updateDeveloperPanel(collectFormData());
|
||||
}
|
||||
document.getElementById("developerEnabled").onchange = updateDisabledFields
|
||||
document.getElementById("developerLoggingRDFServiceEnable").onchange = updateDisabledFields
|
||||
}
|
||||
|
||||
function updateDisabledFields() {
|
||||
var developerEnabled = document.getElementById("developerEnabled").checked;
|
||||
document.getElementById("developerDefeatFreemarkerCache").disabled = !developerEnabled;
|
||||
document.getElementById("developerInsertFreemarkerDelimiters").disabled = !developerEnabled;
|
||||
document.getElementById("developerPageContentsLogCustomListView").disabled = !developerEnabled;
|
||||
document.getElementById("developerPageContentsLogCustomShortView").disabled = !developerEnabled;
|
||||
document.getElementById("developerI18nDefeatCache").disabled = !developerEnabled;
|
||||
document.getElementById("developerI18nLogStringRequests").disabled = !developerEnabled;
|
||||
document.getElementById("developerLoggingRDFServiceEnable").disabled = !developerEnabled;
|
||||
|
||||
var rdfServiceEnabled = developerEnabled && document.getElementById("developerLoggingRDFServiceEnable").checked;
|
||||
document.getElementById("developerLoggingRDFServiceStackTrace").disabled = !rdfServiceEnabled;
|
||||
document.getElementById("developerLoggingRDFServiceQueryRestriction").disabled = !rdfServiceEnabled;
|
||||
document.getElementById("developerLoggingRDFServiceStackRestriction").disabled = !rdfServiceEnabled;
|
||||
}
|
||||
|
||||
function collectFormData() {
|
||||
var data = new Object();
|
||||
getCheckbox("developerEnabled", data);
|
||||
getCheckbox("developerDefeatFreemarkerCache", data);
|
||||
getCheckbox("developerInsertFreemarkerDelimiters", data);
|
||||
getCheckbox("developerPageContentsLogCustomListView", data);
|
||||
getCheckbox("developerPageContentsLogCustomShortView", data);
|
||||
getCheckbox("developerI18nDefeatCache", data);
|
||||
getCheckbox("developerI18nLogStringRequests", data);
|
||||
getCheckbox("developerLoggingRDFServiceEnable", data);
|
||||
getCheckbox("developerLoggingRDFServiceStackTrace", data);
|
||||
getText("developerLoggingRDFServiceQueryRestriction", data);
|
||||
getText("developerLoggingRDFServiceStackRestriction", data);
|
||||
return data;
|
||||
}
|
||||
|
||||
function getCheckbox(key, dest) {
|
||||
dest[key] = document.getElementById(key).checked;
|
||||
}
|
||||
|
||||
function getText(key, dest) {
|
||||
dest[key] = document.getElementById(key).value;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Relies on the global variable for the AJAX URL.
|
||||
*/
|
||||
$(document).ready(function() {
|
||||
new DeveloperPanel(developerAjaxUrl).setupDeveloperPanel({});
|
||||
});
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||
|
||||
<#-- Template for the main Site Administration page -->
|
||||
|
||||
<#if indexCacheRebuild?has_content>
|
||||
<section class="pageBodyGroup indexCacheRebuild" role="region">
|
||||
<h3>${i18n().refresh_content}</h3>
|
||||
|
||||
<ul role="navigation">
|
||||
<#if indexCacheRebuild.rebuildSearchIndex?has_content>
|
||||
<li role="listitem"><a href="${indexCacheRebuild.rebuildSearchIndex }" title="${i18n().rebuild_search_index}">${i18n().rebuild_search_index}</a></li>
|
||||
</#if>
|
||||
|
||||
<#if indexCacheRebuild.rebuildVisCache?has_content>
|
||||
<li role="listitem"><a href="${indexCacheRebuild.rebuildVisCache}" title="${i18n().rebuild_vis_cache}">${i18n().rebuild_vis_cache}</a></li>
|
||||
</#if>
|
||||
|
||||
<#if indexCacheRebuild.recomputeInferences?has_content>
|
||||
<li role="listitem"><a href="${indexCacheRebuild.recomputeInferences}" title="${i18n().recompute_inferences}">${i18n().recompute_inferences_mixed_caps}</a></li>
|
||||
</#if>
|
||||
</ul>
|
||||
</section>
|
||||
</#if>
|
|
@ -13,5 +13,5 @@ ${stylesheets.add('<link rel="stylesheet" href="${urls.base}/css/admin.css" />')
|
|||
<#include "siteAdmin-siteConfiguration.ftl">
|
||||
<#include "siteAdmin-ontologyEditor.ftl">
|
||||
<#include "siteAdmin-advancedDataTools.ftl">
|
||||
<#include "siteAdmin-indexCacheRebuild.ftl">
|
||||
<#include "siteAdmin-siteMaintenance.ftl">
|
||||
</div>
|
|
@ -23,10 +23,6 @@
|
|||
<li role="listitem"><a href="${siteConfig.menuManagement}" title="${i18n().menu_ordering}">${i18n().menu_ordering_mixed_caps}</a></li>
|
||||
</#if>
|
||||
|
||||
<#if siteConfig.restrictLogins?has_content>
|
||||
<li role="listitem"><a href="${siteConfig.restrictLogins}" title="${i18n().restrict_logins}">${i18n().restrict_logins_mixed_caps}</a></li>
|
||||
</#if>
|
||||
|
||||
<#if siteConfig.siteInfo?has_content>
|
||||
<li role="listitem"><a href="${siteConfig.siteInfo}" title="${i18n().site_information}">${i18n().site_information}</a></li>
|
||||
</#if>
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||
|
||||
<#-- Template for the main Site Administration page -->
|
||||
|
||||
<#if siteMaintenance?has_content>
|
||||
<section class="pageBodyGroup" role="region">
|
||||
<h3>${i18n().site_maintenance}</h3>
|
||||
|
||||
<ul role="navigation">
|
||||
<#if siteMaintenance.rebuildSearchIndex?has_content>
|
||||
<li role="listitem"><a href="${siteMaintenance.rebuildSearchIndex }" title="${i18n().rebuild_search_index}">${i18n().rebuild_search_index}</a></li>
|
||||
</#if>
|
||||
|
||||
<#if siteMaintenance.rebuildVisCache?has_content>
|
||||
<li role="listitem"><a href="${siteMaintenance.rebuildVisCache}" title="${i18n().rebuild_vis_cache}">${i18n().rebuild_vis_cache}</a></li>
|
||||
</#if>
|
||||
|
||||
<#if siteMaintenance.recomputeInferences?has_content>
|
||||
<li role="listitem"><a href="${siteMaintenance.recomputeInferences}" title="${i18n().recompute_inferences}">${i18n().recompute_inferences_mixed_caps}</a></li>
|
||||
</#if>
|
||||
|
||||
<#if siteMaintenance.restrictLogins?has_content>
|
||||
<li role="listitem"><a href="${siteMaintenance.restrictLogins}" title="${i18n().restrict_logins}">${i18n().restrict_logins_mixed_caps}</a></li>
|
||||
</#if>
|
||||
|
||||
<#if siteMaintenance.activateDeveloperPanel?has_content>
|
||||
<li role="listitem"><a href="${siteMaintenance.activateDeveloperPanel}" title="${i18n().activate_developer_panel}">${i18n().activate_developer_panel_mixed_caps}</a></li>
|
||||
</#if>
|
||||
</ul>
|
||||
</section>
|
||||
</#if>
|
|
@ -9,7 +9,7 @@
|
|||
-->
|
||||
|
||||
<#assign rangeOptionsExist = true />
|
||||
|
||||
<#assign rangeVClassURI = editConfiguration.objectPredicateProperty.rangeVClassURI!"" />
|
||||
<#assign objectTypes = editConfiguration.pageData.objectTypes />
|
||||
<#assign objectTypesSize = objectTypes?length />
|
||||
<#assign objectTypesExist = false />
|
||||
|
@ -40,7 +40,7 @@
|
|||
<#assign formTitle = editConfiguration.formTitle />
|
||||
<#if editConfiguration.formTitle?contains("collaborator") >
|
||||
<#assign formTitle = "${i18n().select_existing_collaborator(editConfiguration.subjectName)}" />
|
||||
<#elseif editConfiguration.objectPredicateProperty.rangeVClassURI?contains("IAO_0000030")>
|
||||
<#elseif rangeVClassURI?contains("IAO_0000030")>
|
||||
<#assign formTitle = "${i18n().select_an_existing_document}" + " ${i18n().for} " + editConfiguration.subjectName/>
|
||||
</#if>
|
||||
<#--In order to fill out the subject-->
|
||||
|
|
|
@ -30,9 +30,9 @@
|
|||
|
||||
<input type="hidden" name="subjectUri" value="${editConfiguration.subjectUri}" role="input" />
|
||||
<input type="hidden" name="predicateUri" value="${editConfiguration.predicateUri}" role="input" />
|
||||
<input type="hidden" name="domainUri" value="${editConfiguration.domainUri}" role="input" />
|
||||
<input type="hidden" name="rangeUri" value="${editConfiguration.rangeUri}" role="input" />
|
||||
|
||||
<input type="hidden" name="domainUri" value="${editConfiguration.domainUri!}" role="input" />
|
||||
<input type="hidden" name="rangeUri" value="${editConfiguration.rangeUri!}" role="input" />
|
||||
<input type="hidden" name="deleteObjectUri" value="${editConfiguration.customDeleteObjectUri!}" />
|
||||
<#if editConfiguration.dataProperty = true>
|
||||
<input type="hidden" name="datapropKey" value="${editConfiguration.datapropKey}" role="input" />
|
||||
<input type="hidden" name="vitroNsProp" value="${editConfiguration.vitroNsProperty}" role="input" />
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
<input type="hidden" name="subjectUri" value="${editConfiguration.subjectUri}"/>
|
||||
<input type="hidden" name="predicateUri" value="${editConfiguration.predicateUri}"/>
|
||||
<input type="hidden" name="domainUri" value="${editConfiguration.domainUri}"/>
|
||||
<input type="hidden" name="rangeUri" value="${editConfiguration.rangeUri}"/>
|
||||
<input type="hidden" name="domainUri" value="${editConfiguration.domainUri!}"/>
|
||||
<input type="hidden" name="rangeUri" value="${editConfiguration.rangeUri!}"/>
|
||||
<input type="hidden" name="cmd" value="delete"/>
|
||||
<input type="hidden" name="editKey" value="${editConfiguration.editKey}"/>
|
||||
<#if editConfiguration.dataProperty = true>
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
<input type="hidden" value="${editConfiguration.subjectUri}" name="subjectUri" role="input" />
|
||||
<input type="hidden" value="${editConfiguration.predicateUri}" name="predicateUri" role="input" />
|
||||
<input type="hidden" value="${objectUri}" name="objectUri" role="input" />
|
||||
<input type="hidden" name="domainUri" value="${editConfiguration.domainUri!}"/>
|
||||
<input type="hidden" name="rangeUri" value="${editConfiguration.rangeUri!}"/>
|
||||
<input type="hidden" value="create" name="cmd" role="input" />
|
||||
|
||||
<select id="typeOfNew" name="typeOfNew" role="selection">
|
||||
|
|
|
@ -6,8 +6,9 @@
|
|||
<#if (rangeOptions?keys?size > 0)>
|
||||
<#assign rangeOptionsExist = true/>
|
||||
</#if>
|
||||
<#assign rangeUri = editConfiguration.objectPredicateProperty.rangeVClassURI!"" />
|
||||
<#assign formTitle = editConfiguration.formTitle />
|
||||
<#if editConfiguration.objectPredicateProperty.rangeVClassURI?contains("IAO_0000030")>
|
||||
<#if rangeUri?contains("IAO_0000030")>
|
||||
<#assign formTitle = "${i18n().select_an_existing_document}" + " ${i18n().for} " + editConfiguration.subjectName/>
|
||||
</#if>
|
||||
<h2>${formTitle}</h2>
|
||||
|
|
|
@ -118,7 +118,7 @@ name will be used as the label. -->
|
|||
</#if>
|
||||
-->
|
||||
<#if editable>
|
||||
<h2 id="${property.localName}">${label} ${addLink!} ${verboseDisplay!}</h2>
|
||||
<h2 id="${property.localName!}">${label} ${addLink!} ${verboseDisplay!}</h2>
|
||||
</#if>
|
||||
</#macro>
|
||||
|
||||
|
@ -134,15 +134,15 @@ name will be used as the label. -->
|
|||
<#local domainUri = "" />
|
||||
</#if>
|
||||
<#if editable>
|
||||
<#local url = property.addUrl>
|
||||
<#if url?has_content>
|
||||
<#if property.addUrl?has_content>
|
||||
<#local url = property.addUrl>
|
||||
<@showAddLink property.localName label url rangeUri domainUri/>
|
||||
</#if>
|
||||
</#if>
|
||||
</#macro>
|
||||
|
||||
<#macro showAddLink propertyLocalName label url rangeUri domainUri="">
|
||||
<#if (rangeUri?contains("Authorship") && domainUri?contains("IAO_0000030")) || (rangeUri?contains("Editorship") && domainUri?contains("IAO_0000030"))|| rangeUri?contains("URL") || label == "hasResearchArea">
|
||||
<#if (rangeUri?contains("Authorship") && domainUri?contains("IAO_0000030")) || (rangeUri?contains("Editorship") && domainUri?contains("IAO_0000030"))|| rangeUri?contains("URL") || propertyLocalName == "hasResearchArea">
|
||||
<a class="add-${propertyLocalName}" href="${url}" title="${i18n().manage_list_of} ${label?lower_case}">
|
||||
<img class="add-individual" src="${urls.images}/individual/manage-icon.png" alt="${i18n().manage}" /></a>
|
||||
<#else>
|
||||
|
@ -171,22 +171,22 @@ name will be used as the label. -->
|
|||
<#macro editingLinks propertyLocalName propertyName statement editable rangeUri="">
|
||||
<#if editable >
|
||||
<#if (!rangeUri?contains("Authorship") && !rangeUri?contains("URL") && !rangeUri?contains("Editorship") && propertyLocalName != "hasResearchArea")>
|
||||
<@editLink propertyLocalName propertyName statement />
|
||||
<@deleteLink propertyLocalName propertyName statement />
|
||||
<@editLink propertyLocalName propertyName statement rangeUri/>
|
||||
<@deleteLink propertyLocalName propertyName statement rangeUri/>
|
||||
</#if>
|
||||
</#if>
|
||||
</#macro>
|
||||
<#macro editLink propertyLocalName propertyName statement>
|
||||
<#macro editLink propertyLocalName propertyName statement rangeUri="">
|
||||
<#if propertyLocalName?contains("ARG_2000028")>
|
||||
<#if propertyName?contains("mailing address")>
|
||||
<#if rangeUri?contains("Address")>
|
||||
<#local url = statement.editUrl + "&addressUri=" + "${statement.address!}">
|
||||
<#elseif propertyName?contains("phone") || propertyName?contains("fax")>
|
||||
<#elseif rangeUri?contains("Telephone") || rangeUri?contains("Fax")>
|
||||
<#local url = statement.editUrl + "&phoneUri=" + "${statement.phone!}">
|
||||
<#elseif propertyName?contains("primary email") || propertyName?contains("additional emails")>
|
||||
<#elseif rangeUri?contains("Work") || rangeUri?contains("Email")>
|
||||
<#local url = statement.editUrl + "&emailUri=" + "${statement.email!}">
|
||||
<#elseif propertyName?contains("full name")>
|
||||
<#elseif rangeUri?contains("Name")>
|
||||
<#local url = statement.editUrl + "&fullNameUri=" + "${statement.fullName!}">
|
||||
<#elseif propertyName?contains("preferred title")>
|
||||
<#elseif rangeUri?contains("Title")>
|
||||
<#local url = statement.editUrl + "&titleUri=" + "${statement.title!}">
|
||||
</#if>
|
||||
<#else>
|
||||
|
@ -202,9 +202,23 @@ name will be used as the label. -->
|
|||
<a class="edit-${propertyLocalName}" href="${url}" title="${i18n().edit_entry}"><img class="edit-individual" src="${urls.images}/individual/editIcon.gif" alt="${i18n().edit_entry}" /></a>
|
||||
</#macro>
|
||||
|
||||
<#macro deleteLink propertyLocalName propertyName statement>
|
||||
<#macro deleteLink propertyLocalName propertyName statement rangeUri="">
|
||||
<#local url = statement.deleteUrl>
|
||||
<#if url?has_content>
|
||||
<#--We need to specify the actual object to be deleted as it is different from the object uri-->
|
||||
<#if propertyLocalName?contains("ARG_2000028")>
|
||||
<#if rangeUri?contains("Address")>
|
||||
<#local url = url + "&deleteObjectUri=" + "${statement.address!}">
|
||||
<#elseif rangeUri?contains("Telephone") || rangeUri?contains("Fax")>
|
||||
<#local url = url + "&deleteObjectUri=" + "${statement.phone!}">
|
||||
<#elseif rangeUri?contains("Work") || rangeUri?contains("Email")>
|
||||
<#local url = url + "&deleteObjectUri=" + "${statement.email!}">
|
||||
<#elseif rangeUri?contains("Name")>
|
||||
<#local url = url + "&deleteObjectUri=" + "${statement.fullName!}">
|
||||
<#elseif rangeUri?contains("Title")>
|
||||
<#local url = url + "&deleteObjectUri=" + "${statement.title!}">
|
||||
</#if>
|
||||
</#if>
|
||||
<@showDeleteLink propertyLocalName url />
|
||||
</#if>
|
||||
</#macro>
|
||||
|
@ -217,6 +231,9 @@ name will be used as the label. -->
|
|||
<#local verboseDisplay = property.verboseDisplay!>
|
||||
<#if verboseDisplay?has_content>
|
||||
<section class="verbosePropertyListing">
|
||||
<#if verboseDisplay.fauxProperty??>
|
||||
a faux property of
|
||||
</#if>
|
||||
<a class="propertyLink" href="${verboseDisplay.propertyEditUrl}" title="${i18n().name}">${verboseDisplay.localName}</a>
|
||||
(<span>${property.type?lower_case}</span> property);
|
||||
order in group: <span>${verboseDisplay.displayRank};</span>
|
||||
|
@ -260,7 +277,8 @@ name will be used as the label. -->
|
|||
<#assign labelPropertyUri = ("http://www.w3.org/2000/01/rdf-schema#label"?url) />
|
||||
<#assign useEditLink = false />
|
||||
<#--edit link used if in edit mode and only one label and one language-->
|
||||
<#if labelCount = 1 && editable && localesCount = 1 >
|
||||
<#--locales count may be 0 in case where no languages/selectable locales are specified-->
|
||||
<#if labelCount = 1 && editable && (localesCount >= 0) >
|
||||
<#assign useEditLink = true/>
|
||||
</#if>
|
||||
<#local label = individual.nameStatement>
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||
|
||||
<div id="developerPanel" > </div>
|
||||
<script>developerAjaxUrl = '${urls.developerAjax}'</script>
|
||||
${scripts.add('<script type="text/javascript" src="${urls.base}/js/developer/developerPanel.js"></script>')}
|
||||
<link rel="stylesheet" href="${urls.base}/css/developer/developerPanel.css" />
|
105
webapp/web/templates/freemarker/page/partials/developerPanel.ftl
Normal file
105
webapp/web/templates/freemarker/page/partials/developerPanel.ftl
Normal file
|
@ -0,0 +1,105 @@
|
|||
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||
|
||||
|
||||
<#macro showCheckbox key>
|
||||
<input type="checkbox" id="${key}" <#if settings[key]>checked</#if>>
|
||||
</#macro>
|
||||
|
||||
<#macro showTextbox key>
|
||||
<input type="text" id="${key}" size="30" value="${settings[key]}" >
|
||||
</#macro>
|
||||
|
||||
<#if !settings.developerEnabled>
|
||||
<#elseif !settings.mayControl>
|
||||
<div class="developer">
|
||||
<h1>${siteName} is running in developer mode.</h1>
|
||||
</div>
|
||||
<#else>
|
||||
<div class="developer">
|
||||
<h1 id="developerPanelClickMe">${siteName} is running in developer mode.
|
||||
<span id="developerPanelClickText">(click for Options)</span>
|
||||
</h1>
|
||||
<div id="developerPanelBody">
|
||||
<div>
|
||||
<label>
|
||||
<@showCheckbox "developerEnabled" />
|
||||
Enable developer mode
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="devright">
|
||||
<div class="container">
|
||||
Page configuration
|
||||
<label>
|
||||
<@showCheckbox "developerPageContentsLogCustomListView" />
|
||||
Log the use of custom list view XML files.
|
||||
</label>
|
||||
<label>
|
||||
<@showCheckbox "developerPageContentsLogCustomShortView" />
|
||||
Log the use of custom short views in search, index and browse pages.
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
Language support
|
||||
<label>
|
||||
<@showCheckbox "developerI18nDefeatCache" />
|
||||
Defeat the cache of language property files
|
||||
</label>
|
||||
<label>
|
||||
<@showCheckbox "developerI18nLogStringRequests" />
|
||||
Log the retrieval of language strings
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
Links
|
||||
<br/>
|
||||
<a href="${urls.base}/admin/log4j.jsp">Set log levels</a>
|
||||
<a href="${urls.base}/admin/showAuth">Show authorization info</a>
|
||||
<a href="${urls.base}/admin/showThreads">Show background threads</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="devleft">
|
||||
<div class="container">
|
||||
Freemarker templates
|
||||
<label>
|
||||
<@showCheckbox "developerDefeatFreemarkerCache" />
|
||||
Defeat the template cache
|
||||
</label>
|
||||
<label>
|
||||
<@showCheckbox "developerInsertFreemarkerDelimiters" />
|
||||
Insert HTML comments at start and end of templates
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
SPARQL Queries
|
||||
<label>
|
||||
<@showCheckbox "developerLoggingRDFServiceEnable" />
|
||||
Log each query
|
||||
</label>
|
||||
<div class="within">
|
||||
<label>
|
||||
<@showCheckbox "developerLoggingRDFServiceStackTrace" />
|
||||
Add stack trace
|
||||
</label>
|
||||
<label>
|
||||
Restrict by query string
|
||||
<@showTextbox "developerLoggingRDFServiceQueryRestriction" />
|
||||
</label>
|
||||
<label>
|
||||
Restrict by calling stack
|
||||
<@showTextbox "developerLoggingRDFServiceStackRestriction" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input type="button" id="developerPanelSaveButton" value="Save Settings" name="foo" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</#if>
|
|
@ -6,11 +6,11 @@
|
|||
What was the right way to do this?
|
||||
-->
|
||||
|
||||
<#-- This is included by identity.ftl -->
|
||||
<#-- This is included by identity.ftl -->
|
||||
<#if selectLocale??>
|
||||
<#list selectLocale.locales as locale>
|
||||
<li>
|
||||
<a href="${selectLocale.selectLocaleUrl}?selection=${locale.code}" title="${i18n().select_locale} -- ${locale.label}">
|
||||
<a href="${selectLocale.selectLocaleUrl}?selection=${locale.code}" title="${i18n().select_locale} -- ${locale.label}" <#if locale.selected>style="padding-bottom:1px;border-bottom: 1px solid #ccdfe6"</#if>>
|
||||
<img src="${locale.imageUrl}" height="15" style="vertical-align:middle" alt="${locale.label}"/>
|
||||
</a>
|
||||
</li>
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||
|
||||
<#include "developer.ftl">
|
||||
|
||||
<nav role="navigation">
|
||||
<ul id="main-nav" role="list">
|
||||
<#list menu.items as item>
|
||||
|
|
Loading…
Add table
Reference in a new issue