Create ConfigurationBeansLoader.
Also dependent classes and unit tests.
This commit is contained in:
parent
645bc92d99
commit
73b200aac1
13 changed files with 2151 additions and 0 deletions
|
@ -0,0 +1,139 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.utils.configuration;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import static com.hp.hpl.jena.rdf.model.ResourceFactory.*;
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import com.hp.hpl.jena.rdf.model.Model;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Resource;
|
||||||
|
import com.hp.hpl.jena.rdf.model.ResourceFactory;
|
||||||
|
import com.hp.hpl.jena.vocabulary.RDF;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.jena.Critical;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load one or more Configuration beans from a specified model.
|
||||||
|
*/
|
||||||
|
public class ConfigurationBeanLoader {
|
||||||
|
|
||||||
|
private static final String JAVA_URI_PREFIX = "java:";
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// utility methods
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
public static String toJavaUri(Class<?> clazz) {
|
||||||
|
return JAVA_URI_PREFIX + clazz.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isJavaUri(String uri) {
|
||||||
|
return uri.startsWith(JAVA_URI_PREFIX);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String fromJavaUri(String uri) {
|
||||||
|
if (!isJavaUri(uri)) {
|
||||||
|
throw new IllegalArgumentException("Not a java class URI: '" + uri
|
||||||
|
+ "'");
|
||||||
|
}
|
||||||
|
return uri.substring(JAVA_URI_PREFIX.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// the instance
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Must not be null. */
|
||||||
|
private final Model model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* May be null, but the loader will be unable to satisfy instances of
|
||||||
|
* ContextModelUser.
|
||||||
|
*/
|
||||||
|
private final ServletContext ctx;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* May be null, but the loader will be unable to satisfy instances of
|
||||||
|
* RequestModelUser.
|
||||||
|
*/
|
||||||
|
private final HttpServletRequest req;
|
||||||
|
|
||||||
|
public ConfigurationBeanLoader(Model model) {
|
||||||
|
this(model, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigurationBeanLoader(Model model, ServletContext ctx) {
|
||||||
|
this(model, ctx, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigurationBeanLoader(Model model, HttpServletRequest req) {
|
||||||
|
this(model,
|
||||||
|
(req == null) ? null : req.getSession().getServletContext(),
|
||||||
|
req);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConfigurationBeanLoader(Model model, ServletContext ctx,
|
||||||
|
HttpServletRequest req) {
|
||||||
|
if (model == null) {
|
||||||
|
throw new NullPointerException("model may not be null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.model = model;
|
||||||
|
this.req = req;
|
||||||
|
this.ctx = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the instance with this URI, if it is assignable to this class.
|
||||||
|
*/
|
||||||
|
public <T> T loadInstance(String uri, Class<T> resultClass)
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
if (uri == null) {
|
||||||
|
throw new NullPointerException("uri may not be null.");
|
||||||
|
}
|
||||||
|
if (resultClass == null) {
|
||||||
|
throw new NullPointerException("resultClass may not be null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ConfigurationRdf<T> parsedRdf = ConfigurationRdfParser.parse(model,
|
||||||
|
uri, resultClass);
|
||||||
|
WrappedInstance<T> wrapper = InstanceWrapper.wrap(parsedRdf
|
||||||
|
.getConcreteClass());
|
||||||
|
wrapper.satisfyInterfaces(ctx, req);
|
||||||
|
wrapper.setProperties(this, parsedRdf.getPropertyStatements());
|
||||||
|
wrapper.validate();
|
||||||
|
return wrapper.getInstance();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ConfigurationBeanLoaderException("Failed to load '" + uri
|
||||||
|
+ "'", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all of the resources with the specified class, and instantiate them.
|
||||||
|
*/
|
||||||
|
public <T> Set<T> loadAll(Class<T> resultClass)
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
Set<String> uris = new HashSet<>();
|
||||||
|
try (Critical section = Critical.read(model)) {
|
||||||
|
List<Resource> resources = model.listResourcesWithProperty(
|
||||||
|
RDF.type, createResource(toJavaUri(resultClass))).toList();
|
||||||
|
for (Resource r : resources) {
|
||||||
|
if (r.isURIResource()) {
|
||||||
|
uris.add(r.getURI());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<T> instances = new HashSet<>();
|
||||||
|
for (String uri : uris) {
|
||||||
|
instances.add(loadInstance(uri, resultClass));
|
||||||
|
}
|
||||||
|
return instances;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.utils.configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the loading of configuration beans did not succeed.
|
||||||
|
*/
|
||||||
|
public class ConfigurationBeanLoaderException extends Exception {
|
||||||
|
public ConfigurationBeanLoaderException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigurationBeanLoaderException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.utils.configuration;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.PropertyStatement;
|
||||||
|
|
||||||
|
public class ConfigurationRdf<T> {
|
||||||
|
private final Class<? extends T> concreteClass;
|
||||||
|
private final Set<PropertyStatement> properties;
|
||||||
|
|
||||||
|
public ConfigurationRdf(Class<? extends T> concreteClass,
|
||||||
|
Set<PropertyStatement> properties) {
|
||||||
|
this.concreteClass = concreteClass;
|
||||||
|
this.properties = Collections
|
||||||
|
.unmodifiableSet(new HashSet<>(properties));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<? extends T> getConcreteClass() {
|
||||||
|
return concreteClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<PropertyStatement> getPropertyStatements() {
|
||||||
|
return new HashSet<>(properties);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,251 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.utils.configuration;
|
||||||
|
|
||||||
|
import static com.hp.hpl.jena.rdf.model.ResourceFactory.createResource;
|
||||||
|
import static com.hp.hpl.jena.rdf.model.ResourceFactory.createStatement;
|
||||||
|
import static edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationBeanLoader.fromJavaUri;
|
||||||
|
import static edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationBeanLoader.isJavaUri;
|
||||||
|
import static edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationBeanLoader.toJavaUri;
|
||||||
|
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.hp.hpl.jena.rdf.model.Model;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Property;
|
||||||
|
import com.hp.hpl.jena.rdf.model.RDFNode;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Selector;
|
||||||
|
import com.hp.hpl.jena.rdf.model.SimpleSelector;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Statement;
|
||||||
|
import com.hp.hpl.jena.vocabulary.RDF;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.PropertyStatement;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.PropertyTypeException;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.jena.Critical;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the RDF for a single individual in the model to create a
|
||||||
|
* ConfigurationRdf object.
|
||||||
|
*/
|
||||||
|
public class ConfigurationRdfParser {
|
||||||
|
public static <T> ConfigurationRdf<T> parse(Model model, String uri,
|
||||||
|
Class<T> resultClass) throws InvalidConfigurationRdfException {
|
||||||
|
if (model == null) {
|
||||||
|
throw new NullPointerException("model may not be null.");
|
||||||
|
}
|
||||||
|
if (uri == null) {
|
||||||
|
throw new NullPointerException("uri may not be null.");
|
||||||
|
}
|
||||||
|
if (resultClass == null) {
|
||||||
|
throw new NullPointerException("resultClass may not be null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
confirmExistenceInModel(model, uri);
|
||||||
|
|
||||||
|
confirmEligibilityForResultClass(model, uri, resultClass);
|
||||||
|
|
||||||
|
Set<PropertyStatement> properties = loadProperties(model, uri);
|
||||||
|
|
||||||
|
Class<? extends T> concreteClass = determineConcreteClass(model, uri,
|
||||||
|
resultClass);
|
||||||
|
|
||||||
|
return new ConfigurationRdf<T>(concreteClass, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void confirmExistenceInModel(Model model, String uri)
|
||||||
|
throws InvalidConfigurationRdfException {
|
||||||
|
Selector s = new SimpleSelector(createResource(uri), null,
|
||||||
|
(RDFNode) null);
|
||||||
|
try (Critical section = Critical.read(model)) {
|
||||||
|
if (model.listStatements(s).toList().isEmpty()) {
|
||||||
|
throw individualDoesNotAppearInModel(uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void confirmEligibilityForResultClass(Model model,
|
||||||
|
String uri, Class<?> resultClass)
|
||||||
|
throws InvalidConfigurationRdfException {
|
||||||
|
Statement s = createStatement(createResource(uri), RDF.type,
|
||||||
|
createResource(toJavaUri(resultClass)));
|
||||||
|
try (Critical section = Critical.read(model)) {
|
||||||
|
if (!model.contains(s)) {
|
||||||
|
throw noTypeStatementForResultClass(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<PropertyStatement> loadProperties(Model model, String uri)
|
||||||
|
throws InvalidConfigurationRdfException {
|
||||||
|
Set<PropertyStatement> set = new HashSet<>();
|
||||||
|
|
||||||
|
try (Critical section = Critical.read(model)) {
|
||||||
|
List<Statement> rawStatements = model.listStatements(
|
||||||
|
model.getResource(uri), (Property) null, (RDFNode) null)
|
||||||
|
.toList();
|
||||||
|
if (rawStatements.isEmpty()) {
|
||||||
|
throw noRdfStatements(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Statement s : rawStatements) {
|
||||||
|
if (s.getPredicate().equals(RDF.type)) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
set.add(PropertyType.createPropertyStatement(s));
|
||||||
|
} catch (PropertyTypeException e) {
|
||||||
|
throw new InvalidConfigurationRdfException(
|
||||||
|
"Invalid property statement on '" + uri + "'",
|
||||||
|
e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> Class<? extends T> determineConcreteClass(Model model,
|
||||||
|
String uri, Class<T> resultClass)
|
||||||
|
throws InvalidConfigurationRdfException {
|
||||||
|
Set<Class<? extends T>> concreteClasses = new HashSet<>();
|
||||||
|
|
||||||
|
try (Critical section = Critical.read(model)) {
|
||||||
|
for (RDFNode node : model.listObjectsOfProperty(
|
||||||
|
createResource(uri), RDF.type).toSet()) {
|
||||||
|
if (!node.isURIResource()) {
|
||||||
|
throw typeMustBeUriResource(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
String typeUri = node.asResource().getURI();
|
||||||
|
if (!isConcreteClass(typeUri)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
concreteClasses.add(processTypeUri(typeUri, resultClass));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (concreteClasses.isEmpty()) {
|
||||||
|
throw noConcreteClasses(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (concreteClasses.size() > 1) {
|
||||||
|
throw tooManyConcreteClasses(uri, concreteClasses);
|
||||||
|
}
|
||||||
|
|
||||||
|
return concreteClasses.iterator().next();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isConcreteClass(String typeUri)
|
||||||
|
throws InvalidConfigurationRdfException {
|
||||||
|
try {
|
||||||
|
if (!isJavaUri(typeUri)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Class<?> clazz = Class.forName(fromJavaUri(typeUri));
|
||||||
|
if (clazz.isInterface()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Modifier.isAbstract(clazz.getModifiers())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (ClassNotFoundException | ExceptionInInitializerError e) {
|
||||||
|
throw failedToLoadClass(typeUri, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static <T> Class<? extends T> processTypeUri(String typeUri,
|
||||||
|
Class<T> resultClass) throws InvalidConfigurationRdfException {
|
||||||
|
try {
|
||||||
|
Class<?> clazz = Class.forName(fromJavaUri(typeUri));
|
||||||
|
if (!resultClass.isAssignableFrom(clazz)) {
|
||||||
|
throw notAssignable(resultClass, clazz);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
clazz.getConstructor();
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
throw noZeroArgumentConstructor(clazz);
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
throw constructorNotPublic(clazz);
|
||||||
|
}
|
||||||
|
return (Class<? extends T>) clazz;
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw failedToLoadClass(typeUri, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InvalidConfigurationRdfException individualDoesNotAppearInModel(
|
||||||
|
String uri) {
|
||||||
|
return new InvalidConfigurationRdfException(
|
||||||
|
"The model contains no statements about '" + uri + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InvalidConfigurationRdfException noConcreteClasses(String uri) {
|
||||||
|
return new InvalidConfigurationRdfException(
|
||||||
|
"No concrete class is declared for '" + uri + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InvalidConfigurationRdfException tooManyConcreteClasses(
|
||||||
|
String uri, Set<?> concreteClasses) {
|
||||||
|
return new InvalidConfigurationRdfException("'" + uri
|
||||||
|
+ "' is declared with more than one " + "concrete class: "
|
||||||
|
+ concreteClasses);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InvalidConfigurationRdfException notAssignable(
|
||||||
|
Class<?> resultClass, Class<?> clazz) {
|
||||||
|
return new InvalidConfigurationRdfException(clazz
|
||||||
|
+ " cannot be assigned to " + resultClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InvalidConfigurationRdfException noZeroArgumentConstructor(
|
||||||
|
Class<?> clazz) {
|
||||||
|
return new InvalidConfigurationRdfException("Can't instantiate '"
|
||||||
|
+ clazz + "': no zero-argument constructor.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InvalidConfigurationRdfException constructorNotPublic(
|
||||||
|
Class<?> clazz) {
|
||||||
|
return new InvalidConfigurationRdfException("Can't instantiate '"
|
||||||
|
+ clazz + "': zero-argument constructor is not public.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InvalidConfigurationRdfException failedToLoadClass(
|
||||||
|
String typeUri, Throwable e) {
|
||||||
|
return new InvalidConfigurationRdfException("Can't load this type: '"
|
||||||
|
+ typeUri + "'", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InvalidConfigurationRdfException typeMustBeUriResource(
|
||||||
|
RDFNode node) {
|
||||||
|
return new InvalidConfigurationRdfException(
|
||||||
|
"Type must be a URI Resource: " + node);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InvalidConfigurationRdfException noTypeStatementForResultClass(
|
||||||
|
Statement s) {
|
||||||
|
return new InvalidConfigurationRdfException(
|
||||||
|
"A type statement is required: '" + s);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InvalidConfigurationRdfException noRdfStatements(String uri) {
|
||||||
|
return new InvalidConfigurationRdfException("'" + uri
|
||||||
|
+ "' does not appear as the subject of any "
|
||||||
|
+ "statements in the model.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class InvalidConfigurationRdfException extends Exception {
|
||||||
|
public InvalidConfigurationRdfException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidConfigurationRdfException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.utils.configuration;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.modelaccess.ContextModelAccess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the ConfigurationBeanLoader creates an instance of this class, it will
|
||||||
|
* call this method, supplying the RDF models from the context.
|
||||||
|
*/
|
||||||
|
public interface ContextModelsUser {
|
||||||
|
void setContextModels(ContextModelAccess models);
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.utils.configuration;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.PropertyMethod;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.PropertyTypeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the annotations on this class and package them with a newly-created
|
||||||
|
* instance of the class.
|
||||||
|
*/
|
||||||
|
public class InstanceWrapper {
|
||||||
|
public static <T> WrappedInstance<T> wrap(Class<? extends T> concreteClass)
|
||||||
|
throws InstanceWrapperException {
|
||||||
|
return new WrappedInstance<T>(createInstance(concreteClass),
|
||||||
|
parsePropertyAnnotations(concreteClass),
|
||||||
|
parseValidationAnnotations(concreteClass));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> T createInstance(Class<? extends T> concreteClass)
|
||||||
|
throws InstanceWrapperException {
|
||||||
|
try {
|
||||||
|
return concreteClass.newInstance();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InstanceWrapperException("Failed to create an instance.",
|
||||||
|
e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, PropertyMethod> parsePropertyAnnotations(
|
||||||
|
Class<?> concreteClass) throws InstanceWrapperException {
|
||||||
|
Map<String, PropertyMethod> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<Method> parseValidationAnnotations(Class<?> concreteClass)
|
||||||
|
throws InstanceWrapperException {
|
||||||
|
Set<Method> methods = new HashSet<>();
|
||||||
|
for (Method method : concreteClass.getDeclaredMethods()) {
|
||||||
|
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.add(method);
|
||||||
|
}
|
||||||
|
return methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class InstanceWrapperException extends Exception {
|
||||||
|
public InstanceWrapperException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InstanceWrapperException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.utils.configuration;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The annotated method should be called each time a property with a matching
|
||||||
|
* URI is found on the bean.
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
public @interface Property {
|
||||||
|
String uri();
|
||||||
|
}
|
|
@ -0,0 +1,243 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
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 java.lang.reflect.InvocationTargetException;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An enumeration of the types of properties that the ConfigurationBeanLoader
|
||||||
|
* will support.
|
||||||
|
*
|
||||||
|
* Also, classes that represent the Java methods and RDF statements associated
|
||||||
|
* with those types.
|
||||||
|
*/
|
||||||
|
public enum PropertyType {
|
||||||
|
RESOURCE {
|
||||||
|
@Override
|
||||||
|
public PropertyStatement buildPropertyStatement(Statement s) {
|
||||||
|
return new ResourcePropertyStatement(s.getPredicate(), s
|
||||||
|
.getObject().asResource().getURI());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PropertyMethod buildPropertyMethod(Method method) {
|
||||||
|
return new ResourcePropertyMethod(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
STRING {
|
||||||
|
@Override
|
||||||
|
public PropertyStatement buildPropertyStatement(Statement s) {
|
||||||
|
return new StringPropertyStatement(s.getPredicate(), s.getObject()
|
||||||
|
.asLiteral().getString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PropertyMethod buildPropertyMethod(Method method) {
|
||||||
|
return new StringPropertyMethod(method);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
FLOAT {
|
||||||
|
@Override
|
||||||
|
public PropertyStatement buildPropertyStatement(Statement s) {
|
||||||
|
return new FloatPropertyStatement(s.getPredicate(), s.getObject()
|
||||||
|
.asLiteral().getFloat());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PropertyMethod buildPropertyMethod(Method method) {
|
||||||
|
return new FloatPropertyMethod(method);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static PropertyType typeForObject(RDFNode object)
|
||||||
|
throws PropertyTypeException {
|
||||||
|
if (object.isURIResource()) {
|
||||||
|
return RESOURCE;
|
||||||
|
}
|
||||||
|
if (object.isLiteral()) {
|
||||||
|
Literal literal = object.asLiteral();
|
||||||
|
RDFDatatype datatype = literal.getDatatype();
|
||||||
|
if (datatype == null || datatype.equals(XSDstring)) {
|
||||||
|
return STRING;
|
||||||
|
}
|
||||||
|
if (datatype.equals(XSDfloat)) {
|
||||||
|
return FLOAT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new PropertyTypeException("Unsupported datatype on object: "
|
||||||
|
+ object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PropertyType typeForParameterType(Class<?> parameterType)
|
||||||
|
throws PropertyTypeException {
|
||||||
|
if (Float.TYPE.equals(parameterType)) {
|
||||||
|
return FLOAT;
|
||||||
|
}
|
||||||
|
if (String.class.equals(parameterType)) {
|
||||||
|
return STRING;
|
||||||
|
}
|
||||||
|
if (!parameterType.isPrimitive()) {
|
||||||
|
return RESOURCE;
|
||||||
|
}
|
||||||
|
throw new PropertyTypeException(
|
||||||
|
"Unsupported parameter type on method: " + parameterType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PropertyStatement createPropertyStatement(Statement s)
|
||||||
|
throws PropertyTypeException {
|
||||||
|
PropertyType type = PropertyType.typeForObject(s.getObject());
|
||||||
|
return type.buildPropertyStatement(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PropertyMethod createPropertyMethod(Method method)
|
||||||
|
throws PropertyTypeException {
|
||||||
|
Class<?> parameterType = method.getParameterTypes()[0];
|
||||||
|
PropertyType type = PropertyType.typeForParameterType(parameterType);
|
||||||
|
return type.buildPropertyMethod(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract PropertyStatement buildPropertyStatement(Statement s);
|
||||||
|
|
||||||
|
protected abstract PropertyMethod buildPropertyMethod(Method method);
|
||||||
|
|
||||||
|
public static abstract class PropertyStatement {
|
||||||
|
private final PropertyType type;
|
||||||
|
private final String predicateUri;
|
||||||
|
|
||||||
|
public PropertyStatement(PropertyType type, Property predicate) {
|
||||||
|
this.type = type;
|
||||||
|
this.predicateUri = predicate.getURI();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPredicateUri() {
|
||||||
|
return predicateUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Object getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ResourcePropertyStatement extends PropertyStatement {
|
||||||
|
private final String objectUri;
|
||||||
|
|
||||||
|
public ResourcePropertyStatement(Property predicate, String objectUri) {
|
||||||
|
super(RESOURCE, predicate);
|
||||||
|
this.objectUri = objectUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValue() {
|
||||||
|
return objectUri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class StringPropertyStatement extends PropertyStatement {
|
||||||
|
private final String string;
|
||||||
|
|
||||||
|
public StringPropertyStatement(Property predicate, String string) {
|
||||||
|
super(STRING, predicate);
|
||||||
|
this.string = string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValue() {
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FloatPropertyStatement extends PropertyStatement {
|
||||||
|
private final float f;
|
||||||
|
|
||||||
|
public FloatPropertyStatement(Property predicate, float f) {
|
||||||
|
super(FLOAT, predicate);
|
||||||
|
this.f = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float getValue() {
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static abstract class PropertyMethod {
|
||||||
|
protected final PropertyType type;
|
||||||
|
protected final Method method;
|
||||||
|
|
||||||
|
public PropertyMethod(PropertyType type, Method method) {
|
||||||
|
this.type = type;
|
||||||
|
this.method = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Method getMethod() {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<?> getParameterType() {
|
||||||
|
return method.getParameterTypes()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void confirmCompatible(PropertyStatement ps)
|
||||||
|
throws PropertyTypeException {
|
||||||
|
if (type != ps.getType()) {
|
||||||
|
throw new PropertyTypeException(
|
||||||
|
"Can't apply statement of type " + ps.getType()
|
||||||
|
+ " to a method of type " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void invoke(Object instance, Object value)
|
||||||
|
throws PropertyTypeException {
|
||||||
|
try {
|
||||||
|
method.invoke(instance, value);
|
||||||
|
} catch (IllegalAccessException | IllegalArgumentException
|
||||||
|
| InvocationTargetException e) {
|
||||||
|
throw new PropertyTypeException("Property method failed.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ResourcePropertyMethod extends PropertyMethod {
|
||||||
|
public ResourcePropertyMethod(Method method) {
|
||||||
|
super(RESOURCE, method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class StringPropertyMethod extends PropertyMethod {
|
||||||
|
public StringPropertyMethod(Method method) {
|
||||||
|
super(STRING, method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FloatPropertyMethod extends PropertyMethod {
|
||||||
|
public FloatPropertyMethod(Method method) {
|
||||||
|
super(FLOAT, method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PropertyTypeException extends Exception {
|
||||||
|
public PropertyTypeException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyTypeException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.utils.configuration;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.modelaccess.RequestModelAccess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the ConfigurationBeanLoader creates an instance of this class, it will
|
||||||
|
* call this method, supplying the RDF models for the current HTTP request.
|
||||||
|
*/
|
||||||
|
public interface RequestModelsUser {
|
||||||
|
void setRequestModels(RequestModelAccess models);
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.utils.configuration;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The annotated method should be called after the bean is instantiated, to
|
||||||
|
* confirm that the bean is correctly formed.
|
||||||
|
*
|
||||||
|
* If the bean is not correctly formed, throw a runtime exception.
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
public @interface Validation {
|
||||||
|
// No elements
|
||||||
|
}
|
|
@ -0,0 +1,135 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
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.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.PropertyMethod;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.PropertyStatement;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.PropertyTypeException;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.ResourcePropertyStatement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An instance of a ConfigurationBean, packaged with the distilled information
|
||||||
|
* about the annotated methods on the class.
|
||||||
|
*/
|
||||||
|
public class WrappedInstance<T> {
|
||||||
|
private final T instance;
|
||||||
|
private final Map<String, PropertyMethod> propertyMethods;
|
||||||
|
private final Set<Method> validationMethods;
|
||||||
|
|
||||||
|
public WrappedInstance(T instance,
|
||||||
|
Map<String, PropertyMethod> propertyMethods,
|
||||||
|
Set<Method> validationMethods) {
|
||||||
|
this.instance = instance;
|
||||||
|
this.propertyMethods = propertyMethods;
|
||||||
|
this.validationMethods = validationMethods;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The loader calls this as soon as the instance is created.
|
||||||
|
*
|
||||||
|
* If the loader did not have access to a request object, then req will be
|
||||||
|
* null. If the instance expects request models, an exception will be
|
||||||
|
* thrown.
|
||||||
|
*/
|
||||||
|
public void satisfyInterfaces(ServletContext ctx, HttpServletRequest req)
|
||||||
|
throws ResourceUnavailableException {
|
||||||
|
if (instance instanceof ContextModelsUser) {
|
||||||
|
if (ctx == null) {
|
||||||
|
throw new ResourceUnavailableException("Cannot satisfy "
|
||||||
|
+ "ContextModelsUser interface: context not available.");
|
||||||
|
} else {
|
||||||
|
ContextModelsUser cmu = (ContextModelsUser) instance;
|
||||||
|
cmu.setContextModels(ModelAccess.on(ctx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (instance instanceof RequestModelsUser) {
|
||||||
|
if (req == null) {
|
||||||
|
throw new ResourceUnavailableException("Cannot satisfy "
|
||||||
|
+ "RequestModelsUser interface: request not available.");
|
||||||
|
} else {
|
||||||
|
RequestModelsUser rmu = (RequestModelsUser) instance;
|
||||||
|
rmu.setRequestModels(ModelAccess.on(req));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The loader provides the distilled property statements from the RDF, to
|
||||||
|
* populate the instance.
|
||||||
|
*/
|
||||||
|
public void setProperties(ConfigurationBeanLoader loader,
|
||||||
|
Collection<PropertyStatement> propertyStatements)
|
||||||
|
throws PropertyTypeException, NoSuchPropertyMethodException,
|
||||||
|
ConfigurationBeanLoaderException {
|
||||||
|
for (PropertyStatement ps : propertyStatements) {
|
||||||
|
PropertyMethod pm = propertyMethods.get(ps.getPredicateUri());
|
||||||
|
if (pm == null) {
|
||||||
|
throw new NoSuchPropertyMethodException(ps);
|
||||||
|
}
|
||||||
|
|
||||||
|
pm.confirmCompatible(ps);
|
||||||
|
|
||||||
|
if (ps instanceof ResourcePropertyStatement) {
|
||||||
|
ResourcePropertyStatement rps = (ResourcePropertyStatement) ps;
|
||||||
|
Object subordinate = loader.loadInstance(rps.getValue(),
|
||||||
|
pm.getParameterType());
|
||||||
|
pm.invoke(instance, subordinate);
|
||||||
|
} else {
|
||||||
|
pm.invoke(instance, ps.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After the interfaces have been satisfied and the instance has been
|
||||||
|
* populated, call any validation methods to see whether the instance is
|
||||||
|
* viable.
|
||||||
|
*/
|
||||||
|
public void validate() throws ValidationFailedException {
|
||||||
|
for (Method method : validationMethods) {
|
||||||
|
try {
|
||||||
|
method.invoke(instance);
|
||||||
|
} catch (IllegalAccessException | IllegalArgumentException
|
||||||
|
| InvocationTargetException e) {
|
||||||
|
throw new ValidationFailedException(
|
||||||
|
"Error executing validation method '" + method + "'", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Once satisfied, populated, and validated, the instance is ready to go.
|
||||||
|
*/
|
||||||
|
public T getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ResourceUnavailableException extends Exception {
|
||||||
|
public ResourceUnavailableException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ValidationFailedException extends Exception {
|
||||||
|
public ValidationFailedException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class NoSuchPropertyMethodException extends Exception {
|
||||||
|
public NoSuchPropertyMethodException(PropertyStatement ps) {
|
||||||
|
super("No property method for '" + ps.getPredicateUri() + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.testing;
|
||||||
|
|
||||||
|
import static com.hp.hpl.jena.rdf.model.ResourceFactory.createLangLiteral;
|
||||||
|
import static com.hp.hpl.jena.rdf.model.ResourceFactory.createPlainLiteral;
|
||||||
|
import static com.hp.hpl.jena.rdf.model.ResourceFactory.createProperty;
|
||||||
|
import static com.hp.hpl.jena.rdf.model.ResourceFactory.createResource;
|
||||||
|
import static com.hp.hpl.jena.rdf.model.ResourceFactory.createStatement;
|
||||||
|
import static com.hp.hpl.jena.rdf.model.ResourceFactory.createTypedLiteral;
|
||||||
|
|
||||||
|
import java.util.SortedSet;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import com.hp.hpl.jena.datatypes.xsd.XSDDatatype;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Model;
|
||||||
|
import com.hp.hpl.jena.rdf.model.ModelFactory;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Statement;
|
||||||
|
import com.hp.hpl.jena.vocabulary.RDF;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Just some helper methods for Test classes that work with models.
|
||||||
|
*/
|
||||||
|
public class ModelUtilitiesTestHelper {
|
||||||
|
public static Model model(Statement... stmts) {
|
||||||
|
return ModelFactory.createDefaultModel().add(stmts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Statement typeStatement(String subjectUri, String classUri) {
|
||||||
|
return createStatement(createResource(subjectUri), RDF.type,
|
||||||
|
createResource(classUri));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Statement objectProperty(String subjectUri,
|
||||||
|
String propertyUri, String objectUri) {
|
||||||
|
return createStatement(createResource(subjectUri),
|
||||||
|
createProperty(propertyUri), createResource(objectUri));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Statement dataProperty(String subjectUri, String propertyUri,
|
||||||
|
String objectValue) {
|
||||||
|
return createStatement(createResource(subjectUri),
|
||||||
|
createProperty(propertyUri), createPlainLiteral(objectValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Statement dataProperty(String subjectUri, String propertyUri,
|
||||||
|
Object objectValue, XSDDatatype dataType) {
|
||||||
|
return createStatement(createResource(subjectUri),
|
||||||
|
createProperty(propertyUri),
|
||||||
|
createTypedLiteral(String.valueOf(objectValue), dataType));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Statement dataProperty(String subjectUri, String propertyUri,
|
||||||
|
String objectValue, String language) {
|
||||||
|
return createStatement(createResource(subjectUri),
|
||||||
|
createProperty(propertyUri),
|
||||||
|
createLangLiteral(objectValue, language));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SortedSet<String> modelToStrings(Model m) {
|
||||||
|
SortedSet<String> set = new TreeSet<>();
|
||||||
|
for (Statement stmt : m.listStatements().toList()) {
|
||||||
|
set.add(stmt.toString());
|
||||||
|
}
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue