From 481a2152065e24697446fae6cf9c0e9fe6d59fe4 Mon Sep 17 00:00:00 2001 From: Jim Blake Date: Sun, 29 May 2016 10:25:23 -0400 Subject: [PATCH 1/4] VIVO-1246 improve the ConfigurationBeanLoader: Add cardinality parameters minOccurs and maxOccurs Create README.md document in the edu.cornell.mannlib.vitro.webapp.utils.configuration package Split large class of unit tests into separate classes by functionality --- .../ConfigurationBeanLoader.java | 1 + .../utils/configuration/InstanceWrapper.java | 181 ++++++--- .../webapp/utils/configuration/Property.java | 2 + .../utils/configuration/PropertyType.java | 90 +++-- .../webapp/utils/configuration/README.md | 174 +++++++++ .../utils/configuration/WrappedInstance.java | 47 ++- .../testing/ModelUtilitiesTestHelper.java | 6 + .../ConfigurationBeanLoaderTest.java | 364 +----------------- .../ConfigurationBeanLoaderTestBase.java | 102 +++++ ...figurationBeanLoader_Cardinality_Test.java | 252 ++++++++++++ .../ConfigurationBeanLoader_PropertyTest.java | 339 ++++++++++++++++ ...onfigurationBeanLoader_ValidationTest.java | 215 +++++++++++ 12 files changed, 1332 insertions(+), 441 deletions(-) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/README.md create mode 100644 webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoaderTestBase.java create mode 100644 webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_Cardinality_Test.java create mode 100644 webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_PropertyTest.java create mode 100644 webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_ValidationTest.java diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader.java index fa7249297..36d399224 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader.java @@ -116,6 +116,7 @@ public class ConfigurationBeanLoader { WrappedInstance wrapper = InstanceWrapper.wrap(parsedRdf .getConcreteClass()); wrapper.satisfyInterfaces(ctx, req); + wrapper.checkCardinality(parsedRdf.getPropertyStatements()); wrapper.setProperties(this, parsedRdf.getPropertyStatements()); wrapper.validate(); return wrapper.getInstance(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/InstanceWrapper.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/InstanceWrapper.java index c882ccfd5..45db851ad 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/InstanceWrapper.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/InstanceWrapper.java @@ -6,7 +6,9 @@ import java.lang.reflect.Method; import java.util.HashMap; import java.util.HashSet; import java.util.Map; -import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.PropertyMethod; import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.PropertyTypeException; @@ -16,11 +18,17 @@ import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.Propert * instance of the class. */ public class InstanceWrapper { + private static final Log log = LogFactory.getLog(InstanceWrapper.class); + public static WrappedInstance wrap(Class concreteClass) throws InstanceWrapperException { - return new WrappedInstance(createInstance(concreteClass), - parsePropertyAnnotations(concreteClass), - parseValidationAnnotations(concreteClass)); + T instance = createInstance(concreteClass); + HashSet validationMethods = new HashSet<>( + parseValidationAnnotations(concreteClass).values()); + Map propertyMethods = new PropertyAnnotationsMap( + concreteClass).byUri(); + return new WrappedInstance(instance, propertyMethods, + validationMethods); } private static T createInstance(Class concreteClass) @@ -33,58 +41,131 @@ public class InstanceWrapper { } } - private static Map parsePropertyAnnotations( - Class concreteClass) throws InstanceWrapperException { - Map map = new HashMap<>(); - for (Method method : concreteClass.getDeclaredMethods()) { - Property annotation = method.getAnnotation(Property.class); - if (annotation == null) { - continue; - } - if (!method.getReturnType().equals(Void.TYPE)) { - throw new InstanceWrapperException("Property method '" + method - + "' should return void."); - } - Class[] parameterTypes = method.getParameterTypes(); - if (parameterTypes.length != 1) { - throw new InstanceWrapperException("Property method '" + method - + "' must accept exactly one parameter."); - } - - String uri = annotation.uri(); - if (map.containsKey(uri)) { - throw new InstanceWrapperException( - "Two property methods have the same URI value: " - + map.get(uri).getMethod() + ", and " + method); - } - try { - map.put(uri, PropertyType.createPropertyMethod(method)); - } catch (PropertyTypeException e) { - throw new InstanceWrapperException( - "Failed to create the PropertyMethod", e); + private static Map parseValidationAnnotations(Class clazz) + throws InstanceWrapperException { + if (Object.class.equals(clazz)) { + return new HashMap<>(); + } else { + Map methods = parseValidationAnnotations(clazz + .getSuperclass()); + for (Method method : clazz.getDeclaredMethods()) { + String name = method.getName(); + if (methods.containsKey(name)) { + Method m = methods.get(name); + throw new InstanceWrapperException("Method " + name + + " in " + method.getDeclaringClass().getName() + + " overrides a validation method in " + + m.getDeclaringClass().getName()); + } + if (method.getAnnotation(Validation.class) == null) { + continue; + } + if (method.getParameterTypes().length > 0) { + throw new InstanceWrapperException("Validation method '" + + method + "' should not have parameters."); + } + if (!method.getReturnType().equals(Void.TYPE)) { + throw new InstanceWrapperException("Validation method '" + + method + "' should return void."); + } + methods.put(name, method); } + return methods; } - return map; } - private static Set parseValidationAnnotations(Class concreteClass) - throws InstanceWrapperException { - Set methods = new HashSet<>(); - for (Method method : concreteClass.getDeclaredMethods()) { - if (method.getAnnotation(Validation.class) == null) { - continue; + private static class PropertyAnnotationsMap { + private Map mapByUri = new HashMap<>(); + private Map mapByName = new HashMap<>(); + + public PropertyAnnotationsMap(Class clazz) + throws InstanceWrapperException { + if (!Object.class.equals(clazz)) { + populateTheMaps(clazz); } - if (method.getParameterTypes().length > 0) { - throw new InstanceWrapperException("Validation method '" - + method + "' should not have parameters."); - } - if (!method.getReturnType().equals(Void.TYPE)) { - throw new InstanceWrapperException("Validation method '" - + method + "' should return void."); - } - methods.add(method); } - return methods; + + private void populateTheMaps(Class clazz) + throws InstanceWrapperException { + PropertyAnnotationsMap superMap = new PropertyAnnotationsMap( + clazz.getSuperclass()); + mapByUri = superMap.byUri(); + mapByName = superMap.byName(); + for (Method method : clazz.getDeclaredMethods()) { + String name = method.getName(); + + Method matchByName = methodByName(name); + if (matchByName != null) { + throw new InstanceWrapperException("Method " + name + + " in " + clazz.getName() + + " conflicts with a property method in " + + matchByName.getDeclaringClass().getName()); + } + + Property annotation = method.getAnnotation(Property.class); + if (annotation == null) { + continue; + } + + if (!method.getReturnType().equals(Void.TYPE)) { + throw new InstanceWrapperException("Property method '" + + method + "' should return void."); + } + + if (method.getParameterTypes().length != 1) { + throw new InstanceWrapperException("Property method '" + + method + "' must accept exactly one parameter."); + } + + String uri = annotation.uri(); + Method matchByUri = methodByUri(uri); + if (matchByUri != null) { + throw new InstanceWrapperException( + "Two property methods have the same URI value: " + + matchByUri + ", and " + method); + } + + if (annotation.minOccurs() < 0) { + throw new InstanceWrapperException( + "minOccurs must not be negative."); + } + + if (annotation.maxOccurs() < annotation.minOccurs()) { + throw new InstanceWrapperException( + "maxOccurs must not be less than minOccurs."); + } + + try { + PropertyMethod pm = PropertyType.createPropertyMethod( + method, annotation); + mapByUri.put(uri, pm); + mapByName.put(name, pm); + } catch (PropertyTypeException e) { + throw new InstanceWrapperException( + "Failed to create the PropertyMethod", e); + } + } + + } + + private Method methodByName(String name) { + PropertyMethod pm = mapByName.get(name); + return (pm == null) ? null : pm.getMethod(); + } + + private Method methodByUri(String name) { + PropertyMethod pm = mapByUri.get(name); + return (pm == null) ? null : pm.getMethod(); + } + + public Map byUri() { + return mapByUri; + } + + public Map byName() { + return mapByName; + } + } public static class InstanceWrapperException extends Exception { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/Property.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/Property.java index 0eecb23e8..bcc60bba3 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/Property.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/Property.java @@ -15,4 +15,6 @@ import java.lang.annotation.Target; @Target(ElementType.METHOD) public @interface Property { String uri(); + int minOccurs() default 0; + int maxOccurs() default Integer.MAX_VALUE; } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/PropertyType.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/PropertyType.java index 397008548..9560fd5f8 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/PropertyType.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/PropertyType.java @@ -10,7 +10,6 @@ import java.lang.reflect.Method; import com.hp.hpl.jena.datatypes.RDFDatatype; import com.hp.hpl.jena.rdf.model.Literal; -import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.Statement; @@ -25,38 +24,41 @@ public enum PropertyType { RESOURCE { @Override public PropertyStatement buildPropertyStatement(Statement s) { - return new ResourcePropertyStatement(s.getPredicate(), s + return new ResourcePropertyStatement(s.getPredicate().getURI(), s .getObject().asResource().getURI()); } @Override - protected PropertyMethod buildPropertyMethod(Method method) { - return new ResourcePropertyMethod(method); + protected PropertyMethod buildPropertyMethod(Method method, + Property annotation) { + return new ResourcePropertyMethod(method, annotation); } }, STRING { @Override public PropertyStatement buildPropertyStatement(Statement s) { - return new StringPropertyStatement(s.getPredicate(), s.getObject() - .asLiteral().getString()); + return new StringPropertyStatement(s.getPredicate().getURI(), s + .getObject().asLiteral().getString()); } @Override - protected PropertyMethod buildPropertyMethod(Method method) { - return new StringPropertyMethod(method); + protected PropertyMethod buildPropertyMethod(Method method, + Property annotation) { + return new StringPropertyMethod(method, annotation); } }, FLOAT { @Override public PropertyStatement buildPropertyStatement(Statement s) { - return new FloatPropertyStatement(s.getPredicate(), s.getObject() - .asLiteral().getFloat()); + return new FloatPropertyStatement(s.getPredicate().getURI(), s + .getObject().asLiteral().getFloat()); } @Override - protected PropertyMethod buildPropertyMethod(Method method) { - return new FloatPropertyMethod(method); + protected PropertyMethod buildPropertyMethod(Method method, + Property annotation) { + return new FloatPropertyMethod(method, annotation); } }; @@ -100,24 +102,25 @@ public enum PropertyType { return type.buildPropertyStatement(s); } - public static PropertyMethod createPropertyMethod(Method method) - throws PropertyTypeException { + public static PropertyMethod createPropertyMethod(Method method, + Property annotation) throws PropertyTypeException { Class parameterType = method.getParameterTypes()[0]; PropertyType type = PropertyType.typeForParameterType(parameterType); - return type.buildPropertyMethod(method); + return type.buildPropertyMethod(method, annotation); } protected abstract PropertyStatement buildPropertyStatement(Statement s); - protected abstract PropertyMethod buildPropertyMethod(Method method); + protected abstract PropertyMethod buildPropertyMethod(Method method, + Property annotation); public static abstract class PropertyStatement { private final PropertyType type; private final String predicateUri; - public PropertyStatement(PropertyType type, Property predicate) { + public PropertyStatement(PropertyType type, String predicateUri) { this.type = type; - this.predicateUri = predicate.getURI(); + this.predicateUri = predicateUri; } public PropertyType getType() { @@ -134,8 +137,8 @@ public enum PropertyType { public static class ResourcePropertyStatement extends PropertyStatement { private final String objectUri; - public ResourcePropertyStatement(Property predicate, String objectUri) { - super(RESOURCE, predicate); + public ResourcePropertyStatement(String predicateUri, String objectUri) { + super(RESOURCE, predicateUri); this.objectUri = objectUri; } @@ -148,8 +151,8 @@ public enum PropertyType { public static class StringPropertyStatement extends PropertyStatement { private final String string; - public StringPropertyStatement(Property predicate, String string) { - super(STRING, predicate); + public StringPropertyStatement(String predicateUri, String string) { + super(STRING, predicateUri); this.string = string; } @@ -162,8 +165,8 @@ public enum PropertyType { public static class FloatPropertyStatement extends PropertyStatement { private final float f; - public FloatPropertyStatement(Property predicate, float f) { - super(FLOAT, predicate); + public FloatPropertyStatement(String predicateUri, float f) { + super(FLOAT, predicateUri); this.f = f; } @@ -176,10 +179,23 @@ public enum PropertyType { public static abstract class PropertyMethod { protected final PropertyType type; protected final Method method; + protected final String propertyUri; + protected final int minOccurs; + protected final int maxOccurs; - public PropertyMethod(PropertyType type, Method method) { + // Add cardinality values here! Final, with getters. + public PropertyMethod(PropertyType type, Method method, + Property annotation) { this.type = type; this.method = method; + this.propertyUri = annotation.uri(); + this.minOccurs = annotation.minOccurs(); + this.maxOccurs = annotation.maxOccurs(); + checkCardinalityBounds(); + } + + private void checkCardinalityBounds() { + // This is where we check for negative values or out of order. } public Method getMethod() { @@ -190,6 +206,18 @@ public enum PropertyType { return method.getParameterTypes()[0]; } + public String getPropertyUri() { + return propertyUri; + } + + public int getMinOccurs() { + return minOccurs; + } + + public int getMaxOccurs() { + return maxOccurs; + } + public void confirmCompatible(PropertyStatement ps) throws PropertyTypeException { if (type != ps.getType()) { @@ -212,20 +240,20 @@ public enum PropertyType { } public static class ResourcePropertyMethod extends PropertyMethod { - public ResourcePropertyMethod(Method method) { - super(RESOURCE, method); + public ResourcePropertyMethod(Method method, Property annotation) { + super(RESOURCE, method, annotation); } } public static class StringPropertyMethod extends PropertyMethod { - public StringPropertyMethod(Method method) { - super(STRING, method); + public StringPropertyMethod(Method method, Property annotation) { + super(STRING, method, annotation); } } public static class FloatPropertyMethod extends PropertyMethod { - public FloatPropertyMethod(Method method) { - super(FLOAT, method); + public FloatPropertyMethod(Method method, Property annotation) { + super(FLOAT, method, annotation); } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/README.md b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/README.md new file mode 100644 index 000000000..68da421fa --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/README.md @@ -0,0 +1,174 @@ +# package edu.cornell.mannlib.vitro.webapp.utils.configuration; +## Overview +### Purpose +This package consists of `ConfigurationBeanLoader` and associated classes. +`ConfigurationBeanLoader` will instantiate and populate objects according to a +description encoded in the triples of an RDF Graph, +and annotations within the Java class of the instantiated object. + +The description must include + ++ the URI of exactly one concrete Java class, from which the instance will be created. + +The description may also include + ++ URIs of Java interfaces which the concrete class implements. +The description may be use to satisfy a request +for any of those interfaces, as well as a request for the concrete class. + ++ Data properties. These will be passed to "property methods" in the instance +as part of the creation/initialization. The data value must be an untyped +literal (String) or a numeric literal (Float). + ++ Object properties. The URI is assumed to be that of another loader description. +The loader will attempt to instantiate the described object, and pass it to +the appropriate property method on the original instance. The result may be a +network of instances, nested to an arbitrary level. + +The loader also recognizes two special interfaces: `RequestModelsUser` and `ContextModelsUser`. +If a created instance implements these interfaces, +the loader will provide the appropriate `ModelAccess` object, +allowing the instance to access the Vitro triple-stores. + +### Examples of use + +#### ApplicationSetup + +When Vitro starts up, `ApplicationSetup` uses a `ConfigurationBeanLoader` to instantiate the Vitro's component modules. +The loader creates an RDF Graph from the file `applicationSetup.n3` and instantiates a `SearchEngine` instance, +a `FileStorage` instance, etc. + +Here is some RDF that might be used by `ApplicationSetup`: + + @prefix : . + :application + a , + ; + :hasSearchEngine :instrumentedSearchEngineWrapper ; + :hasFileStorage :ptiFileStorage . + + :ptiFileStorage + a , + . + + :instrumentedSearchEngineWrapper + a , + ; + :wraps :solrSearchEngine . + + :solrSearchEngine + a , + . + +In this case, the `ConfigurationBeanLoader` would be asked to load all instances of +`edu.cornell.mannlib.vitro.webapp.modules.Application`. +The application individual is declared to be both an `Application` and an `ApplicationImpl`. +This is valid because `Application` is an interface, and `ApplicationImpl` implements that interface. +An instance of `ApplicationImpl` will be created. + +The application instance has two child objects: a `SearchEngine` and a `FileStorage`. +These objects will also be created, and calls will be made to the application's "property methods" (see below). + +The `SearchEngine` in turn has a child object, so that also will be created, and provided to the `SearchEngine`. + +#### SearchIndexer + +When Vitro's `SearchIndexer` is initialized, it uses a `ConfigurationBeanLoader` to create +lists of `SearchIndexExcluder`s, `DocumentModifier`s, and `IndexingUriFinder`s. +Descriptions of these are taken from Vitro's display model. + +## Specifications + +### ConfigurationBeanLoader +The principal methods are: + ++ `public T loadInstance(String uri, Class resultClass) throws ConfigurationBeanLoaderException` + + Search the graph for triples that describe the `uri`. + If the description indicates that the individual is of type `resultClass`, create an instance and populate it. + Return a reference to the created instance. Throw an exception if the `uri` does not exist in the graph, + or if the description does not correctly describe an individual. + + The `resultClass` may be an interface. In that case, each individual must also have a type statement that refers + to a concrete class that satisfies the interface. An instance of the concrete class will be created. + ++ `public Set loadAll(Class resultClass) throws ConfigurationBeanLoaderException` + + 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`. + +### Restrictions on instantiated classes. +Each class to be instantiated must have a niladic constructor. + +### Property methods +When the loader encounters a data property or an object property in a description, +it will look in the instantiated class for a method tagged with the +`edu.cornell.mannlib.vitro.webapp.utils.configuration.Property` annotation. + +For example: + + @Property( + uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasConfigurationTripleSource" + minOccurs = 1, + maxOccurs = 3) + public void setTBoxReasonerModule(TBoxReasonerModule module) { + this.module = module; + } + + +In more detail: + ++ A class must contain exactly one method that serves each property URI in the description. ++ 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 +with the same name in the class. ++ Property methods in superclasses will be recognized and accepted, but they may not be +overridden in a subclass. ++ If `minOccurs` is omitted, the default is `0`. If `minOccurs` is provided, it must be non-negative. ++ If `maxOccurs` is omitted, the default is `MAXINT`. If `maxOccurs` is provided, it must not be less than `minOccurs`. + +When instantiating: + ++ The parameter on a property method must match the value supplied in the RDF description. + + If the type of the parameter is `Float`, the object of the triple must be a numeric literal, or +an untyped literal that can be parsed as a number. + + If the type of the parameter is `String`, the object of the triple must be a String literal or an untyped literal. + + If the type of the parameter is another class, then the object of the triple must be the URI of +another RDF description, from which the loader can create an instance of the required class. ++ The number of values for a given property URI must not be less than the `minOccurs` value on the corresponding property method. ++ The number of values for a given property URI must not be greater than the `maxOccurs` value on the corresponding property method. + +### Validation methods +When the loader has satisfied all of the properties in an instance, it will +look in the instantiated class for any methods tagged with the +`edu.cornell.mannlib.vitro.webapp.utils.configuration.Validation` annotation. + +For example: + + @Validation + public void validate() throws Exception { + if (baseUri == null) { + throw new IllegalStateException( + "Configuration did not include a BaseURI."); + } + } + +Each such method will be called by the loader, and provides a opportunity to +confirm that the bean has been properly initialized. + +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. ++ Validation methods in superclasses will be called, but may not be overridden in a subclass. + +### Life cycle +For each instance that the loader creates, the loader will: + ++ Call the appropriate property method for each property in the description. +For object properties, this includes recursive calls to create subordinate objects. +The order of property method calls is undefined. ++ Call the validation methods on the class. The order of validation method calls is undefined. + +If any property method or validation method throws an exception, the process stops, +and the exception is propagated upward. \ No newline at end of file diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/WrappedInstance.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/WrappedInstance.java index ced8285bb..4b739c6ec 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/WrappedInstance.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/WrappedInstance.java @@ -5,6 +5,7 @@ package edu.cornell.mannlib.vitro.webapp.utils.configuration; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Collection; +import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -63,6 +64,45 @@ public class WrappedInstance { } } + /** + * The loader provides the distilled property statements from the RDF. Check + * that they satisfy the cardinality requested on their methods. + */ + public void checkCardinality(Set propertyStatements) + throws CardinalityException { + Map statementCounts = countPropertyStatementsByPredicateUri(propertyStatements); + for (PropertyMethod pm : propertyMethods.values()) { + Integer c = statementCounts.get(pm.getPropertyUri()); + int count = (c == null) ? 0 : c; + if (count < pm.getMinOccurs()) { + throw new CardinalityException("Expecting at least " + + pm.getMinOccurs() + " values for '" + + pm.getPropertyUri() + "', but found " + count + "."); + } + if (count > pm.getMaxOccurs()) { + throw new CardinalityException("Expecting no more than " + + pm.getMaxOccurs() + " values for '" + + pm.getPropertyUri() + "', but found " + count + "."); + } + } + statementCounts.hashCode(); + } + + private Map countPropertyStatementsByPredicateUri( + Set propertyStatements) { + Map statementCounts = new HashMap<>(); + for (String pmPredicateUri : propertyMethods.keySet()) { + int count = 0; + for (PropertyStatement ps : propertyStatements) { + if (ps.getPredicateUri().equals(pmPredicateUri)) { + count++; + } + } + statementCounts.put(pmPredicateUri, count); + } + return statementCounts; + } + /** * The loader provides the distilled property statements from the RDF, to * populate the instance. @@ -76,7 +116,6 @@ public class WrappedInstance { if (pm == null) { throw new NoSuchPropertyMethodException(ps); } - pm.confirmCompatible(ps); if (ps instanceof ResourcePropertyStatement) { @@ -132,4 +171,10 @@ public class WrappedInstance { } } + public static class CardinalityException extends Exception { + public CardinalityException(String message) { + super(message); + } + } + } \ No newline at end of file diff --git a/webapp/test/edu/cornell/mannlib/vitro/testing/ModelUtilitiesTestHelper.java b/webapp/test/edu/cornell/mannlib/vitro/testing/ModelUtilitiesTestHelper.java index 69c29537f..e38a0e3b7 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/testing/ModelUtilitiesTestHelper.java +++ b/webapp/test/edu/cornell/mannlib/vitro/testing/ModelUtilitiesTestHelper.java @@ -43,6 +43,12 @@ public class ModelUtilitiesTestHelper { createProperty(propertyUri), createPlainLiteral(objectValue)); } + public static Statement dataProperty(String subjectUri, String propertyUri, + Float objectValue) { + return createStatement(createResource(subjectUri), + createProperty(propertyUri), createTypedLiteral(objectValue)); + } + public static Statement dataProperty(String subjectUri, String propertyUri, Object objectValue, XSDDatatype dataType) { return createStatement(createResource(subjectUri), diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoaderTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoaderTest.java index da924567a..3d2ff1fff 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoaderTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoaderTest.java @@ -5,7 +5,6 @@ package edu.cornell.mannlib.vitro.webapp.utils.configuration; import static com.hp.hpl.jena.datatypes.xsd.XSDDatatype.XSDfloat; import static com.hp.hpl.jena.datatypes.xsd.XSDDatatype.XSDstring; import static edu.cornell.mannlib.vitro.testing.ModelUtilitiesTestHelper.dataProperty; -import static edu.cornell.mannlib.vitro.testing.ModelUtilitiesTestHelper.model; 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; @@ -20,28 +19,19 @@ import java.util.Collections; import java.util.HashSet; import java.util.Set; -import org.junit.Before; import org.junit.Ignore; import org.junit.Test; -import stubs.edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccessFactoryStub; -import stubs.javax.servlet.ServletContextStub; -import stubs.javax.servlet.http.HttpServletRequestStub; -import stubs.javax.servlet.http.HttpSessionStub; - import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.Statement; -import edu.cornell.mannlib.vitro.testing.AbstractTestClass; import edu.cornell.mannlib.vitro.webapp.modelaccess.ContextModelAccess; -import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess.ModelAccessFactory; 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; -import edu.cornell.mannlib.vitro.webapp.utils.configuration.WrappedInstance.ValidationFailedException; /** * TODO @@ -50,47 +40,8 @@ import edu.cornell.mannlib.vitro.webapp.utils.configuration.WrappedInstance.Vali * instances by URIs, so if a property refers to a created instance, we just * pass it in. */ -public class ConfigurationBeanLoaderTest extends AbstractTestClass { - private static final String GENERIC_INSTANCE_URI = "http://mytest.edu/some_instance"; - private static final String GENERIC_PROPERTY_URI = "http://mytest.edu/some_property"; - - private static final String SIMPLE_SUCCESS_INSTANCE_URI = "http://mytest.edu/simple_success_instance"; - - private static final String FULL_SUCCESS_INSTANCE_URI = "http://mytest.edu/full_success_instance"; - private static final String FULL_SUCCESS_BOOST_PROPERTY = "http://mydomain.edu/hasBoost"; - private static final String FULL_SUCCESS_TEXT_PROPERTY = "http://mydomain.edu/hasText"; - private static final String FULL_SUCCESS_HELPER_PROPERTY = "http://mydomain.edu/hasHelper"; - private static final String FULL_SUCCESS_HELPER_INSTANCE_URI = "http://mytest.edu/full_success_helper_instance"; - - private ServletContextStub ctx; - private HttpSessionStub session; - private HttpServletRequestStub req; - - private Model model; - - private ConfigurationBeanLoader loader; - private ConfigurationBeanLoader noRequestLoader; - private ConfigurationBeanLoader noContextLoader; - - @Before - public void setup() { - ctx = new ServletContextStub(); - - session = new HttpSessionStub(); - session.setServletContext(ctx); - - req = new HttpServletRequestStub(); - req.setSession(session); - - @SuppressWarnings("unused") - ModelAccessFactory maf = new ModelAccessFactoryStub(); - - model = model(); - - loader = new ConfigurationBeanLoader(model, req); - noRequestLoader = new ConfigurationBeanLoader(model, ctx); - noContextLoader = new ConfigurationBeanLoader(model); - } +public class ConfigurationBeanLoaderTest extends + ConfigurationBeanLoaderTestBase { // ---------------------------------------------------------------------- // Constructor tests @@ -308,276 +259,6 @@ public class ConfigurationBeanLoaderTest extends AbstractTestClass { // -------------------------------------------- - @Test - public void propertyMethodHasNoParameter_throwsException() - throws ConfigurationBeanLoaderException { - model.add(typeStatement(GENERIC_INSTANCE_URI, - toJavaUri(NoParameterOnPropertyMethod.class))); - - expectSimpleFailure( - NoParameterOnPropertyMethod.class, - throwable(ConfigurationBeanLoaderException.class, - "Failed to load"), - throwable(InstanceWrapperException.class, - "must accept exactly one parameter")); - } - - public static class NoParameterOnPropertyMethod { - @Property(uri = GENERIC_PROPERTY_URI) - public void methodTakesNoParameters() { - // Not suitable as a property method. - } - } - - // -------------------------------------------- - - @Test - public void propertyMethodHasMultipleParameters_throwsException() - throws ConfigurationBeanLoaderException { - model.add(typeStatement(GENERIC_INSTANCE_URI, - toJavaUri(MultipleParametersOnPropertyMethod.class))); - - expectSimpleFailure( - MultipleParametersOnPropertyMethod.class, - throwable(ConfigurationBeanLoaderException.class, - "Failed to load"), - throwable(InstanceWrapperException.class, - "must accept exactly one parameter")); - } - - public static class MultipleParametersOnPropertyMethod { - @SuppressWarnings("unused") - @Property(uri = GENERIC_PROPERTY_URI) - public void methodTakesMultipleParameters(String s, Float f) { - // Not suitable as a property method. - } - } - - // -------------------------------------------- - - @Test - public void propertyMethodHasInvalidParameter_throwsException() - throws ConfigurationBeanLoaderException { - model.add(typeStatement(GENERIC_INSTANCE_URI, - toJavaUri(InvalidParameterOnPropertyMethod.class))); - - expectSimpleFailure( - InvalidParameterOnPropertyMethod.class, - throwable(ConfigurationBeanLoaderException.class, - "Failed to load"), - throwable(InstanceWrapperException.class, - "Failed to create the PropertyMethod")); - } - - public static class InvalidParameterOnPropertyMethod { - @SuppressWarnings("unused") - @Property(uri = GENERIC_PROPERTY_URI) - public void methodTakesInvalidParameters(byte b) { - // Not suitable as a property method. - } - } - - // -------------------------------------------- - - @Test - public void propertyMethodDoesNotReturnVoid_throwsException() - throws ConfigurationBeanLoaderException { - model.add(typeStatement(GENERIC_INSTANCE_URI, - toJavaUri(PropertyMethodMustReturnVoid.class))); - - expectSimpleFailure( - PropertyMethodMustReturnVoid.class, - throwable(ConfigurationBeanLoaderException.class, - "Failed to load"), - throwable(InstanceWrapperException.class, "should return void")); - } - - public static class PropertyMethodMustReturnVoid { - @Property(uri = GENERIC_PROPERTY_URI) - public String methodReturnIsNotVoid(String s) { - // Not suitable as a property method. - return s; - } - } - - // -------------------------------------------- - - @Test - public void propertyMethodNotAccessible_throwsException() - throws ConfigurationBeanLoaderException { - model.add(typeStatement(GENERIC_INSTANCE_URI, - toJavaUri(PropertyMethodIsPrivate.class))); - model.add(dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI, - "can't store in a private method.")); - - expectSimpleFailure( - PropertyMethodIsPrivate.class, - throwable(ConfigurationBeanLoaderException.class, - "Failed to load"), - throwable(PropertyTypeException.class, - "Property method failed.")); - } - - public static class PropertyMethodIsPrivate { - @SuppressWarnings("unused") - @Property(uri = GENERIC_PROPERTY_URI) - private void methodReturnIsNotVoid(String s) { - // Not suitable as a property method. - } - } - - // -------------------------------------------- - - @Test - public void propertyMethodThrowsException_throwsException() - throws ConfigurationBeanLoaderException { - model.add(typeStatement(GENERIC_INSTANCE_URI, - toJavaUri(PropertyMethodFails.class))); - model.add(dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI, - "exception while loading.")); - - expectSimpleFailure( - PropertyMethodFails.class, - throwable(ConfigurationBeanLoaderException.class, - "Failed to load"), - throwable(PropertyTypeException.class, - "Property method failed.")); - } - - public static class PropertyMethodFails { - @SuppressWarnings("unused") - @Property(uri = GENERIC_PROPERTY_URI) - public void methodThrowsException(String s) { - if (true) { - throw new RuntimeException("property method fails."); - } - } - } - - // -------------------------------------------- - - @Test - public void propertyMethodDuplicateUri_throwsException() - throws ConfigurationBeanLoaderException { - model.add(typeStatement(GENERIC_INSTANCE_URI, - toJavaUri(TwoMethodsWithSameUri.class))); - - expectSimpleFailure( - TwoMethodsWithSameUri.class, - throwable(ConfigurationBeanLoaderException.class, - "Failed to load"), - throwable(InstanceWrapperException.class, - "methods have the same URI")); - } - - public static class TwoMethodsWithSameUri { - @SuppressWarnings("unused") - @Property(uri = GENERIC_PROPERTY_URI) - public void firstProperty(String s) { - // Nothing to do - } - - @SuppressWarnings("unused") - @Property(uri = GENERIC_PROPERTY_URI) - public void secondProperty(String s) { - // Nothing to do - } - } - - // -------------------------------------------- - - @Test - public void validationMethodHasParameters_throwsException() - throws ConfigurationBeanLoaderException { - model.add(typeStatement(GENERIC_INSTANCE_URI, - toJavaUri(ValidationMethodWithParameter.class))); - - expectSimpleFailure( - ValidationMethodWithParameter.class, - throwable(ConfigurationBeanLoaderException.class, - "Failed to load"), - throwable(InstanceWrapperException.class, - "should not have parameters")); - } - - public static class ValidationMethodWithParameter { - @SuppressWarnings("unused") - @Validation - public void validateWithParameter(String s) { - // Nothing to do - } - } - - // -------------------------------------------- - - @Test - public void validationMethodDoesNotReturnVoid_throwsException() - throws ConfigurationBeanLoaderException { - model.add(typeStatement(GENERIC_INSTANCE_URI, - toJavaUri(ValidationMethodShouldReturnVoid.class))); - - expectSimpleFailure( - ValidationMethodShouldReturnVoid.class, - throwable(ConfigurationBeanLoaderException.class, - "Failed to load"), - throwable(InstanceWrapperException.class, "should return void")); - } - - public static class ValidationMethodShouldReturnVoid { - @Validation - public String validateWithReturnType() { - return "Hi there!"; - } - } - - // -------------------------------------------- - - @Test - public void validationMethodNotAccessible_throwsException() - throws ConfigurationBeanLoaderException { - model.add(typeStatement(GENERIC_INSTANCE_URI, - toJavaUri(ValidationMethodIsPrivate.class))); - - expectSimpleFailure( - ValidationMethodIsPrivate.class, - throwable(ConfigurationBeanLoaderException.class, - "Failed to load"), - throwable(ValidationFailedException.class, - "Error executing validation method")); - } - - public static class ValidationMethodIsPrivate { - @Validation - private void validateIsPrivate() { - // private method - } - } - - // -------------------------------------------- - - @Test - public void validationMethodThrowsException_throwsException() - throws ConfigurationBeanLoaderException { - model.add(typeStatement(GENERIC_INSTANCE_URI, - toJavaUri(ValidationThrowsException.class))); - - expectSimpleFailure( - ValidationThrowsException.class, - throwable(ConfigurationBeanLoaderException.class, - "Failed to load"), - throwable(ValidationFailedException.class, - "Error executing validation method")); - } - - public static class ValidationThrowsException { - @Validation - public void validateFails() { - throw new RuntimeException("from validation method"); - } - } - - // -------------------------------------------- - @Test public void loaderCantSatisfyContextModelsUser_throwsException() throws ConfigurationBeanLoaderException { @@ -1041,6 +722,7 @@ public class ConfigurationBeanLoaderTest extends AbstractTestClass { // Additional tests // ---------------------------------------------------------------------- + @SuppressWarnings("unused") @Test @Ignore // TODO @@ -1049,6 +731,7 @@ public class ConfigurationBeanLoaderTest extends AbstractTestClass { fail("circularReferencesAreNotFatal not implemented"); } + @SuppressWarnings("unused") @Test @Ignore // TODO deals with circularity. @@ -1057,6 +740,7 @@ public class ConfigurationBeanLoaderTest extends AbstractTestClass { fail("subordinateObjectCantBeLoaded_leavesNoAccessibleInstanceOfParent not implemented"); } + @SuppressWarnings("unused") @Test @Ignore // TODO deals with circularity. @@ -1065,42 +749,4 @@ public class ConfigurationBeanLoaderTest extends AbstractTestClass { fail("parentObjectCantBeLoaded_leavesNoAccessibleInstanceOfSubordinate not implemented"); } - // ---------------------------------------------------------------------- - // Helper methods for simple failure - // ---------------------------------------------------------------------- - - private void expectSimpleFailure(Class failureClass, - ExpectedThrowable expected, ExpectedThrowable cause) - throws ConfigurationBeanLoaderException { - expectException(expected.getClazz(), expected.getMessageSubstring(), - cause.getClazz(), cause.getMessageSubstring()); - - @SuppressWarnings("unused") - Object unused = loader.loadInstance(GENERIC_INSTANCE_URI, failureClass); - } - - private ExpectedThrowable throwable(Class clazz, - String messageSubstring) { - return new ExpectedThrowable(clazz, messageSubstring); - } - - private static class ExpectedThrowable { - private final Class clazz; - private final String messageSubstring; - - public ExpectedThrowable(Class clazz, - String messageSubstring) { - this.clazz = clazz; - this.messageSubstring = messageSubstring; - } - - public Class getClazz() { - return clazz; - } - - public String getMessageSubstring() { - return messageSubstring; - } - } - } diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoaderTestBase.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoaderTestBase.java new file mode 100644 index 000000000..0725f9a6c --- /dev/null +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoaderTestBase.java @@ -0,0 +1,102 @@ +/* $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.model; + +import org.junit.Before; + +import stubs.edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccessFactoryStub; +import stubs.javax.servlet.ServletContextStub; +import stubs.javax.servlet.http.HttpServletRequestStub; +import stubs.javax.servlet.http.HttpSessionStub; + +import com.hp.hpl.jena.rdf.model.Model; + +import edu.cornell.mannlib.vitro.testing.AbstractTestClass; +import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess.ModelAccessFactory; + +/** + * TODO + */ +public class ConfigurationBeanLoaderTestBase extends AbstractTestClass { + protected static final String GENERIC_INSTANCE_URI = "http://mytest.edu/some_instance"; + protected static final String GENERIC_PROPERTY_URI = "http://mytest.edu/some_property"; + + protected static final String SIMPLE_SUCCESS_INSTANCE_URI = "http://mytest.edu/simple_success_instance"; + + protected static final String FULL_SUCCESS_INSTANCE_URI = "http://mytest.edu/full_success_instance"; + protected static final String FULL_SUCCESS_BOOST_PROPERTY = "http://mydomain.edu/hasBoost"; + protected static final String FULL_SUCCESS_TEXT_PROPERTY = "http://mydomain.edu/hasText"; + protected static final String FULL_SUCCESS_HELPER_PROPERTY = "http://mydomain.edu/hasHelper"; + protected static final String FULL_SUCCESS_HELPER_INSTANCE_URI = "http://mytest.edu/full_success_helper_instance"; + + private ServletContextStub ctx; + private HttpSessionStub session; + private HttpServletRequestStub req; + + protected Model model; + + protected ConfigurationBeanLoader loader; + protected ConfigurationBeanLoader noRequestLoader; + protected ConfigurationBeanLoader noContextLoader; + + @Before + public void setup() { + ctx = new ServletContextStub(); + + session = new HttpSessionStub(); + session.setServletContext(ctx); + + req = new HttpServletRequestStub(); + req.setSession(session); + + @SuppressWarnings("unused") + ModelAccessFactory maf = new ModelAccessFactoryStub(); + + model = model(); + + loader = new ConfigurationBeanLoader(model, req); + noRequestLoader = new ConfigurationBeanLoader(model, ctx); + noContextLoader = new ConfigurationBeanLoader(model); + } + + // ---------------------------------------------------------------------- + // Helper methods for simple failure + // ---------------------------------------------------------------------- + + protected void expectSimpleFailure(Class failureClass, + ExpectedThrowable expected, ExpectedThrowable cause) + throws ConfigurationBeanLoaderException { + expectException(expected.getClazz(), expected.getMessageSubstring(), + cause.getClazz(), cause.getMessageSubstring()); + + @SuppressWarnings("unused") + Object unused = loader.loadInstance(GENERIC_INSTANCE_URI, failureClass); + } + + protected ExpectedThrowable throwable(Class clazz, + String messageSubstring) { + return new ExpectedThrowable(clazz, messageSubstring); + } + + private static class ExpectedThrowable { + private final Class clazz; + private final String messageSubstring; + + public ExpectedThrowable(Class clazz, + String messageSubstring) { + this.clazz = clazz; + this.messageSubstring = messageSubstring; + } + + public Class getClazz() { + return clazz; + } + + public String getMessageSubstring() { + return messageSubstring; + } + } + +} diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_Cardinality_Test.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_Cardinality_Test.java new file mode 100644 index 000000000..13e767265 --- /dev/null +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_Cardinality_Test.java @@ -0,0 +1,252 @@ +/* $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.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.junit.Assert.assertEquals; + +import java.util.Set; + +import org.junit.Test; + +import com.hp.hpl.jena.rdf.model.Statement; + +import edu.cornell.mannlib.vitro.webapp.utils.configuration.InstanceWrapper.InstanceWrapperException; +import edu.cornell.mannlib.vitro.webapp.utils.configuration.WrappedInstance.CardinalityException; + +/** + * Tests for minOccurs, maxOccurs on the @Property annotation. + */ +public class ConfigurationBeanLoader_Cardinality_Test extends + ConfigurationBeanLoaderTestBase { + + private static final Statement[] FOUND_NONE = new Statement[0]; + + private static final Statement[] FOUND_ONE = new Statement[] { dataProperty( + GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI, "value One") }; + + private static final Statement[] FOUND_TWO = new Statement[] { + dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI, + "value One"), + dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI, + "value Two") }; + + private static final Statement[] FOUND_THREE = new Statement[] { + dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI, + "value One"), + dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI, + "value Two"), + dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI, + "value Three") }; + + private static final Statement[] FOUND_FOUR = new Statement[] { + dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI, + "value One"), + dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI, + "value Two"), + dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI, + "value Three"), + dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI, + "value Four") }; + + // -------------------------------------------- + + @Test + public void minOccursIsNegative_throwsException() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(NegativeMinOccurs.class))); + model.add(objectProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI, + "http://some.other/uri")); + + expectSimpleFailure( + NegativeMinOccurs.class, + throwable(ConfigurationBeanLoaderException.class, + "Failed to load"), + throwable(InstanceWrapperException.class, + "must not be negative")); + } + + public static class NegativeMinOccurs { + @SuppressWarnings("unused") + @Property(uri = GENERIC_PROPERTY_URI, minOccurs = -1) + public void setValue(String value) { + // Nothing to do + } + } + + // -------------------------------------------- + + @Test + public void maxOccursLessThanMinOccurs_throwsException() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(MaxOccursLessThanMinOccurs.class))); + model.add(objectProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI, + "http://some.other/uri")); + + expectSimpleFailure( + MaxOccursLessThanMinOccurs.class, + throwable(ConfigurationBeanLoaderException.class, + "Failed to load"), + throwable(InstanceWrapperException.class, + "not be less than minOccurs")); + } + + public static class MaxOccursLessThanMinOccurs { + @SuppressWarnings("unused") + @Property(uri = GENERIC_PROPERTY_URI, minOccurs = 2, maxOccurs = 1) + public void setValue(String value) { + // Nothing to do + } + } + + // -------------------------------------------- + + @Test + public void expectingSomeFoundNone_throwsException() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(ExpectingSome.class))); + model.add(FOUND_NONE); + + expectSimpleFailure( + ExpectingSome.class, + throwable(ConfigurationBeanLoaderException.class, + "Failed to load"), + throwable(CardinalityException.class, "Expecting at least 2")); + } + + @Test + public void expectingSomeFoundFewer_throwsException() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(ExpectingSome.class))); + model.add(FOUND_ONE); + + expectSimpleFailure( + ExpectingSome.class, + throwable(ConfigurationBeanLoaderException.class, + "Failed to load"), + throwable(CardinalityException.class, "Expecting at least 2")); + } + + @Test + public void expectingSomeFoundMore_throwsException() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(ExpectingSome.class))); + model.add(FOUND_FOUR); + + expectSimpleFailure( + ExpectingSome.class, + throwable(ConfigurationBeanLoaderException.class, + "Failed to load"), + throwable(CardinalityException.class, + "Expecting no more than 3")); + } + + @Test + public void expectingSomeFoundSome_success() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(ExpectingSome.class))); + model.add(FOUND_THREE); + Set instances = loader.loadAll(ExpectingSome.class); + assertEquals(1, instances.size()); + model.removeAll(); + + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(ExpectingSome.class))); + model.add(FOUND_TWO); + instances = loader.loadAll(ExpectingSome.class); + assertEquals(1, instances.size()); + } + + public static class ExpectingSome { + @SuppressWarnings("unused") + @Property(uri = GENERIC_PROPERTY_URI, minOccurs = 2, maxOccurs = 3) + public void setValue(String value) { + // Nothing to do + } + } + + // -------------------------------------------- + + @Test + public void notSpecifiedFoundNone_success() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(CardinalityNotSpecified.class))); + model.add(FOUND_NONE); + + Set instances = loader + .loadAll(CardinalityNotSpecified.class); + assertEquals(1, instances.size()); + } + + @Test + public void notSpecifiedFoundSome_success() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(CardinalityNotSpecified.class))); + model.add(FOUND_FOUR); + + Set instances = loader + .loadAll(CardinalityNotSpecified.class); + assertEquals(1, instances.size()); + } + + public static class CardinalityNotSpecified { + @SuppressWarnings("unused") + @Property(uri = GENERIC_PROPERTY_URI) + public void setValue(String value) { + // Nothing to do + } + } + + // -------------------------------------------- + + @Test + public void expectNoneFoundNone_success() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(ExpectNone.class))); + model.add(FOUND_NONE); + + Set instances = loader.loadAll(ExpectNone.class); + assertEquals(1, instances.size()); + } + + public static class ExpectNone { + @SuppressWarnings("unused") + @Property(uri = GENERIC_PROPERTY_URI, maxOccurs = 0) + public void setValue(String value) { + // Nothing to do + } + } + + // -------------------------------------------- + + @Test + public void expectExactlyFoundExactly_success() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(ExpectTwo.class))); + model.add(FOUND_TWO); + + Set instances = loader.loadAll(ExpectTwo.class); + assertEquals(1, instances.size()); + } + + public static class ExpectTwo { + @SuppressWarnings("unused") + @Property(uri = GENERIC_PROPERTY_URI, minOccurs = 2, maxOccurs = 2) + public void setValue(String value) { + // Nothing to do + } + } +} diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_PropertyTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_PropertyTest.java new file mode 100644 index 000000000..52996bd0e --- /dev/null +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_PropertyTest.java @@ -0,0 +1,339 @@ +/* $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.dataProperty; +import static edu.cornell.mannlib.vitro.testing.ModelUtilitiesTestHelper.typeStatement; +import static edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationBeanLoader.toJavaUri; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; + +import com.hp.hpl.jena.rdf.model.Statement; + +import edu.cornell.mannlib.vitro.webapp.utils.configuration.InstanceWrapper.InstanceWrapperException; +import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.PropertyTypeException; + +/** + * Tests of the @Property annotation. + */ +public class ConfigurationBeanLoader_PropertyTest extends + ConfigurationBeanLoaderTestBase { + protected static final String OTHER_PROPERTY_URI = "http://mytest.edu/different_property"; + + // -------------------------------------------- + + @Test + public void propertyMethodHasNoParameter_throwsException() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(NoParameterOnPropertyMethod.class))); + + expectSimpleFailure( + NoParameterOnPropertyMethod.class, + throwable(ConfigurationBeanLoaderException.class, + "Failed to load"), + throwable(InstanceWrapperException.class, + "must accept exactly one parameter")); + } + + public static class NoParameterOnPropertyMethod { + @Property(uri = GENERIC_PROPERTY_URI) + public void methodTakesNoParameters() { + // Not suitable as a property method. + } + } + + // -------------------------------------------- + + @Test + public void propertyMethodHasMultipleParameters_throwsException() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(MultipleParametersOnPropertyMethod.class))); + + expectSimpleFailure( + MultipleParametersOnPropertyMethod.class, + throwable(ConfigurationBeanLoaderException.class, + "Failed to load"), + throwable(InstanceWrapperException.class, + "must accept exactly one parameter")); + } + + public static class MultipleParametersOnPropertyMethod { + @SuppressWarnings("unused") + @Property(uri = GENERIC_PROPERTY_URI) + public void methodTakesMultipleParameters(String s, Float f) { + // Not suitable as a property method. + } + } + + // -------------------------------------------- + + @Test + public void propertyMethodHasInvalidParameter_throwsException() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(InvalidParameterOnPropertyMethod.class))); + + expectSimpleFailure( + InvalidParameterOnPropertyMethod.class, + throwable(ConfigurationBeanLoaderException.class, + "Failed to load"), + throwable(InstanceWrapperException.class, + "Failed to create the PropertyMethod")); + } + + public static class InvalidParameterOnPropertyMethod { + @SuppressWarnings("unused") + @Property(uri = GENERIC_PROPERTY_URI) + public void methodTakesInvalidParameters(byte b) { + // Not suitable as a property method. + } + } + + // -------------------------------------------- + + @Test + public void propertyMethodDoesNotReturnVoid_throwsException() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(PropertyMethodMustReturnVoid.class))); + + expectSimpleFailure( + PropertyMethodMustReturnVoid.class, + throwable(ConfigurationBeanLoaderException.class, + "Failed to load"), + throwable(InstanceWrapperException.class, "should return void")); + } + + public static class PropertyMethodMustReturnVoid { + @Property(uri = GENERIC_PROPERTY_URI) + public String methodReturnIsNotVoid(String s) { + // Not suitable as a property method. + return s; + } + } + + // -------------------------------------------- + + @Test + public void propertyMethodNotAccessible_throwsException() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(PropertyMethodIsPrivate.class))); + model.add(dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI, + "can't store in a private method.")); + + expectSimpleFailure( + PropertyMethodIsPrivate.class, + throwable(ConfigurationBeanLoaderException.class, + "Failed to load"), + throwable(PropertyTypeException.class, + "Property method failed.")); + } + + public static class PropertyMethodIsPrivate { + @SuppressWarnings("unused") + @Property(uri = GENERIC_PROPERTY_URI) + private void methodReturnIsNotVoid(String s) { + // Not suitable as a property method. + } + } + + // -------------------------------------------- + + @Test + public void propertyMethodThrowsException_throwsException() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(PropertyMethodFails.class))); + model.add(dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI, + "exception while loading.")); + + expectSimpleFailure( + PropertyMethodFails.class, + throwable(ConfigurationBeanLoaderException.class, + "Failed to load"), + throwable(PropertyTypeException.class, + "Property method failed.")); + } + + public static class PropertyMethodFails { + @SuppressWarnings("unused") + @Property(uri = GENERIC_PROPERTY_URI) + public void methodThrowsException(String s) { + if (true) { + throw new RuntimeException("property method fails."); + } + } + } + + // -------------------------------------------- + + @Test + public void propertyMethodDuplicateUri_throwsException() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(TwoMethodsWithSameUri.class))); + + expectSimpleFailure( + TwoMethodsWithSameUri.class, + throwable(ConfigurationBeanLoaderException.class, + "Failed to load"), + throwable(InstanceWrapperException.class, + "methods have the same URI")); + } + + public static class TwoMethodsWithSameUri { + @SuppressWarnings("unused") + @Property(uri = GENERIC_PROPERTY_URI) + public void firstProperty(String s) { + // Nothing to do + } + + @SuppressWarnings("unused") + @Property(uri = GENERIC_PROPERTY_URI) + public void secondProperty(String s) { + // Nothing to do + } + } + + // -------------------------------------------- + + @Test + public void superclassContainsPropertyAnnotation_success() + throws ConfigurationBeanLoaderException { + model.add(new Statement[] { + typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(EmptyPropertyMethodSubclass.class)), + dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI, + "Value") }); + + EmptyPropertyMethodSubclass instance = loader.loadInstance( + GENERIC_INSTANCE_URI, EmptyPropertyMethodSubclass.class); + + assertNotNull(instance); + assertEquals("Value", instance.value); + } + + @Test + public void propertyMethodOverridesPropertyMethod_throwsException() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(PropertyMethodOverPropertyMethodSubclass.class))); + + expectSimpleFailure( + PropertyMethodOverPropertyMethodSubclass.class, + throwable(ConfigurationBeanLoaderException.class, + "Failed to load"), + throwable(InstanceWrapperException.class, + "conflicts with a property method")); + } + + @Test + public void plainMethodOverridesPropertyMethod_throwsException() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(PlainOverPropertyMethodSubclass.class))); + + expectSimpleFailure( + PlainOverPropertyMethodSubclass.class, + throwable(ConfigurationBeanLoaderException.class, + "Failed to load"), + throwable(InstanceWrapperException.class, + "conflicts with a property method")); + } + + @Test + public void uriConflictsBetweenSubclassAndSuperclassPropertyMethods_throwsException() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(ConflictingUriPropertyMethodSubclass.class))); + + expectSimpleFailure( + ConflictingUriPropertyMethodSubclass.class, + throwable(ConfigurationBeanLoaderException.class, + "Failed to load"), + throwable(InstanceWrapperException.class, + "Two property methods have the same URI")); + } + + @Test + public void propertyMethodSameNameButDoesNotOverride_throwsException() + throws ConfigurationBeanLoaderException { + model.add(new Statement[] { + typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(DistinctPropertyMethodSubclass.class)), + dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI, + "Value"), + dataProperty(GENERIC_INSTANCE_URI, OTHER_PROPERTY_URI, + 100.0F) }); + + expectSimpleFailure( + DistinctPropertyMethodSubclass.class, + throwable(ConfigurationBeanLoaderException.class, + "Failed to load"), + throwable(InstanceWrapperException.class, + "conflicts with a property method")); + } + + public static class PropertyMethodSuperclass { + public String value = null; + + @Property(uri = GENERIC_PROPERTY_URI) + public void propertySuper(String v) { + if (value != null) { + throw new RuntimeException("propertySuper has already run."); + } + value = v; + } + } + + public static class EmptyPropertyMethodSubclass extends + PropertyMethodSuperclass { + // Just want to see that the superclass method is run. + } + + public static class DistinctPropertyMethodSubclass extends + PropertyMethodSuperclass { + public float fvalue; + + @Property(uri = OTHER_PROPERTY_URI) + public void propertySuper(Float f) { + if (fvalue != 0.0) { + throw new RuntimeException("propertySub has already run."); + } + fvalue = f; + } + } + + public static class ConflictingUriPropertyMethodSubclass extends + PropertyMethodSuperclass { + + @Property(uri = GENERIC_PROPERTY_URI) + public void propertyConflict(String v) { + // nothing to do. + } + } + + public static class PropertyMethodOverPropertyMethodSubclass extends + EmptyPropertyMethodSubclass { + @Override + @SuppressWarnings("unused") + @Property(uri = GENERIC_PROPERTY_URI) + public void propertySuper(String v) { + // Should fail (two levels down) + } + } + + public static class PlainOverPropertyMethodSubclass extends + PropertyMethodSuperclass { + @SuppressWarnings("unused") + public void propertySuper(Float f) { + // nothing to do + } + } + +} diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_ValidationTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_ValidationTest.java new file mode 100644 index 000000000..8e3498a56 --- /dev/null +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_ValidationTest.java @@ -0,0 +1,215 @@ +/* $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.toJavaUri; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import edu.cornell.mannlib.vitro.webapp.utils.configuration.InstanceWrapper.InstanceWrapperException; +import edu.cornell.mannlib.vitro.webapp.utils.configuration.WrappedInstance.ValidationFailedException; + +/** + * Test the @Validation annotation. + */ +public class ConfigurationBeanLoader_ValidationTest extends + ConfigurationBeanLoaderTestBase { + // -------------------------------------------- + + @Test + public void validationMethodHasParameters_throwsException() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(ValidationMethodWithParameter.class))); + + expectSimpleFailure( + ValidationMethodWithParameter.class, + throwable(ConfigurationBeanLoaderException.class, + "Failed to load"), + throwable(InstanceWrapperException.class, + "should not have parameters")); + } + + public static class ValidationMethodWithParameter { + @SuppressWarnings("unused") + @Validation + public void validateWithParameter(String s) { + // Nothing to do + } + } + + // -------------------------------------------- + + @Test + public void validationMethodDoesNotReturnVoid_throwsException() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(ValidationMethodShouldReturnVoid.class))); + + expectSimpleFailure( + ValidationMethodShouldReturnVoid.class, + throwable(ConfigurationBeanLoaderException.class, + "Failed to load"), + throwable(InstanceWrapperException.class, "should return void")); + } + + public static class ValidationMethodShouldReturnVoid { + @Validation + public String validateWithReturnType() { + return "Hi there!"; + } + } + + // -------------------------------------------- + + @Test + public void validationMethodNotAccessible_throwsException() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(ValidationMethodIsPrivate.class))); + + expectSimpleFailure( + ValidationMethodIsPrivate.class, + throwable(ConfigurationBeanLoaderException.class, + "Failed to load"), + throwable(ValidationFailedException.class, + "Error executing validation method")); + } + + public static class ValidationMethodIsPrivate { + @Validation + private void validateIsPrivate() { + // private method + } + } + + // -------------------------------------------- + + @Test + public void validationMethodThrowsException_throwsException() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(ValidationThrowsException.class))); + + expectSimpleFailure( + ValidationThrowsException.class, + throwable(ConfigurationBeanLoaderException.class, + "Failed to load"), + throwable(ValidationFailedException.class, + "Error executing validation method")); + } + + public static class ValidationThrowsException { + @Validation + public void validateFails() { + throw new RuntimeException("from validation method"); + } + } + + // -------------------------------------------- + + @Test + public void superclassContainsValidationMethod_success() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(EmptyValidationSubclass.class))); + + EmptyValidationSubclass instance = loader.loadInstance( + GENERIC_INSTANCE_URI, EmptyValidationSubclass.class); + + assertNotNull(instance); + assertTrue(instance.validatorSuperHasRun); + } + + @Test + public void superclassAndSubclassContainValidationMethods_success() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(AdditionalValidationSubclass.class))); + + AdditionalValidationSubclass instance = loader.loadInstance( + GENERIC_INSTANCE_URI, AdditionalValidationSubclass.class); + + assertNotNull(instance); + assertTrue(instance.validatorSuperHasRun); + assertTrue(instance.validatorSubHasRun); + } + + @Test + public void validationMethodOverridesValidationMethod_throwsException() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(ValidationOverValidationSubclass.class))); + + expectSimpleFailure( + ValidationOverValidationSubclass.class, + throwable(ConfigurationBeanLoaderException.class, + "Failed to load"), + throwable(InstanceWrapperException.class, + "overrides a validation method")); + } + + @Test + public void plainMethodOverridesValidationMethod_throwsException() + throws ConfigurationBeanLoaderException { + model.add(typeStatement(GENERIC_INSTANCE_URI, + toJavaUri(PlainOverValidationSubclass.class))); + + expectSimpleFailure( + PlainOverValidationSubclass.class, + throwable(ConfigurationBeanLoaderException.class, + "Failed to load"), + throwable(InstanceWrapperException.class, + "overrides a validation method")); + } + + public static class ValidationSuperclass { + public boolean validatorSuperHasRun = false; + + @Validation + public void validatorSuper() { + if (validatorSuperHasRun) { + throw new RuntimeException("validatorSuper has already run."); + } + validatorSuperHasRun = true; + } + } + + public static class EmptyValidationSubclass extends ValidationSuperclass { + // Just want to see that the superclass validation is run. + } + + public static class AdditionalValidationSubclass extends + ValidationSuperclass { + public boolean validatorSubHasRun = false; + + @Validation + public void validatorSub() { + if (validatorSubHasRun) { + throw new RuntimeException("validatorSub has already run."); + } + validatorSubHasRun = true; + } + } + + public static class ValidationOverValidationSubclass extends + EmptyValidationSubclass { + @Override + @Validation + public void validatorSuper() { + // Should fail (two levels down) + } + } + + public static class PlainOverValidationSubclass extends + ValidationSuperclass { + @Override + public void validatorSuper() { + // Should fail + } + } + +} From d752989003a5f6c06fb025c165bdf643e79cac34 Mon Sep 17 00:00:00 2001 From: Jim Blake Date: Sun, 29 May 2016 16:12:11 -0400 Subject: [PATCH 2/4] VIVO-1247, remove duplicate code used with ConfigurationBeanLoader. Now that the @Property annotation includes cardinality parameters, we can remove a lot of duplicate code. --- .../webapp/application/ApplicationImpl.java | 103 +++--------------- .../InstrumentedSearchEngineWrapper.java | 71 +++++------- .../webapp/searchindex/SearchIndexerImpl.java | 61 +++++------ .../documentBuilding/FieldBooster.java | 13 +-- .../indexing/SelectQueryUriFinder.java | 6 +- .../sparql/ContentTripleSourceSPARQL.java | 29 +---- .../impl/tdb/ContentTripleSourceTDB.java | 22 +--- .../virtuoso/ContentTripleSourceVirtuoso.java | 48 +------- 8 files changed, 86 insertions(+), 267 deletions(-) diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/application/ApplicationImpl.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/application/ApplicationImpl.java index 36e230466..1f840ae37 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/application/ApplicationImpl.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/application/ApplicationImpl.java @@ -25,7 +25,6 @@ import edu.cornell.mannlib.vitro.webapp.startup.ComponentStartupStatusImpl; import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; import edu.cornell.mannlib.vitro.webapp.triplesource.impl.BasicCombinedTripleSource; import edu.cornell.mannlib.vitro.webapp.utils.configuration.Property; -import edu.cornell.mannlib.vitro.webapp.utils.configuration.Validation; /** * The basic implementation of the Application interface. @@ -69,15 +68,9 @@ public class ApplicationImpl implements Application { return searchEngine; } - @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasSearchEngine") + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasSearchEngine", minOccurs = 1, maxOccurs = 1) public void setSearchEngine(SearchEngine se) { - if (searchEngine == null) { - searchEngine = se; - } else { - throw new IllegalStateException( - "Configuration includes multiple SearchEngine instances: " - + searchEngine + ", and " + se); - } + searchEngine = se; } @Override @@ -85,15 +78,9 @@ public class ApplicationImpl implements Application { return searchIndexer; } - @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasSearchIndexer") + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasSearchIndexer", minOccurs = 1, maxOccurs = 1) public void setSearchIndexer(SearchIndexer si) { - if (searchIndexer == null) { - searchIndexer = si; - } else { - throw new IllegalStateException( - "Configuration includes multiple SearchIndexer instances: " - + searchIndexer + ", and " + si); - } + searchIndexer = si; } @Override @@ -101,15 +88,9 @@ public class ApplicationImpl implements Application { return imageProcessor; } - @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasImageProcessor") + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasImageProcessor", minOccurs = 1, maxOccurs = 1) public void setImageProcessor(ImageProcessor ip) { - if (imageProcessor == null) { - imageProcessor = ip; - } else { - throw new IllegalStateException( - "Configuration includes multiple ImageProcessor instances: " - + imageProcessor + ", and " + ip); - } + imageProcessor = ip; } @Override @@ -117,15 +98,9 @@ public class ApplicationImpl implements Application { return fileStorage; } - @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasFileStorage") + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasFileStorage", minOccurs = 1, maxOccurs = 1) public void setFileStorage(FileStorage fs) { - if (fileStorage == null) { - fileStorage = fs; - } else { - throw new IllegalStateException( - "Configuration includes multiple FileStorage instances: " - + fileStorage + ", and " + fs); - } + fileStorage = fs; } @Override @@ -133,15 +108,9 @@ public class ApplicationImpl implements Application { return contentTripleSource; } - @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasContentTripleSource") + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasContentTripleSource", minOccurs = 1, maxOccurs = 1) public void setContentTripleSource(ContentTripleSource source) { - if (contentTripleSource == null) { - contentTripleSource = source; - } else { - throw new IllegalStateException( - "Configuration includes multiple instances of ContentTripleSource: " - + contentTripleSource + ", and " + source); - } + contentTripleSource = source; } @Override @@ -149,15 +118,9 @@ public class ApplicationImpl implements Application { return configurationTripleSource; } - @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasConfigurationTripleSource") + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasConfigurationTripleSource", minOccurs = 1, maxOccurs = 1) public void setConfigurationTripleSource(ConfigurationTripleSource source) { - if (configurationTripleSource == null) { - configurationTripleSource = source; - } else { - throw new IllegalStateException( - "Configuration includes multiple instances of ConfigurationTripleSource: " - + configurationTripleSource + ", and " + source); - } + configurationTripleSource = source; } @Override @@ -165,47 +128,9 @@ public class ApplicationImpl implements Application { return tboxReasonerModule; } - @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasTBoxReasonerModule") + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasTBoxReasonerModule", minOccurs = 1, maxOccurs = 1) public void setTBoxReasonerModule(TBoxReasonerModule module) { - if (tboxReasonerModule == null) { - tboxReasonerModule = module; - } else { - throw new IllegalStateException( - "Configuration includes multiple instances of TBoxReasonerModule: " - + tboxReasonerModule + ", and " + module); - } - } - - @Validation - public void validate() throws Exception { - if (searchEngine == null) { - throw new IllegalStateException( - "Configuration did not include a SearchEngine."); - } - if (searchIndexer == null) { - throw new IllegalStateException( - "Configuration did not include a SearchIndexer."); - } - if (imageProcessor == null) { - throw new IllegalStateException( - "Configuration did not include an ImageProcessor."); - } - if (fileStorage == null) { - throw new IllegalStateException( - "Configuration did not include a FileStorage."); - } - if (contentTripleSource == null) { - throw new IllegalStateException( - "Configuration did not include a ContentTripleSource."); - } - if (configurationTripleSource == null) { - throw new IllegalStateException( - "Configuration did not include a ConfigurationTripleSource."); - } - if (tboxReasonerModule == null) { - throw new IllegalStateException( - "Configuration did not include a TBoxReasonerModule."); - } + tboxReasonerModule = module; } @Override diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/searchengine/InstrumentedSearchEngineWrapper.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/searchengine/InstrumentedSearchEngineWrapper.java index 72228d940..d4ea2382e 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/searchengine/InstrumentedSearchEngineWrapper.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/searchengine/InstrumentedSearchEngineWrapper.java @@ -26,7 +26,6 @@ import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchResponse; import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchResultDocument; import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchResultDocumentList; import edu.cornell.mannlib.vitro.webapp.utils.configuration.Property; -import edu.cornell.mannlib.vitro.webapp.utils.configuration.Validation; /** * Manages the life-cycle of the SearchEngine. Adds logging, controlled by @@ -40,26 +39,11 @@ public class InstrumentedSearchEngineWrapper implements SearchEngine { private volatile LifecycleState lifecycleState = NEW; - @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#wraps") + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#wraps", minOccurs = 1, maxOccurs = 1) public void setInnerEngine(SearchEngine inner) { - if (innerEngine == null) { - innerEngine = inner; - } else { - throw new IllegalStateException( - "Configuration includes multiple SearchEngine instancess: " - + innerEngine + ", and " + inner); - } + innerEngine = inner; } - @Validation - public void validate() throws Exception { - if (innerEngine == null) { - throw new IllegalStateException( - "Configuration did not include a wrapped SearchEngine."); - } - } - - /** * Complain unless ACTIVE. */ @@ -222,13 +206,13 @@ public class InstrumentedSearchEngineWrapper implements SearchEngine { return count; } } - + // ---------------------------------------------------------------------- // Helper classes // ---------------------------------------------------------------------- - - private static class SearchResponseForDocumentCount implements SearchResponse { + private static class SearchResponseForDocumentCount implements + SearchResponse { private final int count; public SearchResponseForDocumentCount(int count) { @@ -254,28 +238,29 @@ public class InstrumentedSearchEngineWrapper implements SearchEngine { public List getFacetFields() { return Collections.emptyList(); } - - private class EmptyDocumentListWithCount implements SearchResultDocumentList { - @Override - public Iterator iterator() { - return Collections.emptyIterator(); - } - - @Override - public int size() { - return 0; - } - - @Override - public long getNumFound() { - return count; - } - - @Override - public SearchResultDocument get(int i) { - throw new ArrayIndexOutOfBoundsException(i); - } + + private class EmptyDocumentListWithCount implements + SearchResultDocumentList { + @Override + public Iterator iterator() { + return Collections.emptyIterator(); + } + + @Override + public int size() { + return 0; + } + + @Override + public long getNumFound() { + return count; + } + + @Override + public SearchResultDocument get(int i) { + throw new ArrayIndexOutOfBoundsException(i); + } } } - + } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/searchindex/SearchIndexerImpl.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/searchindex/SearchIndexerImpl.java index e9a6a9a81..2b63123bc 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/searchindex/SearchIndexerImpl.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/searchindex/SearchIndexerImpl.java @@ -99,7 +99,7 @@ public class SearchIndexerImpl implements SearchIndexer { private Set uriFinders; private WebappDaoFactory wadf; - private boolean rebuildOnUnpause = false; + private boolean rebuildOnUnpause = false; private volatile int paused = 0; @@ -110,25 +110,14 @@ public class SearchIndexerImpl implements SearchIndexer { // ConfigurationBeanLoader methods. // ---------------------------------------------------------------------- - @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#threadPoolSize") + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#threadPoolSize", minOccurs = 1, maxOccurs = 1) public void setThreadPoolSize(String size) { - if (threadPoolSize == null) { - threadPoolSize = Integer.parseInt(size); - } else { - throw new IllegalStateException( - "Configuration includes multiple values for threadPoolSize: " - + threadPoolSize + ", and " + size); - } + threadPoolSize = Integer.parseInt(size); } @Validation public void validate() throws Exception { - if (threadPoolSize == null) { - throw new IllegalStateException( - "Configuration did not include a value for threadPoolSize."); - } else { - this.pool = new WorkerThreadPool(threadPoolSize); - } + this.pool = new WorkerThreadPool(threadPoolSize); } // ---------------------------------------------------------------------- @@ -241,7 +230,7 @@ public class SearchIndexerImpl implements SearchIndexer { } } - private synchronized void schedulePendingUris() { + private synchronized void schedulePendingUris() { if (paused == 0 && pendingUris.size() > 0) { scheduleUpdatesForUris(pendingUris); pendingUris = new ArrayList<>(); @@ -278,13 +267,14 @@ public class SearchIndexerImpl implements SearchIndexer { if (changes == null || changes.isEmpty()) { return; } - if (paused > 0) { + if (paused > 0) { if (addToPendingStatements(changes)) { return; } - } + } - scheduler.scheduleTask(new UpdateStatementsTask(new IndexerConfigImpl(this), changes)); + scheduler.scheduleTask(new UpdateStatementsTask(new IndexerConfigImpl( + this), changes)); log.debug("Scheduled updates for " + changes.size() + " statements."); } @@ -306,13 +296,14 @@ public class SearchIndexerImpl implements SearchIndexer { if (uris == null || uris.isEmpty()) { return; } - if (paused > 0) { + if (paused > 0) { if (pendingUris.addAll(uris)) { return; } - } + } - scheduler.scheduleTask(new UpdateUrisTask(new IndexerConfigImpl(this), uris)); + scheduler.scheduleTask(new UpdateUrisTask(new IndexerConfigImpl(this), + uris)); log.debug("Scheduled updates for " + uris.size() + " uris."); } @@ -332,13 +323,14 @@ public class SearchIndexerImpl implements SearchIndexer { return; } fireEvent(REBUILD_REQUESTED); - if (paused > 0) { + if (paused > 0) { // Make sure that we are rebuilding when we unpause // and don't bother noting any other changes until unpaused - rebuildOnUnpause = true; - return; - } - scheduler.scheduleTask(new RebuildIndexTask(new IndexerConfigImpl(this))); + rebuildOnUnpause = true; + return; + } + scheduler + .scheduleTask(new RebuildIndexTask(new IndexerConfigImpl(this))); log.debug("Scheduled a full rebuild."); } @@ -447,13 +439,13 @@ public class SearchIndexerImpl implements SearchIndexer { } public synchronized void scheduleTask(Task task) { - if (!started) { - deferredQueue.add(task); - log.debug("added task to deferred queue: " + task); - } else { + if (!started) { + deferredQueue.add(task); + log.debug("added task to deferred queue: " + task); + } else { taskQueue.scheduleTask(task); log.debug("added task to task queue: " + task); - } + } } public synchronized void start() { @@ -463,8 +455,9 @@ public class SearchIndexerImpl implements SearchIndexer { private void processDeferredTasks() { for (Task task : deferredQueue) { - taskQueue.scheduleTask(task); - log.debug("moved task from deferred queue to task queue: " + task); + taskQueue.scheduleTask(task); + log.debug("moved task from deferred queue to task queue: " + + task); } deferredQueue.clear(); } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/searchindex/documentBuilding/FieldBooster.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/searchindex/documentBuilding/FieldBooster.java index 5a86e1f65..7a3f0dad9 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/searchindex/documentBuilding/FieldBooster.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/searchindex/documentBuilding/FieldBooster.java @@ -17,27 +17,18 @@ public class FieldBooster implements DocumentModifier { private final List fieldNames = new ArrayList<>(); private volatile Float boost; - @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasTargetField") + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasTargetField", minOccurs = 1) public void addTargetField(String fieldName) { fieldNames.add(fieldName); } - @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasBoost") + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasBoost", minOccurs = 1) public void setBoost(float boost) { this.boost = boost; } @Validation public void validate() { - if (boost == null) { - throw new IllegalStateException( - "Configuration did not include a boost value."); - } - if (fieldNames.isEmpty()) { - throw new IllegalStateException( - "Configuration did not include a target field."); - } - Set uniqueFieldNames = new HashSet<>(fieldNames); List duplicateFieldNames = new ArrayList<>(fieldNames); for (String fn : uniqueFieldNames) { diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/searchindex/indexing/SelectQueryUriFinder.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/searchindex/indexing/SelectQueryUriFinder.java index a0e50797a..efaf41964 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/searchindex/indexing/SelectQueryUriFinder.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/searchindex/indexing/SelectQueryUriFinder.java @@ -74,7 +74,7 @@ public class SelectQueryUriFinder implements IndexingUriFinder, label = l; } - @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasSelectQuery") + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasSelectQuery", minOccurs = 1) public void addQuery(String query) { queries.add(query); } @@ -89,10 +89,6 @@ public class SelectQueryUriFinder implements IndexingUriFinder, if (label == null) { label = this.getClass().getSimpleName() + ":" + this.hashCode(); } - if (queries.isEmpty()) { - throw new IllegalStateException( - "Configuration contains no queries for " + label); - } } @Override diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/triplesource/impl/sparql/ContentTripleSourceSPARQL.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/triplesource/impl/sparql/ContentTripleSourceSPARQL.java index cc19fac1e..044492036 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/triplesource/impl/sparql/ContentTripleSourceSPARQL.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/triplesource/impl/sparql/ContentTripleSourceSPARQL.java @@ -19,7 +19,6 @@ import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceFactorySingle; import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.logging.LoggingRDFServiceFactory; import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.sparql.RDFServiceSparql; import edu.cornell.mannlib.vitro.webapp.utils.configuration.Property; -import edu.cornell.mannlib.vitro.webapp.utils.configuration.Validation; import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString; /** @@ -41,34 +40,14 @@ public class ContentTripleSourceSPARQL extends ContentTripleSource { private Dataset dataset; private ModelMaker modelMaker; - @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasEndpointURI") + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasEndpointURI", minOccurs = 1, maxOccurs = 1) public void setEndpointURI(String eUri) { - if (endpointURI == null) { - endpointURI = eUri; - } else { - throw new IllegalStateException( - "Configuration includes multiple instances of EndpointURI: " - + endpointURI + ", and " + eUri); - } + endpointURI = eUri; } - @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasUpdateEndpointURI") + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasUpdateEndpointURI", maxOccurs = 1) public void setUpdateEndpointURI(String ueUri) { - if (updateEndpointURI == null) { - updateEndpointURI = ueUri; - } else { - throw new IllegalStateException( - "Configuration includes multiple instances of UpdateEndpointURI: " - + updateEndpointURI + ", and " + ueUri); - } - } - - @Validation - public void validate() throws Exception { - if (endpointURI == null) { - throw new IllegalStateException( - "Configuration did not include an EndpointURI."); - } + updateEndpointURI = ueUri; } @Override diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/triplesource/impl/tdb/ContentTripleSourceTDB.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/triplesource/impl/tdb/ContentTripleSourceTDB.java index 4591559b0..595633252 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/triplesource/impl/tdb/ContentTripleSourceTDB.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/triplesource/impl/tdb/ContentTripleSourceTDB.java @@ -24,7 +24,6 @@ import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.jena.tdb.RDFServiceTDB; import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.logging.LoggingRDFServiceFactory; import edu.cornell.mannlib.vitro.webapp.servlet.setup.JenaDataSourceSetupBase; import edu.cornell.mannlib.vitro.webapp.utils.configuration.Property; -import edu.cornell.mannlib.vitro.webapp.utils.configuration.Validation; import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString; /** @@ -49,23 +48,9 @@ public class ContentTripleSourceTDB extends ContentTripleSource { private Dataset dataset; private ModelMaker modelMaker; - @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasTdbDirectory") + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasTdbDirectory", minOccurs = 1, maxOccurs = 1) public void setTdbPath(String path) { - if (tdbPath == null) { - tdbPath = path; - } else { - throw new IllegalStateException( - "Configuration includes multiple instances of TdbDirectory: " - + tdbPath + ", and " + path); - } - } - - @Validation - public void validate() throws Exception { - if (tdbPath == null) { - throw new IllegalStateException( - "Configuration did not include a TdbDirectory."); - } + tdbPath = path; } @Override @@ -106,7 +91,8 @@ public class ContentTripleSourceTDB extends ContentTripleSource { } private void checkForFirstTimeStartup() { - if (this.dataset.getNamedModel(ModelNames.TBOX_ASSERTIONS).getGraph().isEmpty()) { + if (this.dataset.getNamedModel(ModelNames.TBOX_ASSERTIONS).getGraph() + .isEmpty()) { JenaDataSourceSetupBase.thisIsFirstStartup(); } } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/triplesource/impl/virtuoso/ContentTripleSourceVirtuoso.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/triplesource/impl/virtuoso/ContentTripleSourceVirtuoso.java index 441279fb3..5cb4c0ce0 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/triplesource/impl/virtuoso/ContentTripleSourceVirtuoso.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/triplesource/impl/virtuoso/ContentTripleSourceVirtuoso.java @@ -7,7 +7,6 @@ import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.virtuoso.RDFServiceVirtuoso; import edu.cornell.mannlib.vitro.webapp.triplesource.impl.sparql.ContentTripleSourceSPARQL; import edu.cornell.mannlib.vitro.webapp.utils.configuration.Property; -import edu.cornell.mannlib.vitro.webapp.utils.configuration.Validation; import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString; /** @@ -19,54 +18,19 @@ public class ContentTripleSourceVirtuoso extends ContentTripleSourceSPARQL { private String username; private String password; - @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasBaseURI") + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasBaseURI", minOccurs = 1, maxOccurs = 1) public void setBaseUri(String uri) { - if (baseUri == null) { - baseUri = uri; - } else { - throw new IllegalStateException( - "Configuration includes multiple instances of BaseURI: " - + baseUri + ", and " + uri); - } + baseUri = uri; } - @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasUsername") + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasUsername", minOccurs = 1, maxOccurs = 1) public void setUsername(String user) { - if (username == null) { - username = user; - } else { - throw new IllegalStateException( - "Configuration includes multiple instances of Username: " - + username + ", and " + user); - } + username = user; } - @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasPassword") + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasPassword", minOccurs = 1, maxOccurs = 1) public void setPassword(String pass) { - if (password == null) { - password = pass; - } else { - throw new IllegalStateException( - "Configuration includes multiple instances of Password: " - + password + ", and " + pass); - } - } - - @Override - @Validation - public void validate() throws Exception { - if (baseUri == null) { - throw new IllegalStateException( - "Configuration did not include a BaseURI."); - } - if (username == null) { - throw new IllegalStateException( - "Configuration did not include a Username."); - } - if (password == null) { - throw new IllegalStateException( - "Configuration did not include a Password."); - } + password = pass; } @Override From ac6f8722d7ae8ee852ca3c48900c6f0bd1af8e4b Mon Sep 17 00:00:00 2001 From: Jim Blake Date: Tue, 31 May 2016 12:25:52 -0400 Subject: [PATCH 3/4] VIVO-1246 Move unit tests to the new location. --- .../utils/configuration/ConfigurationBeanLoaderTestBase.java | 0 .../configuration/ConfigurationBeanLoader_Cardinality_Test.java | 0 .../utils/configuration/ConfigurationBeanLoader_PropertyTest.java | 0 .../configuration/ConfigurationBeanLoader_ValidationTest.java | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename {webapp/test => api/src/test/java}/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoaderTestBase.java (100%) rename {webapp/test => api/src/test/java}/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_Cardinality_Test.java (100%) rename {webapp/test => api/src/test/java}/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_PropertyTest.java (100%) rename {webapp/test => api/src/test/java}/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_ValidationTest.java (100%) diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoaderTestBase.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoaderTestBase.java similarity index 100% rename from webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoaderTestBase.java rename to api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoaderTestBase.java diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_Cardinality_Test.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_Cardinality_Test.java similarity index 100% rename from webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_Cardinality_Test.java rename to api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_Cardinality_Test.java diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_PropertyTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_PropertyTest.java similarity index 100% rename from webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_PropertyTest.java rename to api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_PropertyTest.java diff --git a/webapp/test/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 similarity index 100% rename from webapp/test/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_ValidationTest.java rename to api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader_ValidationTest.java From 41ff46e771b1da456817cf8f2eadf26c1ceaacf6 Mon Sep 17 00:00:00 2001 From: Jim Blake Date: Tue, 21 Jun 2016 14:06:04 -0400 Subject: [PATCH 4/4] VIVO-1246 The documentation was in the wrong place. --- .../cornell/mannlib/vitro/webapp/utils/configuration/README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {webapp/src => api/src/main/java}/edu/cornell/mannlib/vitro/webapp/utils/configuration/README.md (100%) diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/README.md b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/README.md similarity index 100% rename from webapp/src/edu/cornell/mannlib/vitro/webapp/utils/configuration/README.md rename to api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/README.md