VIVO-823 Create some tests for the VitroModelFactory
Make changes as determined by the tests, to BulkUpdatingOntModel as well. Add debug statements to ModelSynchronizer.
This commit is contained in:
parent
04f763109e
commit
63ed82cef9
5 changed files with 982 additions and 59 deletions
|
@ -3,79 +3,115 @@
|
|||
package edu.cornell.mannlib.vitro.webapp.dao.jena;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.hp.hpl.jena.rdf.model.Model;
|
||||
import com.hp.hpl.jena.rdf.model.ModelChangedListener;
|
||||
import com.hp.hpl.jena.rdf.model.Statement;
|
||||
import com.hp.hpl.jena.rdf.model.StmtIterator;
|
||||
import com.hp.hpl.jena.rdf.model.impl.StmtIteratorImpl;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.event.CloseEvent;
|
||||
|
||||
/**
|
||||
* Simple change listener to keep a model (the 'synchronizee') in synch with the model with which it is registered.
|
||||
* Simple change listener to keep a model (the 'synchronizee') in synch with the
|
||||
* model with which it is registered.
|
||||
*
|
||||
* @author bjl23
|
||||
*
|
||||
*/
|
||||
public class ModelSynchronizer implements ModelChangedListener {
|
||||
private static final Log log = LogFactory.getLog(ModelSynchronizer.class);
|
||||
|
||||
private Model m;
|
||||
private String hash;
|
||||
|
||||
public ModelSynchronizer (Model synchronizee) {
|
||||
public ModelSynchronizer(Model synchronizee, String name) {
|
||||
this.m = synchronizee;
|
||||
this.hash = Integer.toHexString(this.hashCode());
|
||||
log.debug(String.format("create: %s, wraps %s(%s) as %s", hash, this.m
|
||||
.getClass().getName(), Integer.toHexString(this.m.hashCode()),
|
||||
name));
|
||||
}
|
||||
|
||||
public void addedStatement(Statement arg0) {
|
||||
m.add(arg0);
|
||||
@Override
|
||||
public void addedStatement(Statement s) {
|
||||
log.debug(hash + " addedStatement" + s);
|
||||
m.add(s);
|
||||
}
|
||||
|
||||
public void addedStatements(Statement[] arg0) {
|
||||
m.add(arg0);
|
||||
@Override
|
||||
public void addedStatements(Statement[] statements) {
|
||||
log.debug(hash + " addedStatements: " + statements.length);
|
||||
m.add(statements);
|
||||
}
|
||||
|
||||
|
||||
public void addedStatements(List arg0) {
|
||||
m.add(arg0);
|
||||
@Override
|
||||
public void addedStatements(List<Statement> statements) {
|
||||
log.debug(hash + " addedStatements: " + statements.size());
|
||||
m.add(statements);
|
||||
}
|
||||
|
||||
|
||||
public void addedStatements(StmtIterator arg0) {
|
||||
m.add(arg0);
|
||||
@Override
|
||||
public void addedStatements(StmtIterator statements) {
|
||||
if (log.isDebugEnabled()) {
|
||||
Set<Statement> set = statements.toSet();
|
||||
log.debug(hash + " addedStatements: " + set.size());
|
||||
m.add(new StmtIteratorImpl(set.iterator()));
|
||||
} else {
|
||||
m.add(new StmtIteratorImpl(statements));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void addedStatements(Model arg0) {
|
||||
m.add(arg0);
|
||||
@Override
|
||||
public void addedStatements(Model model) {
|
||||
log.debug(hash + " addedStatements: " + model.size());
|
||||
m.add(model);
|
||||
}
|
||||
|
||||
|
||||
public void notifyEvent(Model arg0, Object arg1) {
|
||||
if ( arg1 instanceof CloseEvent ) {
|
||||
@Override
|
||||
public void notifyEvent(Model model, Object event) {
|
||||
if (event instanceof CloseEvent) {
|
||||
m.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void removedStatement(Statement arg0) {
|
||||
m.remove(arg0);
|
||||
@Override
|
||||
public void removedStatement(Statement s) {
|
||||
log.debug(hash + " removedStatement" + s);
|
||||
m.remove(s);
|
||||
}
|
||||
|
||||
|
||||
public void removedStatements(Statement[] arg0) {
|
||||
m.remove(arg0);
|
||||
@Override
|
||||
public void removedStatements(Statement[] statements) {
|
||||
log.debug(hash + " removedStatements: " + statements.length);
|
||||
m.remove(statements);
|
||||
}
|
||||
|
||||
public void removedStatements(List arg0) {
|
||||
m.remove(arg0);
|
||||
@Override
|
||||
public void removedStatements(List<Statement> statements) {
|
||||
log.debug(hash + " removedStatements: " + statements.size());
|
||||
m.remove(statements);
|
||||
}
|
||||
|
||||
|
||||
public void removedStatements(StmtIterator arg0) {
|
||||
m.remove(arg0);
|
||||
@Override
|
||||
public void removedStatements(StmtIterator statements) {
|
||||
if (log.isDebugEnabled()) {
|
||||
Set<Statement> set = statements.toSet();
|
||||
log.debug(hash + " removedStatements: " + set.size());
|
||||
m.remove(new StmtIteratorImpl(set.iterator()));
|
||||
} else {
|
||||
m.remove(new StmtIteratorImpl(statements));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void removedStatements(Model arg0) {
|
||||
m.remove(arg0);
|
||||
@Override
|
||||
public void removedStatements(Model model) {
|
||||
log.debug(hash + " removedStatements: " + model.size());
|
||||
m.remove(model);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,8 +9,14 @@ import java.net.URL;
|
|||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.hp.hpl.jena.graph.BulkUpdateHandler;
|
||||
import com.hp.hpl.jena.graph.Graph;
|
||||
import com.hp.hpl.jena.graph.Triple;
|
||||
import com.hp.hpl.jena.graph.impl.GraphWithPerform;
|
||||
import com.hp.hpl.jena.graph.impl.WrappedBulkUpdateHandler;
|
||||
import com.hp.hpl.jena.ontology.OntModel;
|
||||
import com.hp.hpl.jena.rdf.model.Model;
|
||||
import com.hp.hpl.jena.rdf.model.ModelFactory;
|
||||
|
@ -27,13 +33,31 @@ import com.hp.hpl.jena.util.iterator.Map1;
|
|||
* BulkUpdateHandler.
|
||||
*/
|
||||
public class BulkUpdatingOntModel extends AbstractOntModelDecorator {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(BulkUpdatingOntModel.class);
|
||||
|
||||
private static final RDFReaderF readerFactory = new RDFReaderFImpl();
|
||||
|
||||
private final BulkUpdateHandler buh;
|
||||
|
||||
public BulkUpdatingOntModel(OntModel inner, BulkUpdateHandler buh) {
|
||||
public BulkUpdatingOntModel(OntModel inner) {
|
||||
super(inner);
|
||||
this.buh = buh;
|
||||
this.buh = inner.getGraph().getBulkUpdateHandler();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private static BulkUpdateHandler getWrappedBulkUpdateHandler(Graph graph) {
|
||||
if (graph instanceof GraphWithPerform) {
|
||||
return new WrappedBulkUpdateHandler((GraphWithPerform) graph,
|
||||
graph.getBulkUpdateHandler());
|
||||
} else {
|
||||
try {
|
||||
throw new IllegalStateException();
|
||||
} catch (IllegalStateException e) {
|
||||
log.warn("Graph is not an instance of GraphWithPerform", e);
|
||||
}
|
||||
return graph.getBulkUpdateHandler();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
|
|
|
@ -4,16 +4,25 @@ package edu.cornell.mannlib.vitro.webapp.rdfservice.adapters;
|
|||
|
||||
import static com.hp.hpl.jena.ontology.OntModelSpec.OWL_MEM;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.hp.hpl.jena.graph.BulkUpdateHandler;
|
||||
import com.hp.hpl.jena.graph.Graph;
|
||||
import com.hp.hpl.jena.graph.compose.Union;
|
||||
import com.hp.hpl.jena.graph.impl.WrappedBulkUpdateHandler;
|
||||
import com.hp.hpl.jena.ontology.OntModel;
|
||||
import com.hp.hpl.jena.ontology.impl.OntModelImpl;
|
||||
import com.hp.hpl.jena.rdf.model.Model;
|
||||
import com.hp.hpl.jena.rdf.model.ModelFactory;
|
||||
import com.hp.hpl.jena.rdf.model.impl.ModelCom;
|
||||
|
||||
/**
|
||||
* Make models that will do proper bulk updates.
|
||||
*/
|
||||
public class VitroModelFactory {
|
||||
private static final Log log = LogFactory.getLog(VitroModelFactory.class);
|
||||
|
||||
public static Model createModel() {
|
||||
return ModelFactory.createDefaultModel();
|
||||
}
|
||||
|
@ -23,36 +32,52 @@ public class VitroModelFactory {
|
|||
}
|
||||
|
||||
public static OntModel createOntologyModel(Model model) {
|
||||
@SuppressWarnings("deprecation")
|
||||
BulkUpdateHandler buh = model.getGraph().getBulkUpdateHandler();
|
||||
|
||||
OntModel ontModel = ModelFactory.createOntologyModel(OWL_MEM, model);
|
||||
return new BulkUpdatingOntModel(ontModel, buh);
|
||||
Graph graph = model.getGraph();
|
||||
Model bareModel = new ModelCom(graph);
|
||||
OntModel ontModel = new OntModelImpl(OWL_MEM, bareModel);
|
||||
return new BulkUpdatingOntModel(ontModel);
|
||||
}
|
||||
|
||||
public static Model createUnion(Model baseModel, Model otherModel) {
|
||||
@SuppressWarnings("deprecation")
|
||||
BulkUpdateHandler buh = baseModel.getGraph().getBulkUpdateHandler();
|
||||
public static Model createUnion(Model baseModel, Model plusModel) {
|
||||
Graph baseGraph = baseModel.getGraph();
|
||||
Graph plusGraph = plusModel.getGraph();
|
||||
BulkUpdatingUnion unionGraph = new BulkUpdatingUnion(baseGraph,
|
||||
plusGraph);
|
||||
|
||||
Model unionModel = ModelFactory.createUnion(baseModel, otherModel);
|
||||
BulkUpdateHandler buh = getBulkUpdateHandler(unionGraph);
|
||||
Model unionModel = ModelFactory.createModelForGraph(unionGraph);
|
||||
return new BulkUpdatingModel(unionModel, buh);
|
||||
}
|
||||
|
||||
public static OntModel createUnion(OntModel baseModel, OntModel otherModel) {
|
||||
@SuppressWarnings("deprecation")
|
||||
BulkUpdateHandler buh = baseModel.getGraph().getBulkUpdateHandler();
|
||||
public static OntModel createUnion(OntModel baseModel, OntModel plusModel) {
|
||||
Graph baseGraph = baseModel.getGraph();
|
||||
Graph plusGraph = plusModel.getGraph();
|
||||
BulkUpdatingUnion unionGraph = new BulkUpdatingUnion(baseGraph,
|
||||
plusGraph);
|
||||
|
||||
Model unionModel = createUnion((Model) baseModel, (Model) otherModel);
|
||||
Model unionModel = ModelFactory.createModelForGraph(unionGraph);
|
||||
OntModel unionOntModel = ModelFactory.createOntologyModel(OWL_MEM,
|
||||
unionModel);
|
||||
return new BulkUpdatingOntModel(unionOntModel, buh);
|
||||
return new BulkUpdatingOntModel(unionOntModel);
|
||||
}
|
||||
|
||||
public static Model createModelForGraph(Graph g) {
|
||||
@SuppressWarnings("deprecation")
|
||||
BulkUpdateHandler buh = g.getBulkUpdateHandler();
|
||||
|
||||
BulkUpdateHandler buh = getBulkUpdateHandler(g);
|
||||
return new BulkUpdatingModel(ModelFactory.createModelForGraph(g), buh);
|
||||
}
|
||||
|
||||
private static class BulkUpdatingUnion extends Union {
|
||||
@SuppressWarnings("deprecation")
|
||||
public BulkUpdatingUnion(Graph L, Graph R) {
|
||||
super(L, R);
|
||||
this.bulkHandler = new WrappedBulkUpdateHandler(this,
|
||||
L.getBulkUpdateHandler());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private static BulkUpdateHandler getBulkUpdateHandler(Graph graph) {
|
||||
return graph.getBulkUpdateHandler();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.testing;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The create() method creates a dynamic Proxy that wraps your inner object, and
|
||||
* implements your interfaze.
|
||||
*
|
||||
* It also implements the MethodCallRecorder interface (although you will need
|
||||
* to cast it), so you can find out what methods were called on the proxy.
|
||||
*/
|
||||
public class RecordingProxy {
|
||||
public static <T> T create(T inner, Class<T> interfaze) {
|
||||
RecordingInvocationHandler handler = new RecordingInvocationHandler(
|
||||
inner);
|
||||
|
||||
ClassLoader classLoader = interfaze.getClassLoader();
|
||||
Class<?>[] interfaces = new Class<?>[] { interfaze,
|
||||
MethodCallRecorder.class };
|
||||
return interfaze.cast(Proxy.newProxyInstance(classLoader, interfaces,
|
||||
handler));
|
||||
}
|
||||
|
||||
/**
|
||||
* The "add-on" interface that allows us to ask what methods were called on
|
||||
* the proxy since it was created, or since it was reset.
|
||||
*/
|
||||
public interface MethodCallRecorder {
|
||||
List<MethodCall> getMethodCalls();
|
||||
|
||||
List<String> getMethodCallNames();
|
||||
|
||||
void resetMethodCalls();
|
||||
}
|
||||
|
||||
public static class MethodCall {
|
||||
/** a convenience method to get just the names of the methods called. */
|
||||
public static Object justNames(List<MethodCall> methodCalls) {
|
||||
List<String> names = new ArrayList<>();
|
||||
for (MethodCall methodCall : methodCalls) {
|
||||
names.add(methodCall.getName());
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
private final String name;
|
||||
private final List<Object> argList;
|
||||
|
||||
public MethodCall(String name, Object[] args) {
|
||||
this.name = name;
|
||||
if (args == null) {
|
||||
this.argList = Collections.emptyList();
|
||||
} else {
|
||||
this.argList = Collections.unmodifiableList(new ArrayList<>(
|
||||
Arrays.asList(args)));
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<Object> getArgList() {
|
||||
return argList;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class RecordingInvocationHandler implements InvocationHandler {
|
||||
private final Object inner;
|
||||
private final List<MethodCall> methodCalls = new ArrayList<>();
|
||||
|
||||
RecordingInvocationHandler(Object inner) {
|
||||
this.inner = inner;
|
||||
}
|
||||
|
||||
List<MethodCall> getMethodCalls() {
|
||||
return new ArrayList<>(methodCalls);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
methodCalls.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args)
|
||||
throws Throwable {
|
||||
switch (method.getName()) {
|
||||
case "getMethodCalls":
|
||||
return new ArrayList<MethodCall>(methodCalls);
|
||||
case "getMethodCallNames":
|
||||
return MethodCall.justNames(methodCalls);
|
||||
case "resetMethodCalls":
|
||||
methodCalls.clear();
|
||||
return null;
|
||||
case "equals":
|
||||
if (args == null) return false;
|
||||
if (args.length == 0) return false;
|
||||
return args[0].equals(inner);
|
||||
default:
|
||||
methodCalls.add(new MethodCall(method.getName(), args));
|
||||
return method.invoke(inner, args);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,722 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.rdfservice.adapters;
|
||||
|
||||
import static com.hp.hpl.jena.ontology.OntModelSpec.OWL_MEM;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.hp.hpl.jena.graph.BulkUpdateHandler;
|
||||
import com.hp.hpl.jena.graph.impl.GraphWithPerform;
|
||||
import com.hp.hpl.jena.graph.impl.SimpleBulkUpdateHandler;
|
||||
import com.hp.hpl.jena.mem.GraphMem;
|
||||
import com.hp.hpl.jena.ontology.OntModel;
|
||||
import com.hp.hpl.jena.rdf.listeners.StatementListener;
|
||||
import com.hp.hpl.jena.rdf.model.Literal;
|
||||
import com.hp.hpl.jena.rdf.model.Model;
|
||||
import com.hp.hpl.jena.rdf.model.ModelChangedListener;
|
||||
import com.hp.hpl.jena.rdf.model.ModelFactory;
|
||||
import com.hp.hpl.jena.rdf.model.Property;
|
||||
import com.hp.hpl.jena.rdf.model.RDFNode;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
import com.hp.hpl.jena.rdf.model.ResourceFactory;
|
||||
import com.hp.hpl.jena.rdf.model.Statement;
|
||||
|
||||
import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
|
||||
import edu.cornell.mannlib.vitro.testing.RecordingProxy;
|
||||
import edu.cornell.mannlib.vitro.testing.RecordingProxy.MethodCall;
|
||||
import edu.cornell.mannlib.vitro.testing.RecordingProxy.MethodCallRecorder;
|
||||
|
||||
/**
|
||||
* Test that the VitroModelFactory is doing what we want, with regard to bulk
|
||||
* updates.
|
||||
*
|
||||
* With the switch to Jena 2.10, bulk update operations are deprecated, but
|
||||
* still supported, to a large extent. A Graph still has a bulk updater which
|
||||
* can be called for bulk operations (like adding multiple statements). However,
|
||||
* the default Model won't call the bulk updater of its Graph, and neither will
|
||||
* the default OntModel.
|
||||
*
|
||||
* VitroModelFactory creates Models and OntModels that do call the bulk updaters
|
||||
* of their respective graphs.
|
||||
*
|
||||
* ---------------
|
||||
*
|
||||
* These tests show which methods are called on which objects (graph, model,
|
||||
* listener) for both simple operations (add a statement) and bulk operations
|
||||
* (add multiple statements).
|
||||
*
|
||||
* The tests of the default ModelFactory aren't necessary. They do add
|
||||
* confidence to the testing mechanism, and provide a contrast with the
|
||||
* VitroModelFactory.
|
||||
*
|
||||
* The tests of simple operations may or may not add value. Probably good to
|
||||
* keep them.
|
||||
*
|
||||
* ----------------
|
||||
*
|
||||
* Who knows how we will deal with this in the next Jena upgrade, when
|
||||
* presumably the bulk updaters will be removed completely.
|
||||
*/
|
||||
public class VitroModelFactoryTest extends AbstractTestClass {
|
||||
private static final Statement SINGLE_STATEMENT = stmt(
|
||||
resource("http://subject"), property("http://add"),
|
||||
literal("object"));
|
||||
private static final Statement[] MULTIPLE_STATEMENTS = {
|
||||
stmt(resource("http://subject"), property("http://add"),
|
||||
literal("first")),
|
||||
stmt(resource("http://subject"), property("http://add"),
|
||||
literal("second")) };
|
||||
|
||||
private static final String[] BORING_METHOD_NAMES = { "getPrefixMapping",
|
||||
"getEventManager", "getBulkUpdateHandler", "find", "getGraph" };
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// createModelForGraph()
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A ModelGroup has a talkative graph, with a talkative bulkUpdater, wrapped
|
||||
* by a model that has a talkative listener attached.
|
||||
*
|
||||
* But what kind of model?
|
||||
*/
|
||||
private static abstract class ModelGroup extends TestObjectGrouping {
|
||||
final GraphWithPerform g;
|
||||
final BulkUpdateHandler bu;
|
||||
final ModelChangedListener l;
|
||||
final Model m;
|
||||
|
||||
protected ModelGroup() {
|
||||
MyGraphMem rawGraph = new MyGraphMem();
|
||||
this.g = wrapGraph(rawGraph);
|
||||
this.bu = makeBulkUpdater(this.g, rawGraph);
|
||||
this.l = makeListener();
|
||||
|
||||
this.m = wrapModel(makeModel(this.g));
|
||||
this.m.register(this.l);
|
||||
|
||||
reset(g);
|
||||
reset(bu);
|
||||
reset(l);
|
||||
reset(m);
|
||||
}
|
||||
|
||||
protected abstract Model makeModel(GraphWithPerform g);
|
||||
}
|
||||
|
||||
/** A ModelGroup with a default-style model. */
|
||||
private static class DefaultModelGroup extends ModelGroup {
|
||||
@Override
|
||||
protected Model makeModel(GraphWithPerform g) {
|
||||
return ModelFactory.createModelForGraph(g);
|
||||
}
|
||||
}
|
||||
|
||||
/** A ModelGroup with a Vitro-style model. */
|
||||
private static class VitroModelGroup extends ModelGroup {
|
||||
@Override
|
||||
protected Model makeModel(GraphWithPerform g) {
|
||||
return VitroModelFactory.createModelForGraph(g);
|
||||
}
|
||||
}
|
||||
|
||||
private ModelGroup mg;
|
||||
|
||||
@Test
|
||||
public void addOneToModel() {
|
||||
mg = new DefaultModelGroup();
|
||||
mg.m.add(SINGLE_STATEMENT);
|
||||
new MethodCalls().add(mg.g, "add").add(mg.bu)
|
||||
.add(mg.l, "addedStatement").test();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addOneToVitroModel() {
|
||||
mg = new VitroModelGroup();
|
||||
mg.m.add(SINGLE_STATEMENT);
|
||||
new MethodCalls().add(mg.g, "add").add(mg.bu)
|
||||
.add(mg.l, "addedStatement").test();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addMultipleToModel() {
|
||||
mg = new DefaultModelGroup();
|
||||
mg.m.add(MULTIPLE_STATEMENTS);
|
||||
new MethodCalls().add(mg.g, "performAdd", "performAdd").add(mg.bu)
|
||||
.add(mg.l, "addedStatements").test();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addMultipleToVitroModel() {
|
||||
mg = new VitroModelGroup();
|
||||
mg.m.add(MULTIPLE_STATEMENTS);
|
||||
new MethodCalls().add(mg.g, "performAdd", "performAdd")
|
||||
.add(mg.bu, "add").add(mg.l, "addedStatements").test();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// createOntologyModel()
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
private OntModelGroup omg;
|
||||
|
||||
/**
|
||||
* An OntModelGroup is like a ModelGroup, but the model is wrapped in an
|
||||
* OntModel that has its own talkative listener.
|
||||
*
|
||||
* But what kind of Model, and what kind of OntModel?
|
||||
*/
|
||||
private static abstract class OntModelGroup extends ModelGroup {
|
||||
final ModelChangedListener ol;
|
||||
final OntModel om;
|
||||
|
||||
protected OntModelGroup() {
|
||||
this.ol = makeListener();
|
||||
this.om = wrapOntModel(makeOntModel(this.m));
|
||||
this.om.register(this.ol);
|
||||
}
|
||||
|
||||
protected abstract OntModel makeOntModel(Model m);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* An OntModelGroup with a default-style OntModel and a default-style Model.
|
||||
*/
|
||||
private static class DefaultOntModelGroup extends OntModelGroup {
|
||||
@Override
|
||||
protected OntModel makeOntModel(Model m) {
|
||||
return ModelFactory.createOntologyModel(OWL_MEM, m);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Model makeModel(GraphWithPerform g) {
|
||||
return ModelFactory.createModelForGraph(g);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An OntModelGroup with a Vitro-style OntModel and a Vitro-style Model.
|
||||
*/
|
||||
private static class VitroOntModelGroup extends OntModelGroup {
|
||||
@Override
|
||||
protected OntModel makeOntModel(Model m) {
|
||||
return VitroModelFactory.createOntologyModel(m);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Model makeModel(GraphWithPerform g) {
|
||||
return VitroModelFactory.createModelForGraph(g);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addOneToOntModel() {
|
||||
omg = new DefaultOntModelGroup();
|
||||
omg.om.add(SINGLE_STATEMENT);
|
||||
new MethodCalls().add(omg.g, "add").add(omg.bu)
|
||||
.add(omg.l, "addedStatement").add(omg.ol, "addedStatement")
|
||||
.test();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addOneToVitroOntModel() {
|
||||
omg = new VitroOntModelGroup();
|
||||
omg.om.add(SINGLE_STATEMENT);
|
||||
new MethodCalls().add(omg.g, "add").add(omg.bu)
|
||||
.add(omg.l, "addedStatement").add(omg.ol, "addedStatement")
|
||||
.test();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addMultipleToOntModel() {
|
||||
omg = new DefaultOntModelGroup();
|
||||
omg.om.add(MULTIPLE_STATEMENTS);
|
||||
new MethodCalls().add(omg.g, "add", "add").add(omg.bu)
|
||||
.add(omg.l, "addedStatement", "addedStatement")
|
||||
.add(omg.ol, "addedStatements").test();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addMultipleToVitroOntModel() {
|
||||
omg = new VitroOntModelGroup();
|
||||
omg.om.add(MULTIPLE_STATEMENTS);
|
||||
new MethodCalls().add(omg.g, "performAdd", "performAdd")
|
||||
.add(omg.bu, "add").add(omg.l, "addedStatements")
|
||||
.add(omg.ol, "addedStatements").test();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// createUnion(Model, Model)
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A UnionModelGroup is two ModelGroups, joined into a union that has its
|
||||
* own talkative listener.
|
||||
*
|
||||
* But what kind of ModelGroup, and what kind of union?
|
||||
*/
|
||||
private abstract static class UnionModelGroup extends TestObjectGrouping {
|
||||
final ModelGroup base;
|
||||
final ModelGroup plus;
|
||||
final Model m;
|
||||
final ModelChangedListener l;
|
||||
|
||||
protected UnionModelGroup() {
|
||||
this.base = makeModelGroup();
|
||||
this.plus = makeModelGroup();
|
||||
this.m = wrapModel(makeUnion(this.base.m, this.plus.m));
|
||||
|
||||
this.l = makeListener();
|
||||
this.m.register(this.l);
|
||||
|
||||
}
|
||||
|
||||
protected abstract ModelGroup makeModelGroup();
|
||||
|
||||
protected abstract Model makeUnion(Model baseModel, Model plusModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* A UnionModelGroup with default-style Models and a default-style union.
|
||||
*/
|
||||
private static class DefaultUnionModelGroup extends UnionModelGroup {
|
||||
@Override
|
||||
protected ModelGroup makeModelGroup() {
|
||||
return new DefaultModelGroup();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Model makeUnion(Model baseModel, Model plusModel) {
|
||||
return ModelFactory.createUnion(baseModel, plusModel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A UnionModelGroup with Vitro-style Models and a Vitro-style union.
|
||||
*/
|
||||
private static class VitroUnionModelGroup extends UnionModelGroup {
|
||||
@Override
|
||||
protected ModelGroup makeModelGroup() {
|
||||
return new VitroModelGroup();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Model makeUnion(Model baseModel, Model plusModel) {
|
||||
return VitroModelFactory.createUnion(baseModel, plusModel);
|
||||
}
|
||||
}
|
||||
|
||||
private UnionModelGroup umg;
|
||||
|
||||
@Test
|
||||
public void addOneToUnion() {
|
||||
umg = new DefaultUnionModelGroup();
|
||||
umg.m.add(SINGLE_STATEMENT);
|
||||
new MethodCalls().add(umg.base.g, "add").add(umg.base.bu)
|
||||
.add(umg.base.l, "addedStatement").add(umg.plus.g)
|
||||
.add(umg.plus.bu).add(umg.plus.l).add(umg.l, "addedStatement")
|
||||
.test();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addOneToVitroUnion() {
|
||||
umg = new VitroUnionModelGroup();
|
||||
umg.m.add(SINGLE_STATEMENT);
|
||||
new MethodCalls().add(umg.base.g, "add").add(umg.base.bu)
|
||||
.add(umg.base.l, "addedStatement").add(umg.plus.g)
|
||||
.add(umg.plus.bu).add(umg.plus.l).add(umg.l, "addedStatement")
|
||||
.test();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addMultipleToUnion() {
|
||||
umg = new DefaultUnionModelGroup();
|
||||
umg.m.add(MULTIPLE_STATEMENTS);
|
||||
new MethodCalls().add(umg.base.g, "add", "add").add(umg.base.bu)
|
||||
.add(umg.base.l, "addedStatement", "addedStatement")
|
||||
.add(umg.plus.g).add(umg.plus.bu).add(umg.plus.l)
|
||||
.add(umg.l, "addedStatements").test();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addMultipleToVitroUnion() {
|
||||
umg = new VitroUnionModelGroup();
|
||||
umg.m.add(MULTIPLE_STATEMENTS);
|
||||
new MethodCalls().add(umg.base.g, "performAdd", "performAdd")
|
||||
.add(umg.base.bu, "add").add(umg.base.l, "addedStatements")
|
||||
.add(umg.plus.g).add(umg.plus.bu).add(umg.plus.l)
|
||||
.add(umg.l, "addedStatements").test();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// createUnion(OntModel, OntModel)
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A UnionOntModelGroup is two OntModelGroups, joined into a union that has
|
||||
* its own talkative listener.
|
||||
*
|
||||
* But what kind of OntModelGroup, and what kind of union?
|
||||
*/
|
||||
private abstract static class UnionOntModelGroup extends TestObjectGrouping {
|
||||
final OntModelGroup base;
|
||||
final OntModelGroup plus;
|
||||
final OntModel om;
|
||||
final ModelChangedListener l;
|
||||
|
||||
protected UnionOntModelGroup() {
|
||||
this.base = makeOntModelGroup();
|
||||
this.plus = makeOntModelGroup();
|
||||
this.om = wrapOntModel(makeOntUnion(this.base.om, this.plus.om));
|
||||
|
||||
this.l = makeListener();
|
||||
this.om.register(this.l);
|
||||
|
||||
}
|
||||
|
||||
protected abstract OntModelGroup makeOntModelGroup();
|
||||
|
||||
protected abstract OntModel makeOntUnion(OntModel baseModel,
|
||||
OntModel plusModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* A UnionOntModelGroup with default-style OntModels and a default-style
|
||||
* union.
|
||||
*/
|
||||
private static class DefaultUnionOntModelGroup extends UnionOntModelGroup {
|
||||
@Override
|
||||
protected OntModelGroup makeOntModelGroup() {
|
||||
return new DefaultOntModelGroup();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OntModel makeOntUnion(OntModel baseModel, OntModel plusModel) {
|
||||
return ModelFactory.createOntologyModel(OWL_MEM,
|
||||
ModelFactory.createUnion(baseModel, plusModel));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A UnionOntModelGroup with Vitro-style OntModels and a Vitro-style union.
|
||||
*/
|
||||
private static class VitroUnionOntModelGroup extends UnionOntModelGroup {
|
||||
@Override
|
||||
protected OntModelGroup makeOntModelGroup() {
|
||||
return new VitroOntModelGroup();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OntModel makeOntUnion(OntModel baseModel, OntModel plusModel) {
|
||||
return VitroModelFactory.createUnion(baseModel, plusModel);
|
||||
}
|
||||
}
|
||||
|
||||
private UnionOntModelGroup uomg;
|
||||
|
||||
@Test
|
||||
public void addOneToOntUnion() {
|
||||
uomg = new DefaultUnionOntModelGroup();
|
||||
uomg.om.add(SINGLE_STATEMENT);
|
||||
new MethodCalls().add(uomg.base.g, "add").add(uomg.base.bu)
|
||||
.add(uomg.base.l, "addedStatement").add(uomg.plus.g)
|
||||
.add(uomg.plus.bu).add(uomg.plus.l)
|
||||
.add(uomg.l, "addedStatement").test();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addOneToVitroOntUnion() {
|
||||
uomg = new VitroUnionOntModelGroup();
|
||||
uomg.om.add(SINGLE_STATEMENT);
|
||||
new MethodCalls().add(uomg.base.g, "add").add(uomg.base.bu)
|
||||
.add(uomg.base.l, "addedStatement").add(uomg.plus.g)
|
||||
.add(uomg.plus.bu).add(uomg.plus.l)
|
||||
.add(uomg.l, "addedStatement").test();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addMultipleToOntUnion() {
|
||||
uomg = new DefaultUnionOntModelGroup();
|
||||
uomg.om.add(MULTIPLE_STATEMENTS);
|
||||
new MethodCalls().add(uomg.base.g, "add", "add").add(uomg.base.bu)
|
||||
.add(uomg.base.l, "addedStatement", "addedStatement")
|
||||
.add(uomg.plus.g).add(uomg.plus.bu).add(uomg.plus.l)
|
||||
.add(uomg.l, "addedStatements").test();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addMultipleToVitroOntUnion() {
|
||||
uomg = new VitroUnionOntModelGroup();
|
||||
uomg.om.add(MULTIPLE_STATEMENTS);
|
||||
new MethodCalls().add(uomg.base.g, "performAdd", "performAdd")
|
||||
.add(uomg.base.bu, "add").add(uomg.base.l, "addedStatements")
|
||||
.add(uomg.plus.g).add(uomg.plus.bu).add(uomg.plus.l)
|
||||
.add(uomg.l, "addedStatements").test();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// OntModel of Union of Models
|
||||
//
|
||||
// This shouldn't hold any surprises, should it?
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A OntModelUnionModelGroup is a UnionModelGroup wrapped by an OntModel
|
||||
* with a listener.
|
||||
*
|
||||
* But what kind of UnionModelGroup, and what kind of OntModel?
|
||||
*/
|
||||
private abstract static class OntModelUnionModelGroup extends
|
||||
TestObjectGrouping {
|
||||
final UnionModelGroup union;
|
||||
final OntModel om;
|
||||
final ModelChangedListener ol;
|
||||
|
||||
protected OntModelUnionModelGroup() {
|
||||
this.union = makeUnionModelGroup();
|
||||
this.om = wrapOntModel(makeOntModel(union.m));
|
||||
|
||||
this.ol = makeListener();
|
||||
this.om.register(this.ol);
|
||||
reset(om);
|
||||
}
|
||||
|
||||
protected abstract UnionModelGroup makeUnionModelGroup();
|
||||
|
||||
protected abstract OntModel makeOntModel(Model m);
|
||||
}
|
||||
|
||||
/**
|
||||
* A OntModelUnionModelGroup with default-style UnionModelGroup and a
|
||||
* default-style OntModel.
|
||||
*/
|
||||
private static class DefaultOntModelUnionModelGroup extends
|
||||
OntModelUnionModelGroup {
|
||||
@Override
|
||||
protected UnionModelGroup makeUnionModelGroup() {
|
||||
return new DefaultUnionModelGroup();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OntModel makeOntModel(Model m) {
|
||||
return ModelFactory.createOntologyModel(OWL_MEM, m);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A OntModelUnionModelGroup with Vitro-style UnionModelGroup and a
|
||||
* Vitro-style OntModel.
|
||||
*/
|
||||
private static class VitroOntModelUnionModelGroup extends
|
||||
OntModelUnionModelGroup {
|
||||
@Override
|
||||
protected UnionModelGroup makeUnionModelGroup() {
|
||||
return new VitroUnionModelGroup();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OntModel makeOntModel(Model m) {
|
||||
return VitroModelFactory.createOntologyModel(m);
|
||||
}
|
||||
}
|
||||
|
||||
private OntModelUnionModelGroup omumg;
|
||||
|
||||
@Test
|
||||
public void addOneToOntModeledUnionModel() {
|
||||
omumg = new DefaultOntModelUnionModelGroup();
|
||||
omumg.om.add(SINGLE_STATEMENT);
|
||||
new MethodCalls().add(omumg.om, "add").add(omumg.ol, "addedStatement")
|
||||
.add(omumg.union.base.g, "add").add(omumg.union.base.bu)
|
||||
.add(omumg.union.base.m)
|
||||
.add(omumg.union.base.l, "addedStatement")
|
||||
.add(omumg.union.plus.g).add(omumg.union.plus.bu)
|
||||
.add(omumg.union.plus.m).add(omumg.union.plus.l).test();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addOneToVitroOntModeledUnionModel() {
|
||||
omumg = new VitroOntModelUnionModelGroup();
|
||||
omumg.om.add(SINGLE_STATEMENT);
|
||||
new MethodCalls().add(omumg.om, "add").add(omumg.ol, "addedStatement")
|
||||
.add(omumg.union.base.g, "add").add(omumg.union.base.bu)
|
||||
.add(omumg.union.base.m)
|
||||
.add(omumg.union.base.l, "addedStatement")
|
||||
.add(omumg.union.plus.g).add(omumg.union.plus.bu)
|
||||
.add(omumg.union.plus.m).add(omumg.union.plus.l).test();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addMultipleToOntModeledUnionModel() {
|
||||
omumg = new DefaultOntModelUnionModelGroup();
|
||||
omumg.om.add(MULTIPLE_STATEMENTS);
|
||||
new MethodCalls().add(omumg.om, "add").add(omumg.ol, "addedStatements")
|
||||
.add(omumg.union.base.g, "add", "add").add(omumg.union.base.bu)
|
||||
.add(omumg.union.base.m)
|
||||
.add(omumg.union.base.l, "addedStatement", "addedStatement")
|
||||
.add(omumg.union.plus.g).add(omumg.union.plus.bu)
|
||||
.add(omumg.union.plus.m).add(omumg.union.plus.l).test();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addMultipleToVitroOntModeledUnionModel() {
|
||||
omumg = new VitroOntModelUnionModelGroup();
|
||||
omumg.om.add(MULTIPLE_STATEMENTS);
|
||||
new MethodCalls().add(omumg.om, "add").add(omumg.ol, "addedStatements")
|
||||
.add(omumg.union.base.g, "performAdd", "performAdd")
|
||||
.add(omumg.union.base.bu, "add").add(omumg.union.base.m)
|
||||
.add(omumg.union.base.l, "addedStatements")
|
||||
.add(omumg.union.plus.g).add(omumg.union.plus.bu)
|
||||
.add(omumg.union.plus.m).add(omumg.union.plus.l).test();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Helper methods
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
private static Statement stmt(Resource subject, Property predicate,
|
||||
RDFNode object) {
|
||||
return ResourceFactory.createStatement(subject, predicate, object);
|
||||
}
|
||||
|
||||
private static Resource resource(String uri) {
|
||||
return ResourceFactory.createResource(uri);
|
||||
}
|
||||
|
||||
private static Property property(String uri) {
|
||||
return ResourceFactory.createProperty(uri);
|
||||
}
|
||||
|
||||
private static Literal literal(String value) {
|
||||
return ResourceFactory.createPlainLiteral(value);
|
||||
}
|
||||
|
||||
/** Just for debugging */
|
||||
private void dumpMethodCalls(String message, Object proxy) {
|
||||
System.out.println(message + " method calls:");
|
||||
for (MethodCall call : ((MethodCallRecorder) proxy).getMethodCalls()) {
|
||||
String formatted = " " + call.getName();
|
||||
for (Object arg : call.getArgList()) {
|
||||
formatted += " " + arg.getClass();
|
||||
}
|
||||
System.out.println(formatted);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Helper classes
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The latest Graph classes allow you to get their BulkUpdateHandler, but
|
||||
* won't allow you to set it.
|
||||
*/
|
||||
private static class MyGraphMem extends GraphMem {
|
||||
public void setBulkUpdateHandler(BulkUpdateHandler bulkHandler) {
|
||||
this.bulkHandler = bulkHandler;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection of "CallNames", each of which holds a list of expected
|
||||
* calls, a recording proxy from which we can get the actual calls, and a
|
||||
* method to compare them.
|
||||
*/
|
||||
private static class MethodCalls {
|
||||
private final List<CallNames> list = new ArrayList<>();
|
||||
|
||||
public MethodCalls add(Object proxy, String... names) {
|
||||
list.add(new CallNames((MethodCallRecorder) proxy, names));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a string that represents all of the expected method calls.
|
||||
* Create a string that represents all of the interesting actual calls.
|
||||
* Compare the strings.
|
||||
*/
|
||||
private void test() {
|
||||
try (StringWriter expectSw = new StringWriter();
|
||||
PrintWriter expectWriter = new PrintWriter(expectSw, true);
|
||||
StringWriter actualSw = new StringWriter();
|
||||
PrintWriter actualWriter = new PrintWriter(actualSw, true);) {
|
||||
for (CallNames calls : list) {
|
||||
expectWriter.println(Arrays.asList(calls.names));
|
||||
actualWriter.println(filterMethodNames(calls.proxy
|
||||
.getMethodCallNames()));
|
||||
}
|
||||
assertEquals(expectSw.toString(), actualSw.toString());
|
||||
} catch (IOException e) {
|
||||
fail(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> filterMethodNames(List<String> raw) {
|
||||
List<String> filtered = new ArrayList<>(raw);
|
||||
filtered.removeAll(Arrays.asList(BORING_METHOD_NAMES));
|
||||
return filtered;
|
||||
}
|
||||
|
||||
private static class CallNames {
|
||||
private final MethodCallRecorder proxy;
|
||||
private final String[] names;
|
||||
|
||||
public CallNames(MethodCallRecorder proxy, String[] names) {
|
||||
this.proxy = proxy;
|
||||
this.names = names;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Some utility methods for creating a group of test objects.
|
||||
*/
|
||||
private static abstract class TestObjectGrouping {
|
||||
protected GraphWithPerform wrapGraph(MyGraphMem raw) {
|
||||
return RecordingProxy.create(raw, GraphWithPerform.class);
|
||||
}
|
||||
|
||||
protected BulkUpdateHandler makeBulkUpdater(GraphWithPerform g,
|
||||
MyGraphMem raw) {
|
||||
SimpleBulkUpdateHandler rawBu = new SimpleBulkUpdateHandler(g);
|
||||
BulkUpdateHandler bu = RecordingProxy.create(rawBu,
|
||||
BulkUpdateHandler.class);
|
||||
raw.setBulkUpdateHandler(bu);
|
||||
return bu;
|
||||
}
|
||||
|
||||
protected static ModelChangedListener makeListener() {
|
||||
return RecordingProxy.create(new StatementListener(),
|
||||
ModelChangedListener.class);
|
||||
}
|
||||
|
||||
protected Model wrapModel(Model m) {
|
||||
return RecordingProxy.create(m, Model.class);
|
||||
}
|
||||
|
||||
protected OntModel wrapOntModel(OntModel om) {
|
||||
return RecordingProxy.create(om, OntModel.class);
|
||||
}
|
||||
|
||||
protected <T> T reset(T proxy) {
|
||||
((MethodCallRecorder) proxy).resetMethodCalls();
|
||||
return proxy;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue