IndexNextUpPreviousUrbi SDK 2.7.5

Chapter 5
The UObject Java API

The UObject Java API can be used to add new remote objects written in Java to the urbiscript language, and to interact from Java with the objects that are already defined. We cover the use cases of interfacing higher-level components (voice recognition, object detection…) with Urbi using Java.

The Java API defines the UObject class. To each instance of a Java class deriving from UObject will correspond an urbiscript object sharing some of its methods and attributes. The API provides methods to declare which elements of your object are to be shared. To share a variable with Urbi, you have to give it the type UVar. This type is a container that provides conversion and setter member functions for all types known to Urbi: double, java.lang.String, the binary-holding structures urbi.UBinary, urbi.USound and urbi.UImage, list types urbi.UList and dictionaries urbi.Dictionary. This type can also read from and write to the urbi.UValue class. The API provides methods to set up callbacks functions that will be notified when a variable is modified or read from urbiscript code. Instance methods of any prototype can be made accessible from urbiscript, providing all the parameter types and the return type can be converted to/from urbi.UValue.

The UObject Java API has the following limitations:

 5.1 Compiling and running UObjects
  5.1.1 Compiling and running by hand
  5.1.2 The umake-java and urbi-launch-java tools
 5.2 Creating a class, binding variables and functions
 5.3 Creating new instances
 5.4 Binding functions
  5.4.1 Simple binding
 5.5 Notification of a variable change or access
 5.6 Timers
 5.7 Using Urbi variables
 5.8 Sending Urbi code
 5.9 Providing a main class or not
 5.10 Import the examples with Eclipse
 5.11 Run the UObject Java examples

5.1 Compiling and running UObjects

UObjects can be compiled easily directly with the javac compiler, then you can create JAR archives using the jar tool.

In the following sections, we will try to create an uobject jar archive named ‘machine.jar’ from a set of two files (‘Machine.java’, ‘UMachine.java’.

In what follows, urbi-root denotes the top-level directory of your Urbi SDK package, see Section 16.2.

5.1.1 Compiling and running by hand

To compile your UObject you need to include in the classpath liburbijava.jar:

 
$ javac -cp urbi-root/share/sdk-remote/java/lib/liburbijava.jar:. \ 
  Machine.java UMachine.java 
$ jar -cvf machine.jar UMachine.class Machine.class 
added manifest 
adding: UMachine.class 
adding: Machine.class  

Then to run your uobject, you need to call java. We provide a main class called urbi.UMain in the liburbijava.jar archive. You can use this class to start your UObjects. This class takes the names of your uobjects jar files as argument. You also need to specify the lib folder of the urbi SDK into java.library.path:

 
$ java -Djava.library.path=urbi-root/lib                          \ 
    -cp urbi-root/share/sdk-remote/java/lib/liburbijava.jar       \ 
     urbi.UMain ./machine.jar 
urbi-launch: obeying to URBI_ROOT = /usr/local/gostai 
UObject: Urbi SDK version 2.3 rev. 3e93ec1 
Copyright (C) 2004-2010 Gostai S.A.S. 
 
Libport version urbi-sdk-2.3 rev. 66cb0ec 
Copyright (C) 2004-2010 Gostai S.A.S. 
UObject: Remote Component Running on 127.0.0.1 54000 
Kernel Version: 0 
[LibUObject] Registering function UMachine.init 1 into UMachine.init from UMachine 
[LibUObject] Pushing UMachine.init in function  

5.1.2 The umake-java and urbi-launch-java tools

umake-java can be used to compile Java UObjects. It will produce a JAR archive that you can use with urbi-launch-java.

You can give it a list of files to compile:

 
$ umake-java -q machine.uob/*.java -o machine.jar  

or directories in which C++ sources are looked for:

 
$ umake-java -q machine.uob -o machine.jar  

or finally, if you give no argument at all, the sources in the current directory:

 
cd machine.uob 
$ umake-java -q -o machine.jar  

To run your UObject then use urbi-launch-java (see Section 21.6):

 
$ urbi-launch-java machine.jar 
urbi-launch: obeying to URBI_ROOT = /usr/local/gostai 
UObject: Urbi SDK version 2.3 rev. 3e93ec1 
Copyright (C) 2004-2010 Gostai S.A.S. 
 
Libport version urbi-sdk-2.3 rev. 66cb0ec 
Copyright (C) 2004-2010 Gostai S.A.S. 
UObject: Remote Component Running on 127.0.0.1 54000 
Kernel Version: 0 
[LibUObject] Registering function UMachine.init 1 into UMachine.init from UMachine 
[LibUObject] Pushing UMachine.init in function  

5.2 Creating a class, binding variables and functions

Let’s illustrate those concepts by defining a simple object: adder. This object has one variable v, and a method add that returns the sum of this variable and its argument.

If you run this UObject and test it from Urbi it gives:

 
[00000102] *** ******************************************************** 
[00000102] *** Urbi SDK version 2.0 rev. 96a4b2f 
[00000102] *** Copyright (C) 2004-2010 Gostai S.A.S. 
[00000102] *** 
[00000102] *** This program comes with ABSOLUTELY NO WARRANTY. 
[00000102] *** It can be used under certain conditions. 
[00000102] *** Type ‘license;’ or ‘copyright;’ for more information. 
[00000102] *** 
[00000102] *** Check our community site: http://www.urbiforge.org. 
[00000102] *** ******************************************************** 
Adder; 
[00006783] Adder 
Adder.v; 
[00010871] 42 
Adder.add(-26); 
[00025795] 16 
Adder.add(-2.6); 
[00035411] 39.4  

To summarize:

5.3 Creating new instances

When you start an Urbi server, an object of each class registered with UStart is created with the same name as the class. New instances can be created from Urbi using the new method. For each instance created in Urbi, a corresponding instance of the Java object is created. You can get the arguments passed to the constructor by defining and binding a method named init with the appropriate number of arguments.

For example let’s add an Urbi constructor to our Adder class. We rewrite it as follow:

 
public class Adder extends UObject // must extends UObject 

  /// Register the class within urbi 
  static { UStart(Adder.class); } 
 
  /// Declare a variable v that will be accessible in Urbi 
  private UVar v = new UVar (); 
 
  /// Constructor 
  public Adder (String s) 
  { 
    super (s); 
    UBindFunction ("init"); 
  } 
 
  /// The init function is the constructor in Urbi. Here it takes 
  /// one argument that we use to initialize the ’v’ variable. 
  /// The init function must return an int of value 0 
  /// if all went OK. 
  public int init (double v_init) 
  { 
    /// Bind the variable v to Urbi 
    UBindVar (v, "v"); 
 
    /// Initialize our UVar v to the value given in the 
    /// constructor 
    v.setValue(v_init); 
 
    /// Bind the function add to Urbi 
    UBindFunction ("add"); 
 
    return 0; 
  } 
 
  public double add (double rhs) 
  { 
    /// Return the value of our UVar v (converted to double) 
    /// plus the value of the argument of the function. 
    return v.doubleValue () + rhs; 
  } 
}  

Now ’v’ and ’add’ are bound only when instance of the Adder object are constructed. We have added an ’init’ constructor with one parameter that we use to initialize the value of v. You can run this UObject and test it in Urbi to see the difference with the previous example. Here is what it gives:

 
[00000097] *** ******************************************************** 
[00000097] *** Urbi SDK version 2.0 rev. 96a4b2f 
[00000097] *** Copyright (C) 2004-2010 Gostai S.A.S. 
[00000097] *** 
[00000097] *** This program comes with ABSOLUTELY NO WARRANTY. 
[00000097] *** It can be used under certain conditions. 
[00000097] *** Type ‘license;’ or ‘copyright;’ for more information. 
[00000097] *** 
[00000097] *** Check our community site: http://www.urbiforge.org. 
[00000097] *** ******************************************************** 
Adder; 
[00010592] Adder 
Adder.v; 
[00013094:error] !!! 2.1-7: lookup failed: v 
var a = Adder.new(51); 
[00041405] object_13 
a.v; 
[00044742] 51 
a.add(10); 
[00054783] 61  

5.4 Binding functions

5.4.1 Simple binding

To bind the functions to Urbi, you can use:

 
void UBindFunction (Object obj, String method_name, String[] parameters_name)  
or one of the convenient version:
 
void UBindFunction (String method_name) 
void UBindFunctions(String ... method_names) 
void UBindFunction (Object obj, String method_name) 
void UBindFunctions (Object obj, String ... method_names)  

The first function takes as parameter the object containing the function (for now it is only possible to bind instance method, we do not handle static methods). The second parameter is the name of the function you want to bind. The third parameter is a list of the names if the types of the arguments. For example for the function add, in the previous Adder example, we could have used:

 
String[] params = { "double" }; 
UBindFunction (this"add", params);  

If in your UObject you have different names for each of your methods, then you can use the shorter versions of UBindFunction.

The functions you can bind must follow these rules:

5.5 Notification of a variable change or access

You can register a function that will be called each time a variable is modified by calling UNotifyChange, passing either an UVar or a variable name as first argument, and a member function of your UObject as second argument (and optionally a String array containing the name of the types of the parameters). The prototype for UNotifyChange is:

 
void UNotifyChange(String var_name, String method_name, String[] args_name); 
void UNotifyChange(String var_name, String method_name); 
void UNotifyChange(UVar v, String method_name, String[] args_name); 
void UNotifyChange(UVar v, String method_name);  

The callback function can take zero or one argument: an UVar pointing to the UVar being modified. And the callback function must return an int (the value returned is currently ignored in the actual implementation) or nothing at all (void). The notifyChange callback function is always called after the variable value is changed.

Notify functions can be unregistered by calling the unnotify function of the UVar class.

5.6 Timers

The API provides two methods to have a function called periodically:

5.7 Using Urbi variables

You can read or write any Urbi variable by creating an UVar passing the variable name to the constructor. Change the value by writing any compatible type to the UVar, and access the value by casting the UVar to any compatible type.

Note however that changes on the variable coming from Urbi code or an other module can take time to propagate to the UVar. You can read and write all the Urbi properties of an UVar by reading and writing the appropriate UProp object in the UVar.

5.8 Sending Urbi code

If you need to send Urbi code to the server, the send() function is available. You can pass it a string containing Urbi code:

 
send ("myTag:1+1;");  

You can also use the call method to make an urbiscript function call:

 
// Java equivalent of urbiscript ’System.someFunc(12, "foo");’ 
call("System""someFunc", new UValue(12), new UValue("foo"));  

These functions are member functions of the UObject class.

5.9 Providing a main class or not

We provide a main class, containing a main function, embedded in the liburbijava.jar file. This main class, called urbi.UMain is responsible for the loading of the liburbijava native library, and also for the registering of your uobjects.

5.10 Import the examples with Eclipse

We provide a sample Eclipse project configuration that you can import in Eclipse and use to create your own UObject Java.

We illustrate here how you can do this:

  1. Open Eclipse

    PIC

  2. Right click in the Package Explorer panel and select ’import’ (or go in File/import)

    PIC

  3. Select ’Existing Projects into Workspace’ in the opened windows
  4. Click ’Next’

    PIC

  5. Enter the path of the Urbi SDK on your computer
  6. Eclipse should find the .project file we provide and display the ’urbijava’ project
  7. Select the ’urbijava’ project and click ’Finish’

    PIC

The Java project is loaded. You can see the jar containing the liburbi (liburbijava.jar, storing the UObject Java API) which contains the urbi package, and also see the sources of the example we provide. We put them in the packages examples. You can inspire yourself from these examples to make your own UObjects. Here, we will see how to compile and run them in eclipse

NB: If Eclipse complains about errors in the source code, it can be that your compiler compliance level is two low. You have to set the compiler compliance level to Java 5 at least (Windows/Preferences/Java/Compiler).

PIC

5.11 Run the UObject Java examples

We provide a sample uobjectjava.launch files that you can load in eclipse to run the projects.