Home
Categories
Dictionary
Glossary
Download
Project Details
Changes Log
What Links Here
FAQ
License

Third map ontology tutorial



This tutorial use the same Ontology as the second map ontology tutorial, but it uses a SPARQL custom function to handle requests concerning the Meteo on a Waypoint.

Use case

We have exactly the same use case as for the previous tutorial, but:
  • We will add a METAR for each Waypoint. This METAR will be handled by a new module which will provide the visibility for a Waypoint
  • The visibility will be added in the query, as a new keyword. The visibility will not be part of the Owl database, but it will be retrieved by the Jena engine, using the SPARQL custom functions framework

Architecture

Overview

We add the two following modules to the architecture of the previous ontology tutorial:
  • A meteoProvider module which will store the METAR for the Waypoints, and return the visibility for one Waypoint
  • A Meteo module used by the previous module to decode the METAR and get the visibility

mapOntologyarchi3

Add new services for getting the visibility

We will use the http://dassault-aviation.com/meteo:decodeDatas service of the Meteo module:
      <namespace uri="http://dassault-aviation.com/meteo">
         <requestResponse name="decodeDatas">
            <request>
               <data name="meteoType" desc="Type of meteo to decode" type="meteoType" />
               <data name="encoded" desc="Meteo coded content" type="string" />
               <data name="level" desc="message level" type="messageLevel" />
               <data name="datas" desc="keys of the datas to decode" type="stringArray" />
            </request>
            <response>
               <data name="decoded" desc="Decoded datas" type="map" />
               <data name="decodeStatus" desc="Request status" type="decodeStatus" />
            </response>
         </requestResponse>      
      </namespace>
This service will be ued by our meteoProvider module.

We will also add a new meteo service which will return a specified METAR parameter:
      <requestResponse name="meteo">
         <request>
            <data name="waypoint" desc="Waypoint ID" type="string" />
            <data name="type" desc="Meteo type" type="string" />
         </request>
         <response>
            <data name="result" desc="Result" type="string" />
            <data name="validity" desc="Content validity" type="bool" />
         </response>
      </requestResponse>
This service will be returned by our meteoProvider module.

Add the meteoProvider module and the Meteo module

We will add our two applications to the configuration:
      <applications>   
         <deployment>
            <lib url="tacticalEnvCommon.jar" />   
            <lib url="JenaCommon.jar" /> 
      <lib url="MeteoCommon.jar" />          	  
         </deployment>  
      ...
   
         <application name="meteoProvider">
            <deployment>
               <lib url="MeteoProvider.jar" />
            </deployment>
            <module name="meteoProvider" >
               <implementation path="org.da.meteoprovider.MeteoProvider" >
                  <initEntryPoint method="init" />
                  <defaultReceiveEntryPoint method="subscribe" />
               </implementation>           
               <interfaces>
                  <requestReceived service="meteo" />  
                  <requestSend service="decodeDatas" uri="http://dassault-aviation.com/meteo" timeOut="500ms" />            
               </interfaces>
            </module>
         </application>                  
   
         <application name="meteo">
            <deployment>
               <lib url="MeteoModule.jar" />
            </deployment>
         </application>   
      </applications>
We also need to add the meteo service as an interface of the Jena Jena module:
      <application name="jena">
         <deployment>
            <lib url="JenaModule.jar" />
         </deployment>
         <modules>      
            <module name="jena">      
               <interfaces>
                  <requestReceived service="owlRequest"/>
                  <requestReceived service="owlObjectRequest" uri="http://dassault-aviation.com/jena" />
                  <requestReceived service="applyOperations" uri="http://dassault-aviation.com/jena" />    
                  <eventReceived service="saveSchema"/>
                  <requestSend service="meteo" />  
               </interfaces>      
            </module>
         </modules>      
      </application>
The following diagram shows how the visibility data will be computed and passed on to the Jena module:
mapOntologyfunction

Develop the meteoProvider module

The meteoProvider module has nothing special:
  • It parse an xml file bundled with the module to get the METAR for the Waypoints
  • When it receives a request for the meteo service, it sends a request for the http://dassault-aviation.com/meteo:decodeDatas service, and returns the result for the specified meteo parameter type as a response

Initialize the module

The bundle xml file holding the METAR associates an encoded METAR to a Waypoint:
      <meteo>
         <metar waypoint="WPT4">METAR LFPG 291300Z 23014KT 9999 BKN006 14/14 Q1009 NOSIG</metar>
         <metar waypoint="WPT5">LFGJ 291300Z AUTO 19011KT 9999 BKN008 BKN012 BKN023 13/12 Q1013 TEMPO 3000 -DZ BR OVC003</metar>
         <metar waypoint="WPT6">LFPN 291300Z AUTO 25014KT 9999 BKN009 OVC014 14/13 Q1009 TEMPO 2000 DZ BKN002</metar>  
      ...
      </meteo>
The init method is used to parse the xml file holding the METAR content:
      public class MeteoProvider {
         private static final NamespaceKey METEO_REQUEST = NamespaceKey.createKey("meteo");
         private static final NamespaceKey DECODE_DATAS_REQUEST = NamespaceKey.createKey("http://dassault-aviation.com/meteo", "decodeDatas");
         private ResponseServiceInstance meteoService;
         private RequestServiceInstance decodeDatasService;
         private Module module = null;
         private String meteoType = null;
         private Map<String, String> metarMap = null;  
       
         public void init(Module module) {
           this.module = module;
           this.meteoService = (ResponseServiceInstance) module.getService(METEO_REQUEST);
           this.decodeDatasService = (RequestServiceInstance) module.getService(DECODE_DATAS_REQUEST);
           MetarParser parser = new MetarParser();
           try {
             this.metarMap = parser.parse();
           } catch (IOException ex) {
             ex.printStackTrace();
           }
         }
      }      

Handle the meteo requests

When receiving a request for the meteo service, the module:
  • Get the encoded METAR associated with the waypoint in its internal Map
  • Sends a request for the http://dassault-aviation.com/meteo:decodeDatas service with the encoded METAR and the specified parameter type
  • Upon reception of the response, sends the meteo service response
We have the following code:
      public void subscribe(ServiceInstance service) {
         if (service.getKey().equals(METEO_REQUEST)) {
           String waypoint = service.getValueAsString("waypoint");
           String type = service.getValueAsString("type");
           handleMeteo(waypoint, type);
         } else if (service.getKey().equals(DECODE_DATAS_REQUEST)) {
           Map<String, Object> map = (Map<String, Objec>) decodeDatasService.getData("decoded").getValue();
           String result = map.get(meteoType).toString();
           meteoService.setDataBooleanValue("validity", true);
           meteoService.setDataStringValue("result", result);
           meteoService.invoke();
        }
      }

      private void handleMeteo(String waypoint, String type) {
         if (metarMap.containsKey(waypoint)) {
           this.meteoType = type;
           String metar = metarMap.get(waypoint);
           decodeDatasService.getData("meteoType").setValue("METAR");
           decodeDatasService.getData("level").setValue("COMPACT");
           List<String> datas = new ArrayList<>();
           datas.add(type);
           decodeDatasService.getData("encoded").setValue(metar);
           decodeDatasService.getData("datas").setValue(datas);
           decodeDatasService.invoke();
         } else {
           meteoService.setDataBooleanValue("validity", false);
           meteoService.invoke();
         }
      }      

Implement the new keyword


Now we are dealing with the core of this tutorial: we will implement the new http://www.dassault.aviation.com/meteo:visibility keyword for the Jena engine.

Edit the closest ATT waypoint query


We will edit this query to add the visibility in the query:
      public void queryClosestATTWaypoint() {
         SparqlRequest request = new SparqlRequest(SCHEMA);
         requestType = CLOSEST_ATT_WAYPOINT;
         request.addSelect("label");
         request.addSelect("distance");
         request.addSelect("visi"); // we add the new visi variable for the visibility
         request.addAdditionalVariable("wpt");
         request.addAdditionalVariable("ac");

         request.addType("wpt", "Waypoint");
         request.addPropertyIndividualRef("wpt", "hasWaypointType", "ATT");
         request.addPropertyRef("wpt", "Label", "label");
         request.addType("ac", "Aircraft");
         request.addPropertyValue("ac", "Label", "falcon");
         request.addDistance("wpt", "ac", "distance", ISparqlRequest.DISTANCE_NM, true);

         // we add a new BIND construct for the visibility
         Bind bind = request.addBind("visi");
         FunctionExpression expression = new FunctionExpression("visibility", "da");
         expression.addArgument(new VariableExpression("label"));
         bind.addExpression(expression);

         request.setLimit(1);
         request.setOrderBy("distance", true);

         objectRequestService.setDataStringValue("reqSchema", SCHEMA);
         objectRequestService.setDataStringValue("query", request.toString());
         objectRequestService.invoke();
      }      
The constructed request will look like that:
      SELECT ?label ?distance ?visibility
      WHERE {
         ?wpt rdf:type inav:Waypoint .
         ?wpt inav:Label ?label .
         ?wpt inav:hasWaypointType <http://localhost/INAV#ATT> .
         ?ac  rdf:type inav:Aircraft .          ?ac  inav:Label "falcon" .          ?wpt inav:hasExactGeometry ?auto_2 .          ?auto_2 inav:asWKT ?auto_3 .          ?ac inav:hasExactGeometry ?auto_4 .          ?auto_4 inav:asWKT ?auto_5 .          BIND (geof:distance(?auto_3, ?auto_5, <http://www.opengis.net/def/uom/OGC/1.0/nauticalMile>) as ?distance)          BIND (da:visibility(?label) as ?visibility)       }       ORDER BY ASC( ?distance )?      LIMIT 1      a   c  rdf:type inav:Aircraft .
         ?ac 
And we will also edit the handling of the result:
      // there is only one result
      QueryResults.Result result = results.getOrderedResultsList().iterator().next();
      String label = result.getValue("label").getValueAsString();
      double distance = result.getValue("distance").getValueAsDouble();
      int visibility = (int) result.getValue("visi").getValueAsFloat();
      if (visibility > 0) {
         System.out.println("Closest ATT Waypoint is " + label + " at " + distance + " NM and visibility " + visibility + " m");
      } else {
         System.out.println("Closest ATT Waypoint is " + label + " at " + distance + " NM");
      } 

Asking requests

In this tutorial, the requests are sent using the requestEngine UI window:
mapontologyreqGUI
We only changed the "Closest ATT Waypoint" request.

Click on the "Closest ATT Waypoint" button: you will have this kind of result on the Java console:
      Closest ATT Waypoint is ATT1 at 47.34699500770006 NM and visibility 10000 m

Using a sub-query to speed-up the query

The way we bind the visibility is not optimal, because we will get the visibility for every Waypoint, even those which are not the closest.

Ideally we would want to get the visibility for only the closest. To achieve that, we will use a sub-query:
      public void queryClosestATTWaypoint() {
         SparqlRequest request = new SparqlRequest(SCHEMA);
         requestType = CLOSEST_ATT_WAYPOINT;
         request.addSelect("label");
         request.addSelect("distance");
         request.addSelect("visibility"); // we add the new visi variable for the visibility

         SparqlRequest innerRequest = request.addInnerQuery();
         innerRequest.addSelect("label");
         innerRequest.addSelect("distance");
         innerRequest.addAdditionalVariable("wpt");
         innerRequest.addAdditionalVariable("ac");

         innerRequest.addType("wpt", "Waypoint");
         innerRequest.addPropertyIndividualRef("wpt", "hasWaypointType", "ATT");
         innerRequest.addPropertyRef("wpt", "Label", "label");
         innerRequest.addType("ac", "Aircraft");
         innerRequest.addPropertyValue("ac", "Label", "falcon");
         innerRequest.addDistance("wpt", "ac", "distance", ISparqlRequest.DISTANCE_NM, true);

         innerRequest.setLimit(1);
         innerRequest.setOrderBy("distance", true);

         // we add a new BIND construct for the visibility
         Bind bind = request.addBind("visibility");
         FunctionExpression expression = new FunctionExpression("visibility", "da");
         expression.addArgument(new VariableExpression("label"));
         bind.addExpression(expression);

         String str = request.toString();
         System.out.println(str);
         objectRequestService.setDataStringValue("reqSchema", SCHEMA);
         objectRequestService.setDataStringValue("query", request.toString());
         objectRequestService.invoke();
      }      
You must be aware that the inner query is always performed prior to the outer one, so in this case:
  • We get the closest Waypoint in the outer query
  • We bind with the visibility in the inner query
The constructed request will look like that:
      SELECT ?label ?distance ?visibility  
      {
         {SELECT ?label ?distance  
         WHERE 
         {   
           ?wpt rdf:type inav:Waypoint .
           ?wpt inav:Label ?label .
           ?wpt inav:hasWaypointType <http://localhost/INAV#ATT> .
           ?ac rdf:type inav:Aircraft .            ?ac inav:Label "falcon" .            ?wpt inav:hasExactGeometry ?auto_2 .            ?auto_2 inav:asWKT ?auto_3 .            ?ac inav:hasExactGeometry ?auto_4 .            ?auto_4 inav:asWKT ?auto_5 .            BIND (geof:distance(?auto_3, ?auto_5, <http://www.opengis.net/def/uom/OGC/1.0/nauticalMile>) as ?distance)           }           ORDER BY ASC(?distance )           LIMIT 1          } BIND (da:visibility(?label) as ?visibility)       }    ?   ac rdf:type inav:Aircraft .
           ?ac

See also


Categories: tutorials

Copyright 2017-2020 Dassault Aviation. All Rights Reserved. Documentation and source under the LGPL v3 licence