JDAPI is designed to be familiar to users of the C API (without laying aside
the conventions of Java) and uses the Java Native Interface (JNI) to call the
Forms stack. There is a single Java package (oracle.forms.jdapi
)
which is usually distributed as a jar file. The package contains a number of
interfaces and abstract types, utility classes and classes representing all
Forms objects. There is no Forms Context object - this behavior is encapsulated
by the Jdapi
class.
Design-time Forms objects are basically sets of properties of Boolean, integer,
string and object types. All JDAPI Forms object classes implement the JdapiObject
interface, which is also the fundamental type of all objects. This interface
includes generic property accessors by type, i.e. JdapiObject.getStringProperty(),
JdapiObject.setStringProperty(), JdapiObject.getIntegerProperty(), JdapiObject.setIntegerProperty()
etc.
Object properties represent the "child object" lists of a given Forms
object, for example, the Items, Triggers and Relations owned by a Block, and
the respective accessor methods return iterators for the requested child list.
JDAPI includes an iterator interface, JdapiIterator
, which extends
java.util.Iterator
, and all methods returning iterator objects
return this type, regardless of the implementing subclass. Since the methods
of java.util.Iterator
return java.lang.Object
, so
do those of JdapiIterator
and it is necessary to cast to the appropriate
return type or supertype. For example:
// Get the block list from the form module
JdapiIterator blocks = myForm.getObjectProperty(JdapiTypes.BLOCK_PTID); Block myBlock = (Block)blocks.next(); System.out.println(myBlock.getStringProperty(JdapiTypes.NAME_PTID));// Now get the item list from the first block
JdapiIterator items = Block.getObjectProperty(JdapiTypes.ITEM_PTID); Item myItem = (Item)items.next(); System.out.println(myBlock.getStringProperty(JdapiTypes.NAME_PTID));
The class JdapiTypes
contains a full set of Property Type ID constants
(*_PTID
) representing specific Forms object properties, and a similar
set of (Forms) Object Type ID constants (*_OTID
) which represent
the Forms Object types themselves. (Note that these values are NOT declared
final - this is deliberate and prevents the compiler from optimizing the constant
values into user code directly, thus preserving binary compatibility between
releases without recompilation).
In addition to the generic accessor methods, each class has specific and more Java-like accessors for its pertinent set of properties. For example, the following code fragment is equivalent to the previous one:
// Get the block list from the form module
JdapiIterator blocks = myForm.getBlocks(); Block myBlock = (Block)blocks.next(); System.out.println(myBlock.getName());// Now get the item list from the first block
JdapiIterator items = Block.getItems(); Item myItem = (Item)items.next(); System.out.println(myBlock.getName());
The method getBlocks()
will be a member of only the FormModule
class, since only Form Modules can own Blocks, and likewise only the Block
class will have a getItems()
method. On the other hand, several
Forms object classes will implement a getTriggers()
method, and
almost all will implement getName()
.
The JdapiObject
interface is initially implemented by an abstract
class, BaseFormsObject
, which all Forms object classes extend.
As the main implementation class, BaseFormsObject
itself has only
package-level visibility. This is intentional, so that its implementation can
be changed without modifying the public API.
The Java classes representing the Forms objects constitute only a thin convenience layer over the native C API objects and functions i.e. a facade pattern. There is very little Forms functionality implemented in the Java code, which calls directly to the C API via JNI to perform all Forms behavior Because of this there is a significant memory management issue, but fortunately this is mostly handled automatically by the high-level code interacting with Jdapi's object cache.
This is a performance and efficiency feature which the end user need not be concerned with, but is described here only for information.
Two problems present themselves when using Java objects which are facades for native Forms objects:
The object cache exists to solve these problems. The cache retains a mapping of every accessed Forms object against a reference to the Java object which represents it. Whenever a Forms object is created or accessed (via JNI), the address of the Forms object is used as a key to retrieve the corresponding Java object. If there is none, as in the case of creation or the first instance of access, then the Java object is constructed automatically. Furthermore, each Java object retains a memory pointer to the Forms object it represents, and if the underlying Forms object is destroyed this pointer automatically gets set to null, indicating an invalid object.
The cache ensures that the creation of Java objects is minimized, compared to the case otherwise where during repeated iteration, each access of a Forms object would require instantiation (and subsequent garbage collection) of a new Java object to represent it, resulting in many objects being created and destroyed. Since memory allocation and object creation is one of the slowest aspects of the Java runtime this in itself greatly improves the speed and efficiency of Jdapi programs.
Figure 1 illustrates the JDAPI class diagram.