From 8a21f918462f23c866f28da38a5d82746faaf50d Mon Sep 17 00:00:00 2001 From: Calum Mackervoy Date: Fri, 7 May 2021 22:14:58 +0100 Subject: [PATCH 1/8] added SPARQLDescriber boilerplate --- .../calum/mud/content/SPARQLDescriber.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/main/java/com/mackervoy/calum/mud/content/SPARQLDescriber.java 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..2685572 --- /dev/null +++ b/src/main/java/com/mackervoy/calum/mud/content/SPARQLDescriber.java @@ -0,0 +1,20 @@ +package com.mackervoy.calum.mud.content; + +import java.util.Optional; + +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.Resource; + +import com.mackervoy.calum.mud.vocabularies.MUDCharacter; + +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()); + } + + public Optional describe(Resource agent, Resource r) { + return Optional.empty(); + } +} From 9ec763f196213b4685b82d0e63391ea78cb5c199 Mon Sep 17 00:00:00 2001 From: Calum Mackervoy Date: Fri, 7 May 2021 22:39:07 +0100 Subject: [PATCH 2/8] added content collection to TDBStore, initialised from demo data --- .../mackervoy/calum/mud/MUDApplication.java | 26 +++++++++++++++++++ .../com/mackervoy/calum/mud/TDBStore.java | 1 + 2 files changed, 27 insertions(+) diff --git a/src/main/java/com/mackervoy/calum/mud/MUDApplication.java b/src/main/java/com/mackervoy/calum/mud/MUDApplication.java index f5ef024..8037870 100644 --- a/src/main/java/com/mackervoy/calum/mud/MUDApplication.java +++ b/src/main/java/com/mackervoy/calum/mud/MUDApplication.java @@ -104,6 +104,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 @@ -136,6 +161,7 @@ public MUDApplication() { 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 a7436e6..b6bf526 100644 --- a/src/main/java/com/mackervoy/calum/mud/TDBStore.java +++ b/src/main/java/com/mackervoy/calum/mud/TDBStore.java @@ -18,6 +18,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/"); From 1d625f8e26c64963c3defefe454db5865fc08955 Mon Sep 17 00:00:00 2001 From: Calum Mackervoy Date: Sun, 9 May 2021 13:26:33 +0100 Subject: [PATCH 3/8] connecting SPARQLDescriber to character and content datasetItem --- .../mackervoy/calum/mud/MUDApplication.java | 1 + .../calum/mud/content/ContentController.java | 5 ++--- .../calum/mud/content/SPARQLDescriber.java | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/mackervoy/calum/mud/MUDApplication.java b/src/main/java/com/mackervoy/calum/mud/MUDApplication.java index 8037870..512cf84 100644 --- a/src/main/java/com/mackervoy/calum/mud/MUDApplication.java +++ b/src/main/java/com/mackervoy/calum/mud/MUDApplication.java @@ -149,6 +149,7 @@ public static void initWorld() { */ public static void registerDescribers() { new StadiumDescriber(); + new SPARQLDescriber(); } public static void registerActors() { 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 74072c4..acb215f 100644 --- a/src/main/java/com/mackervoy/calum/mud/content/ContentController.java +++ b/src/main/java/com/mackervoy/calum/mud/content/ContentController.java @@ -48,9 +48,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()) { @@ -70,7 +68,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) { @@ -82,6 +79,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 index 2685572..6ba7ac1 100644 --- a/src/main/java/com/mackervoy/calum/mud/content/SPARQLDescriber.java +++ b/src/main/java/com/mackervoy/calum/mud/content/SPARQLDescriber.java @@ -2,9 +2,14 @@ import java.util.Optional; +import javax.ws.rs.NotFoundException; + import org.apache.jena.rdf.model.Model; 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; public class SPARQLDescriber extends AbstractDescriber { @@ -14,7 +19,21 @@ 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(); + } + } + public Optional describe(Resource agent, Resource r) { + this.getContentDatasetItem().ifPresent(datasetItem -> System.out.println(datasetItem.getModel())); + return Optional.empty(); } } From cd040f75f38e0660735b8df9e49cd53cc0b5e230 Mon Sep 17 00:00:00 2001 From: Calum Mackervoy Date: Mon, 10 May 2021 22:26:36 +0100 Subject: [PATCH 4/8] SPARQL query for generic MUDCharacter description --- .../calum/mud/content/SPARQLDescriber.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/mackervoy/calum/mud/content/SPARQLDescriber.java b/src/main/java/com/mackervoy/calum/mud/content/SPARQLDescriber.java index 6ba7ac1..1927f70 100644 --- a/src/main/java/com/mackervoy/calum/mud/content/SPARQLDescriber.java +++ b/src/main/java/com/mackervoy/calum/mud/content/SPARQLDescriber.java @@ -11,6 +11,7 @@ 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 { @@ -31,8 +32,20 @@ protected Optional getContentDatasetItem() { } } + protected void getContentDescribingObject(DatasetItem contentDataset, 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); + + try (QueryExecution qexec = QueryExecutionFactory.create(query, contentDataset.getModel())) { + ResultSet results = qexec.execSelect(); + ResultSetFormatter.out(System.out, results, query); + } + } + public Optional describe(Resource agent, Resource r) { - this.getContentDatasetItem().ifPresent(datasetItem -> System.out.println(datasetItem.getModel())); + this.getContentDatasetItem().ifPresent(datasetItem -> this.getContentDescribingObject(datasetItem, r)); return Optional.empty(); } From f11fade041c34d88915114befcdec035c36a15c9 Mon Sep 17 00:00:00 2001 From: Calum Mackervoy Date: Mon, 10 May 2021 22:41:40 +0100 Subject: [PATCH 5/8] SPARQLDescriber returning subjects which describe a MUDCharacter --- .../calum/mud/content/SPARQLDescriber.java | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/mackervoy/calum/mud/content/SPARQLDescriber.java b/src/main/java/com/mackervoy/calum/mud/content/SPARQLDescriber.java index 1927f70..632f2be 100644 --- a/src/main/java/com/mackervoy/calum/mud/content/SPARQLDescriber.java +++ b/src/main/java/com/mackervoy/calum/mud/content/SPARQLDescriber.java @@ -5,6 +5,7 @@ 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.Resource; import org.apache.jena.query.*; @@ -32,21 +33,32 @@ protected Optional getContentDatasetItem() { } } - protected void getContentDescribingObject(DatasetItem contentDataset, Resource r) { + protected Optional getContentDescribingObject(DatasetItem contentDataset, 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, contentDataset.getModel())) { + try (QueryExecution qexec = QueryExecutionFactory.create(query, contentGraph)) { ResultSet results = qexec.execSelect(); - ResultSetFormatter.out(System.out, results, query); + + while(results.hasNext()) { + Resource subject = results.nextSolution().getResource("s"); + + // read the full subject into the result graph + // TODO: this could probably be more efficient + result.add(ModelFactory.createDefaultModel().read(subject.getURI())); + } } + + return result.isEmpty() ? Optional.empty() : Optional.of(result); } public Optional describe(Resource agent, Resource r) { - this.getContentDatasetItem().ifPresent(datasetItem -> this.getContentDescribingObject(datasetItem, r)); - - return Optional.empty(); + return this.getContentDatasetItem() + .flatMap(datasetItem -> this.getContentDescribingObject(datasetItem, r)); } } From f2f6d3e5d1810a920d10a6b5f7dd0c57185633f2 Mon Sep 17 00:00:00 2001 From: Calum Mackervoy Date: Tue, 11 May 2021 19:29:19 +0100 Subject: [PATCH 6/8] added new classes and properties to MUDContent LIT --- .../java/com/mackervoy/calum/mud/vocabularies/MUDContent.java | 3 +++ 1 file changed, 3 insertions(+) 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..9ee511c 100644 --- a/src/main/java/com/mackervoy/calum/mud/vocabularies/MUDContent.java +++ b/src/main/java/com/mackervoy/calum/mud/vocabularies/MUDContent.java @@ -23,6 +23,9 @@ 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"); From bae1c3c194be77a4be3dd829b86351cf26cac6b3 Mon Sep 17 00:00:00 2001 From: Calum Mackervoy Date: Tue, 11 May 2021 19:43:04 +0100 Subject: [PATCH 7/8] added static map conversion of Sense resource to property --- .../mackervoy/calum/mud/vocabularies/MUDContent.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) 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 9ee511c..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.* ; /* @@ -30,4 +34,12 @@ protected static final Property property( String local ) 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); + } } From b37391205ab99101653bc452d16b5a200b808cc7 Mon Sep 17 00:00:00 2001 From: Calum Mackervoy Date: Tue, 11 May 2021 20:19:26 +0100 Subject: [PATCH 8/8] adding perception properties to SPARQLDescriber result --- .../calum/mud/content/SPARQLDescriber.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/mackervoy/calum/mud/content/SPARQLDescriber.java b/src/main/java/com/mackervoy/calum/mud/content/SPARQLDescriber.java index 632f2be..17f9c60 100644 --- a/src/main/java/com/mackervoy/calum/mud/content/SPARQLDescriber.java +++ b/src/main/java/com/mackervoy/calum/mud/content/SPARQLDescriber.java @@ -6,6 +6,7 @@ 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.*; @@ -33,7 +34,7 @@ protected Optional getContentDatasetItem() { } } - protected Optional getContentDescribingObject(DatasetItem contentDataset, Resource r) { + 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() + "> }"; @@ -50,7 +51,14 @@ protected Optional getContentDescribingObject(DatasetItem contentDataset, // read the full subject into the result graph // TODO: this could probably be more efficient - result.add(ModelFactory.createDefaultModel().read(subject.getURI())); + 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); } } @@ -59,6 +67,6 @@ protected Optional getContentDescribingObject(DatasetItem contentDataset, public Optional describe(Resource agent, Resource r) { return this.getContentDatasetItem() - .flatMap(datasetItem -> this.getContentDescribingObject(datasetItem, r)); + .flatMap(datasetItem -> this.getContentDescribingObject(datasetItem, agent, r)); } }