diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader.java index 515269b5e4..10b4510db7 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoader.java @@ -4,8 +4,10 @@ import static org.apache.jena.rdf.model.ResourceFactory.createResource; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.TreeSet; @@ -32,6 +34,9 @@ public class ConfigurationBeanLoader { private static final String JAVA_URI_PREFIX = "java:"; + Map instancesMap = new HashMap(); + + // ---------------------------------------------------------------------- // utility methods // ---------------------------------------------------------------------- @@ -135,7 +140,14 @@ private ConfigurationBeanLoader(LockableModel locking, ServletContext ctx, /** * Load the instance with this URI, if it is assignable to this class. */ - public T loadInstance(String uri, Class resultClass) + public T loadInstance(String uri, Class resultClass) throws ConfigurationBeanLoaderException { + instancesMap.clear(); + T result = loadSubordinateInstance(uri, resultClass); + instancesMap.clear(); + return result; + } + + protected T loadSubordinateInstance(String uri, Class resultClass) throws ConfigurationBeanLoaderException { if (uri == null) { throw new NullPointerException("uri may not be null."); @@ -143,7 +155,15 @@ public T loadInstance(String uri, Class resultClass) if (resultClass == null) { throw new NullPointerException("resultClass may not be null."); } - + if (instancesMap.containsKey(uri)) { + try { + T t = (T) instancesMap.get(uri); + return t; + } catch (ClassCastException e) { + throw new ConfigurationBeanLoaderException(uri, e); + } + } + try { ConfigurationRdf parsedRdf = ConfigurationRdfParser .parse(locking, uri, resultClass); @@ -151,6 +171,7 @@ public T loadInstance(String uri, Class resultClass) .wrap(parsedRdf.getConcreteClass()); wrapper.satisfyInterfaces(ctx, req); wrapper.checkCardinality(parsedRdf.getPropertyStatements()); + instancesMap.put(uri, wrapper.getInstance()); wrapper.setProperties(this, parsedRdf.getPropertyStatements()); wrapper.validate(); return wrapper.getInstance(); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/PropertyType.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/PropertyType.java index 07de259cd4..4c69e3b9e6 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/PropertyType.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/PropertyType.java @@ -2,11 +2,6 @@ package edu.cornell.mannlib.vitro.webapp.utils.configuration; -import static org.apache.jena.datatypes.xsd.XSDDatatype.XSDfloat; -import static org.apache.jena.datatypes.xsd.XSDDatatype.XSDstring; -import static org.apache.jena.datatypes.xsd.XSDDatatype.XSDdateTime; -import static org.apache.jena.datatypes.xsd.XSDDatatype.XSDboolean; - import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -16,6 +11,8 @@ import org.apache.jena.rdf.model.RDFNode; import org.apache.jena.rdf.model.Statement; +import static org.apache.jena.datatypes.xsd.XSDDatatype.*; + /** * An enumeration of the types of properties that the ConfigurationBeanLoader * will support. @@ -32,8 +29,7 @@ public PropertyStatement buildPropertyStatement(Statement s) { } @Override - protected PropertyMethod buildPropertyMethod(Method method, - Property annotation) { + protected PropertyMethod buildPropertyMethod(Method method, Property annotation) { return new ResourcePropertyMethod(method, annotation); } @@ -46,8 +42,7 @@ public PropertyStatement buildPropertyStatement(Statement s) { } @Override - protected PropertyMethod buildPropertyMethod(Method method, - Property annotation) { + protected PropertyMethod buildPropertyMethod(Method method, Property annotation) { return new StringPropertyMethod(method, annotation); } }, @@ -59,11 +54,22 @@ public PropertyStatement buildPropertyStatement(Statement s) { } @Override - protected PropertyMethod buildPropertyMethod(Method method, - Property annotation) { + protected PropertyMethod buildPropertyMethod(Method method, Property annotation) { return new FloatPropertyMethod(method, annotation); } - }, + }, + INTEGER { + @Override + public PropertyStatement buildPropertyStatement(Statement s) { + return new IntegerPropertyStatement(s.getPredicate().getURI(), s + .getObject().asLiteral().getInt()); + } + + @Override + protected PropertyMethod buildPropertyMethod(Method method, Property annotation) { + return new IntegerPropertyMethod(method, annotation); + } + }, BOOLEAN{ @Override public PropertyStatement buildPropertyStatement(Statement s) { @@ -72,8 +78,7 @@ public PropertyStatement buildPropertyStatement(Statement s) { } @Override - protected PropertyMethod buildPropertyMethod(Method method, - Property annotation) { + protected PropertyMethod buildPropertyMethod(Method method, Property annotation) { return new BooleanPropertyMethod(method, annotation); } }; @@ -93,9 +98,14 @@ public static PropertyType typeForObject(RDFNode object) datatype.equals(XSDdateTime)) { return STRING; } - if (datatype.equals(XSDfloat)) { + if (datatype.equals(XSDfloat) || + datatype.equals(XSDdecimal)){ return FLOAT; } + if (datatype.equals(XSDint) || + datatype.equals(XSDinteger)) { + return INTEGER; + } if (datatype.equals(XSDboolean)) { return BOOLEAN; } @@ -109,6 +119,9 @@ public static PropertyType typeForParameterType(Class parameterType) if (Float.TYPE.equals(parameterType)) { return FLOAT; } + if (Integer.TYPE.equals(parameterType)) { + return INTEGER; + } if (Boolean.TYPE.equals(parameterType)) { return BOOLEAN; } @@ -128,8 +141,7 @@ public static PropertyStatement createPropertyStatement(Statement s) return type.buildPropertyStatement(s); } - public static PropertyMethod createPropertyMethod(Method method, - Property annotation) 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, annotation); @@ -201,6 +213,20 @@ public Float getValue() { return f; } } + + public static class IntegerPropertyStatement extends PropertyStatement { + private final int i; + + public IntegerPropertyStatement(String predicateUri, int i) { + super(INTEGER, predicateUri); + this.i = i; + } + + @Override + public Integer getValue() { + return i; + } + } public static class BooleanPropertyStatement extends PropertyStatement { private final Boolean bool; @@ -260,13 +286,20 @@ public int getMaxOccurs() { public void confirmCompatible(PropertyStatement ps) throws PropertyTypeException { - if (type != ps.getType()) { + if (type != ps.getType() && + ! (isSubtype(ps.getType(), type))){ throw new PropertyTypeException( "Can't apply statement of type " + ps.getType() + " to a method of type " + type); } } + private boolean isSubtype(PropertyType subType, PropertyType superType){ + if (subType.equals(INTEGER) && superType.equals(FLOAT)) + return true; + return false; + } + public void invoke(Object instance, Object value) throws PropertyTypeException { try { @@ -296,6 +329,12 @@ public FloatPropertyMethod(Method method, Property annotation) { super(FLOAT, method, annotation); } } + + public static class IntegerPropertyMethod extends PropertyMethod { + public IntegerPropertyMethod(Method method, Property annotation) { + super(INTEGER, method, annotation); + } + } public static class BooleanPropertyMethod extends PropertyMethod { public BooleanPropertyMethod(Method method, Property annotation) { diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/WrappedInstance.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/WrappedInstance.java index 9e889426ce..df04470014 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/WrappedInstance.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/WrappedInstance.java @@ -130,8 +130,7 @@ public void setProperties(ConfigurationBeanLoader loader, if (ps instanceof ResourcePropertyStatement) { ResourcePropertyStatement rps = (ResourcePropertyStatement) ps; - Object subordinate = loader.loadInstance(rps.getValue(), - pm.getParameterType()); + Object subordinate = loader.loadSubordinateInstance(rps.getValue(), pm.getParameterType()); pm.invoke(instance, subordinate); } else { pm.invoke(instance, ps.getValue()); diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoaderTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoaderTest.java index bfd88db4a4..dc6552cb94 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoaderTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/configuration/ConfigurationBeanLoaderTest.java @@ -9,6 +9,7 @@ import static org.apache.jena.datatypes.xsd.XSDDatatype.XSDfloat; import static org.apache.jena.datatypes.xsd.XSDDatatype.XSDstring; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -24,6 +25,7 @@ import org.junit.Ignore; import org.junit.Test; +import edu.cornell.mannlib.vitro.webapp.dynapi.components.OperationalStep; import edu.cornell.mannlib.vitro.webapp.modelaccess.ContextModelAccess; import edu.cornell.mannlib.vitro.webapp.modelaccess.RequestModelAccess; import edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationRdfParser.InvalidConfigurationRdfException; @@ -31,13 +33,6 @@ import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.PropertyTypeException; import edu.cornell.mannlib.vitro.webapp.utils.configuration.WrappedInstance.ResourceUnavailableException; -/** - * TODO - * - * Circularity prevention. Before setting properties, create a WeakMap of - * instances by URIs, so if a property refers to a created instance, we just - * pass it in. - */ public class ConfigurationBeanLoaderTest extends ConfigurationBeanLoaderTestBase { @@ -394,6 +389,19 @@ public void simpleSuccessIgnoringExtraProperties() throws ConfigurationBeanLoade public static class SimpleSuccess { // Nothing of interest. } + + public static class Friend { + + public Friend() { + + } + Friend friend; + + @Property(uri = "http://set.friend/property") + public void setFriend(Friend friend) { + this.friend = friend; + } + } // -------------------------------------------- @@ -673,6 +681,21 @@ public void loadAll_oneResult_success() Set instances = loader.loadAll(SimpleSuccess.class); assertEquals(1, instances.size()); } + + // -------------------------------------------- + + @Test + public void loop_test() throws ConfigurationBeanLoaderException { + model.add(new Statement[] { + typeStatement("http://friend.instance/one", toJavaUri(Friend.class)), + typeStatement("http://friend.instance/two", toJavaUri(Friend.class)), + objectProperty("http://friend.instance/one", "http://set.friend/property", "http://friend.instance/two"), + objectProperty("http://friend.instance/two", "http://set.friend/property", "http://friend.instance/one") }); + + Friend friend = loader.loadInstance("http://friend.instance/one", Friend.class); + assertNotEquals(friend, friend.friend); + assertEquals(friend, friend.friend.friend); + } // --------------------------------------------