The Java Objects library allows you to use Java Objects from Omnis code. Once a Java Object has been created in Omnis, its methods can be called in the same manner as any Omnis object.
This chapter assumes that you have both a basic knowledge of Omnis Studio notation and a good knowledge of the Java Language.
IMPORTANT NOTE: Oracle has changed the way it licenses Java. So in order for you to avoid the ongoing use of Java in connection with Omnis Studio, we no longer provide various Java files in Omnis Studio 10 or above and consequently we have removed various Omnis libraries or features that rely on Java: these files are available from support if you need them. Specifically, the javaobjs and javacore libraries have been removed; the Reset Java Class Cache hyperlink in the Studio Browser is not shown, and will only appear if the JavaObjs Library is put back in the Omnis tree and loaded.
To use Java Objects in Omnis, you must install the latest version of Java 8 which is now available from Oracle who acquired Sun Microsystems and the Java technology.
For Studio 10 or above you need to install the javaobjs and javacore libraries, available from support.
To use Java in Omnis Studio for development and deployment (such as Java Objects or the Web Services component, which uses Java) you need to install and reference Java Version 8, which is available from Oracle: you can download the Java Developer Kit (JDK), for Windows or macOS, or Java Runtime Environment (JRE), for Windows only, from the following location:
Having installed the latest JDK or JRE you need to configure the JVM, either using a new entry in the Omnis configuration file (config.json), or by setting an environment variable: OMNISJVM64 or OMNISJVM32 depending on whether you are running the 64-bit or 32-bit version of Omnis Studio. If you specify a value in config.json, it overrides the value in the environment variable.
To setup the JVM in the config.json file, add an entry named “jvm” in the “java” object in the configuration file, for example, on Windows:
"java": {
"jvmPath":"c:\\Program Files\\Java\\jre8\\bin\\server\\jvm.dll",
"resetClassCacheOnStartup": false
}
Or on macOS:
"java": {
"jvmPath":"/Library/Java/JavaVirtualMachines/jdk1.8.XXX.jdk/Contents/Home/jre/lib/server/libjvm.dylib",
"resetClassCacheOnStartup": false
}
You can set the JVM in the config.json file on a Linux server in a similar manner.
There are currently a number of restrictions imposed on Java Objects as follows:
Java Events are not supported.
The Java Objects component is non-visual and the use of awt/swing is not supported.
Java Interface classes cannot be used directly in Omnis. To use an interface class, create a custom class which implements the interface.
J2SE/Java SE is currently supported, meaning that you will have access to a Java Virtual Machine and can run any Java Code on this virtual machine with respect to “b”. However, J2EE is not supported.
Java Objects under macOS are supported on version 10.3 (Panther) or above.
Omnis Studio includes an example library called “example.lbs” that demonstrates the use of Java Objects. This library is referred to throughout this chapter and is designed to be used in conjunction with the Java Package called ‘example’. Both the Omnis library and the Java Package can be found in the \Java\JavaCode\example in the main Omnis folder.
The following assumes that you are the System Administrator of the platform on which you are working, or that you have a basic knowledge of setting environment variables on your respective platform.
To use Java Objects in Omnis, you must define or edit a number of environment variables, including the CLASSPATH and OMNISJVM64 OR OMNISJVM32 depending on whether you are running the 64-bit or 32-bit version of Omnis Studio. These variables are slightly different for each platform and are described in the following sections.
You do not need to add the Omnis Java folder, ‘OSXX\java\JavaCode’, or any of its sub-folders to the CLASSPATH environment variable since this folder is registered by Omnis automatically. You can place your own Java classes in this folder or any of its sub-folders to register them automatically. However if you want to use any Java classes anywhere on your system you need to include their location in the CLASSPATH.
When setting the CLASSPATH on Linux and macOS, any folder names containing UTF-8 based extended characters should work, but on Windows characters are restricted to extended ASCII only.
The environment variable OMNISJVM64 OR OMNISJVM32 should be defined to point to the installation of the Java Virtual Machine that you wish to use. The Java Virtual Machine is normally located in the bin\client folder of your J2SE installation. For example:
OMNISJVM64 OR OMNISJVM32= C:\jdk8.XXX\jre\bin\client\jvm.dll
or
OMNISJVM64 OR OMNISJVM32= C:\Program Files\Java\jre8.XXX\bin\client\jvm.dll
The CLASSPATH environment variable should also be defined to point to folders that contain any custom classes that you wish to use with Omnis. For example:
CLASSPATH=c:\java\myclass;c:\java\myclass1
Setting environment variables under Windows
In Windows, you can add or edit environment variables in the System Properties dialog in the Control Panel. On the Advanced tab, click the Environment Variables button, then click New to define a new variable, or select the name of the User or System variable you want to change and click Edit.
The CLASSPATH environment variable should be defined to point to folders that contain any custom classes that you wish to use with Omnis. For example:
CLASSPATH=/Volumes/HD/classes/myclass:/Volumes/HD/classes/myclass1
The environment variable OMNISJVM64 OR OMNISJVM32 should be defined to point to the installation of the Java Virtual Machine that you wish to use. The Java Virtual Machine is normally located in the lib/i386/client folder of your J2SE/Java SE installation. For example:
OMNISJVM64 OR OMNISJVM32=/usr/java/jdk8.XXX/jre/lib/i386/client/libjvm.so
export OMNISJVM64 OR OMNISJVM32
The CLASSPATH environment variable should also be defined to point to folders that contain any custom classes that you wish to use with Omnis. For example:
CLASSPATH=/classes/java/myclass:/classes/java/myclass1
export CLASSPATH
The PATH environment variable should be modified to include the path to the bin folder of your J2SE/Java SE installation. For example:
PATH=/usr/java/jdk8.XXX/bin:$PATH
export PATH
The LD_LIBRARY_PATH environment variable should be modified to point to the lib/i386 and lib/i386/client folders of your J2SE/Java SE installation as follows:
LD_LIBRARY_PATH=/usr/java/jdk8.XXX/jre/lib/i386:
/usr/java/jdk8.XXX/jre/lib/i386
/client:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH
Java reflection requires that parameter objects exist on the main classpath. To ensure that objects or object references can be passed to a Java method, place the path to the jar file in the CLASSPATH variable.
You can use the OMNISCLASSPATH environment variable to specify Java classes instead of CLASSPATH. This can increase performance in situations where you have multiple Java applications installed that are not being used with Omnis. Under normal circumstances, the classes for these applications will be added to the Omnis Class Cache, even though they are not being used. By using OMNISCLASSPATH, you will be able to specify only the classes that you wish to use with Omnis.
If OMNISCLASSPATH is not defined, CLASSPATH will be used.
There are three functions in Omnis that you can use to for manipulate environment variables.
Listing Environment Variables
The listenv() function returns a 2 column list of the Omnis process environment variables. Column 1 contains the variable name and column 2 the variable value. The list is sorted by the variable name column, and is case insensitive. There is no need to define the list first; the returned list has 2 character columns, name and value. For example:
Calculate lList as listenv()
# returns a list of environment variables on the current system
Setting an Environment Variable
The putenv(name,value) function sets the Omnis process environment variable with the specified name to the specified value. Creates a new environment variable if necessary, and returns true for success, false for failure. For example:
Do putenv("OMNISCLASSPATH","C:\Program Files\OmnisSoftware\OSXX\java")
# Creates the environment variable OMNISCLASSPATH and sets its value to C:\Program Files\OmnisSoftware\OSXX\java
Getting the value of an Environment Variable
The getenv(name) function returns the value of the Omnis process environment variable with the specified name. For example:
Calculate lVar1 as getenv("OMNISJVM64 OR OMNISJVM32")
# Returns the location of the JVM, e.g. C:\jdk8.XXX\jre\bin\client\jvm.dll
There are some Omnis preferences that allow you to set the memory allocation for Java. You can set the properties on the Java tab of the main Omnis preferences, visible in the Property Manager. The properties are:
$usejavaoptions (boolean)
when kTrue, the Java Virtual Machine will use the options specified in $javaoptions Omnis preference; if set to kFalse, the JVM will use its own internal memory settings.
$javaoptions
You can use this property to specify any switches you wish to pass to the Java Virtual Machine, e.g. to set a system property value, specify -Dproperty=value
In version 8.0.1 and earlier, the $javaoptions preference was limited to 255 chars. This has been extended and the theoretical limit is now the maximum length of an Omnis character variable. You can add the following parameters to the $javaoptions property, assuming $usejavaoptions is set to true.
Original heap size | To specify the original heap size for the JVM add "-Xms <heapsize>" to the $javaoptions property |
Maximum heap size | To specify the maximum heap size for the JVM add "-Xmx <maxheapsize>" to the $javaoptions property |
Stack size | To specify the stack size for the JVM add "-Xss <stacksize>" to the $javaoptions property---- |
Note: The above options are for advanced users only. If you are unsure of what the settings for the above properties should be, you should leave $usejavaoptions set to kFalse.
Note to existing users: the above options replace the Omnis $root preferences $javainitialheap, $javamaxheap and $javathreadstack. The $javaother property was renamed to $javaoptions.
Once you have configured your platform to run J2SE/Java SE, start Omnis. There may be a brief pause during startup. This is because Omnis is starting the Java Virtual Machine and collecting information on Java System Classes. This procedure does not occur every time you start Omnis as Java Class information is cached. However, this procedure will occur again if you reset the Omnis Class Cache (see the Advanced Topics section for further details on resetting the Omnis Class Cache).
When Omnis starts up, it scans all of the paths on the CLASSPATH environment variable and creates a cache of all available classes on your system. When Omnis exits, any classes that you have added are appended to the internal Omnis Java class cache. When Omnis is restarted, all classes are read from this class cache.
Omnis will detect that you are attempting to add an existing class and will not attempt to add the class a second time. This will not produce an error in your code, which means that you do not have to worry about implementing a “first time” flag when adding classes.
To reset the Java class cache, you can either delete the cache file manually or use the Reset class cache option in the Studio Browser (click on the Studio option in the treelist of the Studio Browser, then click on the Java option to show the Reset class cache option). The cache file is called ‘jcache1.dat’ and can be found in the omnis\java folder.
Creating Java Objects is a two-stage process that is similar to the process of creating Automation Objects in Omnis. A Java Object is first declared and then constructed using the $createobject() method. This process is described in the following sections.
Java Objects can be manipulated in a similar manner to other Omnis Objects. A Java Object can be defined in a variety of ways:
or
or
It is not possible to use a Java Class that contains either the string 'omnis' or 'javacore' in its name.
To create a Java Object in the method editor, simply declare an object variable and set its subtype to the desired Java Objects Class. The Java Class can be chosen from the “Select Object” dialog. To select a Class, navigate the Object Selection Tree until the desired class is found, highlight the class and click OK. The Object Selection Tree is split into two sections under the “JavaObjs” heading. These are “ClassPath” and “System”. Any classes that have been placed in any of the folders that are specified in the CLASSPATH environment variable will appear in the “ClassPath” section. All other available classes will appear in the “System” section.
Object References are similar to object variables but you are responsible for the allocation and de-allocation of the object. Object References are declared in the Method Editor but do not have a subtype. The Object that is associated with an Object Reference is determined at runtime when it is allocated via notation:
To declare an Object Reference, simply declare a variable in the Method Editor and set its type to “Object Reference”.
To allocate an Object to an Object Reference, you must use notation. As notation strings for Java Objects can be very long (due to the large hierarchies that are present in some Java Packages) the “Object Selection Tree” is displayed as a helper window when entering Java Objects notation. If a class is selected from this tree then a large portion of the notation is created for you.
All Java Object notation begins with $extobjects.JavaObjs Library.$objects. The remainder of the notation string is dependant on the Java Class that is being used. For example:
$extobjects.JavaObjs Library.$objects.//JavaObjs\ClassPath\zipdemo\zipdemo//
As you can see from the above, the Object Selection Tree has completed the notation string by adding JavaObjs\ClassPath\zipdemo\zipdemo. In addition to this, a call to the $newref() method has to be added manually. This method is responsible for allocating an Object to the Object Reference. The command reads as follows:
Calculate lzipreference as $extobjects.JavaObjs Library.$objects.//JavaObjs\ClassPath\zipdemo\zipdemo//.$newref()
When the above command is executed, a zipdemo Java Object will be created and assigned to the Object Reference lzipreference. It is your responsibility to ensure that this Object is deleted using the $deleteref() method once it has served its purpose. For example:
Do lzipreference.$deleteref()
Java Objects can also be defined using the object type via notation. To define a Java Object via notation, simply follow the instructions in the previous section but use an Object type instead of an Object Reference type and call the $new() method instead of the $newerf() method.
Once a Java Object has been declared, it needs to be constructed. Declaring a Java Object simply tells Omnis that the Object exists. Constructing a Java Object using $createobject() actually performs the work of constructing the Object inside the Java Virtual Machine.
By default all Java Objects will have at least one $createobject() method which takes no parameters. This method can be used to create a Java Object as follows:
Do lzipdemo.$createobject()
Other Java Objects may have more than one $createobject() method. In this case, each $createobject() method corresponds directly to a Java Constructor for the class that is being used. For example, the java.lang.String class has the following constructors:
String() |
String(String original) |
String(byte[] ascii, int hibyte) |
String(byte[] bytes) |
String(char[] value) |
String(byte[] bytes,int offset,int length,String enc) |
String(StringBuffer buffer) |
String(byte[] bytes,String enc) |
String(char[] value,int offset,int count) |
String(byte[] ascii,int hibyte,int offset,int count) |
String(byte[] bytes,int offset,int length) |
These are mirrored in Omnis by the following $createobject() methods:
Calling any of above $createobject() methods will invoke the corresponding Constructor in Java and create the Java Object in the virtual machine. For example, calling:
Do mystring1.$createobject(mystring)
will invoke the String(String original) java.lang.String Constructor if mystring is an Omnis Java Object with a java.lang.String subtype that has been previously declared and created.
Java Objects can be subclassed by creating an Omnis Object class (using the New Class>>Object option in the Studio Browser) and setting its $superclass property to the name of a Java Class using the Object Selection Tree.
As a result of the above, an object class called zipobject becomes a subclassed object of zipdemo and inherits all of its methods as follows:
Subclassed Java Objects can be used to define Object and Object Reference types in the same manner as Java Objects, described in the previous section.
The following sections describe how Omnis Data Types are converted to Java Data Types, how to pass parameters from Omnis to Java, how to handle Return Values and how to retrieve data from Java Objects. Other topics such as Error Handling and Cache Control are also discussed.
To call Java Objects effectively, you need to know how Omnis Data Types are mapped to Java Data Types when passing parameters. The following table shows how Omnis Data Types are converted to Java Data Types when used as parameters to Java Object Methods.
Omnis Type | Converts to {Java Type) |
---|---|
Character* | char or char[] |
Binary* | byte or byte[] |
Number Long integer* | Int, long or byte |
Number Short integer | short |
Number floating dp* or Number |
float or double |
Boolean | Boolean |
List | Java Array |
Object | Java Object |
Object Reference | Java Object |
Those marked ‘*’ are known as Overloaded Types as they are compatible with more than one Java Data Type.
As you can see from the above, most of the Data Types in Omnis can be coerced into multiple Java Data Types. Although this coercion happens automatically, it is useful to be aware of Overloaded Types as they provide you with greater flexibility when programming with Java Objects. For example, if you wish to construct a java.lang.Byte object, you could define a binary variable, load the byte into the variable and call $createobject() with this variable. However, it is much quicker to simply call $createobject() using the integer value of the byte. For example:
Do mybyte.$createobject(65)
will create a Java Byte object whose value is 65.
Java Object Parameters can be categorized into two basic types. Simple Parameters and Complex Parameters. Simple parameters are parameter types that are compatible with java base types. All other parameter types are considered to be Complex.
Omnis data type | converts to (Java base type) |
---|---|
Character | char/char[] |
Binary | byte/byte[] |
Number Long integer | int/long/byte |
Number Short integer | short |
Number floating dp or Number |
float/double |
Boolean | Boolean |
Omnis data type | Can be converted to (Java type) |
---|---|
List | an array of any Java type depending on list content |
Object | an Object of any Java type depending on content |
Object Reference | an Object of any Java Type depending on the content of the referenced Object |
Passing Simple Parameter types to a Java Object is relatively simple. You call the Java Object method with the parameter(s), as you would call any object method in Omnis.
In the above example, the Simple Parameter Type lpos is passed to the java.lang.String charat() function. This function returns the character value ‘o’ (the letter o) as this character resides at index 4 of the Java String.
Complex Parameter types such as lists and Objects can be passed to Java Objects as well. However, these Parameter types must be initialized before being used.
Omnis lists must contain valid data before being passed to a Java Object. Note that if you use a list that has more than one column, only the first column will be used. Omnis lists which do not contain valid data will cause Java Objects to return an error. See the Error Handling section for more information.
Omnis converts Single Column Lists to Java Arrays based on the type of the data that is stored in the list. This conversion can be described by the following table:
Omnis List | Converts to (Java Array Type) |
---|---|
Omnis list containing Number Long integer c | int[] or long[] |
Omnis list containing Number floating dp types | float[] or double[] |
Omnis list containing Number Short integer types | short[] |
Omnis list containing Boolean types | boolean[] |
Omnis list containing Object Reference types | Array of Java Objects |
As you can see from the above, Overloaded Types are also supported by Omnis Lists. For an explanation of Overloaded Types, see the Parameter Data Types section. It should also be noted that char[] and byte[] are absent from the above. This is because Java char[] and byte[] types are created directly from Omnis Character and Binary Variables.
Omnis will always attempt to determine the type of Array that you are trying to pass as a parameter by examining the data in the List. If a list contains Java Objects, Omnis will attempt to determine the type of the objects in the list. If the type of all the objects is found to be the same, it is assumed that you are passing a parameter of that type. For example, if you create an Omnis list of java.lang.String Objects, Omnis will assume that you are passing a String Array Parameter to Java. However, if any of the Objects are found to be of different types, Omnis will assume that you are passing a generic Object Array (java.lang.Object) to Java.
When calling Java methods that take arrays as parameters, it is important to make sure that the Omnis list that you pass to the method in question contains appropriate data. Lists which do not contain appropriate data will cause the function call to fail with an error. (See the Error Handling section.) For example, if you create an Omnis List with 12 java.lang.String Objects and add an extra java.lang.Byte object by mistake, your method call will fail if you are attempting to call a Java Function that accepts a java.lang.String Array as a parameter.
An example of how to use Omnis lists as parameters to Java can be found in the example.lbs Omnis library that accompanies Omnis (in the Java\JavaCode folder). The window class arrayparams, which is part of this library, demonstrates how to call a Java method that takes an Array of java.lang.String and an Array of int as parameters.
Important Note: When creating a list of Java Objects, Object References should be used. This is because standard objects cannot be used in Omnis Lists. Once you have finished using your list of Object References, remember to delete each reference in the list by calling $deleteref() for each reference. Please refer to OO Programming chapter in the Omnis Programming manual for further information about Object References.
Java Objects should be “created” using $createobject() before being passed as parameters to other Java Objects. Passing an uninitialised object to a Java Function will return an error. (See the Error Handling section.)
An example of how to use Java Objects as parameters to other Java methods can be found in the example.lbs Omnis library that accompanies Omnis (in the Java\JavaCode folder). The window class objectparams in the example library demonstrates how to call a Java method that takes a variety of Java Objects as parameters.
The following table shows how Java Return Types are converted to Omnis Data Types.
Java Type | Converts to (Omnis Type) |
---|---|
char[] or char | Character |
byte[] or byte | Binary |
int or long | Number Long integer |
float or double | Number floating dp or Number |
short | Number Short integer |
Boolean | Boolean |
Java Arrays (except char[] and byte[]) | List |
Objects | Object references |
Note: this is a reversal of the table shown in the previous section.
To return a value from a Java Object method, use the Method Editor to specify the variable that will be used to hold the return value. You must ensure that the Omnis variable that you are using is of the correct type to accept the value that will be returned from Java. If this is not the case, an error will occur and the hash variables #ERRCODE and #ERRTEXT will be set accordingly (see Error Handling).
The following shows a String object being returned from Java. The object is created via the use of the Java String “substring” function and is returned as an Object Reference.
Note: The $getobjectvalue method is used to retrieve the character value of the lstringref Object Reference. This method is described in the next section.
There is a Boolean library preference called $javareturnsnative that effects the way in which arrays of Java data types are returned from Java to Omnis. When the property is set to kTrue, Java object methods called from the library return native Omnis types if a suitable conversion exists, rather than an object reference to a Java object. For example, a method returning a Java String object returns an Omnis Character value. Setting the value to kTrue also benefits from the improved performance.
Existing libraries have the $javareturnsnative property set to kFalse for backwards compatibility, but all new libraries will have a default value of kTrue.
Note: If you wish to set the $javareturnsnative property to kTrue in an existing library, you must change the types of the Omnis variables used to return values from Java. For example, when a Java method that returns a java.lang.String is called from an Omnis library with $javareturnsnative set as kFalse, the Omnis return type will be Object reference. Changing the $javareturnsnative property to kTrue means that the return types for these methods need to be changed to the Omnis Character type.
All Java Objects in Omnis have the $getobjectvalue() method. The purpose of this method is to attempt to get the content of the current Java Object and to convert this content into a format that Omnis understands. This is not always possible as many Java Objects do not have a corresponding type in Omnis. However, most of the Objects in Java can usually be coerced into an object type that can, in turn, be converted into an Omnis Data type using $getobjectvalue(). In addition to this, some Objects in Java have their own versions of $getobjectvalue which are designed to convert object content. For example, the java.lang.Float class has functions such as byteValue() and intValue() to coerce the float content to byte and int types.
$getobjectvalue can be used in the following manner:
The above example creates a Java String Object with the value “Hello there”. The call to $getobjectvalue() extracts this value and assigns it to the local variable lchar. The local variable ljerr is a long integer which is used for error handling. If $getobjectvalue() fails to convert the Object value, ljerr will contain an error code, otherwise the value 1 (kJavaCoreOK) is returned.
The $getobjectvalue() method will accept all of the Simple Parameter Types as parameters. Therefore, the format of the $getobjectvalue() method call is the same regardless of the type of data that is being returned. For example, the following is very similar to the previous example:
The $getobjectvalue() method uses the same process of data conversion that is used for Return Values. For a further explanation of this process, see the Returning Values From Java Methods section.
When Omnis is started for the first time, it will create a cache file for all Java System and Class Path classes automatically. This cache improves performance, as it removes the necessity to interrogate the Java Virtual Machine to find out which classes are available every time Omnis starts up.
Once Omnis has started up, and loaded all the Java classes in your Omnis\Java folder and on your CLASSPATH and System, you can load Java classes while Omnis is running using the $addclass() method. The syntax of this method is as follows:
Do JavaObjs Library.$addclass(classgroup, classfilename [,classpath])
The classgroup parameter specifies the Java Objects category or group in the Java Objects class list that the loaded class will be added to. The group is one of the following constants:
kJavaObjsClassPathGroup: Specifies the classpath category.
kJavaObjsWebServicesGroup: Specifies the webservices category.
kJavaObjsWebServicesClientGroup: Specifies the webservices client category.
The classfilename parameter can contain one of the following:
A fully qualified pathname of the class file to be loaded.
A fully qualified folder name that contains one or more class files.
A fully qualified Jar filename.
If a single class is specified, only that class is loaded. If a folder is specified, then all class files within the folder are loaded. If a Jar file is specified, all classes within the Jar file are loaded.
Note: Any classes that are specified must already reside on the Java Classpath. To make the best use of $addclass(), your CLASSPATH environment variable should include any paths that you may want to load classes from while Omnis is running. If you are loading a Jar file that itself requires the use of other Jar files, you should ensure that these dependencies are also listed in your CLASSPATH environment variable.
The classpath parameter specifies the particular classpath that your class resides on. You do not have to specify the entire contents of the CLASSPATH environment variable in this parameter, it is only necessary to specify the classpath that contains the class that you are adding. For example, if your CLASSPATH environment variable contains the path “C:\classes” and you are attempting to add the class “c:\classes\zipdemo\zipdemo.class”, you only need to specify “c:\classes” as your classpath parameter. If you do not specify a classpath parameter, the default classpath is used for the group that you have specified. For example, if you have specified a group constant of “kJavaObjsWebServicesGroup”, Omnis will use the path of the Omnis Web services directory as the classpath.
The built-in classpath definitions for each group are represented by Omnis constants as follows:
kJavaObjsClassPathGroup: <Omnis Folder>\Java\JavaCode
kJavaObjsWebServicesGroup: <Omnis Folder>\Java\WebServices
kJavaObjsWebServicesClientGroup: <Omnis Folder>\Java\WebServices\client
The following code shows some examples of using the $addclass() method:
To load the class “zipdemo.class” that resides on the classpath “c:\classes”, use:
Do JavaObjs Library.$addclass(kJavaObjsClassPathGroup,"c:\classes\zipdemo\zipdemo.class","c:\classes")
The above will add zipdemo.class to the JavaObjs ClassPath group. To add the same class to the Web Services group, use the following:
Do JavaObjs Library.$addclass(kJavaObjsWebServicesGroup,"c:\classes\zipdemo\zipdemo.class","c:\classes")
To load the class example.class from the Omnis JavaCode folder, use:
Do JavaObjs Library.$addclass(kJavaObjsClassPathGroup,"<insert your omnis installation folder pathname here>\Java\JavaCode\example\example.class")
To load all of the classes in the “myclass” folder on the classpath “c:\classes” use:
Do JavaObjs Library.$addclass(kJavaObjsClassPathGroup,"c:\classes\myclass","c:\classes")
Java Objects makes full use of the #ERRCODE and #ERRTEXT Omnis variables. If an error occurs while executing a Java Object Method, the error variables identify the error on return from the method. In addition to this, each Java Object has an error status which you can examine using the $getlasterror() method.
The following example, which is in the example Omnis library, shows how to use $getlasterror() to retrieve the error status of an object.
#ERRCODE and #ERRTEXT can be used as follows:
Both #ERRCODE and $getlasterror will produce the value 1 (kJavaCoreOK) after a successful Java method call. If an error occurs while calling a Java method, an error code is generated.
Java Objects inherits all of the error codes that are supported by the JavaCore. The JavaCore is the Omnis Java Engine which is responsible for managing calls to the Java Virtual Machine. Both Java Objects and the JDBC DAM are clients of the JavaCore. All the error codes supported by the JavaCore are listed in the Omnis Catalog (F9) under ‘JavaCore’. In addition, error codes specific to Java Objects are also listed.
The following information may be useful when developing with Java Objects in Omnis.
Ensure that your Java Code is working correctly before calling it from Omnis. Java Exceptions can be very difficult to track down as it is not possible to use a Java Debugger once a Java object is embedded in Omnis. Java Objects will report exceptions in Java Code. However, because Java Objects uses introspection to call functions in your Java Class, it will only be able to tell you that an Exception occurred while executing your method and the actual nature of the Exception will not be known.
Use Object References with care. Remember that any Java Object that is returned to Omnis is returned as an Object Reference and it is your responsibility to delete this reference using the $deleteref() method. Also remember that arrays of Java Objects are returned to Omnis as lists of Object References which also need to be deleted once they have been used.
It is possible to pass Nested Object Arrays to Java and have Java return Nested Object Arrays to Omnis. Nested Object Arrays are passed to Omnis as a list of Omnis lists which in turn contain Java Objects. Nested Object Arrays are returned from Java in the same format. See the Nested Object Arrays section for further information.
Although Omnis Studio does not normally support the overloading of method names, Java Objects are an exception as method overloading is usually unavoidable when dealing with even the most basic of Java Classes. The following sections discuss how Omnis deals with overloaded methods and how it is possible to manually call an overloaded method directly from Omnis.
Omnis uses pattern matching in order to determine the overloaded method that you are trying to call. Put simply, Omnis examines the parameters that you pass to a method and attempts to call the method whose parameters most closely match the parameters that you are passing. For example, consider the following Java methods:
myfunc(int p1)
myfunc(float p1)
Calling myfunc from Omnis using an Omnis number type set to Long Integer will call myfunc(int p1). Calling myfunc from Omnis using an Omnis number type set to Floating dp will call myfunc(float p2).
An extra level of complexity is added to Pattern Matching with the support of Overloaded Data Types. An Overloaded Data Type is an Omnis Data Type that has more than one matching data type in Java. Overloaded Data Types are split into three groups as follows.
The Omnis “Number Long Integer” type can be translated to the following Java Types.
int
long
byte
If a Number Long Integer Omnis type is passed to an overloaded method, the following occurs:
Omnis attempts to find an overloaded method that has the same number of “int” parameters that you are passing, i.e. if you are calling a method with (int,boolean,int), Omnis will try to find an overloaded method which matches this Parameter Search Pattern.
If a match is not found, Omnis searches for a method that has a matching number of “long” parameters, i.e. Omnis will modify the Parameter Search Pattern in an attempt to find a match using combinations of int and long types. Therefore, if (int,boolean,int) is not found, Omnis will look for the following:
(int,boolean,long)
(long,boolean,int)
(long,boolean,long)
Finally, if this fails, Omnis searches for a method that has a matching number of “byte” parameters, i.e. Omnis will modify the Parameter Search Pattern in an attempt to find a match using combinations of int and byte types. Therefore, if ‘b’ does not find a compatible method, Omnis will look for the following:
(byte,boolean,int)
(int,boolean,byte)
(byte,boolean,byte)
Note that any method that matches the “int” Parameter Search pattern will always be called if it is available. For example, consider the following Java methods:
myfunc(int p1)
myfunc(long p1)
myfunc(byte p1)
myfunc(boolean p1)
calling myfunc using a long integer type will always call myfunc(int p1) in Java. If we remove this method:
myfunc(long p1)
myfunc(byte p1)
myfunc(boolean p1)
calling myfunc using a Long Integer type will always call myfunc(long p1), and so on.
The Omnis Number Floating dp type can be translated to the following Java Types.
float
double
If a Number Floating dp Omnis type is passed to an overloaded method, the following occurs:
Omnis attempts to find an overloaded method that has the same number of “float” parameters that you are passing, i.e. if you are calling a method with (float,boolean,float), Omnis will try to find an overloaded method which matches this Parameter Search Pattern.
If a match is not found, Omnis searches for a method that has a matching number of “double” parameters, i.e. Omnis will modify the Parameter Search Pattern in an attempt to find a match using combinations of float and double types. Therefore, if (float,boolean,float) is not found, Omnis will look for the following:
(float,boolean,double)
(double,boolean,float)
(double,boolean,double)
Note that any method that matches the “float” Parameter Search pattern will always be called if it is available. For example, consider the following Java methods:
myfunc(float p1)
myfunc(double p1)
myfunc(boolean p1)
calling myfunc using a floating dp type will always call myfunc(float p1) in Java. If we remove this function:
myfunc(double p1)
myfunc(boolean p1)
calling myfunc using a floating dp type will always call myfunc(double p1).
The Omnis Java Object type can be translated to the following Java Types.
< The object that you are attempting to pass as a parameter (e.g. java.lang.String)>
java.lang.Object
When matching objects, Omnis will always try to find a method which takes an object parameter that matches the type of the object that you are passing. So if you pass a java.lang.String object to an overloaded method, Omnis will look for a match using java.lang.String as a search pattern. If Omnis fails to find a matching method, a method which takes the generic type java.lang.Object as a parameter will be called, if such a method is available, i.e. if Omnis searches for a method using the Parameter Search Pattern (String,boolean,String) and a matching method is not found, Omnis will look for (Object,boolean,String) followed by (String,boolean,Object) followed by (Object,boolean,Object).
Note that any Java method that has a parameter list which matches the Objects that you are using as parameters will always be called if it is available. For example, consider the following Java methods:
myfunc(String p1)
myfunc(Object p1)
myfunc(boolean p1)
calling myfunc using an Omnis object whose subtype is set to “JavaObjs\System\java\lang\String” will always call myfunc(String p1) in Java. If that function is removed:
myfunc(Object p1)
myfunc(boolean p1)
calling myfunc using an Omnis object whose subtype is set to “JavaObjs\System\java\lang\String” will always call myfunc(Object p1).
The following shows how Omnis converts Character and Binary data types to Java Data types when dealing with overloaded methods.
Omnis | Java | |
---|---|---|
character types (length > 1) | are converted to | char[] |
binary types (length > 1) | are converted to | byte[] |
character types (length <= 1) | are converted to | char |
binary types (length <= 1) | are converted to | byte |
As a result of the above, you should be aware that it is not possible for Omnis to call an overloaded Java function that takes char[] as a parameter using a single character. This is demonstrated in the following example.
myfunc(char p1[])
myfunc(char p1)
Following the rules for data conversion, calling myfunc with a single character will call myfunc(char p1) while calling myfunc with a string of characters will call myfunc(char p1[]). Thus, in this situation it is not possible to call myfunc(char p1[]) with a single character as myfunc(char p1) will always be called if the length of the data that you are passing is 1. However, it is possible to force Omnis to call myfunc(p1[]) with a single character if you call the overloaded method directly. The procedure for doing this is discussed in the next section.
Note: If the length of an Omnis character type is 0, it will be converted into a Java char type whose value is 0. If the length of an Omnis binary type is 0, it will be converted into a Java byte type whose value is 0.
In some rare cases, it may be necessary to call overloaded methods directly. Consider the following example.
You are trying to call overloaded functions in the java.lang.String Class. The functions are defined in Java as follows:
valueof(float f)
valueof(double d)
etc..
You have created an Omnis Object for the String class and you are attempting to call valueof(double d) by passing an Omnis Floating dp type as a parameter. However, because of the Pattern Matching and Data Type Matching rules previously discussed, valueof(float f) is always called.
In situations such as this, it is necessary to call valueof(double d) directly. In order to do this, the method can be called by its “real name”. All overloaded methods have an associated real name. This consists of the method name followed by a string of alpha numeric characters and is used internally by Omnis for pattern matching purposes. The “real name” of an overloaded method can be found by opening the Interface Manager for the Java Object (o open the Interface Manager, right-click on the object in the method editor and select Interface Manager). From the Interface Manager, select the required overloaded method that you wish to call and click on the description tab. This will display the “real name” of the overloaded method as follows:
The above shows the interface manager for the “java.lang.String” class. If you were to call the $valueof method using an Omnis Number floating dp type, Omnis would always call $valueof(nFloat) as this is the closest possible match to the type of data that you are passing to Java. If you wish to call $valueof(nDouble), you must use the “real name” of this method which in this case is $valueof{n1457061552}.
Java Objects support Nested Object Arrays as parameters to Java methods and can also interpret Nested Object Arrays that are returned from Java. A Nested Object Array is an array of type java.lang.Object that is capable of storing any Java Object or Array of Java Objects.
To use a nested Object array you must create an Omnis List variable and define it using a Binary variable. You can then add Java Objects and Lists of Java Objects to the list. Once your list is complete, you may pass it to any Java method that accepts java.lang.Object array as a parameter.
Nested Object Arrays can also be returned by Java methods. A Nested Object Array is returned to Omnis as a Binary list. This list may contain both object references and embedded lists.
An example of how to use Nested Object Arrays can be found in the example.lbs Omnis library that accompanies Omnis (in the Java\JavaCode folder). The window class nestedobjects demonstrates how to call a Java method using a Nested Object Array. The example begins by creating an Omnis list that has the following structure:
Line | Content |
---|---|
1 | List of java.lang.String Objects |
2 | java.lang.Float Object |
3 | List of java.lang.Integer Objects |
The above list is passed to the exnested Java method. This method copies the above list structure and adds another array of java.lang.String objects to the end of the list. The content of each element is displayed in the nestedobjects main window.
Before attempting the following, the Java Object Cache should be cleared and Omnis should be shutdown if it is running. Modifying the Omnis Studio System Package list may cause unpredictable behavior and is not supported by OmnisSoftware. The following is simply provided for those readers who wish to experiment with extra functionality. Users attempting the following procedure should make a copy of the “jfilter.txt” file before proceeding. This file can be found in the Java folder under the main Omnis folder.
When Omnis starts up, the following default System Class packages are available for use with Java Objects:
java.lang
java.io
java.util
java.math
This list can be increased by editing the “jfilter.txt” file that can be found in the Java folder under the main Omnis folder. The default content of this file is as follows:
System\\java\\lang;System\\java\\io;System\\java\\util;System\\java\\math
The above is a list of paths to Java System Class packages. Each path is separated with a semicolon. To add a package to the list, simply insert it at the beginning as follows:
To add the java.net package to the list of available System Java Classes, replace the ‘.’ with a ‘\’ and prefix with “System\” so that
java.net
becomes
System\java\net
The above can then be added to the existing filters in the “jfilter.txt” file as follows:
System\java\net;System\java\lang;System\java\io;System\java\util;System\java\math
To remove a package, delete the relevant path from the path list. Note that deleting the “jfilter.txt” file completely will make all Java System packages available. However, this will significantly worsen performance and is not recommended.
The following sections provide detailed descriptions of the Overloaded Types used by Java Objects.
The Omnis Character type can be converted into the following java types:
char
char[]
This allows you to call any Java object that takes either a char or char[] as a parameter with an Omnis Character variable. You may also place Java return values that are of type char or char[] into an Omnis Character variable.
In the case of “char[]” parameters, the Omnis Character variable is automatically converted into a Java char array (or vice versa if you are dealing with return values). This allows objects such as the Java String to be created easily from Omnis. For example:
Calculate mychar as "hello this is a test"
Do mystring.$createobject(mychar)
The above will invoke the Java String Constructor String(char[] value)
If you attempt to call a Java function that takes a single character as a parameter and the Omnis variable that you are passing contains more than one character, Java will only receive the first character of the string.
The Omnis Binary type can be converted into the following java types:
byte
byte[]
This allows you to call any Java object that takes either a byte or byte[] as a parameter with an Omnis Binary Variable. You may also place Java return values that are of type byte or byte[] into an Omnis Binary variable.
In the case of “byte[]” parameters, the Omnis Binary Type is automatically converted into a Java byte array (or vice versa if you are dealing with return values). This allows objects such as the Java String to be created easily from Omnis. For example:
Do mystring.$createobject(mybinval)
# where mybinval is a binary Omnis variable
The above will invoke the Java String Constructor String(byte[] bytes)
If you attempt to call a Java function that takes a single byte as a parameter and the Omnis variable that you are passing contains more than one byte, Java will only receive the first byte of the data that you are passing.
The Omnis Number Long Integer type can be converted into the following java types:
Int
long
byte
This allows you to pass Omnis Number Long integer variables to Java functions which accept these types.
When dealing with return values, Java int and long types can be converted into the Omnis Number Long integer type. However, all byte return values are always converted to the Omnis Binary type.
The Omnis Number Floating dp type can be converted into the following Java types:
Float
double
This allows you to pass Omnis Number floating dp variables to Java functions which accept these types.
This section aims to answer some common questions about the Java installation and use with Omnis Studio.
Q. I have created an Omnis library which uses Java Objects and have moved this library to another machine. Now when I examine Objects in the method editor using the interface manager, no methods are displayed. Why is this?
A. The Java Virtual Machine has failed to start on the machine that you are now using. This can be confirmed by looking at Omnis Studio Trace Log. Make sure that you have correctly setup your OMNISJVM64 OR OMNISJVM32 environment variable. Also, if you are running under Linux or Solaris, make sure that you have modified both the PATH and the LD_LIBRARY_PATH environment variables. Further information on environment variable settings can be found at the beginning of this chapter.
Q. I have my own Java Package which I have placed on the class path. I have been using this package successfully with Java Objects but I have just compiled and updated my code and Omnis has not recognized the changes. What could be wrong?
A. Omnis Studio caches Java classes and method names to improve performance. Once a java class has been loaded, it will not be loaded again until Omnis is restarted. If you modify your Java Code while Omnis is running, the changes you make will not become apparent until you restart Omnis.
Q. Does Omnis recognize jar files?
A. Omnis will recognize and load any jar files that are located in a folder which has been specified in the CLASSPATH environment variable. All of the classes in your jar file will be available via the Object Selection Tree which is displayed when you create the object variable in the method editor.