diff --git a/src/main/java/com/mackervoy/calum/mud/MUDApplication.java b/src/main/java/com/mackervoy/calum/mud/MUDApplication.java index 7b986ee..15b2a48 100644 --- a/src/main/java/com/mackervoy/calum/mud/MUDApplication.java +++ b/src/main/java/com/mackervoy/calum/mud/MUDApplication.java @@ -92,6 +92,31 @@ protected static void initSettlement() { } } + /** + * A temporary function for initialising a demo content graph on startup + */ + protected static void initDemoContent() { + Dataset dataset = TDB2Factory.connectDataset(TDBStore.CONTENT.getFileLocation()) ; + try { + dataset.begin(ReadWrite.WRITE) ; + + if(!dataset.isEmpty()) { + dataset.abort(); + return; + } + + Model model = dataset.getDefaultModel(); + + //TODO: configure from web.xml + model.read("https://calum.inrupt.net/public/collections/content.ttl"); + + model.commit(); + } + finally { + dataset.end(); + } + } + /** * init a TDB server storing world from configuration in Assembler * https://jena.apache.org/documentation/tdb/java_api.html @@ -112,6 +137,7 @@ public static void initWorld() { */ public static void registerDescribers() { new StadiumDescriber(); + new SPARQLDescriber(); } public static void registerActors() { @@ -127,6 +153,7 @@ public MUDApplication(@Context ServletContext context) { if(!SITE_URL.endsWith("/")) SITE_URL += "/"; MUDApplication.initWorld(); + MUDApplication.initDemoContent(); MUDApplication.registerDescribers(); MUDApplication.registerActors(); } diff --git a/src/main/java/com/mackervoy/calum/mud/TDBStore.java b/src/main/java/com/mackervoy/calum/mud/TDBStore.java index 04b748f..cfa4b35 100644 --- a/src/main/java/com/mackervoy/calum/mud/TDBStore.java +++ b/src/main/java/com/mackervoy/calum/mud/TDBStore.java @@ -17,6 +17,7 @@ */ public class TDBStore { public final static DatasetCollection WORLD = new DatasetCollection("world/"); + public final static DatasetCollection CONTENT = new DatasetCollection("content/"); public final static DatasetCollection ACTIONS = new DatasetCollection("actions/"); public final static DatasetCollection TASK_ACTIONS = new DatasetCollection("actions/tasks/"); diff --git a/src/main/java/com/mackervoy/calum/mud/content/ContentController.java b/src/main/java/com/mackervoy/calum/mud/content/ContentController.java index 8eb79c1..3452ad0 100644 --- a/src/main/java/com/mackervoy/calum/mud/content/ContentController.java +++ b/src/main/java/com/mackervoy/calum/mud/content/ContentController.java @@ -40,9 +40,7 @@ public Response post(String requestBody) { Model m = ModelFactory.createDefaultModel(); m.read(res.getURI()); final Resource r = m.getResource(res.getURI()); - System.out.println(r); - //TODO: technically this should infer any subtype of foaf:Agent ResIterator agents = request.listResourcesWithProperty(RDF.type, MUDCharacter.Character); while(agents.hasNext()) { @@ -62,7 +60,6 @@ private Optional getDescriber(Resource r) { // check if I have a describer for the URI DescriberFactory factory = new DescriberFactory(); IContentDescriber describer = factory.getDescriber(r.getURI()); - System.out.println("found " + describer + " from " + r.getURI()); // if I don't, try the RDF type if (describer == null) { @@ -74,6 +71,8 @@ private Optional getDescriber(Resource r) { describer = null; } } + + System.out.println("found " + describer + " from " + r.getURI()); return Optional.ofNullable(describer); } diff --git a/src/main/java/com/mackervoy/calum/mud/content/SPARQLDescriber.java b/src/main/java/com/mackervoy/calum/mud/content/SPARQLDescriber.java new file mode 100644 index 0000000..17f9c60 --- /dev/null +++ b/src/main/java/com/mackervoy/calum/mud/content/SPARQLDescriber.java @@ -0,0 +1,72 @@ +package com.mackervoy.calum.mud.content; + +import java.util.Optional; + +import javax.ws.rs.NotFoundException; + +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.rdf.model.Property; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.query.*; + +import com.mackervoy.calum.mud.DatasetItem; +import com.mackervoy.calum.mud.TDBStore; +import com.mackervoy.calum.mud.vocabularies.MUDCharacter; +import com.mackervoy.calum.mud.vocabularies.MUDContent; + +public class SPARQLDescriber extends AbstractDescriber { + + //TODO: this class will be a generic describer for completing a SPARQL lookup + public SPARQLDescriber() { + this.addTargetRDFType(MUDCharacter.Character.toString()); + } + + /** + * @return A DatasetItem where the graph of content in the TDBStore is stored, or None + */ + protected Optional getContentDatasetItem() { + try { + return Optional.of(TDBStore.getDatasetItem(TDBStore.CONTENT.getFileLocation())); + } + catch(NotFoundException e) { + return Optional.empty(); + } + } + + protected Optional getContentDescribingObject(DatasetItem contentDataset, Resource agent, Resource r) { + // Select all triples where the subject describes a character + // TODO: prioritise those triples which target *this character* + String queryString = "SELECT ?s WHERE { ?s <" + MUDContent.describes.toString() + "> <" + MUDCharacter.Character.toString() + "> }"; + Query query = QueryFactory.create(queryString); + + Model result = ModelFactory.createDefaultModel(); + Model contentGraph = contentDataset.getModel(); + + try (QueryExecution qexec = QueryExecutionFactory.create(query, contentGraph)) { + ResultSet results = qexec.execSelect(); + + while(results.hasNext()) { + Resource subject = results.nextSolution().getResource("s"); + + // read the full subject into the result graph + // TODO: this could probably be more efficient + Model content = ModelFactory.createDefaultModel().read(subject.getURI()); + + // construct the appropriate sense from the content model + Resource sense = subject.getPropertyResourceValue(MUDContent.usesSense); + Property usesSense = sense == null ? MUDContent.sees : MUDContent.SENSE_TO_PROPERTY.get(sense); + + result.add(agent, usesSense, subject); + result.add(content); + } + } + + return result.isEmpty() ? Optional.empty() : Optional.of(result); + } + + public Optional describe(Resource agent, Resource r) { + return this.getContentDatasetItem() + .flatMap(datasetItem -> this.getContentDescribingObject(datasetItem, agent, r)); + } +} diff --git a/src/main/java/com/mackervoy/calum/mud/vocabularies/MUDContent.java b/src/main/java/com/mackervoy/calum/mud/vocabularies/MUDContent.java index f4a3bca..e41b176 100644 --- a/src/main/java/com/mackervoy/calum/mud/vocabularies/MUDContent.java +++ b/src/main/java/com/mackervoy/calum/mud/vocabularies/MUDContent.java @@ -1,5 +1,9 @@ package com.mackervoy.calum.mud.vocabularies; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + import org.apache.jena.rdf.model.* ; /* @@ -23,8 +27,19 @@ protected static final Property property( String local ) { return ResourceFactory.createProperty( uri, local ); } public final static Resource Content = resource( "Content" ); + public final static Resource Sense = resource("Sense"); + public final static Resource Sight = resource("Sight"); + public final static Property usesSense = property("usesSense"); public final static Property sees = property("sees"); public final static Property describes = property("describes"); public final static Property hasText = property("hasText"); public final static Property hasImage = property("hasImage"); + + //Map of Sense classes to their property values + public static final Map SENSE_TO_PROPERTY; + static { + Map internalMap = new HashMap(); + internalMap.put(Sight, sees); + SENSE_TO_PROPERTY = Collections.unmodifiableMap(internalMap); + } }