jniclient.cpp #3

  • //
  • guest/
  • paul_krause/
  • perforce/
  • api/
  • p4jni/
  • jniclient.cpp
  • View
  • Commits
  • Open Download .zip Download (6 KB)
/*
 * $Id: //guest/paul_krause/perforce/api/p4jni/jniclient.cpp#3 $
 * Author: Paul Krause <[email protected]>
 * Copyright 2001 SoundBite Communications Corp
 * All Rights Reserved (for now)
 */
#include <jni.h>
#include <clientapi.h>

class JniClientUser : public ClientUser {
   JNIEnv *jEnv;
public:
   JniClientUser(JNIEnv *env) : jEnv(env) {};
   JniClientUser() {};
   JniClientUser(const JniClientUser &ignore) {};
   void HandleError (Error *err);
   void RunCmd(const char *command, const char *arg1, const char *arg2, const char *arg3, const char *arg4, const char *pager, Error *e );
   ~JniClientUser() {};
};

void JniClientUser::HandleError (Error *err)
{
   StrBuf msg;
   jclass jerr;
   switch (err->GetSeverity()) {

   case E_EMPTY:
   case E_INFO:
   case E_WARN:
      // for now, just dump to stderr
      // should buffer and make available to JVM
      // maybe by using the logging API
      err->Report();
      break;

   case E_FAILED:
      // for now, just raise an IOException
      // should raise different exceptions for
      // different conditions, i.e., RemoteException
      // also needs to deal with chained Errors
      jerr = jEnv->FindClass("java/io/IOException");
      err->Fmt(&msg);
      jEnv->ThrowNew(jerr, msg.Text());
      break;

   case E_FATAL:
      // also needs to deal with chained Errors
      jerr = jEnv->FindClass("java/lang/RuntimeException");
      err->Fmt(&msg);
      jEnv->ThrowNew(jerr, msg.Text());
      break;

   default:
      // for now, just abort
      // should tell user how to file a bug report first
      err->Fmt(&msg);
      jEnv->FatalError(msg.Text());
      abort();
   }
}

//XXXX TODO figure out what this should do
// for now, just raise an exception
// makes sure no exec is done on the sly
void JniClientUser::RunCmd(const char *command, const char *arg1, const char *arg2, const char *arg3, const char *arg4, const char *pager, Error *e )
{
   jclass jerr;
   jerr = jEnv->FindClass("java/lang/UnsupportedOperationException");
   jEnv->ThrowNew(jerr, command);
}


class JniClient {
   ClientApi     *p4Api;
   JNIEnv        *jEnv;
   JniClientUser jUi;
   Error         errHandle;
public:
   JniClient (JNIEnv *env) : jEnv(env), jUi(env) {};
   JniClient () {};
   JniClient (const JniClient &ignore) {};
   void P4Cmd (jbyteArray jcmd, jobjectArray jargs);
   jstring P4Change ();
   void P4Connect (jobject props);
   void P4Close ();
   ~JniClient () {};
protected:
   // This is trickier than it looks.
   // The call to FatalError should not return;
   // if it does return something, then make
   // damn sure processing does not continue by
   // throwing it as an "uncatchable" C++ exception.
   void ThrowOutOfMemory() {
      throw jEnv->FatalError("Out of memory");
   }
};

void JniClient::P4Cmd (jbyteArray jcmd, jobjectArray jargs) {
   char *cmd, *cmdcpy;
   char* const* argv;
   jsize len;
   jboolean iscopy;

   cmd = (char*) jEnv->GetPrimitiveArrayCritical(jcmd, &iscopy);
   if (cmd == NULL) ThrowOutOfMemory();
   cmdcpy = new char[len = jEnv->GetArrayLength(jcmd)];
   if (cmdcpy == NULL) ThrowOutOfMemory();
   memcpy(cmdcpy, cmd, len);
   jEnv->ReleasePrimitiveArrayCritical(jcmd, cmd, iscopy);

   argv = (char* const*)(jEnv->GetPrimitiveArrayCritical(jargs, &iscopy));
   if (argv == NULL) ThrowOutOfMemory();
   p4Api->SetArgv(jEnv->GetArrayLength(jargs), argv);
   jEnv->ReleasePrimitiveArrayCritical(jargs, (void *)argv, iscopy);

   p4Api->Run(cmdcpy, &jUi);
   delete[] cmdcpy;
}


jstring JniClient::P4Change () {
   p4Api->SetArgv(0, NULL);
   p4Api->Run("change", &jUi);
   return jEnv->NewStringUTF(p4Api->GetVar("changeNo")->Value());
}

void JniClient::P4Connect (jobject props) {
   jclass c = jEnv->GetObjectClass(props);
   jmethodID get_property =
      jEnv->GetMethodID(c, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;");
   jstring port = (jstring)(jEnv->CallObjectMethod(props, get_property, "P4PORT"));
   if (jEnv->ExceptionOccurred()) return;
   p4Api->SetPort(jEnv->GetStringUTFChars(port, NULL));
// p4Api->SetProtocol(protocol);
   p4Api->Init(&errHandle);
   errHandle.Abort(); // ?? copied from samplemain
}

void JniClient::P4Close () {
   p4Api->Final(&errHandle);
   errHandle.Abort(); // ?? copied from samplemain
}

// dereference the C++ object from the Java object
static JniClient *p4(JNIEnv *env, jobject obj) {
   jclass c = env->GetObjectClass(obj);
   jfieldID fld = env->GetFieldID(c, "clientApiHandle", "L");
   return (JniClient *)(env->GetLongField(obj, fld));
}

/*
 * Class:     com_perforce_client_JniClient
 * Method:    p4create
 * Signature: ()J
 */
JNIEXPORT jlong JNICALL Java_com_perforce_client_JniClient_p4create
  (JNIEnv *env, jobject obj)
{
   return (jlong)new JniClient(env);
}

/*
 * Class:     com_perforce_client_JniClient
 * Method:    p4cmd
 * Signature: ([B[[B)V
 */
JNIEXPORT void JNICALL Java_com_perforce_client_JniClient_p4cmd
  (JNIEnv *env, jobject obj, jbyteArray cmd, jobjectArray args)
{
   p4(env, obj)->P4Cmd(cmd, args);
}

/*
 * Class:     com_perforce_client_JniClient
 * Method:    p4change
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_perforce_client_JniClient_p4change
  (JNIEnv *env, jobject obj)
{
   return p4(env, obj)->P4Change();
}

/*
 * Class:     com_perforce_client_JniClient
 * Method:    p4connect
 * Signature: (Ljava/util/Properties;)V
 */
JNIEXPORT void JNICALL Java_com_perforce_client_JniClient_p4connect
  (JNIEnv *env, jobject obj, jobject props)
{
   p4(env, obj)->P4Connect(props);
}

/*
 * Class:     com_perforce_client_JniClient
 * Method:    p4close
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_perforce_client_JniClient_p4close
  (JNIEnv *env, jobject obj)
{
   p4(env, obj)->P4Close();
}

/*
 * Class:     com_perforce_client_JniClient
 * Method:    p4destroy
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_perforce_client_JniClient_p4destroy
  (JNIEnv *env, jobject obj)
{
   delete p4(env, obj);
   //obj.clientApiHandle is no longer valid
}
# Change User Description Committed
#8 2362 Paul Krause update for API release 2002.1
#7 886 Paul Krause create header files for class defs
#6 819 Paul Krause add TestSuite hooks
#5 802 Paul Krause Create a unit test case with the null unit test.
Clean up ThrowOutOfMemory (MCVC 6.0 won't let you throw void).
#4 787 Paul Krause When a JNI library function returns NULL because it failed to allocate memory, it is not necessary to throw an exception, because Java is already throwing one.
#3 771 Paul Krause ktext
#2 768 Paul Krause Rename JniClientApi->JniClient and clean up initialization.
Make an attempt to manage memory correctly.
#1 764 Paul Krause checkpoint - first working compile