![]() | Note |
|---|---|
| Please note that this chapter is incomplete. An update will be published in the future. |
Java source code can directly be inserted into Obix source code. Moreover, Java code can also call Obix code, and data between Obix and Java can easily be exchanged.
The possibility to embed Java source code into Obix source code is certainly one of the most valuable features of Obix, because it enables Obix programmers to use and take advantage of the huge amount of existing and proven Java software.
Embedding Java into Obix is easy. We just have to observe the following simple rules.
Java source code must be embedded between a java and end java instruction.
Example:
java
System.out.println("Hello from Java");
end javaJava source code can appear at different locations in Obix source:
Java source code can appear any number of times in any location of any script
In the following example, a message to the system console is first written with an Obix instruction, and then with a Java statement. (Remark: the word 'statement' is used in the world of Java, rather than the word 'instruction' which is used in Obix).
service java_examples
command example_2
script
system.console.write_line ( "Hello from Obix " )
java
System.out.println ( "Hello from Java" );
end java
end
end
endRunning the above code will output the following on the system console:
Hello from Obix Hello from Java
A java_header element can appear at the beginning of a type, factory or service, just after the first instruction that declares the RSE.
java_header elements are inserted before the class declaration in the Java code. They are typically used to add import statements, and to add annotations to the Java class or interface.
Example:
service java_examples
java_header
import javax.jws.*;
import javax.crypto.*;
@WebService
end java_header
...Java source code can appear at the beginning of a type, factory or service, just after the first instruction that declares the RSE.
Example:
service java_examples
java
private static String java_string = "nice";
private static void shared_method ( String s ) {
int i = 3;
int j = i + 10;
// more Java statements
}
end java
// Obix code
endJava source code at the beginning of an RSE is typically used to store local data in Java fields, and to provide shared methods used from Java source code embedded in the RSE's scripts.
![]() | Note |
|---|---|
java_header must precede java if both are used at the beginning of an RSE. |
Java source code can be embedded just after the first instruction that declares an attribute or command.
This kind of Java code is always inserted before the declaration of the attribute or command in the Java code. It can thus be used to add annotations.
Example:
service java_examples
attribute name type:string default:"Unknown"
java
@javax.xml.bind.annotation.XmlValue
end java
end attribute
endVariables, constants, input arguments and output arguments declared in Obix can be accessed in embedded Java by simply specifying the prefixed identifier of the variable, constant, input argument or output argument.
See following rule for an example.
Scalar values in Obix can be converted to their corresponding primitive Java values by applying the getValue().java_value() methods to the object.
The following example demonstrates how to access primitive Java values stored in Obix variables, constants, input arguments and output arguments:
service java_examples
command example_4
in i1 type:string end
in i2 type:positive32 end
out result type:string end
script
var string name = "Albert"
const string friday = "Friday"
// at this point we have 2 input arguments, one output argument, a variable, and a constant declared in Obix
// we will now access them in embedded Java code:
java
System.out.println ( "values in Java:" );
// access Obix input argument
System.out.println ( "i1: " + i_i1.getValue().java_value() );
// store Obix scalar value into Java primitive value
int i2 = i_i2.getValue().java_value();
System.out.println ( "i2: " + i2 );
// access Obix variable
System.out.println ( "name: " + v_name.getValue().java_value() );
// access Obix constant
System.out.println ( "friday: " + c_friday.getValue().java_value() );
// assign Obix variable to Obix output argument
o_result = v_name;
System.out.println ( "result: " + o_result.getValue().java_value());
System.out.println();
end java
// o_result has been set in Java code; now display it with Obix
system.console.write_line ( "result in Obix: " & result )
end
end
endExecuting
se_java_examples.co_example_4 ( i1 = "foo"; i2 = 17 )
will produce the following output on the system console:
values in Java: i1: foo i2: 17 name: Albert friday: Friday result: Albert result in Obix: Albert
Scalar values in Obix can be created from primitive Java values by using specific Java constructors.
The following example shows the different Java constructors that can be used to create scalar values:
service java_examples
command example_5
script
// declare some scalars in Obix
var string first_name
var positive32 i
var character char
var yes_no flag
// now create Obix objects in Java and assign them to the above variables
java
v_first_name = new fa_string ( "Albert" );
v_i = new fa_positive32 ( 17 );
v_char = new fa_character ( 'A' );
v_flag = new fa_yes_no ( true );
end java
// check values in Obix:
check script first_name =v "Albert"
check script i =v 17
check script char =v 'A'
check script flag =v yes
end
end
endOther scalar values (zero_positive32, non_empty_string, etc.) are created analogously to the examples above.
The value of an attribute can be accessed in Java by using the Java Beans syntax for accessing properties, i.e. get{unprefixed_and_capitalized_attribute_identifier}().
Suppose the following type exists in Obix, and a factory has also been defined to create dogs:
type dog attribute name type:string end command bark end end type
We can then create a dog and access its name in Java as shown below:
service java_examples
command example_6
script
// create dog in Obix
var dog lassie = fa_dog.co_create ( "Lassie" )
// now access the dog's name in Java
java
System.out.println ( "dog's name: " + v_lassie.getName().getValue().java_value() );
end java
end
end
endHere is the result displayed:
dog's name: Lassie dog's name: Lassie
The value of an attribute can be set in Java by using the Java Beans syntax for setting properties, i.e. set{unprefixed_and_capitalized_attribute_identifier}({value}).
Let's reuse the following type defined in the section called “Attribute property setable”:
type person_2 default_factory:yes
attribute_list type:string
attribute first_name end // attribute is immutable. it can only be set in the creator.
// (property 'kind' defaults to 'constant', in which case
// property 'setable' defaults to 'creator')
attribute last_name &
kind:variable setable:factory end // only scripts in the factory that creates the object can change 'last_name'
attribute city &
kind:variable setable:all end // any script can change the value
end attribute_list
end typeWe can now create a person and change the city through embedded Java as follows:
service java_examples
command example_7
script
// create person in Obix
var person_2 paganini = fa_person_2.co_create ( &
first_name = "Nicolas" &
last_name = "Paganini" &
city = "unknown" )
// now set attribute 'city' in Java
java
v_paganini.setCity ( new fa_string("Genoa, Italy") );
end java
// check in Obix
check script paganini.city =v "Genoa, Italy"
end
end
endWhenever a method of a type, factory or service is called in Java, the package path must be specified if no import statements are defined between java_header and end java_header. The package path consists of the library path defined in Obix. For each library, the prefixed library identifier must be used (i.e. li_bar for library bar)
Example:
If a service foo exists in library bar.zar, then the service is accessed in Java with li_bar.li_zar.se_foo.
See also the following rule for an additional example.
An object or service command (including object creators) can be executed in Java by calling the method {prefixed_command_identifier}_command({input_values}), where {prefixed_command_identifier} denotes the actual prefixed identifier of the command, and {input_values} denotes the list of actual input arguments passed to the command.
Example:
service java_examples
command example_8
script
// use Obix service command to display "Hello" on system console
system.console.write_line ( "Hello from Obix" )
java
// now use same command in Java
org.obix.obix_core.system.se_system.getConsole().co_write_line_command ( new fa_string("Hello from Java") );
// the same result can of course also be achieved with the following statement:
System.out.println ("Hello from Java");
end java
// create dog in Obix
var dog bello = fa_dog.co_create ( "Bello" )
// use Java to make him bark
java
v_bello.co_bark_command();
end java
// we can also make the inverse: create the dog in Java and make him bark in Obix:
java
v_bello = manual_examples.li_basics.li_RSE.fa_dog.co_create_command(new fa_string("Bello"));
end java
system.console.write_line ( "Hello from Obix again" )
bello.bark
end
end
endThe result on the system console will be:
Hello from Obix Hello from Java Hello from Java bark bark Hello from Obix again bark bark
![]() | Note |
|---|---|
Whenever in doubt about the correct syntax to use in embedded Java code, it can be useful to first write the instruction(s) in Obix and then look at the Java statements produced by the Obix compiler. Java source code produced by the Obix compiler is created in the application's For example, the following code: service java_examples
command example_9
script
var string capital = "New York"
capital = capital.to_upper_case
var zero_positive32 count = capital.item_count
end
end
endresults in the following Java code produced by the Obix compiler: org.obix.obix_core.basics.scalars.string.in_string v_capital = new fa_non_empty_string ("New York");
v_capital = v_capital.co_to_upper_case_command ();
org.obix.obix_core.basics.scalars.number.integer.integer32.in_zero_positive32 v_count = v_capital.getItem_count(); |
Suppose that a certain software component developed in Java is used again and again in an Obix application.
A first approach for using this component from within Obix would be to embed Java source code each time we need the component, by applying the rules explained above.
However, this would result in two serious inconveniences:
First, the Obix source code would be cluttered with lots of embedded Java source code which makes the application more difficult to write and maintain, because programmers working on the project have to cope with two languages.
Secondly, some features existing in Obix, such as contract programming, are unavailable in embedded Java code, which increases the risk for less reliable code.
A much better approach is to write an Obix wrapper for the existing Java component. An Obix wrapper is simply an Obix software component that internally uses the Java component to implement the functionality.
The advantages are important:
Embedded Java code now only exists in the Obix software component that implements the functionality. All other code using the component is written in Obix.
The interface to the component can be adapted and enhanced. For example, contract programming can be used to make the component more robust. Features can be renamed. Features not existing in the Java component can be added in the Obix wrapper. And obsolete or unused features in the Java component can be made inaccessible.