diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader.java index 9f7f603aa..8c45a2fca 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader.java @@ -8,6 +8,7 @@ import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; +import java.util.TreeSet; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; @@ -34,16 +35,42 @@ public class ConfigurationBeanLoader { return JAVA_URI_PREFIX + clazz.getName(); } + public static String toCanonicalJavaUri(String uri) { + return uri.replace("#", "."); + } + public static boolean isJavaUri(String uri) { return uri.startsWith(JAVA_URI_PREFIX); } - public static String fromJavaUri(String uri) { - if (!isJavaUri(uri)) { - throw new IllegalArgumentException("Not a java class URI: '" + uri - + "'"); + public static Set toPossibleJavaUris(Class clazz) { + Set set = new TreeSet<>(); + String[] uriPieces = toJavaUri(clazz).split("\\."); + for (int hashIndex = 0; hashIndex < uriPieces.length; hashIndex++) { + set.add(joinWithPeriodsAndAHash(uriPieces, hashIndex)); } - return uri.substring(JAVA_URI_PREFIX.length()); + return set; + } + + private static String joinWithPeriodsAndAHash(String[] pieces, + int hashIndex) { + StringBuilder buffer = new StringBuilder(pieces[0]); + for (int i = 1; i < pieces.length; i++) { + buffer.append(i == hashIndex ? '#' : '.').append(pieces[i]); + } + return buffer.toString(); + } + + public static String classnameFromJavaUri(String uri) { + if (!isJavaUri(uri)) { + throw new IllegalArgumentException( + "Not a java class URI: '" + uri + "'"); + } + return toCanonicalJavaUri(uri).substring(JAVA_URI_PREFIX.length()); + } + + public static boolean isMatchingJavaUri(String uri1, String uri2) { + return toCanonicalJavaUri(uri1).equals(toCanonicalJavaUri(uri2)); } // ---------------------------------------------------------------------- @@ -85,9 +112,11 @@ public class ConfigurationBeanLoader { this(new LockableModel(model), req); } - public ConfigurationBeanLoader(LockableModel locking, HttpServletRequest req) { - this(locking, (req == null) ? null : req.getSession() - .getServletContext(), req); + public ConfigurationBeanLoader(LockableModel locking, + HttpServletRequest req) { + this(locking, + (req == null) ? null : req.getSession().getServletContext(), + req); } private ConfigurationBeanLoader(LockableModel locking, ServletContext ctx, @@ -111,18 +140,18 @@ public class ConfigurationBeanLoader { } try { - ConfigurationRdf parsedRdf = ConfigurationRdfParser.parse( - locking, uri, resultClass); - WrappedInstance wrapper = InstanceWrapper.wrap(parsedRdf - .getConcreteClass()); + ConfigurationRdf parsedRdf = ConfigurationRdfParser + .parse(locking, uri, resultClass); + WrappedInstance wrapper = InstanceWrapper + .wrap(parsedRdf.getConcreteClass()); wrapper.satisfyInterfaces(ctx, req); wrapper.checkCardinality(parsedRdf.getPropertyStatements()); wrapper.setProperties(this, parsedRdf.getPropertyStatements()); wrapper.validate(); return wrapper.getInstance(); } catch (Exception e) { - throw new ConfigurationBeanLoaderException("Failed to load '" + uri - + "'", e); + throw new ConfigurationBeanLoaderException( + "Failed to load '" + uri + "'", e); } } @@ -133,11 +162,13 @@ public class ConfigurationBeanLoader { throws ConfigurationBeanLoaderException { Set uris = new HashSet<>(); try (LockedModel m = locking.read()) { - List resources = m.listResourcesWithProperty(RDF.type, - createResource(toJavaUri(resultClass))).toList(); - for (Resource r : resources) { - if (r.isURIResource()) { - uris.add(r.getURI()); + for (String typeUri : toPossibleJavaUris(resultClass)) { + List resources = m.listResourcesWithProperty(RDF.type, + createResource(typeUri)).toList(); + for (Resource r : resources) { + if (r.isURIResource()) { + uris.add(r.getURI()); + } } } } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationRdfParser.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationRdfParser.java index e96488f3a..4153d2295 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationRdfParser.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationRdfParser.java @@ -2,16 +2,18 @@ package edu.cornell.mannlib.vitro.webapp.utils.configuration; +import static edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationBeanLoader.classnameFromJavaUri; +import static edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationBeanLoader.isJavaUri; +import static edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationBeanLoader.isMatchingJavaUri; +import static edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationBeanLoader.toJavaUri; import static org.apache.jena.rdf.model.ResourceFactory.createResource; import static org.apache.jena.rdf.model.ResourceFactory.createStatement; -import static edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationBeanLoader.fromJavaUri; -import static edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationBeanLoader.isJavaUri; -import static edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationBeanLoader.toJavaUri; import java.lang.reflect.Modifier; import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.Set; import org.apache.jena.rdf.model.Property; @@ -64,12 +66,20 @@ public class ConfigurationRdfParser { private static void confirmEligibilityForResultClass(LockableModel locking, String uri, Class resultClass) throws InvalidConfigurationRdfException { - Statement s = createStatement(createResource(uri), RDF.type, - createResource(toJavaUri(resultClass))); + String resultClassUri = toJavaUri(resultClass); try (LockedModel m = locking.read()) { - if (!m.contains(s)) { - throw noTypeStatementForResultClass(s); + Set types = // + m.listObjectsOfProperty(createResource(uri), RDF.type) + .toSet(); + for (RDFNode typeNode : types) { + if (typeNode.isURIResource()) { + String typeUri = typeNode.asResource().getURI(); + if (isMatchingJavaUri(resultClassUri, typeUri)) { + return; + } + } } + throw noTypeStatementForResultClass(uri, resultClassUri); } } @@ -78,9 +88,8 @@ public class ConfigurationRdfParser { Set set = new HashSet<>(); try (LockedModel m = locking.read()) { - List rawStatements = m.listStatements( - m.getResource(uri), (Property) null, (RDFNode) null) - .toList(); + List rawStatements = m.listStatements(m.getResource(uri), + (Property) null, (RDFNode) null).toList(); if (rawStatements.isEmpty()) { throw noRdfStatements(uri); } @@ -108,8 +117,9 @@ public class ConfigurationRdfParser { Set> concreteClasses = new HashSet<>(); try (LockedModel m = locking.read()) { - for (RDFNode node : m.listObjectsOfProperty(createResource(uri), - RDF.type).toSet()) { + for (RDFNode node : m + .listObjectsOfProperty(createResource(uri), RDF.type) + .toSet()) { if (!node.isURIResource()) { throw typeMustBeUriResource(node); } @@ -140,7 +150,7 @@ public class ConfigurationRdfParser { if (!isJavaUri(typeUri)) { return false; } - Class clazz = Class.forName(fromJavaUri(typeUri)); + Class clazz = Class.forName(classnameFromJavaUri(typeUri)); if (clazz.isInterface()) { return false; } @@ -157,7 +167,7 @@ public class ConfigurationRdfParser { private static Class processTypeUri(String typeUri, Class resultClass) throws InvalidConfigurationRdfException { try { - Class clazz = Class.forName(fromJavaUri(typeUri)); + Class clazz = Class.forName(classnameFromJavaUri(typeUri)); if (!resultClass.isAssignableFrom(clazz)) { throw notAssignable(resultClass, clazz); } @@ -180,22 +190,23 @@ public class ConfigurationRdfParser { "The model contains no statements about '" + uri + "'"); } - private static InvalidConfigurationRdfException noConcreteClasses(String uri) { + private static InvalidConfigurationRdfException noConcreteClasses( + String uri) { return new InvalidConfigurationRdfException( "No concrete class is declared for '" + uri + "'"); } private static InvalidConfigurationRdfException tooManyConcreteClasses( String uri, Set concreteClasses) { - return new InvalidConfigurationRdfException("'" + uri - + "' is declared with more than one " + "concrete class: " - + concreteClasses); + return new InvalidConfigurationRdfException( + "'" + uri + "' is declared with more than one " + + "concrete class: " + concreteClasses); } private static InvalidConfigurationRdfException notAssignable( Class resultClass, Class clazz) { - return new InvalidConfigurationRdfException(clazz - + " cannot be assigned to " + resultClass); + return new InvalidConfigurationRdfException( + clazz + " cannot be assigned to " + resultClass); } private static InvalidConfigurationRdfException noZeroArgumentConstructor( @@ -212,8 +223,8 @@ public class ConfigurationRdfParser { private static InvalidConfigurationRdfException failedToLoadClass( String typeUri, Throwable e) { - return new InvalidConfigurationRdfException("Can't load this type: '" - + typeUri + "'", e); + return new InvalidConfigurationRdfException( + "Can't load this type: '" + typeUri + "'", e); } private static InvalidConfigurationRdfException typeMustBeUriResource( @@ -223,15 +234,18 @@ public class ConfigurationRdfParser { } private static InvalidConfigurationRdfException noTypeStatementForResultClass( - Statement s) { + String uri, String resultClassUri) { return new InvalidConfigurationRdfException( - "A type statement is required: '" + s); + "A type statement is required: '" + + createStatement(createResource(uri), RDF.type, + createResource(resultClassUri))); } - private static InvalidConfigurationRdfException noRdfStatements(String uri) { - return new InvalidConfigurationRdfException("'" + uri - + "' does not appear as the subject of any " - + "statements in the model."); + private static InvalidConfigurationRdfException noRdfStatements( + String uri) { + return new InvalidConfigurationRdfException( + "'" + uri + "' does not appear as the subject of any " + + "statements in the model."); } public static class InvalidConfigurationRdfException extends Exception { @@ -239,7 +253,8 @@ public class ConfigurationRdfParser { super(message); } - public InvalidConfigurationRdfException(String message, Throwable cause) { + public InvalidConfigurationRdfException(String message, + Throwable cause) { super(message, cause); } } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/README.md b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/README.md index 68da421fa..0527158e4 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/README.md +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/README.md @@ -95,8 +95,36 @@ The principal methods are: + Search the graph for all individuals of type `resultClass`. For each such individual, call `loadInstance`. Return a set containing the created instances. If no individuals are found, return an empty `Set`. +### Specifying Java class URIs + +Java classes are specified as types in the configurations. The type URIs consist of `java:` and the fully-qualified class path and name. For example, + +``` +:application + a . +``` + +It would be nice to use prefixes to make URIs more readable. This doesn't +work with the scheme above, since none of the characters in the URI are valid +as delimiters of a prefix. + +For this reason, the loader will also recognize a type URI if one of the periods is replaced by a hash (`#`). So, this is equivalent to the previous example (note the `#` after `webapp`): + +``` +:application + a . +``` + +which implies that this is equivalent also: + +``` +@prefix javaWebapp: +:application a javaWebapp:application.ApplicationImpl . + +``` + ### Restrictions on instantiated classes. -Each class to be instantiated must have a niladic constructor. +Each class to be instantiated must have a public niladic constructor. ### Property methods When the loader encounters a data property or an object property in a description, @@ -116,7 +144,8 @@ For example: In more detail: -+ A class must contain exactly one method that serves each property URI in the description. ++ Each property URI in the description may be served by only one method in the class. ++ If a property URI in the description is not served by any method in the class, the loader will ignore that property. + The description need not include properies for all of the property methods in the class. + Each property method must be public, must have exactly one parameter, and must return null. + The name of the property method is immaterial, except that there must not be another method @@ -159,7 +188,7 @@ Again, in detail: + Each validation method must be public, must accept no parameters, and must return null. + The name of the validation method is immaterial, except that there must not be another -+ method with the same name in the lass. ++ method with the same name in the class. + Validation methods in superclasses will be called, but may not be overridden in a subclass. ### Life cycle diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/WrappedInstance.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/WrappedInstance.java index 344016863..ba4a2ab75 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/WrappedInstance.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/WrappedInstance.java @@ -70,7 +70,8 @@ public class WrappedInstance { */ public void checkCardinality(Set propertyStatements) throws CardinalityException { - Map statementCounts = countPropertyStatementsByPredicateUri(propertyStatements); + Map statementCounts = countPropertyStatementsByPredicateUri( + propertyStatements); for (PropertyMethod pm : propertyMethods.values()) { Integer c = statementCounts.get(pm.getPropertyUri()); int count = (c == null) ? 0 : c; @@ -109,12 +110,11 @@ public class WrappedInstance { */ public void setProperties(ConfigurationBeanLoader loader, Collection propertyStatements) - throws PropertyTypeException, NoSuchPropertyMethodException, - ConfigurationBeanLoaderException { + throws PropertyTypeException, ConfigurationBeanLoaderException { for (PropertyStatement ps : propertyStatements) { PropertyMethod pm = propertyMethods.get(ps.getPredicateUri()); if (pm == null) { - throw new NoSuchPropertyMethodException(ps); + continue; // No method for this property? Ignore it. } pm.confirmCompatible(ps); @@ -141,7 +141,8 @@ public class WrappedInstance { } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { throw new ValidationFailedException( - "Error executing validation method '" + method + "'", e); + "Error executing validation method '" + method + "'", + e); } } } @@ -165,12 +166,6 @@ public class WrappedInstance { } } - public static class NoSuchPropertyMethodException extends Exception { - public NoSuchPropertyMethodException(PropertyStatement ps) { - super("No property method for '" + ps.getPredicateUri() + "'"); - } - } - public static class CardinalityException extends Exception { public CardinalityException(String message) { super(message); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/Tags.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/Tags.java index a51e0c541..d89ed61ef 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/Tags.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/Tags.java @@ -2,82 +2,270 @@ package edu.cornell.mannlib.vitro.webapp.web.templatemodels; +import java.io.File; +import java.lang.reflect.Method; import java.util.LinkedHashSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.servlet.ServletContext; -import freemarker.ext.beans.MethodAppearanceFineTuner; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; import freemarker.ext.beans.BeansWrapper; +import freemarker.template.Configuration; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; +/** + * Provides a mechanism for Freemarker templates (main or included, parent or + * child) to add to the lists of scripts and style sheets for the current page. + * + * Each page uses 3 instances of Tags, exposed as ${scripts}, ${headScripts} and + * ${stylesheets}. A template may add a complete <script/$gt; element (for + * scripts or headScripts) or a <link> tag (for stylesheets), and these + * elements will appear at the proper location in the rendered HTML for the + * page. + * + * VIVO-1405: This process is augmented by the TagVersionInfo inner class, which + * attempts to add a "version=" query string to the URL in the supplied element. + * The version number is derived from the last-modified date of the specified + * script or stylesheet on the server. The effect is that a user's browser cache + * is effectively invalidated each time a new version of the script or + * stylesheet is deployed. + */ public class Tags extends BaseTemplateModel { - - private static final Log log = LogFactory.getLog(Tags.class); - - protected final LinkedHashSet tags; + private static final Log log = LogFactory.getLog(Tags.class); - public Tags() { - this.tags = new LinkedHashSet(); - } - - public Tags(LinkedHashSet tags) { - this.tags = tags; - } - - public TemplateModel wrap() { - try { - return new TagsWrapper().wrap(this); - } catch (TemplateModelException e) { - log.error("Error creating Tags template model"); - return null; - } - } - - /** Script and stylesheet lists are wrapped with a specialized BeansWrapper - * that exposes certain write methods, instead of the configuration's object wrapper, - * which doesn't. The templates can then add stylesheets and scripts to the lists - * by calling their add() methods. - */ - static public class TagsWrapper extends BeansWrapper { - - public TagsWrapper() { - // Start by exposing all safe methods. - setExposureLevel(EXPOSE_SAFE); - setMethodAppearanceFineTuner(new MethodAppearanceFineTuner() { - @Override - public void process(MethodAppearanceDecisionInput methodAppearanceDecisionInput, MethodAppearanceDecision methodAppearanceDecision) { - try { - String methodName = methodAppearanceDecisionInput.getMethod().getName(); - if ( ! ( methodName.equals("add") || methodName.equals("list")) ) { - methodAppearanceDecision.setExposeMethodAs(null); - } - } catch (Exception e) { - log.error(e, e); - } - } - }); - } - } - - - /* Template methods */ + protected final LinkedHashSet tags; - public void add(String... tags) { - for (String tag : tags) { - add(tag); - } - } - - public void add(String tag) { - tags.add(tag); - } - - public String list() { - return StringUtils.join(tags, "\n"); - } - + public Tags() { + this.tags = new LinkedHashSet(); + } + public Tags(LinkedHashSet tags) { + this.tags = tags; + } + + public TemplateModel wrap() { + try { + return new TagsWrapper().wrap(this); + } catch (TemplateModelException e) { + log.error("Error creating Tags template model"); + return null; + } + } + + /** + * Script and stylesheet lists are wrapped with a specialized BeansWrapper + * that exposes certain write methods, instead of the configuration's object + * wrapper, which doesn't. The templates can then add stylesheets and + * scripts to the lists by calling their add() methods. + * + * @param Tags + * tags + * @return TemplateModel + */ + static public class TagsWrapper extends BeansWrapper { + + public TagsWrapper() { + super(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); + + // Start by exposing all safe methods. + setExposureLevel(EXPOSE_SAFE); + } + + @SuppressWarnings("rawtypes") + @Override + protected void finetuneMethodAppearance(Class cls, Method method, + MethodAppearanceDecision decision) { + + try { + String methodName = method.getName(); + if (!(methodName.equals("add") || methodName.equals("list"))) { + decision.setExposeMethodAs(null); + } + } catch (Exception e) { + log.error(e, e); + } + } + } + + /* Template methods */ + + @SuppressWarnings("hiding") + public void add(String... tags) { + for (String tag : tags) { + add(tag); + } + } + + public void add(String tag) { + TagVersionInfo info = new TagVersionInfo(tag); + if (info.hasVersion()) { + tags.add(TagVersionInfo.addVersionNumber(tag, info)); + } else { + tags.add(tag); + } + } + + public String list() { + return StringUtils.join(tags, "\n"); + } + + /** + * Find the value of "href" or "src". + * + * If there is such a value, and it doesn't have a query string already, and + * it represents a local URL, and we can locate the file that is served by + * the URL and get the last modified date, then we have found a "version + * number" that we can add to the attribute value. + * + * Reference for parsing attributes: + * https://www.w3.org/TR/html/syntax.html#elements-attributes + */ + protected static class TagVersionInfo { + private static final Pattern PATTERN_DOUBLE_QUOTES = Pattern + .compile("(href|src)\\s*=\\s*\"([^\"]+)\"[\\s|>]"); + private static final int GROUP_INDEX_DOUBLE_QUOTES = 2; + + private static final Pattern PATTERN_SINGLE_QUOTES = Pattern + .compile("(href|src)\\s*=\\s*'([^']+)'[\\s|>]"); + private static final int GROUP_INDEX_SINGLE_QUOTES = 2; + + private static final Pattern PATTERN_NO_QUOTES = Pattern + .compile("(href|src)\\s*=\\s*([^\"'<=>\\s]+)[\\s|>]"); + private static final int GROUP_INDEX_NO_QUOTES = 2; + + public static String addVersionNumber(String rawTag, + TagVersionInfo info) { + String versionString = (info.match.style == MatchResult.Style.NO_QUOTES) + ? "?version&eq;" + : "?version="; + return rawTag.substring(0, info.match.start) + info.match.group + + versionString + smushTimeStamp(info) + + rawTag.substring(info.match.end); + } + + private static String smushTimeStamp(TagVersionInfo info) { + int smushed = (((char) (info.timestamp >> 48)) + ^ ((char) (info.timestamp >> 32)) + ^ ((char) (info.timestamp >> 16)) + ^ ((char) info.timestamp)); + return String.format("%04x", smushed); + } + + private MatchResult match; + private long timestamp = 0L; + + public TagVersionInfo(String rawTag) { + try { + match = findUrlValue(rawTag); + + if (match != null && !hasQueryString(match.group)) { + String stripped = stripContextPath(match.group); + + if (stripped != null) { + String realPath = locateRealPath(stripped); + + if (realPath != null) { + timestamp = getLastModified(realPath); + } + } + } + } catch (Exception e) { + log.debug("Failed to add version info to tag: " + rawTag, e); + timestamp = 0L; + } + } + + public boolean hasVersion() { + return timestamp != 0L; + } + + private static MatchResult findUrlValue(String rawTag) { + Matcher mDouble = PATTERN_DOUBLE_QUOTES.matcher(rawTag); + if (mDouble.find()) { + return new MatchResult(mDouble, GROUP_INDEX_DOUBLE_QUOTES, + MatchResult.Style.DOUBLE_QUOTES); + } + + Matcher mSingle = PATTERN_SINGLE_QUOTES.matcher(rawTag); + if (mSingle.find()) { + return new MatchResult(mSingle, GROUP_INDEX_SINGLE_QUOTES, + MatchResult.Style.SINGLE_QUOTES); + } + + Matcher mNo = PATTERN_NO_QUOTES.matcher(rawTag); + if (mNo.find()) { + return new MatchResult(mNo, GROUP_INDEX_NO_QUOTES, + MatchResult.Style.NO_QUOTES); + } + + log.debug(rawTag + " no match"); + return null; + } + + private static boolean hasQueryString(String group) { + if (group.indexOf('?') > -1) { + log.debug(group + " has query string already"); + return true; + } else { + return false; + } + } + + private static String stripContextPath(String group) { + String contextPath = UrlBuilder.getBaseUrl(); + if (contextPath.isEmpty() || group.startsWith(contextPath)) { + return group.substring(contextPath.length()); + } else { + log.debug(group + " doesn't match context path"); + return null; + } + } + + private static String locateRealPath(String stripped) { + ServletContext ctx = ApplicationUtils.instance() + .getServletContext(); + String realPath = ctx.getRealPath(stripped); + if (realPath == null) { + log.debug(stripped + " has no real path"); + } + return realPath; + } + + private static long getLastModified(String realPath) { + return new File(realPath).lastModified(); + } + + protected static class MatchResult { + public enum Style { + SINGLE_QUOTES, DOUBLE_QUOTES, NO_QUOTES + } + + public final String group; + public final int start; + public final int end; + public final Style style; + + public MatchResult(Matcher matcher, int group, Style style) { + this.group = matcher.group(group); + this.start = matcher.start(group); + this.end = matcher.end(group); + this.style = style; + log.debug(this); + } + + @Override + public String toString() { + return "MatchResult[start=" + start + ", end=" + end + + ", group=" + group + ", style=" + style + "]"; + } + } + } } diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoaderTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoaderTest.java index 17e9f2751..a0ebfa672 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoaderTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoaderTest.java @@ -2,12 +2,12 @@ package edu.cornell.mannlib.vitro.webapp.utils.configuration; -import static org.apache.jena.datatypes.xsd.XSDDatatype.XSDfloat; -import static org.apache.jena.datatypes.xsd.XSDDatatype.XSDstring; import static edu.cornell.mannlib.vitro.testing.ModelUtilitiesTestHelper.dataProperty; import static edu.cornell.mannlib.vitro.testing.ModelUtilitiesTestHelper.objectProperty; import static edu.cornell.mannlib.vitro.testing.ModelUtilitiesTestHelper.typeStatement; import static edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationBeanLoader.toJavaUri; +import static org.apache.jena.datatypes.xsd.XSDDatatype.XSDfloat; +import static org.apache.jena.datatypes.xsd.XSDDatatype.XSDstring; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -19,18 +19,16 @@ import java.util.Collections; import java.util.HashSet; import java.util.Set; -import org.junit.Ignore; -import org.junit.Test; - import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.Statement; +import org.junit.Ignore; +import org.junit.Test; import edu.cornell.mannlib.vitro.webapp.modelaccess.ContextModelAccess; import edu.cornell.mannlib.vitro.webapp.modelaccess.RequestModelAccess; import edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationRdfParser.InvalidConfigurationRdfException; import edu.cornell.mannlib.vitro.webapp.utils.configuration.InstanceWrapper.InstanceWrapperException; import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.PropertyTypeException; -import edu.cornell.mannlib.vitro.webapp.utils.configuration.WrappedInstance.NoSuchPropertyMethodException; import edu.cornell.mannlib.vitro.webapp.utils.configuration.WrappedInstance.ResourceUnavailableException; /** @@ -309,24 +307,6 @@ public class ConfigurationBeanLoaderTest extends // -------------------------------------------- - @Test - public void tripleHasUnrecognizedProperty_throwsException() - throws ConfigurationBeanLoaderException { - model.add(typeStatement(GENERIC_INSTANCE_URI, - toJavaUri(SimpleSuccess.class))); - model.add(dataProperty(GENERIC_INSTANCE_URI, - "http://bogus.property/name", "No place to put it.")); - - expectSimpleFailure( - SimpleSuccess.class, - throwable(ConfigurationBeanLoaderException.class, - "Failed to load"), - throwable(NoSuchPropertyMethodException.class, - "No property method")); - } - - // -------------------------------------------- - @Test public void valueTypeDoesNotMatchArgumentOfPropertyMethod_throwsException() throws ConfigurationBeanLoaderException { @@ -395,10 +375,26 @@ public class ConfigurationBeanLoaderTest extends assertNotNull(instance); } + /** + * Ignores unexpected properties + */ + @Test + public void simpleSuccessIgnoringExtraProperties() throws ConfigurationBeanLoaderException { + model.add(typeStatement(SIMPLE_SUCCESS_INSTANCE_URI, + toJavaUri(SimpleSuccess.class))); + model.add(dataProperty(SIMPLE_SUCCESS_INSTANCE_URI, + "http://surprise.property/name", "No matching method.")); + + SimpleSuccess instance = loader.loadInstance( + SIMPLE_SUCCESS_INSTANCE_URI, SimpleSuccess.class); + + assertNotNull(instance); + } + public static class SimpleSuccess { // Nothing of interest. } - + // -------------------------------------------- /** diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_NamespacesTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_NamespacesTest.java new file mode 100644 index 000000000..61e2b5916 --- /dev/null +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_NamespacesTest.java @@ -0,0 +1,111 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.utils.configuration; + +import static edu.cornell.mannlib.vitro.testing.ModelUtilitiesTestHelper.typeStatement; +import static edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationBeanLoader.toPossibleJavaUris; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +import java.util.HashSet; +import java.util.Random; +import java.util.Set; + +import org.junit.Test; + +/** + * Assure that we can use "namespaces" for Java URIs. The namespace must end + * with a '#'. + */ +public class ConfigurationBeanLoader_NamespacesTest + extends ConfigurationBeanLoaderTestBase { + + // ---------------------------------------------------------------------- + // toPossibleJavaUris() + // ---------------------------------------------------------------------- + + @Test + public void possibleForJavaLangString() { + Set expected = new HashSet<>(); + expected.add("java:java.lang.String"); + expected.add("java:java#lang.String"); + expected.add("java:java.lang#String"); + assertEquals(expected, toPossibleJavaUris(String.class)); + } + + // ---------------------------------------------------------------------- + // loadAll() + // ---------------------------------------------------------------------- + + @Test + public void loadAllForJavaUtilRandom() + throws ConfigurationBeanLoaderException { + model.add(typeStatement("http://noPound", "java:java.util.Random")); + model.add(typeStatement("http://firstPound", "java:java#util.Random")); + model.add(typeStatement("http://secondPound", "java:java.util#Random")); + model.add(typeStatement("http://notARandom", "java:java.util.Set")); + Set instances = loader.loadAll(Random.class); + assertEquals(3, instances.size()); + } + + @Test + public void loadAlForCustomInnerClass() + throws ConfigurationBeanLoaderException { + Set typeUris = toPossibleJavaUris(ExampleClassForLoadAll.class); + for (String typeUri : typeUris) { + model.add(typeStatement("http://testUri" + model.size(), typeUri)); + } + Set instances = loader + .loadAll(ExampleClassForLoadAll.class); + assertEquals(typeUris.size(), instances.size()); + } + + public static class ExampleClassForLoadAll { + // Nothing of interest + } + + // ---------------------------------------------------------------------- + // loadInstance() + // ---------------------------------------------------------------------- + + @Test + public void loadInstanceVariationsForJavaUtilRandom() + throws ConfigurationBeanLoaderException { + model.add(typeStatement("http://noPound", "java:java.util.Random")); + model.add(typeStatement("http://firstPound", "java:java#util.Random")); + model.add(typeStatement("http://secondPound", "java:java.util#Random")); + model.add(typeStatement("http://notARandom", "java:java.util.Set")); + + assertNotNull(loader.loadInstance("http://noPound", Random.class)); + assertNotNull(loader.loadInstance("http://firstPound", Random.class)); + assertNotNull(loader.loadInstance("http://secondPound", Random.class)); + + try { + loader.loadInstance("http://notARandom", Random.class); + fail("Should not be a Random"); + } catch (Exception e) { + // Expected it + } + } + + @Test + public void loadInstanceVariationsForCustomInnerClass() + throws ConfigurationBeanLoaderException { + Set typeUris = toPossibleJavaUris( + ExampleClassForLoadInstance.class); + for (String typeUri : typeUris) { + model.add(typeStatement("http://testUri" + model.size(), typeUri)); + } + for (int i = 0; i < model.size(); i++) { + String instanceUri = "http://testUri" + i; + assertNotNull("No instance for " + instanceUri, loader.loadInstance( + instanceUri, ExampleClassForLoadInstance.class)); + } + } + + public static class ExampleClassForLoadInstance { + // Nothing of interest + } + +} diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_ValidationTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_ValidationTest.java index 59a57a0b0..60e66a5d2 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_ValidationTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_ValidationTest.java @@ -15,8 +15,8 @@ import edu.cornell.mannlib.vitro.webapp.utils.configuration.WrappedInstance.Vali /** * Test the @Validation annotation. */ -public class ConfigurationBeanLoader_ValidationTest extends - ConfigurationBeanLoaderTestBase { +public class ConfigurationBeanLoader_ValidationTest + extends ConfigurationBeanLoaderTestBase { // -------------------------------------------- @Test @@ -25,8 +25,7 @@ public class ConfigurationBeanLoader_ValidationTest extends model.add(typeStatement(GENERIC_INSTANCE_URI, toJavaUri(ValidationMethodWithParameter.class))); - expectSimpleFailure( - ValidationMethodWithParameter.class, + expectSimpleFailure(ValidationMethodWithParameter.class, throwable(ConfigurationBeanLoaderException.class, "Failed to load"), throwable(InstanceWrapperException.class, @@ -49,11 +48,11 @@ public class ConfigurationBeanLoader_ValidationTest extends model.add(typeStatement(GENERIC_INSTANCE_URI, toJavaUri(ValidationMethodShouldReturnVoid.class))); - expectSimpleFailure( - ValidationMethodShouldReturnVoid.class, + expectSimpleFailure(ValidationMethodShouldReturnVoid.class, throwable(ConfigurationBeanLoaderException.class, "Failed to load"), - throwable(InstanceWrapperException.class, "should return void")); + throwable(InstanceWrapperException.class, + "should return void")); } public static class ValidationMethodShouldReturnVoid { @@ -71,8 +70,7 @@ public class ConfigurationBeanLoader_ValidationTest extends model.add(typeStatement(GENERIC_INSTANCE_URI, toJavaUri(ValidationMethodIsPrivate.class))); - expectSimpleFailure( - ValidationMethodIsPrivate.class, + expectSimpleFailure(ValidationMethodIsPrivate.class, throwable(ConfigurationBeanLoaderException.class, "Failed to load"), throwable(ValidationFailedException.class, @@ -94,8 +92,7 @@ public class ConfigurationBeanLoader_ValidationTest extends model.add(typeStatement(GENERIC_INSTANCE_URI, toJavaUri(ValidationThrowsException.class))); - expectSimpleFailure( - ValidationThrowsException.class, + expectSimpleFailure(ValidationThrowsException.class, throwable(ConfigurationBeanLoaderException.class, "Failed to load"), throwable(ValidationFailedException.class, @@ -144,8 +141,7 @@ public class ConfigurationBeanLoader_ValidationTest extends model.add(typeStatement(GENERIC_INSTANCE_URI, toJavaUri(ValidationOverValidationSubclass.class))); - expectSimpleFailure( - ValidationOverValidationSubclass.class, + expectSimpleFailure(ValidationOverValidationSubclass.class, throwable(ConfigurationBeanLoaderException.class, "Failed to load"), throwable(InstanceWrapperException.class, @@ -158,8 +154,7 @@ public class ConfigurationBeanLoader_ValidationTest extends model.add(typeStatement(GENERIC_INSTANCE_URI, toJavaUri(PlainOverValidationSubclass.class))); - expectSimpleFailure( - PlainOverValidationSubclass.class, + expectSimpleFailure(PlainOverValidationSubclass.class, throwable(ConfigurationBeanLoaderException.class, "Failed to load"), throwable(InstanceWrapperException.class, @@ -182,8 +177,8 @@ public class ConfigurationBeanLoader_ValidationTest extends // Just want to see that the superclass validation is run. } - public static class AdditionalValidationSubclass extends - ValidationSuperclass { + public static class AdditionalValidationSubclass + extends ValidationSuperclass { public boolean validatorSubHasRun = false; @Validation @@ -195,8 +190,8 @@ public class ConfigurationBeanLoader_ValidationTest extends } } - public static class ValidationOverValidationSubclass extends - EmptyValidationSubclass { + public static class ValidationOverValidationSubclass + extends EmptyValidationSubclass { @Override @Validation public void validatorSuper() { @@ -204,8 +199,8 @@ public class ConfigurationBeanLoader_ValidationTest extends } } - public static class PlainOverValidationSubclass extends - ValidationSuperclass { + public static class PlainOverValidationSubclass + extends ValidationSuperclass { @Override public void validatorSuper() { // Should fail diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/TagsTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/TagsTest.java new file mode 100644 index 000000000..11fadb585 --- /dev/null +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/TagsTest.java @@ -0,0 +1,248 @@ +package edu.cornell.mannlib.vitro.webapp.web.templatemodels; + +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import java.lang.reflect.Field; + +import org.apache.log4j.Level; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import edu.cornell.mannlib.vitro.testing.AbstractTestClass; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; +import edu.cornell.mannlib.vitro.webapp.web.templatemodels.Tags.TagVersionInfo; +import edu.cornell.mannlib.vitro.webapp.web.templatemodels.Tags.TagVersionInfo.MatchResult; +import stubs.edu.cornell.mannlib.vitro.webapp.modules.ApplicationStub; +import stubs.javax.servlet.ServletContextStub; + +public class TagsTest extends AbstractTestClass { + private ServletContextStub ctx; + private File resource; + + @Before + public void setup() throws IOException { + resource = File.createTempFile("resource", ""); + + ctx = new ServletContextStub(); + ctx.setRealPath("/base/sub/file.js", resource.getPath()); + ctx.setRealPath("/base/sub/file.css", resource.getPath()); + + ApplicationStub.setup(ctx, null); + + setContextPath("/context"); + } + + // ---------------------------------------------------------------------- + // Parsing tests + // + // Reference for parsing attributes: + // https://www.w3.org/TR/html/syntax.html#elements-attributes + // ---------------------------------------------------------------------- + + @Test + public void noAttribute_failure() { + assertNoMatch("
"); + } + + @Test + public void singleQuote_noTerminator_failure() { + assertNoMatch(""); + } + + @Test + public void doubleQuotes_embeddedDoubleQuote_failure() { + assertNoMatch(""); + } + + @Test + public void doubleQuotes_embeddedSingleQuote_success() { + assertMatch("", + "value'noproblem"); + } + + @Test + public void unquotedBadTerminator_failure() { + assertNoMatch("", "value"); + } + + @Test + public void noSpacesAroundEquals_success() { + assertMatch("", "value"); + } + + // ---------------------------------------------------------------------- + // Substitution tests + // ---------------------------------------------------------------------- + + @Test + public void noMatch_noChange() { + assertVersionNotAdded( + "", + "no match"); + } + + @Test + public void alreadyHasQueryString_noChange() { + assertVersionNotAdded( + "", + "has query"); + } + + @Test + public void doesntStartWithContextPath_noChange() { + assertVersionNotAdded( + "", + "context path"); + } + + @Test + public void noRealPath_noChange() { + assertVersionNotAdded( + "", + "real path"); + } + + @Test + @Ignore + public void exception_noChange() { + fail("exception_noChange not implemented"); + } + + @Test + public void doubleQuotes_substitution() { + assertVersionAdded( // + "", // + ""); + } + + @Test + public void singleQuotes_substitution() { + assertVersionAdded( // + "", // + ""); + } + + @Test + public void unquoted_substitution() { + assertVersionAdded( // + "", // + ""); + } + + // ---------------------------------------------------------------------- + // Helper methods + // ---------------------------------------------------------------------- + + private void setContextPath(String contextPath) { + try { + Field f = UrlBuilder.class.getDeclaredField("contextPath"); + f.setAccessible(true); + f.set(null, contextPath); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private void assertMatch(String tag, String expected) { + TagVersionInfo info = new TagVersionInfo(tag); + + try { + Field f = TagVersionInfo.class.getDeclaredField("match"); + f.setAccessible(true); + MatchResult match = (MatchResult) f.get(info); + + assertEquals(expected, match.group); + } catch (Exception e) { + throw new RuntimeException(e); + } + + } + + private void assertNoMatch(String tag) { + TagVersionInfo info = new TagVersionInfo(tag); + assertFalse(info.hasVersion()); + } + + private void assertVersionAdded(String rawTag, String expected) { + String actual = createTag(rawTag); + String canonicalActual = actual.replaceAll("=[0-9a-f]{4}", "=9999") + .replaceAll("&eq;[0-9a-f]{4}", "&eq;9999"); + assertEquals(expected, canonicalActual); + } + + private void assertVersionNotAdded(String rawTag, String debugMessage) { + StringWriter writer = new StringWriter(); + captureLogOutput(Tags.class, writer, true); + setLoggerLevel(Tags.class, Level.DEBUG); + + String actual = createTag(rawTag); + assertEquals(rawTag, actual); + assertThat(writer.toString(), containsString(debugMessage)); + } + + private String createTag(String rawTag) { + Tags t = new Tags(); + t.add(rawTag); + return t.list(); + } + +} \ No newline at end of file diff --git a/home/src/main/resources/config/example.applicationSetup.n3 b/home/src/main/resources/config/example.applicationSetup.n3 index eeb8678a9..6ead57a93 100644 --- a/home/src/main/resources/config/example.applicationSetup.n3 +++ b/home/src/main/resources/config/example.applicationSetup.n3 @@ -11,6 +11,7 @@ # ------------------------------------------------------------------------------ @prefix : . +@prefix vitroWebapp: . # ---------------------------- # @@ -19,8 +20,8 @@ # :application - a , - ; + a vitroWebapp:application.ApplicationImpl , + vitroWebapp:modules.Application ; :hasSearchEngine :instrumentedSearchEngineWrapper ; :hasSearchIndexer :basicSearchIndexer ; :hasImageProcessor :iioImageProcessor ; @@ -35,8 +36,8 @@ # :iioImageProcessor - a , - . + a vitroWebapp:imageprocessor.imageio.IIOImageProcessor , + vitroWebapp:modules.imageProcessor.ImageProcessor . # ---------------------------- # @@ -46,8 +47,8 @@ # :ptiFileStorage - a , - . + a vitroWebapp:filestorage.impl.FileStorageImplWrapper , + vitroWebapp:modules.fileStorage.FileStorage . # ---------------------------- # @@ -58,13 +59,13 @@ # :instrumentedSearchEngineWrapper - a , - ; + a vitroWebapp:searchengine.InstrumentedSearchEngineWrapper , + vitroWebapp:modules.searchEngine.SearchEngine ; :wraps :solrSearchEngine . :solrSearchEngine - a , - . + a vitroWebapp:searchengine.solr.SolrSearchEngine , + vitroWebapp:modules.searchEngine.SearchEngine . # ---------------------------- # @@ -74,8 +75,8 @@ # :basicSearchIndexer - a , - ; + a vitroWebapp:searchindex.SearchIndexerImpl , + vitroWebapp:modules.searchIndexer.SearchIndexer ; :threadPoolSize "10" . # ---------------------------- @@ -89,26 +90,26 @@ # :sdbContentTripleSource - a , - . + a vitroWebapp:triplesource.impl.sdb.ContentTripleSourceSDB , + vitroWebapp:modules.tripleSource.ContentTripleSource . #:tdbContentTripleSource -# a , -# ; +# a vitroWebapp:triplesource.impl.tdb.ContentTripleSourceTDB , +# vitroWebapp:modules.tripleSource.ContentTripleSource ; # # May be an absolute path, or relative to the Vitro home directory. # :hasTdbDirectory "tdbContentModels" . #:sparqlContentTripleSource -# a , -# ; +# a vitroWebapp:triplesource.impl.virtuoso.ContentTripleSourceSPARQL , +# vitroWebapp:modules.tripleSource.ContentTripleSource ; # # The URI of the SPARQL endpoint for your triple-store. # :hasEndpointURI "PUT_YOUR_SPARQL_ENDPOINT_URI_HERE" ; # # The URI to use for SPARQL UPDATE calls against your triple-store. # :hasUpdateEndpointURI "PUT_THE UPDATE_URI_HERE" . #:virtuosoContentTripleSource -# a , -# ; +# a vitroWebapp:triplesource.impl.virtuoso.ContentTripleSourceVirtuoso , +# vitroWebapp:modules.tripleSource.ContentTripleSource ; # # The URI of Virtuoso's SPARQL endpoint. # :hasEndpointURI "PUT_YOUR_VIRTUOSO_URI_HERE" ; # # The URI to use for SPARQL UPDATE calls against Virtuoso. @@ -123,8 +124,8 @@ # :tdbConfigurationTripleSource - a , - . + a vitroWebapp:triplesource.impl.tdb.ConfigurationTripleSourceTDB , + vitroWebapp:modules.tripleSource.ConfigurationTripleSource . # ---------------------------- # @@ -134,5 +135,5 @@ # :jfactTBoxReasonerModule - a , - . + a vitroWebapp:tboxreasoner.impl.jfact.JFactTBoxReasonerModule , + vitroWebapp:modules.tboxreasoner.TBoxReasonerModule . diff --git a/home/src/main/resources/rdf/display/everytime/searchIndexerConfigurationVitro.n3 b/home/src/main/resources/rdf/display/everytime/searchIndexerConfigurationVitro.n3 index 528157150..4c5a384c8 100644 --- a/home/src/main/resources/rdf/display/everytime/searchIndexerConfigurationVitro.n3 +++ b/home/src/main/resources/rdf/display/everytime/searchIndexerConfigurationVitro.n3 @@ -1,6 +1,8 @@ @prefix : . @prefix rdfs: . @prefix xsd: . +@prefix searchIndex: . + # # configure the SearchIndexer @@ -8,8 +10,8 @@ # Individuals with these types will be excluded from the search index :searchExcluder_typeExcluder - a , - ; + a searchIndex:exclusions.ExcludeBasedOnType , + searchIndex:exclusions.SearchIndexExcluder ; :excludes "http://www.w3.org/2002/07/owl#AnnotationProperty" , "http://www.w3.org/2002/07/owl#DatatypeProperty" , @@ -17,8 +19,8 @@ # Individuals with types from these namespaces will be excluded from the search index. :searchExcluder_namespaceExcluder - a , - ; + a searchIndex:exclusions.ExcludeBasedOnNamespace , + searchIndex:exclusions.SearchIndexExcluder ; :excludes "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#" , "http://vitro.mannlib.cornell.edu/ns/vitro/public#" , @@ -27,38 +29,38 @@ # Individuals with URIs in these namespaces will be excluded from the search index. :searchExcluder_typeNamespaceExcluder - a , - ; + a searchIndex:exclusions.ExcludeBasedOnTypeNamespace , + searchIndex:exclusions.SearchIndexExcluder ; :excludes "http://vitro.mannlib.cornell.edu/ns/vitro/role#public" . :searchExcluder_syncingTypeExcluder - a , - . + a searchIndex:exclusions.SyncingExcludeBasedOnType , + searchIndex:exclusions.SearchIndexExcluder . # ------------------------------------ :uriFinder_forDataProperties - a , - . + a searchIndex:indexing.IndexingUriFinder , + searchIndex:indexing.AdditionalURIsForDataProperties . :uriFinder_forObjectProperties - a , - . + a searchIndex:indexing.IndexingUriFinder , + searchIndex:indexing.AdditionalURIsForObjectProperties . :uriFinder_forTypeStatements - a , - . + a searchIndex:indexing.IndexingUriFinder , + searchIndex:indexing.AdditionalURIsForTypeStatements . :uriFinder_forClassGroupChange - a , - . + a searchIndex:indexing.IndexingUriFinder , + searchIndex:indexing.URIsForClassGroupChange . # ------------------------------------ :documentModifier_AllNames - a , - ; + a searchIndex:documentBuilding.SelectQueryDocumentModifier , + searchIndex:documentBuilding.DocumentModifier ; rdfs:label "All labels are added to name fields." ; :hasTargetField "nameRaw" ; :hasSelectQuery """ @@ -70,8 +72,8 @@ """ . :documentModifier_NameFieldBooster - a , - ; + a searchIndex:documentBuilding.FieldBooster , + searchIndex:documentBuilding.DocumentModifier ; :hasTargetField "nameRaw" ; :hasTargetField "nameLowercase" ; :hasTargetField "nameUnstemmed" ; @@ -79,5 +81,5 @@ :hasBoost "1.2"^^xsd:float . :documentModifier_thumbnailImageUrl - a , - . + a searchIndex:documentBuilding.ThumbnailImageURL , + searchIndex:documentBuilding.DocumentModifier .