2005/5/9

     
 

jniext.h

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
// 
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the 
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
//                         ACDK
// 
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
// 
// $Header: /cvsroot/acdk/acdk/acdk_java/src/acdk/java/jniext.h,v 1.17 2005/04/25 13:20:46 kommer Exp $
#ifndef acdk_java_jniext_h
#define acdk_java_jniext_h

#if !defined(DOXYGENONLY)

#include <acdk.h>

#include <jni.h>
#include <acdk/java/JavaInterpreter.h>

namespace acdk {
namespace java {

acdk::lang::Object jobject2aobject(JNIEnv *env, jobject jobj);



// only use this as stack
#define S2JS(str) str->convert(CCUtf8)->c_str()

void handleJException(JNIEnv* env);
void mapException(JNIEnv* env, IN(RThrowable) ex);

inline
void checkExceptions(JNIEnv* env)
{
  if (env->ExceptionCheck() == 0)
    return;
  handleJException(env);
}

bool isString(JNIEnv* env, jobject obj);

class JLocalRes
{
public:
  template <class T> 
  static T init(JNIEnv* env, const T& t)
  {
    return t;
  }
  template <class T> 
  static T duplicate(JNIEnv* env, const T& t)
  {
    //return static_cast<T>(env->NewLocalRef(t));
    return t;
  }
  template <class T> 
  static void release(JNIEnv* env, const T& t)
  {
    //env->DeleteLocalRef(t);
  }
};

class JGlobalRes
{
public:
  template <class T> 
  static T init(JNIEnv* env, const T& t)
  {
    return duplicate(env, t);
  }
  template <class T> 
  static T duplicate(JNIEnv* env, const T& t)
  {
    if (t == 0)
      return t;
    return static_cast<T>(env->NewGlobalRef(t));
  }
  template <class T> 
  static void release(JNIEnv* env, const T& t)
  {
    if (t != 0)
      env->DeleteGlobalRef(t);
  }
};

template <class T, class R = JLocalRes>
class JObjectImpl
{
protected:
  //JNIEnv* _env;
  T _t;
public:
  typedef R JRes;
  JObjectImpl(JNIEnv* env, const T& t = 0)
  : _t(R::init(env, t))
  {
  }
  JObjectImpl(const JObjectImpl<T, R>& t)
  : _t(0)
  {
    if (t._t == 0)
      return;
    _t = JRes::duplicate(getjenv(), t.impl());
    //_t = _env->NewLocalRef(t._t);
  }

  virtual ~JObjectImpl()
  {
    dispose();
  }
  JObjectImpl<T, R>& operator=(const T& t)
  {
    if (_t == t)
      return *this;
    dispose();
    _t = JRes::duplicate(getjenv(), t);
    //_t = t;
    return *this;
  }
  void dispose()
  {
    if (_t)
    {
      JRes::release(getjenv(), _t);
      _t = 0;
    }
  }
  const T& impl() const { return _t; }
  operator T () { return _t; }
};

typedef JObjectImpl<jobject> JObject;

template <class R = JLocalRes> 
class JStringImpl
: public JObjectImpl<jstring, R>
{
protected:
  mutable jboolean _isCopy;
  mutable RString _str;
  mutable const char* _cptr;
public:
  typedef JObjectImpl<jstring, R> Super;
  JStringImpl(JNIEnv* env, const jstring& t = 0)
  : Super(env, t)
  , _isCopy(false)
  , _str(Nil)
  , _cptr(0)
  {
  }
  JStringImpl(const JStringImpl& other)
  : Super(other)
  , _isCopy(false)
  , _str(Nil)
  , _cptr(0)
  {
  }
  JStringImpl(JNIEnv* env, IN(RString) str)
  : Super(env)
  , _isCopy(false)
  , _str(Nil)
  , _cptr(0)
  {
    _t = env->NewStringUTF(S2JS(str));
  }
  JStringImpl<R>& operator=(jstring jstr)
  {
    if (_t == jstr)
      return *this;
    Super::operator=(jstr);
    clearString();
    return *this;
  }
  JStringImpl<R>& operator=(const JStringImpl<R>& other)
  {
    if (_t == other._t)
      return *this;
    Super::operator=(other);
    clearString();
    return *this;
  }
  JStringImpl<R>& operator=(const char* cstr)
  {
    dispose();
    clearString();
    _t = getjenv()->NewStringUTF(cstr);
    return *this;
  }
  JStringImpl<R>& operator=(IN(RString) str)
  {
    return operator=(S2JS(str));
  }
  ~JStringImpl()
  {
    clearString();
  }
  int length() const
  {
    return getjenv()->GetStringUTFLength(_t);
  }
  
  operator const char* () const 
  {
    return cstr();
  }
  ::acdk::lang::RString toString() const
  {
    if (_str == Nil)
      _str = new ::acdk::lang::String(cstr(), CCUtf8 | NormalSST);
    return _str;
  }
  
  bool equals(const char* other) const
  {
    return toString()->equals(other);
  }
  bool equals(IN(RString) other) const 
  {
    return toString()->equals(other); 
  }
  void clearString()
  {
    //if (_isCopy == true) // always free the ptr;
   getjenv()->ReleaseStringUTFChars(_t, _cptr);
    _isCopy = false;
    _str = Nil;
  }
private:
  const char* cstr() const
  {
    if (_cptr != 0)
      return _cptr;
    if (_t == 0)
      return "";
    _cptr = getjenv()->GetStringUTFChars(_t, &_isCopy);
    return _cptr;
  }
};


typedef JStringImpl<JLocalRes> JString;

template <class R = JLocalRes> 
class JObjectArrayImpl
: public JObjectImpl<jobjectArray, R>
{
public:
  typedef JObjectArrayImpl<R> ThisClass;
  typedef JObjectImpl<jobjectArray, R> Super;
  JObjectArrayImpl(JNIEnv* env, const jobjectArray& t = 0)
  : Super(env, t)
  {
  }
  JObjectArrayImpl(const JObjectArrayImpl<R>& other)
  : Super(other)
  {
  }
  ThisClass& operator=(const ThisClass& other)
  {
    Super::operator=(other);
    return *this;
  }
  ThisClass operator=(jobjectArray other)
  {
    Super::operator=(other);
    return *this;
  }
  int length() const 
  {
    int len = getjenv()->GetArrayLength(_t);
    checkExceptions(getjenv());
    return len;
  }
  int size() const { return length(); }

  JObject operator[](int idx) 
  {
    JObject o(getjenv());
    o = getjenv()->GetObjectArrayElement(_t, idx);
    checkExceptions(getjenv());
    return o;
  }
};

typedef JObjectArrayImpl<JLocalRes> JObjectArray;

RString Class_getName(JNIEnv* env, jobject t);
jobject Class_getField(JNIEnv* env, jobject t, IN(RString) name);

template <class R = JLocalRes> 
class JClassImpl
: public JObjectImpl<jclass, R>
{
public:
  typedef JClassImpl<R> ThisClass;
  typedef JObjectImpl<jclass, R> Super;
  JClassImpl(JNIEnv* env, const jclass& t = 0)
  : Super(env, t)
  {
  }
  JClassImpl(const JClassImpl<R>& other)
  : Super(other)
  {
  }
  static JClassImpl getObjectClass(JNIEnv* env, jobject obj)
  {
    JClassImpl ret(env);
    ret = env->GetObjectClass(obj);
    if (ret == 0)
      checkExceptions(env);
    return ret;
  }
  
  static JClassImpl findClass(JNIEnv* env, const char* classname)
  {
    JClassImpl ret(env);
    ret = env->FindClass(classname);
    if (ret == 0)
      checkExceptions(env);
    return ret;
  }
  static JClassImpl findClass(JNIEnv* env, IN(RString) classname)
  {
    return findClass(env, S2JS(classname));
  }
  ThisClass& operator=(const ThisClass& other)
  {
    Super::operator=(other);
    return *this;
  }
  ThisClass operator=(jclass other)
  {
    Super::operator=(other);
    return *this;
  }
  RString getName()
  {
    return  Class_getName(getjenv(), _t);
  }
  jobject getField(IN(RString) fieldname)
  {
    return Class_getField(getjenv(), _t, fieldname);
  }
};


typedef JClassImpl<JLocalRes> JClass;

typedef JObjectImpl<jthrowable> JThrowable;

class JMethod
{
  jmethodID _methodId;
public:
  static JMethod constructor(JNIEnv* env, jclass jcls, IN(RString) signature)
  {
    return JMethod(env, jcls, "<init>", S2JS(signature), true);
  }
  JMethod(JNIEnv* env, jclass jcls, IN(RString) name, IN(RString) signature, bool useasClass)
  : _methodId(0)
  {
    _methodId = env->GetMethodID(jcls, S2JS(name), S2JS(signature));
    if (_methodId == 0)
      checkExceptions(env);
  }
  JMethod(JNIEnv* env, jobject jobj, IN(RString) name, IN(RString) signature)
  :_methodId(0)
  {
    _methodId = env->GetMethodID(
                          env->GetObjectClass(jobj), S2JS(name), S2JS(signature));
    if (_methodId == 0)
      checkExceptions(env);
  }
  bool callBooleanMethod(jobject jobj, ...) 
  {
    va_list args;
	  va_start(args, jobj);
	  bool result = getjenv()->CallBooleanMethodV(jobj, _methodId, args);
	  va_end(args);
	  return result;
  }
  char callCharMethod(jobject jobj, ...) 
  {
    va_list args;
	  va_start(args, jobj);
	  char result = (char)getjenv()->CallCharMethodV(jobj, _methodId, args);
	  va_end(args);
	  return result;
  }
  byte callByteMethod(jobject jobj, ...) 
  {
    va_list args;
	  va_start(args, jobj);
	  byte result = getjenv()->CallByteMethodV(jobj, _methodId, args);
	  va_end(args);
	  return result;
  }
  short callShortMethod(jobject jobj, ...) 
  {
    va_list args;
	  va_start(args, jobj);
	  short result = getjenv()->CallShortMethodV(jobj, _methodId, args);
	  va_end(args);
	  return result;
  }
  int callIntMethod(jobject jobj, ...) 
  {
    va_list args;
	  va_start(args, jobj);
	  int result = getjenv()->CallIntMethodV(jobj, _methodId, args);
	  va_end(args);
	  return result;
  }
  jlong callLongMethod(jobject jobj, ...) 
  {
    va_list args;
	  va_start(args, jobj);
	  jlong result = getjenv()->CallLongMethodV(jobj, _methodId, args);
	  va_end(args);
	  return result;
  }
  float callFloatMethod(jobject jobj, ...) 
  {
    va_list args;
	  va_start(args, jobj);
	  float result = getjenv()->CallFloatMethodV(jobj, _methodId, args);
	  va_end(args);
	  return result;
  }
  double callDoubleMethod(jobject jobj, ...) 
  {
    va_list args;
	  va_start(args, jobj);
	  double result = getjenv()->CallDoubleMethodV(jobj, _methodId, args);
	  va_end(args);
	  return result;
  }
   jobject callObjectMethod(jobject jobj, ...) 
  {
    va_list args;
	  jobject result;
	  va_start(args, jobj);
	  result = getjenv()->CallObjectMethodV(jobj, _methodId, args);
	  va_end(args);
	  return result;
  }
  RString callStringMethod(jobject jobj, ...) 
  {
    va_list args;
	  jobject result;
	  va_start(args, jobj);
	  result = getjenv()->CallObjectMethodV(jobj, _methodId, args);
	  va_end(args);
    return (RString)::acdk::java::jobject2aobject(getjenv(), result);
  }
  jmethodID methodId() { return _methodId; }
};

#define JFIELD_ACCESS(ctype, jtype) \
  ctype getStatic##jtype(jclass cls) \
  { \
    ctype ret = getjenv()->GetStatic##jtype##Field(cls, _fieldId); \
    checkExceptions(getjenv()); \
    return ret; \
  } \
  void setStatic##jtype(jclass cls, ctype v)  \
  { \
    getjenv()->SetStatic##jtype##Field(cls, _fieldId, v); \
    checkExceptions(getjenv()); \
  } \
  ctype get##jtype(jobject jobj) \
  { \
    ctype ret = getjenv()->Get##jtype##Field(jobj, _fieldId); \
    checkExceptions(getjenv()); \
    return ret; \
  } \
  void set##jtype(jobject cls, ctype v)  \
  { \
    getjenv()->Set##jtype##Field(cls, _fieldId, v); \
    checkExceptions(getjenv()); \
  } \


class JField
{
  //JNIEnv* _env; 
  jfieldID _fieldId;
public:
  JField(JNIEnv* env, jclass cls, IN(RString) name, IN(RString) signature, bool isstatic = false)
  : _fieldId(0)
  {
    if (isstatic == true)
      _fieldId = env->GetStaticFieldID(cls, S2JS(name), S2JS(signature));
    else
      _fieldId = env->GetFieldID(cls, S2JS(name), S2JS(signature));
    checkExceptions(env);
  }
  jfieldID fieldId() { return _fieldId; }
  
  JFIELD_ACCESS(bool, Boolean)
  JFIELD_ACCESS(char, Char)
  JFIELD_ACCESS(byte, Byte)
  JFIELD_ACCESS(short, Short)
  JFIELD_ACCESS(int, Int)
  JFIELD_ACCESS(jlong, Long)
  JFIELD_ACCESS(float, Float)
  JFIELD_ACCESS(double, Double)
  JFIELD_ACCESS(jobject, acdk::lang::Object)
  
};

#undef JFIELD_ACCESS

class JStackFrame 
{
  JNIEnv* _env; 
public:
  JStackFrame(JNIEnv* env, int capacity = 32)
  : _env(env)
  {
    //#ifndef ACDK_OS_LINUX
    if (_env->PushLocalFrame(capacity) != 0)
      checkExceptions(_env);
    //#endif
  }
  ~JStackFrame()
  {
    //#ifndef ACDK_OS_LINUX
    _env->PopLocalFrame(0);
    //#endif
  }
};

}
}

#endif //!defined(DOXYGENONLY)
#endif //acdk_java_jniext_h