This tutorial was written with the assumption that the reader is already
familiar with the basics of writing a target. If this is not true, please
read How to Write a Target in Java
first. This tutorial is an introduction to the TargetFacadeForJni,
which takes care of implementing the required interfaces, and exposes the
necessary functions to a C/C++/C# target using the Java Native Interface.
The example target used in this tutorial is an elevator written in C. The elevator contains commands similar to the buttons found on the outside and inside of an elevator (up/down call buttons on the outside and floor select buttons on the inside). It operates by keeping track of each user (identifiable by their session id) along with each user's current location and desired location. While there are commands in progress, the elevator moves up and down, picking up and dropping off users at their desired floor.
Included in the edu.wisc.trace.urcsdk.target.facade
package is a header file containing C method declarations for the native
methods referenced in the TargetFacadeForJni.
These must be implemented by your target. Also included in the package is
template called TargetTemplate.c that contains stubs for these
methods, along with helper methods for making callbacks to the facade.
The C methods will have headers similar to:
JNIEXPORT void JNICALL Java_edu_wisc_trace_urcsdk_target_facade_TargetFacadeForJni_nativeSessionOpened(JNIEnv *env, jobject obj, jstring _sessionId);
Each method will at least contain the arguments JNIEnv *env
and jobject obj. An understanding of these is not necessary, but
can be found in any JNI tutorial. All of the additional arguments will be of
the type jstring. Also, the return type may be of type
jstring. The jstring type is a JNI type used to
represent Java strings. In order to implement these methods, you will need to
convert between char arrays and jstrings.
To convert a jstring argument to a char array, you will need to use the
JNI method GetStringUTFChars. You also should check the return
value from this method, because memory allocation for the chars may fail.
const char * ptr;
ptr = (*env)->GetStringUTFChars(env, _sessionId, NULL);
if(ptr == NULL) {
// If can't read sessionId, behavior undefined, so quit
printf("Couldn't allocate memory for chars\n");
fflush(stdout);
exit(EXIT_FAILURE);
}
Also, to free the memory allocated by this method, call
ReleaseStringUTFChars.
(*env)->ReleaseStringUTFChars(env, _sessionId, ptr);
To create a new jstring (for returning from a method), use
the JNI method NewStringUTF.
jstring val = (*env)->NewStringUTF(env, "InProgress");
In order for the TargetFacadeForJni to parse the target and
socket descriptions, you must make a callback to the initialize(String
codeBase, String tdLocation) method, passing it the code and target
description locations. To do this, use the following JNI calls.
In the elevator target:
jclass cls = (*env)->GetObjectClass(env, obj);
jmethodID mid = (*env)->GetMethodID(env, cls, "initialize", "(Ljava/lang/String;Ljava/lang/String;)V");
if(mid==NULL) {
printf("MethodID initialize not found");
return;
}
jstring codelocation = (*env)->NewStringUTF(env, bufCodeLocation);
jstring tdlocation = (*env)->NewStringUTF(env, "docs/elevator.td.xml");
(*env)->CallVoidMethod(env, obj, mid, codelocation, tdlocation);
The callback methods addTunParameter(String name, String value) and
bindToClientTun(String tunClassName) are provided in the
TargetFacadeForJni. To bind to a TUN, use
addTunParameter(String name, String value) to add each necessary
TUN parameter to the TUN parameter map, and when all parameters are added
call bindToClientTun(String tunClassName).
The elevator binds to the UPnP 2-Service TUN:
// Add necessary parameters to the Tun map and bind to the Tun jstring name = (*env)->NewStringUTF(env, "UDN"); jstring value = (*env)->NewStringUTF(env, "www.myurc.com_UrcSimEnv_elevator_socket"); // concat date later callAddTunParameter(env, obj, name, value); name = (*env)->NewStringUTF(env, "friendlyName"); value = (*env)->NewStringUTF(env, "Elevator"); callAddTunParameter(env, obj, name, value); name = (*env)->NewStringUTF(env, "presentationURL"); value = (*env)->NewStringUTF(env, "file:/C:/Projects/UrcSimEnv/dev/src/edu/wisc/trace/targetsamples/elevator/docs/elevator.td.xml"); callAddTunParameter(env, obj, name, value); name = (*env)->NewStringUTF(env, "targetName"); value = (*env)->NewStringUTF(env, "http://resources.myurc.org/UrcSimEnv/elevator"); callAddTunParameter(env, obj, name, value); callBindToTargetTun(env, obj, (*env)->NewStringUTF(env, "edu.wisc.trace.urcsdk.target.upnp2s.Upnp2sTargetTun"));
More on the TUN parameter map can be found in How to Write a Target in Java.
Back to the URC SDK 1.0 Tutorial
Last updated: Jamie Tabaka, 2006-10-18