package org.gscript.jni;
/**
* JNIReference is a pointer to a native JNIReference which holds a reference to a native ref_ptr ( native reference counted object ).
* As soon as the JNIReference is no longer reachable an internal WeakJNIReference will take care of disposing this pointer.
* The actual garbage collection is done on a seperate thread in WeakJNIReference.
*
* @author rogro82
*/
public abstract class JNIReference {
static {
System.loadLibrary("gscript");
}
public static final long NULL_POINTER = 0;
private long mReferencePointer;
private WeakJNIReference mWeakJNIReference;
protected JNIReference() {
mReferencePointer = NULL_POINTER;
}
protected JNIReference(long refpointer) throws JNIReferenceException {
setReferencePointer(refpointer);
}
protected void setReferencePointer(long refpointer)
throws JNIReferenceException {
/* throw if refpointer is NULL */
if (refpointer == NULL_POINTER)
throw new JNIReferenceException(
JNIReferenceException.EXCEPTION_NULL_POINTER);
/* throw if mRefPointer was already set */
if (mReferencePointer != NULL_POINTER)
throw new JNIReferenceException(
JNIReferenceException.EXCEPTION_REDECLARE_POINTER);
mReferencePointer = refpointer;
mWeakJNIReference = new WeakJNIReference(this);
}
protected long getReferencePointer() {
return mReferencePointer;
}
/**
* Only call this if the object inherited checks the value of the
* reference pointer before calling any native methods.
*/
protected void disposeReference() {
if (mReferencePointer != NULL_POINTER) {
mReferencePointer = NULL_POINTER;
mWeakJNIReference.dispose();
}
}
protected boolean isValidReference() {
return (mReferencePointer != NULL_POINTER);
}
/**
* Never use the same reference pointer of one JNIReference
* in another JNIReference but instead clone the actual reference
* so that the native reference count gets raised else the backing
* object will get disposed as soon as the original JNIReference
* becomes available for garbage collection.
*
* Cloning a JNIReferencePointer is in no way type-safe and should
* only be done if special occasions like Parcelable objects.
*/
protected static long cloneReferencePointer(JNIReference source) {
return cloneReferencePointer(source.getReferencePointer());
}
protected static long cloneReferencePointer(long sourceRefPtr) {
if(sourceRefPtr != NULL_POINTER) {
return nativeCloneReference(sourceRefPtr);
}
return NULL_POINTER;
}
/*
* native methods
*/
protected static native void nativeDispose(long ptr);
protected static native long nativeCloneReference(long ptr);
/**
* JNIReferenceException thown when trying to set JNIReference to NULL or
* when calling setRefPointer on a JNIReference which has already been set.
*/
public static class JNIReferenceException extends Exception {
private static final long serialVersionUID = -5165119629386669573L;
public static final int EXCEPTION_NULL_POINTER = 0;
public static final int EXCEPTION_REDECLARE_POINTER = 1;
public final int what;
public JNIReferenceException(int what) {
super(getExceptionMessage(what));
this.what = what;
}
private static String getExceptionMessage(int what) {
String msg;
switch (what) {
case EXCEPTION_NULL_POINTER:
msg = "Trying to use NULL pointer";
break;
case EXCEPTION_REDECLARE_POINTER:
msg = "Trying to redeclare pointer";
break;
default:
msg = "Unknown exception";
break;
}
return msg;
}
}
}