GlueGen is a compiler
for function and data-structure declarations, generating Java and JNI C
code offline at compile time and allows using native libraries within
your Java application.
GlueGen also provides a comprehensive runtime
library offering
Support for multi-arch and java code fat-jar deployment
Native library including JNI bundle handling and Jar file cache
Platform architecture information retrieval, ELF parser, alignment
etc
Enhanced NIO buffer handling for pointer, arrays, DMA mapping
etc
Network Uri RFC 2396, connection and resource handler to simplify
asset loading
Bitstream, hash maps, ringbuffer, sha cumulator, reflection and
threading utils
Abstract AudioFormat and AudioSink interfaces, concurrent locks ..
and more
GlueGen's compiler reads ANSI C header files and separate
configuration files which provide control over many aspects of the glue
code generation. GlueGen uses a complete ANSI C parser and an internal
representation (IR) capable of representing all C types to represent the
APIs for which it generates interfaces. It has the ability to perform
significant transformations on the IR before glue code emission.
GlueGen supports registering Java™ callback
methods to receive asynchronous and off-thread native toolkit
events, where a generated native callback function dispatches the events
to Java™.
GlueGen is capable to bind low-level APIs such as the Java™ Native
Interface (JNI) and the AWT Native Interface (JAWT) back up to the Java
programming language.
Gluegen has build-in types (terminal symbols) for:
type
java-bits
native-bits x32
native bits x64
type
signed
origin
void
0
0
0
void
void
ANSI-C
char
8
8
8
integer
any
ANSI-C
short
16
16
16
integer
any
ANSI-C
int
32
32
32
integer
any
ANSI-C
long
64
32
32†
integer
any
ANSI-C - Windows
long
64
32
64
integer
any
ANSI-C - Unix
float
32
32
32
float
signed
ANSI-C
double
64
64
64
double
signed
ANSI-C
__int32
32
32
32
integer
any
windows
__int64
64
64
64
integer
any
windows
int8_t
8
8
8
integer
signed
stdint.h
uint8_t
8
8
8
integer
unsigned
stdint.h
int16_t
16
16
16
integer
signed
stdint.h
uint16_t
16
16
16
integer
unsigned
stdint.h
int32_t
32
32
32
integer
signed
stdint.h
uint32_t
32
32
32
integer
unsigned
stdint.h
int64_t
64
64
64
integer
signed
stdint.h
uint64_t
64
64
64
integer
unsigned
stdint.h
intptr_t
64
32
64
integer
signed
stdint.h
uintptr_t
64
32
64
integer
unsigned
stdint.h
ptrdiff_t
64
32
64
integer
signed
stddef.h
size_t
64
32
64
integer
unsigned
stddef.h
wchar_t
32
32
32
integer
signed
stddef.h
Warning: Try to avoid unspecified bit sized types,
especially long, since it differs on Unix and
Windows! Notes:
† Type long will result in broken code on Windows,
since we don't differentiate the OS and it's bit size is ambiguous.
Anonymous void-pointer void* are mapped to NIO
Buffer.
Pointers to pointer-size types like intptr_t*,
uintptr_t*, ptrdiff_t* and size_t* are mapped
to PointerBuffer, to reflect the architecture depending storage
size.
Pointer Mapping
Pointer values itself are represented as long
values on the Java side while using the native pointer-size, e.g. 32-bit
or 64-bit, on the native end.
They may simply be accessible via long or
long[] primitives in Java, or are exposed via
com.jogamp.common.nio.PointerBuffer.
FIXME: This might need more flexibility in case UTF-8 is not
suitable for 8-bit wide char mappings or wide characters,
e.g. for UTF-16 needs to be supported.
Function argument String
values
Function argument values are either mapped from char* to
Java String using UTF-8 via JNI function
String value mapping for Struct fields is performed
solely from the Java side using Charset and is hence most
flexible.
By default, UTF-8 is being used for getter and setter of
String values.
The Struct class provides two methods to get and set the used
Charset for conversion
/** Returns the Charset for this class's String mapping, default is StandardCharsets.UTF_8. */
public static Charset getCharset() { return _charset; };
/** Sets the Charset for this class's String mapping, default is StandardCharsets.UTF_8. */
public static void setCharset(Charset cs) { _charset = cs; }
In case the String length has not been configured via
ReturnedArrayLength, it will be dynamically calculated via
strnlen(aptr, max_len).
The maximum length default for the strnlen(..) operation is
8192 bytes and can be get and set using:
/** Returns the maximum number of bytes to read to determine native string length using `strnlen(..)`, default is 8192. */
public static int getMaxStrnlen() { return _max_strnlen; };
/** Sets the maximum number of bytes to read to determine native string length using `strnlen(..)`, default is 8192. */
public static void setMaxStrnlen(int v) { _max_strnlen = v; }
FIXME: This only works reliable using an 8-bit Charset
encoding, e.g. the default UTF-8.
Alignment for Compound Data
In general, depending on CPU and it's configuration (OS), alignment
is set up for each type (char, short, int, long, ..).
Compounds (structures) are aligned naturally, i.e. their inner
components are aligned
and are itself aligned to it's largest element.
A field may be a direct aggregation, i.e. instance, within the struct
including an array or a reference to a single element or array via a
pointer.
Both, primitive, struct and pointer field
type mappings only produce pure Java code, utilizing the GlueGen
Runtime. Hence no additional native code must be compiled nor a
resulting additional library loaded to use the mapping.
Only when mapping function-pointer within structs,
additional native glue-code is produced to call the underlying native
function which has to be compiled and its library loaded.
The generated method
public static boolean usesNativeCode() can be used to
validate whether the produced Java class requires a corresponding
library for additional native code.
Struct Mapping Notes
Opaque
configured pointer-types are treated as long values
from the Java side
while maintaining their architecture dependent pointer size within
native memory.
ConstElemCount via ReturnedArrayLength
<int> implies native ownership for a
Pointer referenced native memory if the expression is
constant. Otherwise the native memory has java
ownership. See ReturnedArrayLength
Setting below.
Utilizing a flexibleelemCount via
ReturnedArrayLength getValElements() renders us unable
to determine ownership of pointer referenced native memory
segment and hence renders ownership mixed or ambiguous, see
[5]. This is due to the fact, that native code may allocate memory
and writes its elemCount into the designated field
valElements. In such cases, the user being aware of the
underlying API shall utilize setVal(..) and
releaseVal() with care.
To release native memory with java ownership, i.e. a
native ByteBuffer, releaseVal() can be used.
Pointers to T2_UndefStruct will be handled opaque, i.e.
as long values from the Java side while maintaining their
architecture dependent pointer size within native memory.
ImmutableAccesssymbol
Immutable access can be set for a whole struct or a single field of a
struct.
Immutable access will simply suppress generating setters in the Java
code and hence also reduces the footprint of the generated Java class
for such struct.
ImmutableAccess TK_Struct
Immutable access for the whole struct `TK_Struct
Sets pseudo-code flag ImmutableAccess, see below.
ImmutableAccess TK_Struct.val
Immutable access for the single field val within struct
TK_Struct
Sets pseudo-code flag ImmutableAccess, see below.
MaxOneElementsymbol
MaxOneElement TK_Struct.val
Sets field pointer val to point to a array with a
maximum of one element and unset initial value (zero elements).
Sets pseudo-code flag MaxOneElement, see below.
ReturnedArrayLengthsymbolexpression
ReturnedArrayLength TK_Struct.val 3
Sets field pointer val to point to a array with three
elements.
Sets pseudo-code flag ConstElemCount, see below.
Having set ConstElemCount also implies native
ownership for a Pointer referenced native
memory.
ReturnedArrayLength TK_Struct.val 1
Sets field pointer val to point to a array with one
element.
Sets pseudo-code flags ConstElemCount and
MaxOneElement, see below.
Having set ConstElemCount also implies native
ownership for a Pointer referenced native
memory.
Sets field pointer val to point to a array with a
variable length as described by the field valElements
retrievable via its getter getValElements().
Sets pseudo-code flag VariaElemCount, see below.
ReturnsStringsymbol
A direct C code char array or indirect array via pointer
can be interpreted as a Java String.
ReturnsString TK_Struct.name
Sets field char-array or char-pointer name to be
additionally interpreted as a Java String. Besides the
byte[] and ByteBuffer getter and setter
variants, a String variant will be added.
Sets field char-array or char-pointer name to be
exclusively interpreted as a Java String. Instead of the
byte[] and ByteBuffer getter and setter
variants, a String variant will be produced.
ConstElemCount: Reuse native memory and store
value with matching elemCount 1, otherwise Exception
VariaElemCount: Reuse native memory and store
value with matching elemCount 1, otherwise allocates new memory
(had elemCount 0)
Array & VariaValue: Reuse native
memory and store value (has const elemCount 1)
else: SKIP setter for const single-primitive
array
AnyElementCount
String & isByteBuffer & Pointer
ConstElemCount: Reuse native memory and store
UTF-8 bytes with EOS with matching elemCount, otherwise
Exception
StringOnly: End, no more setter for this field, otherwise
continue
VariaElemCount: Allocate new native memory and
store UTF-8 bytes with EOS
StringOnly: End, no more setter for this field, otherwise
continue
ConstValue
Pointer
VariaElemCount: Allocates new native memory and
store value
else: SKIP setter for const primitive array
Array | ConstElemCount: Reuse native
memory and store value with <= elemCount, otherwise
Exception
Pointer & VariaElemCount: Reuse
native memory and store value with <= elemCount,
otherwise allocate new native memory
Struct ...
Struct Java Signature Table
Please find below signature table as generated by the C
Declaration including its C Modifier, e.g.
const for constant, [const] for const and
non-const and empty for non-const (variable).
Further, the GlueGen Setting (see above) impacts the code
generation as well.
Below table demonstrates primitive types being mapped within
a struct named TK_Struct. A similar mapping is
produced for struct types, i.e. compounds.
C Mod
C Declaration
Java Setter
Java Getter
GlueGen Setting
Ownership
Remarks
static boolean usesNativeCode()
Java, static, true if using
native code
static int size()
Java, static, native size in
bytes
static TK_Struct create()
Java, static ctor
static TK_Struct create(ByteBuffer)
Java, static ctor w/ existing
ByteBuffer
static TK_Struct derefPointer(long
addr)
Java, static ctor dereferencing
ByteBuffer at native address of size()
Copies the given source elements into the respective field's existing
memory.
Parameters:
src the source array of elements
srcPos starting element position within the source array with
'srcPos >= 0&&srcPos + length <= src.length`,
otherwise an IndexOutOfBoundsException is thrown
destPos starting element position within the destination with
'destPos >= 0&&destPos + length <=
elemCount`, otherwise an exception is thrown
length the element count to be copied with 'length >=
0&&srcPos + length <=
src.length&&destPos + length <= elemCount`,
otherwise an IndexOutOfBoundsException is thrown
Copies the given source elements into the respective field's existing
memory.
Parameters:
src the source array of elements
srcPos starting element position within the source array with
'srcPos >= 0&&srcPos + length <= src.length`,
otherwise an IndexOutOfBoundsException is thrown
destPos starting element position within the destination with
'destPos >= 0&&destPos + length <=
elemCount`, otherwise an exception is thrown
length the element count to be copied with 'length >=
0&&srcPos + length <=
src.length&&destPos + length <= elemCount`,
otherwise an IndexOutOfBoundsException is thrown
Returns:
this instance of chaining
Signature
int32_t * FreeSize, Java owned
TK_Field com.jogamp.gluegen.test.junit.generation.TK_Field.setVariaInt32PointerVariaLen(boolean subset, int[] src, int srcPos, int destPos, int length)
Setter for native field variaInt32PointerVariaLen, referencing a Java
owned array with variable element count of 0 initial elements.
Copies the given source elements into the respective field, either
writing into the existing memory or creating a new memory and
referencing it.
Parameters:
subset if true keeps the underlying memory and only
allows to set up to elemCount elements. Otherwise may
replace the underlying memory if
destPos + length != elemCount.
src the source array of elements
srcPos starting element position within the source array with
'srcPos >= 0&&srcPos + length <= src.length`,
otherwise an IndexOutOfBoundsException is thrown
destPos starting element position within the destination with
'destPos >= 0. If subset == true, destPos +
length <= elemCountalso must be betrue`. Otherwise an
exception is thrown
length the element count to be copied with 'length >=
0&&srcPos + length <= src.length`, otherwise an
IndexOutOfBoundsException is thrown
Returns:
this instance of chaining
Signature
const int32_t * FreeSize, Java owned
TK_Field com.jogamp.gluegen.test.junit.generation.TK_Field.setConstInt32PointerVariaLen(int[] src, int srcPos, int length)
Setter for native field constInt32PointerVariaLen, referencing a Java
owned array with variable element count of 0 initial elements.
Replaces the respective field's memory with a new memory segment
containing given source elements and referencing it.
Parameters:
src the source array of elements
srcPos starting element position within the source array with
'srcPos >= 0&&srcPos + length <= src.length`,
otherwise an IndexOutOfBoundsException is thrown
length the element count to be copied with 'length >=
0&&srcPos + length <= src.length`, otherwise an
IndexOutOfBoundsException is thrown
TK_Field com.jogamp.gluegen.test.junit.generation.TK_Field.setVariaInt32PointerCustomLen(boolean subset, int[] src, int srcPos, int destPos, int length)
Setter for native field variaInt32PointerCustomLen, referencing a
mixed and ambigously owned (warning) array with variable element count
of getVariaInt32PointerCustomLenElemCount() elements.
Copies the given source elements into the respective field, either
writing into the existing memory or creating a new memory and
referencing it.
Parameters:
subset if true keeps the underlying memory and only
allows to set up to elemCount elements. Otherwise may
replace the underlying memory if
destPos + length != elemCount.
src the source array of elements
srcPos starting element position within the source array with
'srcPos >= 0&&srcPos + length <= src.length`,
otherwise an IndexOutOfBoundsException is thrown
destPos starting element position within the destination with
'destPos >= 0. If subset == true, destPos +
length <= elemCountalso must be betrue`. Otherwise an
exception is thrown
length the element count to be copied with 'length >=
0&&srcPos + length <= src.length`, otherwise an
IndexOutOfBoundsException is thrown
TK_Field com.jogamp.gluegen.test.junit.generation.TK_Field.setConstInt32PointerCustomLen(int[] src, int srcPos, int length)
Setter for native field constIntxxPointerCustomLen, referencing a
mixed and ambigously owned (warning) array with
variable element count of getConstIntxxPointerCustomLenElemCount()
elements.
Replaces the respective field's memory with a new memory segment
containing given source elements and referencing it.
Parameters:
src the source array of elements
srcPos starting element position within the source array with
'srcPos >= 0&&srcPos + length <= src.length`,
otherwise an IndexOutOfBoundsException is thrown
length the element count to be copied with 'length >=
0&&srcPos + length <= src.length`, otherwise an
IndexOutOfBoundsException is thrown
GlueGen supports function pointers as struct fields,
generating function calls as methods as well function-pointer opaque
getter and setter as long types.
The latter only in case if mutable, i.e. non-const.
This will lead to the following result for
const T2_CustomFuncA customFuncA1
/**
* Getter for native field <code>CustomFuncA1</code>, being a <i>struct</i> owned function pointer.
* <p>
* Native Field Signature <code>(PointerType) typedef 'T2_CustomFuncA' -> int32_t (*)(void * aptr), size [fixed false, lnx64 8], const[false], pointer*1, funcPointer</code>
* </p>
*/
public final long getCustomFuncA1() { .. }
/** Interface to C language function: <br> <code>int32_t CustomFuncA1(void * aptr)</code><br> */
public final int CustomFuncA1(long aptr) { ... }
and similar to T2_CustomFuncB customFuncB1
/**
* Setter for native field <code>CustomFuncB1</code>, being a <i>struct</i> owned function pointer.
* <p>
* Native Field Signature <code>(PointerType) typedef 'T2_CustomFuncB' -> int32_t (*)(T2_UserData * pUserData), size [fixed false, lnx64 8], const[false], pointer*1, funcPointer</code>
* </p>
*/
public final T2_InitializeOptions setCustomFuncB1(long src) { .. }
/**
* Getter for native field <code>CustomFuncB1</code>, being a <i>struct</i> owned function pointer.
* <p>
* Native Field Signature <code>(PointerType) typedef 'T2_CustomFuncB' -> int32_t (*)(T2_UserData * pUserData), size [fixed false, lnx64 8], const[false], pointer*1, funcPointer</code>
* </p>
*/
public final long getCustomFuncB1() { .. }
/** Interface to C language function: <br> <code>int32_t CustomFuncB1(T2_UserData * pUserData)</code><br> */
public final int CustomFuncB1(T2_UserData pUserData) { .. }
Java Callback
GlueGen supports registering Java callback methods to receive
asynchronous and off-thread native toolkit events, where a generated
native callback function dispatches the events to Java.
Implementation Details
Implementation generates a static Java callback dispatcher for each
defined SetCallbackFunction, which gets invoked by the
generated native static counterpart with all arguments required.
The static callback utilizes its own synchronization for
thread-safety and fetches the required data set stored at
SetCallbackFunction to dispatch the call to the users'
CallbackFunction.
In case the callback has been removed already, the static
callback simply bails out quietly.
The native code does not create, release or manage heap memory and
therefore is considered safe.
JavaCallbackUserParam Mapping
Usually the same UserParam type is used in both items
(or hooks), SetCallbackFunctionName and
CallbackFunctionType, which we call a homogeneous
UserParam mapping.
Even in a homogeneous UserParam mapping, handling of the
UserParam value might differ in the native binding
code.
To specify a non homogeneous UserParam mapping, i.e.
heterogeneous UserParam mapping, the UserParam
index of the SetCallbackFunction must be set in the configuration.
The following mappings are supported.
Pure Java Object User Type
(default)
A pure Java Object type is used for both,
SetCallbackFunctionName and
CallbackFunctionType.
It's a homogeneous UserParam mapping, where the native
side receives a simple unique ID and shall not dereference the
pointer.
The static Java callback dispatcher fetches the Java
UserParamObject from the key-mapped data
value.
Instead of using the default plain Java Object type, a
custom UserParam
can be specified in the
configuration, which is recommended for more clarity in the
resulting API.
It's a homogeneous UserParam mapping, where the native
side receives the actual native struct address.
The static Java callback dispatcher dereferences the received native
struct address (long), i.e. rebuilding the struct
Object to be passed to the users'
CallbackFunction.
Struct Type User Param
(Heterogeneous)
An anonymous pointer (long) for
SetCallbackFunctionName and a GlueGen generated struct type for
CallbackFunctionType is being used.
It's a heterogeneous UserParam mapping, where the
toolkit is expected to place the given anonymous pointer inside the
defined struct type passed to the
CallbackFunction.
The static Java callback dispatcher dereferences the received native
struct address (long), i.e. rebuilding the struct
Object to be passed to the users'
CallbackFunction.
JavaCallbackDef and JavaCallbackKey use the
name of the SetCallbackFunction as its first attribute, as
it is core to the semantic mapping of all resources. They also have to
use the same CallbackFunctionType.
JavaCallbackDef attributes:
SetCallbackFunction: SetCallbackFunction
name of the native toolkit API responsible to set the callback
SetCallback-UserParamIndex: UserParam
parameter-index of the SetCallbackFunction
CallbackFunctionType: The native toolkit API
typedef-name of the function-pointer-type, aka the callback type
name
CallbackFunction-UserParamIndex: The
userParam parameter-index of the
CallbackFunctionType, which allows to indicate a heterogeneous
UserParam
Callback-UserParamClass: Optional custom UserParam
overriding the default Object for non-compound
UserParam types.
Callback-KeyClass: Optional custom KeyClass, providing
the hash-map-key.
The SetCallbackFunction is utilized to set the
CallbackFunction as well as to remove it passing
null for the CallbackFunction.
If mapping the CallbackFunction to keys, the user must
specify the same key arguments when setting and removing the
CallbackFunction.
JavaCallback Key
Definition
If no keys are defined via JavaCallbackKey or not
manually injected using a custom Callback-KeyClass, see
below, the CallbackFunction has global scope.
In case keys are defined via JavaCallbackKey and no
manually injected custom Callback-KeyClass used, a public
Callback-KeyClass is being generated covering the defined
keys.
Keys allow to limit the scope, i.e. map multiple
CallbackFunction to the different keys.
To remove a previously set CallbackFunction via
SetCallbackFunction, the key arguments must match.
JavaCallbackKey attributes
SetCallbackFunction: SetCallbackFunction
name of the native toolkit API responsible to set the callback
SetCallback-ParamIndex: List of parameter indices of
the SetCallbackFunction, denoting the key(s) limiting the
callback scope, i.e. the callback and all resources will be mapped to
this key. The optional Callback-KeyClass may override this
semantic.
CallbackFunctionType: The native toolkit API
typedef-name of the function-pointer-type, the same callback type name
as defined in JavaCallbackDef
CallbackFunction-ParamIndex: List of parameter indices
of the CallbackFunctionType, matching the semantic
parameter of SetCallback-ParamIndex.
Custom
Callback-UserParamClass
Instead of using the default plain Java Object for
non-compound UserParam types, a custom
Callback-UserParamClass can be specified in the configuration, which
produces more clarity in the resulting API.
Custom
Callback-KeyClass
The Callback-KeyClass is the optional user-written
hash-map-key definition and shall handle all key parameter of the
SetCallbackFunction as defined via
JavaCallbackKey, see above.
Callback-KeyClass may be used to add external
key-components, e.g. current-thread or a toolkit dependent context.
The Callback-KeyClass shall implement the following
hash-map-key standard methods
boolean equals(Object)
int hashCode()
Callback-KeyClassName(...) constructor receiving all
key parameter of SetCallbackFunction as defined via
JavaCallbackKey, see above.
It provides code to allow the generated native callback-function to
attach the current thread to the JavaVM*, retrieving a
valid JNIEnv*, see LibraryOnLoad <LibraryBasename>
for details.
JavaCallback
Generated Interfaces, Classes and Methods
The public CallbackFunction interface is generated.
The default public Callback-KeyClass is generated if
keys are used and no custom class is specified, see above.
The public toolkit API SetCallbackFunction method is
being generated.
Additional public maintenance methods are generated. In case
keys are being used, they expect Callback-KeyClass as an
argument, otherwise they expect no argument for global scope.
In case a Callback-KeyClass is used, the additional
maintenance methods are:
boolean
isSetCallbackFunctionNameMapped(Callback-KeyClass)
queries whether SetCallbackFunctionName is mapped to
key.
CallbackFunction
getSetCallbackFunctionName(Callback-KeyClass)
returns the mapped CallbackFunction, null if not
mapped
Callback-UserParamClass
getSetCallbackFunctionNameUserParam(Callback-KeyClass)
returns the mapped userParam object, null if not
mapped
void
releaseSetCallbackFunctionName(Callback-KeyClass)
releases the mapped CallbackFunction data set associated
via SetCallbackFunctionName.
int releaseAllSetCallbackFunctionName()
releases complete mapped CallbackFunction data set
associated via SetCallbackFunctionName.
If no Callback-KeyClass is used, the additional
maintenance methods are:
boolean isSetCallbackFunctionNameMapped()
queries whether SetCallbackFunctionName is mapped.
CallbackFunction
getSetCallbackFunctionName() returns the mapped
CallbackFunction, null if not mapped
Callback-UserParamClass
getSetCallbackFunctionNameUserParam() returns the
mapped userParam object, null if not mapped
void releaseSetCallbackFunctionName() releases
the mapped CallbackFunction data set associated via
SetCallbackFunctionName.
Note that the releaseSetCallbackFunctionName(*)
and releaseAllSetCallbackFunctionName() methods
are not the proper toolkit API way to remove the callback, try
to use original SetCallbackFunctionName API method instead
using a nullCallbackFunction reference.
JavaCallback Notes
Please consider the following currently enabled constraints
using JavaCallback
Only one interface callback-method binding is allowed for a native
callback function, e.g. T2_CallbackFunc01 (see above)
Implying that the native single function-pointer typedef must be
mapped to a single Java method within its interface
Hence it must be avoided that multiple method variation are
produced, e.g. due to char* to byte[] and
String mapping etc.
The native callback function can only return no-value, i.e.
void, or a primitive type. Usually void is
being used in toolkit APIs.
The native callback function argument types must be convertible to
JNI Java types as (previously) supported for function return values,
using the same conversion function
CMethodBindingEmitter.emitBodyMapCToJNIType(..).
To remove a JavaCallback the SetCallbackFunction must
be called with null for the CallbackFunction
argument but with the same key arguments (see
JavaCallbackKey) as previously called to set the
callback.
The callback T2_CallbackFunc01 has global scope, i.e. is
not mapped to any key and can be only set globally.
C-API header snippet:
typedef void ( * T2_CallbackFunc01)(size_t id, const char* msg, void* usrParam);
/** Sets the given `cbFunc` and associated `usrParam` as the callback. Passing NULL for `func` _and_ same `usrParam` removes the callback and its associated resources. */
void MessageCallback01(T2_CallbackFunc01 cbFunc, void* usrParam);
void InjectMessageCallback01(size_t id, const char* msg);
and the following GlueGen configuration
# JavaCallback requires `JNI_OnLoad*(..)` and `JVMUtil_GetJNIEnv(..)`
LibraryOnLoad Bindingtest2
ArgumentIsString T2_CallbackFunc01 1
ArgumentIsString InjectMessageCallback01 1
# Define a JavaCallback.
# Set JavaCallback via function `MessageCallback01` if `T2_CallbackFunc01` argument is non-null, otherwise removes the mapped callback and associated resources.
#
# It uses the function-pointer argument `T2_CallbackFunc01` as the callback function type
# and marks `T2_CallbackFunc01`s 3rd argument (index 2) as the mandatory user-param.
#
# This callback has no keys defines, rendering it of global scope!
#
# Explicit maintenance methods are generated, passing the keys as paramters
# - `boolean isMessageCallback01Mapped()` queries whether `MessageCallback0` is mapped globally
# - `T2_CallbackFunc01 getMessageCallback01()` returns the global T2_CallbackFunc01, null if not mapped
# - `Object getMessageCallback01UserParam()` returns the global `usrParam` object, null if not mapped
# - `void releaseMessageCallback01()` releases callback data skipping toolkit API. Favor passing `null` callback ref to `MessageCallback01(..)`
JavaCallbackDef MessageCallback01 1 T2_CallbackFunc01 2
Note that LibraryOnLoad Bindingtest2
must be specified in exactly one native code-unit within the library. It
provides code to allow the generated native callback-function to attach
the current thread to the JavaVM* generating a new
JNIEnv*in daemon mode - or just to retrieve the thread's
JNIEnv*, if already attached to the
JavaVM*.
This will lead to the following interface
public interface Bindingtest2 {
/** JavaCallback interface: T2_CallbackFunc01 -> void (*T2_CallbackFunc01)(size_t id, const char * msg, void * usrParam) */
public static interface T2_CallbackFunc01 {
/** Interface to C language function: <br> <code>void callback(size_t id, const char * msg, void * usrParam)</code><br>Alias for: <code>T2_CallbackFunc01</code> */
public void callback(long id, String msg, Object usrParam);
}
...
/** Entry point (through function pointer) to C language function: <br> <code>void MessageCallback01(T2_CallbackFunc01 cbFunc, void * usrParam)</code><br> */
public void MessageCallback01(T2_CallbackFunc01 cbFunc, Object usrParam);
/** Returns if callback is mapped for <br> <code> public void MessageCallback01(T2_CallbackFunc01 cbFunc, Object usrParam)</code> **/
public boolean isMessageCallback01Mapped();
/** Returns T2_CallbackFunc01 callback for <br> <code> public void MessageCallback01(T2_CallbackFunc01 cbFunc, Object usrParam)</code> **/
public T2_CallbackFunc01 getMessageCallback01();
/** Returns user-param for <br> <code> public void MessageCallback01(T2_CallbackFunc01 cbFunc, Object usrParam)</code> **/
public Object getMessageCallback01UserParam();
/** Releases callback data skipping toolkit API. Favor passing `null` callback ref to <br> <code> public void MessageCallback01(T2_CallbackFunc01 cbFunc, Object usrParam)</code> **/
public void releaseMessageCallback01();
/** Entry point (through function pointer) to C language function: <br> <code>void InjectMessageCallback01(size_t id, const char * msg)</code><br> */
public void InjectMessageCallback01(long id, String msg);
Additionally a custom
UserParam type ALCcontext is being used for
more clarity in the resulting API.
This example is derived from OpenAL's
AL_SOFT_callback_buffer extension.
The callback ALBUFFERCALLBACKTYPESOFT is mapped to
buffer name, i.e. one callback can be set for each
buffer.
C-API Header snipped
typedef void ( * ALBUFFERCALLBACKTYPESOFT)(int buffer /* key */, void *userptr, int sampledata, int numbytes);
void alBufferCallback0(int buffer /* key */, int format, int freq, ALBUFFERCALLBACKTYPESOFT callback, void *userptr);
void alBufferCallback0Inject(int buffer, int sampledata, int numbytes);
and the following GlueGen configuration
# Define a JavaCallback.
# Set JavaCallback via function `alBufferCallback0` if `ALBUFFERCALLBACKTYPESOFT` argument is non-null, otherwise removes the mapped callback and associated resources.
#
# It uses the function-pointer argument `ALBUFFERCALLBACKTYPESOFT` as the callback function type
# and marks `ALBUFFERCALLBACKTYPESOFT`s 2nd argument (index 1) as the mandatory user-param.
#
# This callback defines one key, `buffer`, index 0 of alBufferCallback0(..) parameter list, limiting it to buffer-name scope!
# The `buffer` key allows setting one callback per buffer-name, compatible with the `AL_SOFT_callback_buffer` spec.
#
# Explicit queries are generated, passing the keys as paramters
# - `Set<AlBufferCallback0Key> getAlBufferCallback0Keys()` returns set of Key { int buffer }
# - `boolean isAlBufferCallback0Mapped(AlBufferCallback0Key)` queries whether `alBufferCallback0` is mapped to `buffer`.
# - `ALBUFFERCALLBACKTYPESOFT getAlBufferCallback0(AlBufferCallback0Key)` returns the `buffer` mapped ALEVENTPROCSOFT, null if not mapped
# - `ALCcontext getAlBufferCallback0UserParam(AlBufferCallback0Key)` returns the `buffer` mapped `userptr` object, null if not mapped
# - `void releaseAllAlBufferCallback0()` releases all callback data mapped via Key { int buffer } skipping toolkit API. Favor passing `null` callback ref to `alBufferCallback0(..)`
# - `void releaseAlBufferCallback0(AlBufferCallback0Key)` releases callback data mapped to Key { int buffer } skipping toolkit API. Favor passing `null` callback ref to `alBufferCallback0(..)`
JavaCallbackDef alBufferCallback0 4 ALBUFFERCALLBACKTYPESOFT 1 ALCcontext
JavaCallbackKey alBufferCallback0 0 ALBUFFERCALLBACKTYPESOFT 0
leading to the following interface
/** JavaCallback interface: ALBUFFERCALLBACKTYPESOFT -> void (*ALBUFFERCALLBACKTYPESOFT)(int buffer, void * userptr, int sampledata, int numbytes) */
public static interface ALBUFFERCALLBACKTYPESOFT {
/** Interface to C language function: <br> <code>void callback(int buffer, void * userptr, int sampledata, int numbytes)</code><br>Alias for: <code>ALBUFFERCALLBACKTYPESOFT</code> */
public void callback(int buffer, ALCcontext userptr, int sampledata, int numbytes);
}
...
/** Key { int buffer } for <br> <code> public void alBufferCallback0(int buffer, int format, int freq, ALBUFFERCALLBACKTYPESOFT callback, Object userptr)</code> **/
public static class AlBufferCallback0Key {
public final int buffer;
public AlBufferCallback0Key(int buffer) {
this.buffer = buffer;
}
@Override
public boolean equals(final Object o) {
if( this == o ) {
return true;
}
if( !(o instanceof AlBufferCallback0Key) ) {
return false;
}
final AlBufferCallback0Key o2 = (AlBufferCallback0Key)o;
return buffer == o2.buffer;
}
@Override
public int hashCode() {
// 31 * x == (x << 5) - x
int hash = buffer;
return hash;
}
}
...
/** Returns set of Key { int buffer } for <br> <code> void alBufferCallback0(int buffer, int format, int freq, ALBUFFERCALLBACKTYPESOFT callback, ALCcontext userptr)</code> */
public Set<AlBufferCallback0Key> getAlBufferCallback0Keys();
/** Returns whether callback Key { int buffer } is mapped for <br> <code> void alBufferCallback0(int buffer, int format, int freq, ALBUFFERCALLBACKTYPESOFT callback, ALCcontext userptr)</code> */
public boolean isAlBufferCallback0Mapped(AlBufferCallback0Key key);
/** Returns ALBUFFERCALLBACKTYPESOFT callback mapped to Key { int buffer } for <br> <code> void alBufferCallback0(int buffer, int format, int freq, ALBUFFERCALLBACKTYPESOFT callback, ALCcontext userptr)</code> */
public ALBUFFERCALLBACKTYPESOFT getAlBufferCallback0(AlBufferCallback0Key key);
/** Returns user-param mapped to Key { int buffer } for <br> <code> void alBufferCallback0(int buffer, int format, int freq, ALBUFFERCALLBACKTYPESOFT callback, ALCcontext userptr)</code> */
public ALCcontext getAlBufferCallback0UserParam(AlBufferCallback0Key key);
/** Releases all callback data mapped via Key { int buffer } skipping toolkit API. Favor passing `null` callback ref to <br> <code> void alBufferCallback0(int buffer, int format, int freq, ALBUFFERCALLBACKTYPESOFT callback, ALCcontext userptr)</code> */
public int releaseAllAlBufferCallback0();
/** Releases callback data mapped to Key { int buffer } skipping toolkit API. Favor passing `null` callback ref to <br> <code> void alBufferCallback0(int buffer, int format, int freq, ALBUFFERCALLBACKTYPESOFT callback, ALCcontext userptr)</code> */
public void releaseAlBufferCallback0(AlBufferCallback0Key key);
/** Entry point (through function pointer) to C language function: <br> <code>void alBufferCallback0(int buffer, int format, int freq, ALBUFFERCALLBACKTYPESOFT callback, void * userptr)</code><br> */
public void alBufferCallback0(int buffer, int format, int freq, ALBUFFERCALLBACKTYPESOFT callback, ALCcontext userptr);
/** Entry point (through function pointer) to C language function: <br> <code>void alBufferCallback0Inject(int buffer, int sampledata, int numbytes)</code><br> */
public void alBufferCallback0Inject(int buffer, int sampledata, int numbytes);
JavaCallback
Example 2b (Custom KeyClass, different key-parameter
order)
Similar example as example 2a, but using a custom KeyClass to map
CallbackFunction and UserParam and also
accommodating a different key-parameter order between
SetCallbackFunction and CallbackFunction.
C-API Header snipped
typedef void ( * ALBUFFERCALLBACKTYPESOFT)(int buffer /* key */, void *userptr, int sampledata, int numbytes);
void alBufferCallback1(void *user_ptr, int buffer_key /* key */, int format, int freq, ALBUFFERCALLBACKTYPESOFT callback);
void alBufferCallback1Inject(int buffer, int sampledata, int numbytes);
GlueGen configuration snippet with the added option attribute for the
Callback-KeyClass in directive
JavaCallbackDef.
Implementation utilizes a custom Callback-KeyClass
implementation for
void alBufferCallback1(int buffer, int format, int freq, ALBUFFERCALLBACKTYPESOFT callback, ALCcontext userptr),
which uses one key, i.e. buffer.
public static class CustomAlBufferCallback1Key {
private final int buffer;
public CustomAlBufferCallback1Key(final int buffer) {
this.buffer = buffer;
}
@Override
public boolean equals(final Object o) {
if( this == o ) {
return true;
}
if( !(o instanceof CustomAlBufferCallback1Key) ) {
return false;
}
final CustomAlBufferCallback1Key o2 = (CustomAlBufferCallback1Key)o;
return buffer == o2.buffer;
}
@Override
public int hashCode() {
return buffer;
}
@Override
public String toString() {
return "CustomALKey[this "+toHexString(System.identityHashCode(this))+", buffer "+buffer+"]";
}
}
JavaCallback
Example 5b (UserParam part of 2 component-key)
Similar example as example 2a, but having the UserParam
as part of the 2 component-key and defining
Callback-UserParamClass class as
ALCcontext.
/** JavaCallback interface: T2_CallbackFunc11 -> void (*T2_CallbackFunc11)(size_t id, const T2_Callback11UserType * usrParam, long val) */
public static interface T2_CallbackFunc11 {
/** Interface to C language function: <br> <code>void callback(size_t id, const T2_Callback11UserType * usrParam, long val)</code><br>Alias for: <code>T2_CallbackFunc11</code> */
public void callback(long id, T2_Callback11UserType usrParam, long val);
}
...
public static class MessageCallback11aKey { ... }
...
/** Returns set of Key { long id } for <br> <code> void MessageCallback11a(long id, T2_CallbackFunc11 cbFunc, T2_Callback11UserType usrParam)</code> */
public Set<MessageCallback11aKey> getMessageCallback11aKeys();
/** Returns whether callback Key { long id } is mapped for <br> <code> void MessageCallback11a(long id, T2_CallbackFunc11 cbFunc, T2_Callback11UserType usrParam)</code> */
public boolean isMessageCallback11aMapped(MessageCallback11aKey key);
/** Returns T2_CallbackFunc11 callback mapped to Key { long id } for <br> <code> void MessageCallback11a(long id, T2_CallbackFunc11 cbFunc, T2_Callback11UserType usrParam)</code> */
public T2_CallbackFunc11 getMessageCallback11a(MessageCallback11aKey key);
/** Returns user-param mapped to Key { long id } for <br> <code> void MessageCallback11a(long id, T2_CallbackFunc11 cbFunc, T2_Callback11UserType usrParam)</code> */
public T2_Callback11UserType getMessageCallback11aUserParam(MessageCallback11aKey key);
/** Releases all callback data mapped via Key { long id } skipping toolkit API. Favor passing `null` callback ref to <br> <code> void MessageCallback11a(long id, T2_CallbackFunc11 cbFunc, T2_Callback11UserType usrParam)</code> */
public int releaseAllMessageCallback11a();
/** Releases callback data mapped to Key { long id } skipping toolkit API. Favor passing `null` callback ref to <br> <code> void MessageCallback11a(long id, T2_CallbackFunc11 cbFunc, T2_Callback11UserType usrParam)</code> */
public void releaseMessageCallback11a(MessageCallback11aKey key);
/** Entry point (through function pointer) to C language function: <br> <code>void MessageCallback11a(size_t id, T2_CallbackFunc11 cbFunc, const T2_Callback11UserType * usrParam)</code><br> */
public void MessageCallback11a(long id, T2_CallbackFunc11 cbFunc, T2_Callback11UserType usrParam);
/** Entry point (through function pointer) to C language function: <br> <code>void MessageCallback11aInject(size_t id, long val)</code><br> */
public void MessageCallback11aInject(long id, long val);
JavaCallback
Example 11b (Heterogeneous Pointer/Struct Type)
The callback T2_CallbackFunc11 is managed by the toolkit
and passed to the callback function, while user passes a
void* as a long value to the registration
method MessageCallback11b(..). The toolkit associates the
users' void* pointer with the
T2_CallbackFunc11.
C-API Header snipped
typedef struct {
int32_t ApiVersion;
void* Data;
long i;
long r;
size_t id;
} T2_Callback11UserType;
typedef void ( * T2_CallbackFunc11)(size_t id, const T2_Callback11UserType* usrParam, long val);
void MessageCallback11b(size_t id /* key */, T2_CallbackFunc11 cbFunc, void* Data);
void MessageCallback11bInject(size_t id, long val);
/** JavaCallback interface: T2_CallbackFunc11 -> void (*T2_CallbackFunc11)(size_t id, const T2_Callback11UserType * usrParam, long val) */
public static interface T2_CallbackFunc11 {
/** Interface to C language function: <br> <code>void callback(size_t id, const T2_Callback11UserType * usrParam, long val)</code><br>Alias for: <code>T2_CallbackFunc11</code> */
public void callback(long id, T2_Callback11UserType usrParam, long val);
}
...
public static class MessageCallback11bKey { ... }
...
/** Returns set of Key { long id } for <br> <code> void MessageCallback11b(long id, T2_CallbackFunc11 cbFunc, long Data)</code> */
public Set<MessageCallback11bKey> getMessageCallback11bKeys();
/** Returns whether callback Key { long id } is mapped for <br> <code> void MessageCallback11b(long id, T2_CallbackFunc11 cbFunc, long Data)</code> */
public boolean isMessageCallback11bMapped(MessageCallback11bKey key);
/** Returns T2_CallbackFunc11 callback mapped to Key { long id } for <br> <code> void MessageCallback11b(long id, T2_CallbackFunc11 cbFunc, long Data)</code> */
public T2_CallbackFunc11 getMessageCallback11b(MessageCallback11bKey key);
/** Returns user-param mapped to Key { long id } for <br> <code> void MessageCallback11b(long id, T2_CallbackFunc11 cbFunc, long Data)</code> */
public Object getMessageCallback11bUserParam(MessageCallback11bKey key);
/** Releases all callback data mapped via Key { long id } skipping toolkit API. Favor passing `null` callback ref to <br> <code> void MessageCallback11b(long id, T2_CallbackFunc11 cbFunc, long Data)</code> */
public int releaseAllMessageCallback11b();
/** Releases callback data mapped to Key { long id } skipping toolkit API. Favor passing `null` callback ref to <br> <code> void MessageCallback11b(long id, T2_CallbackFunc11 cbFunc, long Data)</code> */
public void releaseMessageCallback11b(MessageCallback11bKey key);
/** Entry point (through function pointer) to C language function: <br> <code>void MessageCallback11b(size_t id, T2_CallbackFunc11 cbFunc, void * Data)</code><br> */
public void MessageCallback11b(long id, T2_CallbackFunc11 cbFunc, long Data);
/** Entry point (through function pointer) to C language function: <br> <code>void MessageCallback11bInject(size_t id, long val)</code><br> */
public void MessageCallback11bInject(long id, long val);
TODO: Enhance documentation
Misc Configurations
LibraryOnLoad <LibraryBasename>
for JNI_OnLoad*(..) ...
LibraryOnLoad <LibraryBasename>can be
specified in one native code-unit within one native library maximum,
otherwise multiple function definitions would occur.
In case Java™ callback methods are used,
it is required to have
LibraryOnLoad <LibraryBasename> specified in exactly
one native code-unit within one native library.
LibraryOnLoad <LibraryBasename> generates native
JNI code to handle the JavaVM* instance
JavaVM* JVMUtil_GetJavaVM() returning the static
JavaVM* instance for LibraryBasename set by
JNI_OnLoad*()
JNI_OnLoad(..) setting the static JavaVM*
instance for LibraryBasename, used for dynamic
libraries,
JNI_OnLoad_<LibraryBasename>(..) setting the
static JavaVM* instance for LibraryBasename,
used for static libraries,
Further the following functions are produced to attach and detach the
current thread to and from the JVM, getting and releasing the
JNIEnv*
JNIEnv* JVMUtil_GetJNIEnv(int asDaemon, int* jvmAttached)
returns the JNIEnv* with current thread being newly
attached to the JavaVM*if result
*jvmAttached == true, otherwise the current thread was
already attached to the JavaVM*
void JVMUtil_ReleaseJNIEnv(JNIEnv* env, int detachJVM)
releases the JNIEnv*, i.e. detaching the current thread
from the JavaVM*ifdetachJVM == true, otherwise funtion does nothing.
Platform Header Files
GlueGen provides convenient platform headers,
which can be included in your C header files for native compilation and
GlueGen code generation.