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

Map ontology custom function



This article presents the development of the custom function used in the third map ontology tutorial.

Overview

This custom function module implements the custom http://www.dassault.aviation.com/meteo:visibility new keyword. It will send a meteo request to the meteoProvider module.

To to that, we need to:
  • Add the meteo service as an interface of the Jena Jena module
  • Develop a UAFunctionFactory to be able to retrieve our function
  • Develop a UAFunction to implement the http://www.dassault.aviation.com/meteo:visibility keyword

Update the Jena module declaration

We need to:
  • Add the meteo service as an interface of the Jena Jena module
  • Add our future UAFunctionFactory to the Jena module library
We have the following Jena application declaration:
      <application name="jena">
         <deployment>
            <lib url="JenaModule.jar" />
      <lib url="JenaFunctions.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>

Declare the path of the UAFunctionFactory in the Jena properties

To be able to handle the new keyword, we must tell the Jena module that there is a custom functions factory in the properties:
      <properties>   
         <application name="jena">
            <module name="jena">
               <moduleArrayGroupProperty key="schemas">
                  <moduleArrayValue>
                     <moduleProperty key="name" value="inav" />
                     <moduleProperty key="owlData" value="MapGeoSparql.owl.rdf" />
                     <moduleProperty key="prefixNS" value="inav:" />
      <moduleProperty key="customFunctions" value="uaFunctions.xml" /> 
                     <moduleProperty key="owlNS" value="http://localhost/INAV#" />
                     <moduleProperty key="geosparql" value="true" />
                  </moduleArrayValue>
               </moduleArrayGroupProperty>
               <moduleProperty key="debug" value="false" />
               <moduleProperty key="commit" value="true" />
            </module>
         </application>
      ...
      </properties>
The uaFunctions.xml only has to declare the path of our factory:
      <customFunctions>
         <factoryPath path="JenaFunctions.jar"/>                         
      </customFunctions>
Now we have to code this factory. Don't worry, it is not as hard as it looks.

Develop the UAFunctionFactory

Specify the manifest for the factory

As specified in the Jena custom functions article, we need to specify the class for the factory in the manifest of our jar file:
      JenaFactoryConf: org/da/jena/functions/uaFunction.xml
The specification of the uaFunction.xml file is the following:
      <customFunctions>
         <factory name="meteoUAFactory" path="org.da.jena.functions.MeteoUAFactory" prefix="da" namespace="http://www.dassault.aviation.com/meteo"> 
            <uaFunction name="visibility" countArguments="1" />
         </factory>                                       
      </customFunctions>
As you can see:
  • We only specify one factory, but we could have defined more than once in several Jar files
  • The org.da.jena.functions.MeteoUAFactory is the path of our UAFunctionFactory
  • We defined the rpefix and the namespace of the vocabulary for our factory
  • Ths factory only handle one function called visibility, with only one argument (in our case, it is the Waypoint Label)
Note that the complete declaration for the keyword will be da:visibility or http://www.dassault.aviation.com/meteo:visibility.

Implement the factory

Our factory lust implement the UAFunctionFactory interface, but as explained in the Jena uaFunctions article, it is simpler to extend the AbstractUAFunctionFactory class:
      public class MeteoUAFactory extends AbstractUAFunctionFactory {

         public MeteoUAFactory() {
           super();
         }

         @Override
         protected Function createImpl(String fctName) {
           FunctionKey fkey = UAFunctionFactory.createFunctionKey(fctName);
           // the complete IRI is http://www.dassault.aviation.com/meteo:visibility
           if (fkey.getURI().equals("http://www.dassault.aviation.com/meteo")) {
             switch (fkey.getName()) {
               case "visibility":
                 return new visibility();
               default:
                 return null;
             }
           } else {
             return null;
           }
         }
      }      
As you see, the only thing the factory must do is return a new instance of the Function class implementing the keyword.

Implement the function

Our function must be able to invoke and be notified from services, so it must implement the UAFunction interface. Also this function has only one argument, so it must extend the FunctionBase1 class:
      public class visibility extends FunctionBase1 implements UAFunction {
      }      

Initialize the function

We will implement the init method to get our factory and the meteo service:
      public class visibility extends FunctionBase1 implements UAFunction {
         private Module module = null;
         private UAFunctionFactory factory = null;
         private ServiceInstance meteoService = null;

         public visibility() {
           super();
         }

         @Override
         public void init(Module module, UAFunctionFactory factory) {
           this.module = module;
           this.factory = factory;
           meteoService = module.getService("meteo");
         }
      }   

Implement the exec method

The exec method for the function will return the result of the function invocation. It is called by the Jena engine upon encountering the keyword for the function:
      public class visibility extends FunctionBase1 implements UAFunction {
         private Module module = null;
         private UAFunctionFactory factory = null;
         private float result = 0;

         public visibility() {
           super();
         }

         @Override
         public NodeValue exec(NodeValue nv) {
           wpt = nv.getString(); // the waypoint name is a string
           factory.invokeAndBlock(this, 100); // we block to be sure that the result will be available immediately
           return NodeValue.makeFloat(result); // the result is a visibility, we decide to return it as a float
         }
      }
As explained in the Jena uaFunctions article, we need to implement the invoke method of the UAFunction interface, because this is this method which will be called by the factory upon calling factory.invokeAndBlock(this, 100):
      @Override
      public void invoke() {
      _  // invoke the meteo service
      _  meteoService.getData("type").setValue("visibility");
      _  meteoService.getData("waypoint").setValue(wpt);
      _  meteoService.invokeAndBlock();

      _  // as the invoke is blocking, we get the result just after the invoke
      _  String resultS = meteoService.getValueAsString("result");
      _  if (resultS.isEmpty()) {
      _    result = -1;
      _  } else {
      _    result = Float.parseFloat(resultS);
      _  }
      _  factory.unlock(); // the calling thread is blocked until unlock is called
      }      
Now everything is done.

See also


Categories: tutorials

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