danaivach / hmas-java

A library for handling resources in Hypermedia Multi-Agent Systems based on the HyperAgents ontologies.
1 stars 2 forks source link

Read and write input specification as SHACL shape #2

Closed danaivach closed 6 months ago

danaivach commented 1 year ago

Feature: read and write a signifier like the following:

@prefix ex: <http://example.org/> .
@prefix hmas: <https://purl.org/hmas/> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix prov: <http://www.w3.org/ns/prov#> .
@prefix xs: <https://www.w3.org/2001/XMLSchema#> .
@prefix hctl: <https://www.w3.org/2019/wot/hypermedia#> .
@prefix htv: <http://www.w3.org/2011/http#> . 

ex:signifier a hmas:Signifier ;
    hmas:signifies ex:moveGripperSpecification .

ex:moveGripperSpecification a sh:NodeShape;
    sh:class hmas:ActionExecution ;
    sh:property [
        sh:path prov:used ;
                sh:minCount 1;
                sh:maxCount 1 ;
                sh:hasValue ex:httpForm ;
        ] ;
       sh:property [
        sh:path hmas:hasInput;
                sh:qualifiedValueShape ex:gripperJointShape ;
                sh:qualifiedMinCount 1 ;
                sh:qualifiedMaxCount 1 
    ] .

ex:gripperJointShape a sh:NodeShape ;
    sh:class ex:GripperJoint ;
    sh:property [
           sh:path ex:hasGripperValue ;
               sh:minCount 1;
               sh:maxCount 1 ;
               sh:datatype xs:integer
    ] .

ex:form a hctl:Form ;
    hctl:hasTarget <https://api.interactions.ics.unisg.ch/leubot1/v1.3.4/gripper> ;
        hctl:forContentType "application/json" ;
        htv:methodName "PUT" .
danaivach commented 1 year ago

ArtifactProfileGraphWriterTest.java:352 fails as follows (see sh:path hmas:hasInput):

Sept 18, 2023 1:51:15 PM ch.unisg.ics.interactions.hmas.interaction.io.ArtifactProfileGraphWriterTest assertIsomorphicGraphs
INFO: Expected:
@prefix hmas: <https://purl.org/hmas/> .
@prefix hctl: <https://www.w3.org/2019/wot/hypermedia#> .
@prefix prs: <http://example.org/prs#> .
@prefix prov: <http://www.w3.org/ns/prov#> .
@prefix urn: <http://example.org/urn#> .
@prefix xs: <http://www.w3.org/2001/XMLSchema#> .
@prefix sh: <http://www.w3.org/ns/shacl#>.
@prefix ex: <http://example.org/> .
@prefix htv: <http://www.w3.org/2011/http#> .
<urn:profile> a hmas:ResourceProfile ;
              hmas:isProfileOf [ a hmas:Artifact ] ;
              hmas:exposesSignifier ex:signifier .

ex:signifier a hmas:Signifier ;
             hmas:signifies ex:moveGripperSpecification .

ex:moveGripperSpecification a sh:NodeShape ;
         sh:class hmas:ActionExecution ;
         sh:property [
             sh:path prov:used ;
             sh:minCount "1"^^xs:int;
             sh:maxCount "1"^^xs:int ;
             sh:hasValue ex:httpForm
         ] ;
         sh:property [
             sh:path hmas:hasInput;
             sh:qualifiedValueShape ex:gripperJointShape ;
             sh:qualifiedMinCount "1"^^xs:int ;
             sh:qualifiedMaxCount "1"^^xs:int
         ] .
ex:httpForm a hctl:Form ;
  hctl:hasTarget <https://api.interactions.ics.unisg.ch/leubot1/v1.3.4/gripper> ;
  hctl:forContentType "application/json" ;
  htv:methodName "PUT" .
ex:gripperJointShape a sh:NodeShape ;
  sh:class ex:GripperJoint ;
  sh:property [
    sh:path ex:hasGripperValue ;
    sh:minCount "1"^^xs:int;
    sh:maxCount "1"^^xs:int;
    sh:datatype xs:integer
  ] .

Sept 18, 2023 1:51:15 PM ch.unisg.ics.interactions.hmas.interaction.io.ArtifactProfileGraphWriterTest assertIsomorphicGraphs
INFO: Actual:
@prefix prs: <http://example.org/prs#> .
@prefix hctl: <https://www.w3.org/2019/wot/hypermedia#> .
@prefix htv: <http://www.w3.org/2011/http#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix prov: <http://www.w3.org/ns/prov#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix urn: <http://example.org/urn#> .
@prefix ex: <http://example.org/> .
@prefix xs: <http://www.w3.org/2001/XMLSchema#> .
@prefix hmas: <https://purl.org/hmas/> .

<urn:profile> a hmas:ResourceProfile;
  hmas:exposesSignifier ex:signifier;
  hmas:isProfileOf [ a hmas:Artifact
    ] .

ex:signifier a hmas:Signifier;
  hmas:signifies ex:moveGripperSpecification .

ex:moveGripperSpecification a sh:NodeShape;
  sh:class hmas:ActionExecution;
  sh:property [
      sh:path prov:used;
      sh:minCount "1"^^xs:int;
      sh:maxCount "1"^^xs:int;
      sh:hasValue ex:httpForm
    ], [
      sh:qualifiedValueShape ex:gripperJointShape;
      sh:path hmas:hasInput
    ] .

ex:httpForm a hctl:Form;
  hctl:hasTarget <https://api.interactions.ics.unisg.ch/leubot1/v1.3.4/gripper>;
  htv:methodName "PUT";
  hctl:forContentType "application/json" .

ex:gripperJointShape a sh:NodeShape;
  sh:class ex:GripperJoint;
  sh:property [
      sh:path ex:hasGripperValue;
      sh:datatype xs:integer
    ] .

expected: <true> but was: <false>
Expected :true
Actual   :false
danaivach commented 1 year ago

Notes:

Suggested test related to the above (the test is for the reader, but the example could be used on the writer too):

@Test
  public void testReadArtifactProfileSemanticTypes() {
    String expectedProfile = PREFIXES +
            ".\n" +
            "@prefix saref: <https://saref.etsi.org/core/> .\n" +
            "@prefix xs: <https://www.w3.org/2001/XMLSchema#> .\n" +
            "@prefix htv: <http://www.w3.org/2011/http#> .\n" +
            "<http://example.org/workspaces/meetingroom/artifacts/lightbulb1> a hmas:ResourceProfile ;\n" +
            "  hmas:isProfileOf <http://example.org/workspaces/meetingroom/artifacts/lightbulb1#artifact>;\n" +
            "  hmas:exposesSignifier [  a hmas:Signifier ;\n" +
            "    hmas:signifies <http://example.org/workspaces/meetingroom/artifacts/lightbulb1#toggle> ; ] .\n" +
            "\n" +
            "<http://example.org/workspaces/meetingroom/artifacts/lightbulb1#artifact> a hmas:Artifact, saref:LightSwitch .\n" +
            "\n" +
            "<http://example.org/workspaces/meetingroom/artifacts/lightbulb1#toggle> a sh:NodeShape;\n" +
            "  sh:class hmas:ActionExecution, saref:ToggleCommand ;\n" +
            "  sh:property [\n" +
            "    sh:path prov:used ;\n" +
            "    sh:minCount 1;\n" +
            "    sh:maxCount 1 ;\n" +
            "    sh:hasValue <http://example.org/workspaces/meetingroom/artifacts/lightbulb1#form> ;\n" +
            "  ] ;\n" +
            "  sh:property [\n" +
            "    sh:path hmas:hasInput;\n" +
            "    sh:qualifiedValueShape <http://example.org/workspaces/meetingroom/artifacts/lightbulb1#input> ;\n" +
            "    sh:qualifiedMinCount 1 ;\n" +
            "    sh:qualifiedMaxCount 1 \n" +
            "  ] .\n" +
            "\n" +
            "<http://example.org/workspaces/meetingroom/artifacts/lightbulb1#input> a sh:NodeShape ;\n" +
            "  sh:class saref:OnOffState ;\n" +
            "  sh:property [\n" +
            "    sh:path saref:hasValue ;\n" +
            "    sh:minCount 1;\n" +
            "    sh:maxCount 1 ;\n" +
            "    sh:datatype xs:integer\n" +
            "  ] .\n" +
            "\n" +
            "<http://example.org/workspaces/meetingroom/artifacts/lightbulb1#form> a hctl:Form ;\n" +
            "  hctl:hasTarget <https://example.org/light> ;\n" +
            "  hctl:forContentType \"application/json\" ;\n" +
            "  htv:methodName \"PUT\" .";
    ArtifactProfile profile = ArtifactProfileGraphReader.readFromString(expectedProfile);

    Artifact artifact = profile.getArtifact();
    assertEquals(ARTIFACT, artifact.getTypeAsIRI());
    assertTrue(artifact.getIRI().isPresent());
    assertTrue(artifact.getSemanticTypes().contains("https://saref.etsi.org/core/LightSwitch"));

    assertEquals(1, profile.getExposedSignifiers().size());
    Set<Signifier> signifiers = profile.getExposedSignifiers();

    List<Signifier> signifiersList = new ArrayList<>(signifiers);
    Signifier signifier = signifiersList.get(0);
    assertEquals(0, signifier.getRecommendedAbilities().size());

    ActionSpecification actionSpec = signifier.getActionSpecification();
    Set<Form> forms = actionSpec.getForms();
    assertEquals(1, forms.size());

    Set<String> actionTypes = actionSpec.getRequiredSemanticTypes();
    assertEquals(1, actionTypes.size());
    actionTypes.contains("https://saref.etsi.org/core/ToggleCommand");

    Optional<InputSpcefication> inputSpec = actionSpec.getInputSpecfication();
    assertTrue(inputSpec.isPresent());
    CompoundInput comInputSpec = (CompoundInput)  inputSpec.get();

    Set<String> inputTypes = comInputSpec.getRequiredSemanticTypes(); //defined as a `Set` since there can be more than one objects for the property `sh:class`
    assertEquals(1, inputTypes.size());
    actionTypes.contains("https://saref.etsi.org/core/OnOffState");

   assertEquals("https://saref.etsi.org/core/hasValue",
            ((SimpleInput) comInputSpec.getInputs().stream().findFirst().get()).getRequiredProperties());
   assertEquals("https://www.w3.org/2001/XMLSchema#integer",
            ((SimpleInput) input.getInputs().stream().findFirst().get()).getRequiredDataType());

   /* To be discussed
   Set<Property> properties = comInputSpec.getRequiredProperties(); 
   assertEquals(1, inputTypes.size());
   actionTypes.contains("https://saref.etsi.org/core/OnOffState");
   assertTrue((comInputSpec.getRequiredProperties.stream().findFirst().get()).getSemanticTypes().contains(https://saref.etsi.org/core/hasValue));
   assertEquals("https://www.w3.org/2001/XMLSchema#integer", (comInputSpec.getRequiredProperties.stream().findFirst().get()).getRequiredDataType());
*/
  }