aboutsummaryrefslogtreecommitdiffstats
path: root/doc
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2023-06-30 11:36:33 +0200
committerSven Gothel <[email protected]>2023-06-30 11:36:33 +0200
commita73c992290930e617c78241bae9fe20cb18a01a9 (patch)
tree85115a5cf25d8b5018a8c2d78244272f504851e0 /doc
parentb35d62425311ec50e6c80b07372bc411aa287bb4 (diff)
GlueGen JavaCallback: Resolve key mapping of callback and associated resources via 'JavaCallbackKey' config and custom `SetCallback-KeyClass`
Updated unit test and doc accordingly. Unit tests handle OpenAL's AL_SOFT_callback_buffer and AL_SOFT_events. Tested global scope (no key, default) and 1 key (default) and 1 key (custom class). Added more query functions, which all only take the `SetCallbackFunction` key arguments as specified. Cleaned up JavaCallback* config class field naminig scheme. Added 'synchronized (..Map) { }' block in crucial `SetCallbackFunction`, rendering implementation thread safe.
Diffstat (limited to 'doc')
-rw-r--r--doc/GlueGen_Mapping.html313
-rw-r--r--doc/GlueGen_Mapping.md257
2 files changed, 518 insertions, 52 deletions
diff --git a/doc/GlueGen_Mapping.html b/doc/GlueGen_Mapping.html
index 5881a9d..2bbc07a 100644
--- a/doc/GlueGen_Mapping.html
+++ b/doc/GlueGen_Mapping.html
@@ -452,8 +452,16 @@
<li><a href="#java-callback-from-native-c-api-support">Java Callback
from Native C-API Support</a>
<ul>
- <li><a href="#javacallback-constraints">JavaCallback
- Constraints</a></li>
+ <li><a href="#required-libraryonload">Required
+ <em>LibraryOnLoad</em></a></li>
+ <li><a href="#javacallback-configuration"><em>JavaCallback</em>
+ Configuration</a></li>
+ <li><a href="#javacallback-notes"><em>JavaCallback</em> Notes</a></li>
+ <li><a href="#javacallback-example-1">JavaCallback Example 1</a></li>
+ <li><a href="#javacallback-example-2a-default-keyclass">JavaCallback
+ Example 2a (Default <em>KeyClass</em>)</a></li>
+ <li><a href="#javacallback-example-2b-custom-keyclass">JavaCallback
+ Example 2b (Custom <em>KeyClass</em>)</a></li>
</ul></li>
<li><a href="#misc-configurations">Misc Configurations</a>
<ul>
@@ -1929,6 +1937,126 @@ Native C-API Support</h2>
<p>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.</p>
+<h3 id="required-libraryonload">Required <em>LibraryOnLoad</em></h3>
+<p>Note that <a
+href="#libraryonload-librarybasename-for-jni_onload-"><code>LibraryOnLoad Bindingtest2</code></a>
+must be specified in exactly one native code-unit. It provides code to
+allow the generated native callback-function to attach the current
+thread to the <code>JavaVM*</code> generating a new
+<code>JNIEnv*</code>in daemon mode - or just to retrieve the thread's
+<code>JNIEnv*</code>, if already attached to the
+<code>JavaVM*</code>.</p>
+<h3 id="javacallback-configuration"><em>JavaCallback</em>
+Configuration</h3>
+<p>Configuration directives are as follows:</p>
+<pre><code>JavaCallbackDef &lt;SetCallbackFunctionName&gt; &lt;CallbackFunctionType&gt; &lt;CallbackFunction-UserParamIndex&gt; [&lt;SetCallback-KeyClassName&gt;]
+JavaCallbackKey &lt;SetCallbackFunctionName&gt; (SetCallback-ParamIdx)*</code></pre>
+<p><code>JavaCallbackDef</code> and <code>JavaCallbackKey</code> use the
+name of the <code>SetCallbackFunction</code> as its first attribute, as
+it is core to the semantic mapping of all resources.</p>
+<p><code>JavaCallbackDef</code> attributes:</p>
+<ul>
+<li><code>SetCallbackFunction</code>: <code>SetCallbackFunction</code>
+name of the native toolkit API responsible to set the callback</li>
+<li><code>CallbackFunctionType</code>: The native toolkit API
+typedef-name of the function-pointer-type, aka the callback type
+name</li>
+<li><code>CallbackFunction-UserParamIndex</code>: The
+<code>userParam</code> parameter-index of the
+<code>CallbackFunctionType</code></li>
+<li><code>SetCallback-KeyClassName</code>: Name of an optional
+user-implemented <code>SetCallback-KeyClass</code>, providing the
+hash-map-key - see below</li>
+</ul>
+<p>The <code>SetCallbackFunction</code> is utilized to set the
+<code>CallbackFunction</code> as well as to remove it passing
+<code>null</code> for the <code>CallbackFunction</code>.</p>
+<p>If mapping the <code>CallbackFunction</code> to keys, the user must
+specify the same key arguments when setting and removing the
+``CallbackFunction`.</p>
+<h4 id="javacallback-key-definition"><em>JavaCallback</em> Key
+Definition</h4>
+<p>If no keys are defined via <code>JavaCallbackKey</code>, or manually
+injected using a custom <code>SetCallback-KeyClass</code>, see below,
+the <code>CallbackFunction</code> has global scope.</p>
+<p>Keys allow to limit the scope, i.e. map multiple
+<code>CallbackFunction</code> to the different keys.</p>
+<p>Key arguments must match in <code>SetCallbackFunction</code> to
+remove a previously set <code>CallbackFunction</code>.</p>
+<p><code>JavaCallbackKey</code> attributes</p>
+<ul>
+<li><code>SetCallbackFunction</code>: <code>SetCallbackFunction</code>
+name of the native toolkit API responsible to set the callback</li>
+<li><code>SetCallback-ParamIdx</code>: List of parameter indices of the
+<code>SetCallbackFunction</code>, denoting the key(s) limiting the
+callback scope, i.e. the callback and all resources will be mapped to
+this key. The optional <code>SetCallback-KeyClass</code> may override
+this semantic.</li>
+</ul>
+<p>Beside generating the actual function mapping of the API, additional
+query methods are generated, passing the keys as its paramters</p>
+<ul>
+<li><code>boolean is&lt;SetCallbackFunctionName&gt;Mapped((key-arg)*)</code>
+queries whether <code>SetCallbackFunctionName</code> is mapped.</li>
+<li><code>ALBUFFERCALLBACKTYPESOFT get&lt;SetCallbackFunctionName&gt;((key-arg)*)</code>
+returns the mapped <code>CallbackFunction</code>, null if not
+mapped</li>
+<li><code>Object get&lt;SetCallbackFunctionName&gt;UserParam((key-arg)*)</code>
+returns the mapped <code>userParam</code> object, null if not
+mapped</li>
+</ul>
+<h4 id="custom-setcallback-keyclass">Custom
+<code>SetCallback-KeyClass</code></h4>
+<p>The <code>SetCallback-KeyClass</code> is the optional user-written
+hash-map-key definition and shall handle all key parameter of the
+<code>SetCallbackFunction</code> as defined via
+<code>JavaCallbackKey</code>, see above.</p>
+<p><code>SetCallback-KeyClass</code> may be used to add external
+key-components, e.g. current-thread or a toolkit dependent context.</p>
+<p>The <code>SetCallback-KeyClass</code> shall implement the following
+hash-map-key standard methods</p>
+<ul>
+<li><code>boolean equals(Object)</code></li>
+<li><code>int hashCode()</code></li>
+<li><code>SetCallback-KeyClassName(...)</code> constructor receiving all
+key parameter of <code>SetCallbackFunction</code> as defined via
+<code>JavaCallbackKey</code>, see above.</li>
+</ul>
+<h3 id="javacallback-notes"><em>JavaCallback</em> Notes</h3>
+<p>Please consider the following <em>currently enabled</em> constraints
+using JavaCallback</p>
+<ul>
+<li>Only one interface callback-method binding is allowed for a native
+callback function, e.g. <code>T2_CallbackFunc01</code> (see above)
+<ul>
+<li>Implying that the native single function-pointer typedef must be
+mapped to a single Java method within its interface</li>
+<li>Hence it must be avoided that multiple method variation are
+produced, e.g. due to <code>char*</code> to <code>byte[]</code> and
+<code>String</code> mapping etc.</li>
+</ul></li>
+<li>The native callback function can only return no-value, i.e.
+<code>void</code>, or a primitive type. Usually <code>void</code> is
+being used in toolkit APIs.</li>
+<li>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
+<code>CMethodBindingEmitter.emitBodyMapCToJNIType(..)</code>.</li>
+<li>To remove a JavaCallback the <code>SetCallbackFunction</code> must
+be called with <code>null</code> for the <code>CallbackFunction</code>
+argument but with the same <a
+href="#javacallback-key-definition"><em>key arguments</em> (see
+<code>JavaCallbackKey</code>)</a> as previously called to set the
+callback.</li>
+<li>Exactly one native code-unit for the library must specify <a
+href="#libraryonload-librarybasename-for-jni_onload-"><code>LibraryOnLoad libraryBasename</code></a></li>
+<li><code>SetCallbackFunction</code> is thread safe</li>
+<li>...</li>
+</ul>
+<h3 id="javacallback-example-1">JavaCallback Example 1</h3>
+<p>This is a generic example.</p>
+<p>The callback <code>T2_CallbackFunc01</code> has global scope, i.e. is
+not mapped to any key and can be only set globally.</p>
<p>C-API header snippet:</p>
<pre><code>typedef void ( * T2_CallbackFunc01)(size_t id, const char* msg, void* usrParam);
@@ -1942,16 +2070,19 @@ 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 callback and associated resources.
-# It uses `usrParam` as the resource-key to map to the hidden native-usrParam object,
-# hence a matching &#39;usrParam&#39; must be passed for setting and removal of the callback.
+# 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 for Java Object mapping.
+# 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!
#
-# Note: An explicit `isMessageCallback01Mapped(Object usrParam)` is being created to explicitly query whether `usrParam` maps to the associated resources.
+# Explicit queries 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
JavaCallbackDef MessageCallback01 T2_CallbackFunc01 2</code></pre>
<p>Note that <a
href="#libraryonload-librarybasename-for-jni_onload-"><code>LibraryOnLoad Bindingtest2</code></a>
@@ -1961,7 +2092,7 @@ thread to the <code>JavaVM*</code> generating a new
<code>JNIEnv*</code>in daemon mode - or just to retrieve the thread's
<code>JNIEnv*</code>, if already attached to the
<code>JavaVM*</code>.</p>
-<p>This will lead to the following result</p>
+<p>This will lead to the following interface</p>
<pre><code>public interface Bindingtest2 {
/** JavaCallback interface: T2_CallbackFunc01 -&gt; void (*T2_CallbackFunc01)(size_t id, const char * msg, void * usrParam) */
@@ -1974,33 +2105,149 @@ thread to the <code>JavaVM*</code> generating a new
/** Entry point (through function pointer) to C language function: &lt;br&gt; &lt;code&gt;void MessageCallback01(T2_CallbackFunc01 cbFunc, void * usrParam)&lt;/code&gt;&lt;br&gt; */
public void MessageCallback01(T2_CallbackFunc01 cbFunc, Object usrParam);
-
- public boolean isMessageCallback01Mapped(final Object usrParam);
+
+ public boolean isMessageCallback01Mapped();
+ public T2_CallbackFunc01 getMessageCallback01();
+ public Object getMessageCallback01UserParam();
/** Entry point (through function pointer) to C language function: &lt;br&gt; &lt;code&gt;void InjectMessageCallback01(size_t id, const char * msg)&lt;/code&gt;&lt;br&gt; */
public void InjectMessageCallback01(long id, String msg);</code></pre>
-<h3 id="javacallback-constraints">JavaCallback Constraints</h3>
-<p>Please consider the following <em>currently enabled</em> constraints
-using <code>JavaCallbackDef</code></p>
-<ul>
-<li>Only one interface callback-method binding is allowed for a native
-callback function, e.g. <code>T2_CallbackFunc01</code> (see above).</li>
-<li>The native callback function can only return no-value, i.e.
-<code>void</code>, or a primitive type. Usually <code>void</code> is
-being used in toolkit APIs.</li>
-<li>The native callback function argument types must be able to be
-mapped to JNI Java types as supported for return values of all native
-functions, the same code path is being used within
-<code>CMethodBindingEmitter.emitBodyMapCToJNIType(..)</code>.</li>
-<li>To remove a JavaCallback the specified and mapped setter function,
-e.g. <code>MessageCallback01</code>, must be called with
-<code>null</code> for the callback interface but the very same
-<code>userParam</code> instance as previously called to set the
-callback.</li>
-<li>Exactly one native code-unit for the library must specify <a
-href="#libraryonload-librarybasename-for-jni_onload-"><code>LibraryOnLoad libraryBasename</code></a></li>
-<li>...</li>
-</ul>
+<p>Implementation utilizes the default <code>SetCallback-KeyClass</code>
+implementation for
+<code>void MessageCallback01(T2_CallbackFunc01 cbFunc, Object usrParam)</code>,
+which is key-less and hence minimalistic.</p>
+<pre><code> private static class MessageCallback01Key {
+ MessageCallback01Key() {
+ }
+ @Override
+ public boolean equals(final Object o) {
+ if( this == o ) {
+ return true;
+ }
+ if( !(o instanceof MessageCallback01Key) ) {
+ return false;
+ }
+ return true;
+ }
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+ }</code></pre>
+<h3 id="javacallback-example-2a-default-keyclass">JavaCallback Example
+2a (Default <em>KeyClass</em>)</h3>
+<p>This examples is derived from OpenAL's
+<code>AL_SOFT_callback_buffer</code> extension.</p>
+<p>The callback <code>ALBUFFERCALLBACKTYPESOFT</code> is mapped to
+<code>buffer</code> name, i.e. one callback can be set for each
+buffer.</p>
+<p>C-API Header snipped</p>
+<pre><code> typedef void ( * ALBUFFERCALLBACKTYPESOFT)(int buffer, 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);</code></pre>
+<p>and the following GlueGen configuration</p>
+<pre><code> # 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
+ # - `boolean isAlBufferCallback0Mapped(int buffer)` queries whether `alBufferCallback0` is mapped to `buffer`.
+ # - `ALBUFFERCALLBACKTYPESOFT getAlBufferCallback0(int buffer)` returns the `buffer` mapped ALEVENTPROCSOFT, null if not mapped
+ # - `Object getAlBufferCallback0UserParam(int buffer)` returns the `buffer` mapped `userptr` object, null if not mapped
+ JavaCallbackDef alBufferCallback0 ALBUFFERCALLBACKTYPESOFT 1
+ JavaCallbackKey alBufferCallback0 0</code></pre>
+<p>leading to the following interface</p>
+<pre><code> /** JavaCallback interface: ALBUFFERCALLBACKTYPESOFT -&gt; void (*ALBUFFERCALLBACKTYPESOFT)(int buffer, void * userptr, int sampledata, int numbytes) */
+ public static interface ALBUFFERCALLBACKTYPESOFT {
+ /** Interface to C language function: &lt;br&gt; &lt;code&gt;void callback(int buffer, void * userptr, int sampledata, int numbytes)&lt;/code&gt;&lt;br&gt;Alias for: &lt;code&gt;ALBUFFERCALLBACKTYPESOFT&lt;/code&gt; */
+ public void callback(int buffer, Object userptr, int sampledata, int numbytes);
+ }
+
+ ...
+
+ /** Entry point (through function pointer) to C language function: &lt;br&gt; &lt;code&gt;void alBufferCallback0(int buffer, int format, int freq, ALBUFFERCALLBACKTYPESOFT callback, void * userptr)&lt;/code&gt;&lt;br&gt; */
+ public void alBufferCallback0(int buffer, int format, int freq, ALBUFFERCALLBACKTYPESOFT callback, Object userptr);
+
+ public boolean isAlBufferCallback0Mapped(int buffer);
+ public ALBUFFERCALLBACKTYPESOFT getAlBufferCallback0(int buffer);
+ public Object getAlBufferCallback0UserParam(int buffer);
+
+ /** Entry point (through function pointer) to C language function: &lt;br&gt; &lt;code&gt;void alEventCallbackInject(int eventType, int object, int param, const char * msg)&lt;/code&gt;&lt;br&gt; */
+ public void alEventCallbackInject(int eventType, int object, int param, String msg); </code></pre>
+<p>Implementation utilizes the default <code>SetCallback-KeyClass</code>
+implementation for
+<code>void alBufferCallback0(int buffer, int format, int freq, ALBUFFERCALLBACKTYPESOFT callback, Object userptr)</code>,
+which uses one key, i.e. <code>buffer</code>.</p>
+<pre><code> private static class AlBufferCallback0Key {
+ private final int buffer;
+ 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 &lt;&lt; 5) - x
+ int hash = buffer;
+ return hash;
+ }
+ }</code></pre>
+<h3 id="javacallback-example-2b-custom-keyclass">JavaCallback Example 2b
+(Custom <em>KeyClass</em>)</h3>
+<p>Same as example 2a, but implementing a custom
+<code>SetCallback-KeyClass</code>.</p>
+<p>Instead of <code>Callback0</code>, the unit <code>test2.*</code> uses
+<code>Callback1</code> to differentiate this case.</p>
+<p>GlueGen configuration snippet with the added option attribute for the
+<code>SetCallback-KeyClass</code> in directive
+<code>JavaCallbackDef</code>.</p>
+<pre><code>JavaCallbackDef alBufferCallback1 ALBUFFERCALLBACKTYPESOFT 1 com.jogamp.gluegen.test.junit.generation.Test4JavaCallback.CustomAlBufferCallback1Key
+JavaCallbackKey alBufferCallback1 0</code></pre>
+<p>Implementation utilizes a custom <code>SetCallback-KeyClass</code>
+implementation for
+<code>void alBufferCallback1(int buffer, int format, int freq, ALBUFFERCALLBACKTYPESOFT callback, Object userptr)</code>,
+which uses one key, i.e. <code>buffer</code>.</p>
+<pre><code> 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 &quot;CustomALKey[this &quot;+toHexString(System.identityHashCode(this))+&quot;, buffer &quot;+buffer+&quot;]&quot;;
+ }
+ }</code></pre>
<p><em>TODO: Enhance documentation</em></p>
<h2 id="misc-configurations">Misc Configurations</h2>
<h3
diff --git a/doc/GlueGen_Mapping.md b/doc/GlueGen_Mapping.md
index a8bcfbc..dbc66aa 100644
--- a/doc/GlueGen_Mapping.md
+++ b/doc/GlueGen_Mapping.md
@@ -761,6 +761,82 @@ 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.
+### Required *LibraryOnLoad*
+Note that [`LibraryOnLoad Bindingtest2`](#libraryonload-librarybasename-for-jni_onload-) must be specified in exactly one native code-unit.
+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*`.
+
+### *JavaCallback* Configuration
+
+Configuration directives are as follows:
+
+ JavaCallbackDef <SetCallbackFunctionName> <CallbackFunctionType> <CallbackFunction-UserParamIndex> [<SetCallback-KeyClassName>]
+ JavaCallbackKey <SetCallbackFunctionName> (SetCallback-ParamIdx)*
+
+`JavaCallbackDef` and `JavaCallbackKey` use the name of the `SetCallbackFunction` as its first attribute,
+as it is core to the semantic mapping of all resources.
+
+`JavaCallbackDef` attributes:
+- `SetCallbackFunction`: `SetCallbackFunction` name of the native toolkit API responsible to set the callback
+- `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`
+- `SetCallback-KeyClassName`: Name of an optional user-implemented `SetCallback-KeyClass`, providing the hash-map-key - see below
+
+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 manually injected using a custom `SetCallback-KeyClass`, see below,
+the `CallbackFunction` has global scope.
+
+Keys allow to limit the scope, i.e. map multiple `CallbackFunction` to the different keys.
+
+Key arguments must match in `SetCallbackFunction` to remove a previously set `CallbackFunction`.
+
+`JavaCallbackKey` attributes
+- `SetCallbackFunction`: `SetCallbackFunction` name of the native toolkit API responsible to set the callback
+- `SetCallback-ParamIdx`: 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 `SetCallback-KeyClass` may override this semantic.
+
+Beside generating the actual function mapping of the API, additional query methods are generated, passing the keys as its paramters
+- `boolean is<SetCallbackFunctionName>Mapped((key-arg)*)` queries whether `SetCallbackFunctionName` is mapped.
+- `ALBUFFERCALLBACKTYPESOFT get<SetCallbackFunctionName>((key-arg)*)` returns the mapped `CallbackFunction`, null if not mapped
+- `Object get<SetCallbackFunctionName>UserParam((key-arg)*)` returns the mapped `userParam` object, null if not mapped
+
+
+#### Custom `SetCallback-KeyClass`
+
+The `SetCallback-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.
+
+`SetCallback-KeyClass` may be used to add external key-components, e.g. current-thread or a toolkit dependent context.
+
+The `SetCallback-KeyClass` shall implement the following hash-map-key standard methods
+- `boolean equals(Object)`
+- `int hashCode()`
+- `SetCallback-KeyClassName(...)` constructor receiving all key parameter of `SetCallbackFunction` as defined via `JavaCallbackKey`, see above.
+
+
+### *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`)](#javacallback-key-definition) as previously called to set the callback.
+- Exactly one native code-unit for the library must specify [`LibraryOnLoad libraryBasename`](#libraryonload-librarybasename-for-jni_onload-)
+- `SetCallbackFunction` is thread safe
+- ...
+
+### JavaCallback Example 1
+This is a generic example.
+
+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);
@@ -778,23 +854,27 @@ 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 callback and associated resources.
-# It uses `usrParam` as the resource-key to map to the hidden native-usrParam object,
-# hence a matching 'usrParam' must be passed for setting and removal of the callback.
+# 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 for Java Object mapping.
+# 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!
#
-# Note: An explicit `isMessageCallback01Mapped(Object usrParam)` is being created to explicitly query whether `usrParam` maps to the associated resources.
+# Explicit queries 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
JavaCallbackDef MessageCallback01 T2_CallbackFunc01 2
```
+
Note that [`LibraryOnLoad Bindingtest2`](#libraryonload-librarybasename-for-jni_onload-) must be specified in exactly one native code-unit.
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 result
+This will lead to the following interface
```
public interface Bindingtest2 {
@@ -808,23 +888,162 @@ public interface Bindingtest2 {
/** 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);
-
- public boolean isMessageCallback01Mapped(final Object usrParam);
+
+ public boolean isMessageCallback01Mapped();
+ public T2_CallbackFunc01 getMessageCallback01();
+ public Object getMessageCallback01UserParam();
/** 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);
```
-### JavaCallback Constraints
-Please consider the following *currently enabled* constraints using `JavaCallbackDef`
-- Only one interface callback-method binding is allowed for a native callback function, e.g. `T2_CallbackFunc01` (see above).
-- 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 able to be mapped to JNI Java types as supported for return values of all native functions,
- the same code path is being used within `CMethodBindingEmitter.emitBodyMapCToJNIType(..)`.
-- To remove a JavaCallback the specified and mapped setter function, e.g. `MessageCallback01`, must be called with `null` for the callback interface
- but the very same `userParam` instance as previously called to set the callback.
-- Exactly one native code-unit for the library must specify [`LibraryOnLoad libraryBasename`](#libraryonload-librarybasename-for-jni_onload-)
-- ...
+Implementation utilizes the default `SetCallback-KeyClass` implementation for `void MessageCallback01(T2_CallbackFunc01 cbFunc, Object usrParam)`,
+which is key-less and hence minimalistic.
+```
+ private static class MessageCallback01Key {
+ MessageCallback01Key() {
+ }
+ @Override
+ public boolean equals(final Object o) {
+ if( this == o ) {
+ return true;
+ }
+ if( !(o instanceof MessageCallback01Key) ) {
+ return false;
+ }
+ return true;
+ }
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+ }
+```
+
+### JavaCallback Example 2a (Default *KeyClass*)
+
+This examples 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, 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
+ # - `boolean isAlBufferCallback0Mapped(int buffer)` queries whether `alBufferCallback0` is mapped to `buffer`.
+ # - `ALBUFFERCALLBACKTYPESOFT getAlBufferCallback0(int buffer)` returns the `buffer` mapped ALEVENTPROCSOFT, null if not mapped
+ # - `Object getAlBufferCallback0UserParam(int buffer)` returns the `buffer` mapped `userptr` object, null if not mapped
+ JavaCallbackDef alBufferCallback0 ALBUFFERCALLBACKTYPESOFT 1
+ JavaCallbackKey alBufferCallback0 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, Object userptr, int sampledata, int numbytes);
+ }
+
+ ...
+
+ /** 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, Object userptr);
+
+ public boolean isAlBufferCallback0Mapped(int buffer);
+ public ALBUFFERCALLBACKTYPESOFT getAlBufferCallback0(int buffer);
+ public Object getAlBufferCallback0UserParam(int buffer);
+
+ /** Entry point (through function pointer) to C language function: <br> <code>void alEventCallbackInject(int eventType, int object, int param, const char * msg)</code><br> */
+ public void alEventCallbackInject(int eventType, int object, int param, String msg);
+```
+
+Implementation utilizes the default `SetCallback-KeyClass` implementation for `void alBufferCallback0(int buffer, int format, int freq, ALBUFFERCALLBACKTYPESOFT callback, Object userptr)`,
+which uses one key, i.e. `buffer`.
+```
+ private static class AlBufferCallback0Key {
+ private final int buffer;
+ 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;
+ }
+ }
+```
+
+### JavaCallback Example 2b (Custom *KeyClass*)
+
+Same as example 2a, but implementing a custom `SetCallback-KeyClass`.
+
+Instead of `Callback0`, the unit `test2.*` uses `Callback1` to differentiate this case.
+
+GlueGen configuration snippet with the added option attribute for the `SetCallback-KeyClass` in directive `JavaCallbackDef`.
+```
+JavaCallbackDef alBufferCallback1 ALBUFFERCALLBACKTYPESOFT 1 com.jogamp.gluegen.test.junit.generation.Test4JavaCallback.CustomAlBufferCallback1Key
+JavaCallbackKey alBufferCallback1 0
+```
+
+Implementation utilizes a custom `SetCallback-KeyClass` implementation for `void alBufferCallback1(int buffer, int format, int freq, ALBUFFERCALLBACKTYPESOFT callback, Object 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+"]";
+ }
+ }
+```
*TODO: Enhance documentation*