// uses double-checker locking pattern [8]
class SampleContainer {
static SampleContainer *instance;
typedef multimap<string, JNIGlobalRef<jobject> *>
MapOfObjects;
MapOfObjects mapOfObjects; // the container implementation
JNIGlobalRef<jobject> monitor; // monitor (for
// critical sections)
JNIEnv *_env; // the environment variable
SampleContainer(JNIEnv *env)
: _env(env), monitor(env, getMonitorObject(env)) {}
~SampleContainer(); // the dtor purges all the map
// elements
// allocating the monitor object
jobject getMonitorObject(JNIEnv *env) {
JNIClass objectClass(env, "java/lang/Object");
jmethodID constructorId =
env->GetMethodID(objectClass, "<init>", "()V");
return env->NewObject(objectClass, constructorId);
}
public:
static SampleContainer *getInstance(JNIEnv *env = 0) {
if (instance == 0) {
if (env == 0) { // raise an exception flag in Java,
// then throw a C++ exception
env->ThrowNew(JNIClass(env, "java/lang/Exception"),
"Init failed");
throw new JNIException("Init failed");
}
static JNIGlobalRef<jobject>
initMonitor(env, getMonitorObject(env));
// Double-checked locking is used to
// provide correct initialization
JNIMonitor startCriticalSection(env, initMonitor);
if (instance == 0)
instance = new SampleContainer(env);
}
return instance;
}
// explicitly release the native resources
static void clean() { delete instance; }
void insert(jobject obj) {
JNIMonitor startCriticalSection(_env, monitor);
// retrieve the object ID
JNIStringUTFChars str(_env, obj, "name");
JNIGlobalRef<jobject> *ref =
new JNIGlobalRef<jobject>(_env, obj);
mapOfObjects.insert(make_pair(str.asString(), ref));
}
vector<JNIGlobalRef<jobject> *> exportAllObjects() {
JNIMonitor startCriticalSection(_env, monitor);
vector<JNIGlobalRef<jobject> *>
result(mapOfObjects.size(), 0);
MapOfObjects::iterator p;
vector<JNIGlobalRef<jobject> *>::iterator q;
for (p = mapOfObjects.begin(), q = result.begin();
p != mapOfObjects.end(); p++, q++)
*q = (*p).second;
return result;
}
};
// Singleton instance
SampleContainer *SampleContainer::instance = 0;
/* Implementation of native calls (note that their
prototypes are automatically generated) */
// init_native_resources()
JNIEXPORT void JNICALL
Java_JniComplexExample_init_1native_1resources
(JNIEnv *env, jclass clazz)
{ SampleContainer::getInstance(env); }
// clean_native_resources()
JNIEXPORT void JNICALL
Java_JniComplexExample_clean_1native_1resources
(JNIEnv *env, jclass clazz)
{ SampleContainer::clean(); }
// register_object()
JNIEXPORT void JNICALL
Java_JniComplexExample_register_1object
(JNIEnv *env, jclass clazz, jobject obj)
{ SampleContainer::getInstance()->insert(obj); }
// recall_objects
JNIEXPORT jobjectArray JNICALL
Java_JniComplexExample_recall_1objects
(JNIEnv *env, jclass clazz) {
// obtain the vector of global references
vector<JNIGlobalRef<jobject> *> allObjects =
SampleContainer::getInstance()->exportAllObjects();
// create an output array of type 'NameWithInfo[]'
JNIClass objectClass(env, "NameWithInfo");
jobjectArray result =
env->NewObjectArray(allObjects.size(), objectClass, 0);
// export the objects
for (int i = 0; i < allObjects.size(); i++)
env->SetObjectArrayElement(result, i, *allObjects[i]);
return result;
}
End of Listing