You are not logged in. Click here to log in.

Application Lifecycle Management

Search In Project

Search inClear

Tags:  not added yet

OMS JNI Architecture

This document serves as a reference for all JNI related issues of OMS components.

Supported Scenario

A native source (maybe some subrouting/function out of an existing model) already exists and it should be used as a component. The Java Component can be derived from the Fortran/C source.

Calling sequence

In order to use native code, there need to be three files in total:
  • The OMS Java component file (e.g. Soil.java)
  • The original native source and (e.g. soil.f77)
  • A C++ Bridge, which mediates between the native source and the component (e.g. Soil_Bridge.C)

Java Component <=> C++ Bridge <=> Fortran/C

The Fortran source exists at the beginning, the Java Component is derived/generated from the Fortran/C source, and the C++ Bridge is generated from the Java Component.

Compilation & Linking

The Java source gets compiled into a class file, the other files make it into a dynamic loadable library

   Component          C++ Bridge                  Fortran/C   
(Comp.java)       (Comp_Bridge.C)                (comp.for)
      |                   |                          |              Compilation
      |                   V                          V
      |            Comp_Bridge.o                   comp.o      
      |                   |                          |              Linking
      |                   + ----------+--------------+
      |                               |
      V                               V
 Comp.class                       libComp.dll                       Executable

Compiler/Linker Settings

Compiler and Linker options for several compiler need to be choosen to ensure the following requirements:

  1. The compiler does not change the case of a symbol.
  2. The compiler does not append additional symbols, such as trailing underscores.

GNU/GCC

Fortran Compiler Flags to be used:

  • -Wimplicit Warn whenever a variable, array, or function is implicitly declared.
  • -fcase-preserve Preserves all case in user-defined symbols, while allowing any-case matching of intrinsics and keywords.
  • -fno-underscoring Do not transform names of entities specified in the Fortran source file by appending underscores to them.

CCompiler flags to be used:

Digital Fortran/MSVC

Fortran Compiler Flags to be used:

  • /names:as_is Keeps the symbol case.

Intel C/Fortran

TBD

<oms.h>

The file <oms.h> gets included in a Bridge file. The structure of this file results out of the following strategies:

  • Only 1.4 JNI is supported, since it relies on the call GetDirectBufferAddress .
  • Defines are used to (i) fetch direct buffers (ii) print out exectiopn debugging information.
  • Since cygwin is not supporting int64 as defined in jni_md.h the required adjustments have be made before including <jni.h>.

/**
 * OMS JNI Support. DO NOT EDIT UNLESS YOU ARE KNOW WHAT YOU ARE DOING!
 * Jnisupport Version : 1.0
 * @author Olaf David
 * @author Ian Schneider
 */

#ifdef __CYGWIN__ 

#define JNIEXPORT __declspec(dllexport)
#define JNIIMPORT __declspec(dllimport)
#define JNICALL __stdcall

typedef long jint;
typedef long long jlong;
typedef signed char jbyte;

#define _JAVASOFT_JNI_MD_H_
#endif 

#include <jni.h>

#if defined(DEBUG)
   #define GETATTR(TYPE, NAME) \
      TYPE __ ## NAME ## __ = (TYPE) GetDebugBuffer(env, NAME, #NAME);\
      if (!__ ## NAME ## __) return; 

   #define PRECALL(NAME) { puts("leaving to : #NAME"); fflush(stdout);} 
   #define POSTCALL(NAME) { puts("returning from : #NAME"); fflush(stdout); } 
#elif defined(FAST)
   #define GETATTR(TYPE, NAME) \
      TYPE __ ## NAME ## __ = (TYPE)GetFastBuffer(env, NAME);

   #define PRECALL(NAME)
   #define POSTCALL(NAME)
#else
   #define GETATTR(TYPE, NAME) \
      TYPE __ ## NAME ## __ = (TYPE)GetSafeBuffer(env, NAME, #NAME);\
      if (!__ ## NAME ## __) return; 

   #define PRECALL(NAME)
   #define POSTCALL(NAME)
#endif

 
/** JNI 1.4 is required to support direct buffers
 */
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
    return JNI_VERSION_1_4;
}

/** GetSafeBuffer decodes the memory buffer of a Java NIO Buffer object
 *  with checking for exeptions
 */
void* GetSafeBuffer(JNIEnv *env, jobject buffer, const char* name) {
    if (!buffer) {
        env->ThrowNew(env->FindClass("java/lang/NullPointerException"), name);
        return NULL;
    }
    void *nat_buffer = env->GetDirectBufferAddress(buffer);
    if (!nat_buffer)
        env->ThrowNew(env->FindClass("java/lang/IllegalArgumentException"), name);
    return nat_buffer;
}

/** GetSafeBuffer decodes the memory buffer of a Java NIO Buffer object
 *  with checking for exeptions
 */
void* GetDebugBuffer(JNIEnv *env, jobject buffer, const char* name) {
    if (!buffer) {
        env->ThrowNew(env->FindClass("java/lang/NullPointerException"), name);
        return NULL;
    }
    void *nat_buffer = env->GetDirectBufferAddress(buffer);
    puts("Getting Attrbute "); puts(name);
    if (!nat_buffer)
        env->ThrowNew(env->FindClass("java/lang/IllegalArgumentException"), name);
    return nat_buffer;
}

/** GetFastBuffer decodes the memory buffer of a Java NIO Buffer object
 *  without checking anything
 */
static inline void* GetFastBuffer(JNIEnv *env, jobject buffer) {
    return env->GetDirectBufferAddress(buffer);
}

The Bridge File

The Bridge file is usually generated from the component file. The it should be not modified manually. The build system (build.properties) should be used to set defines

Supported 'defines'

  • DEBUG : print out debugging information while executing the bridge.
  • FAST : fast Buffer fetching, no check of valid pointers or arguments; a brodge should be used in such a mode only when it was tested before.
  • If no define is set the Bridge executes quietely and implements a fail-safe procedure.

JNI Component Example

Fortran Source Test.for


   SUBROUTINE SLOSS(IPLANE,LOAD,TCEND,WIDTH,RSPACE,EFFDRN,THETA,
     1    SLPLEN,IRDGDX,QSOUT,DSLOST,AVSOLE,NPLANE,QOUT)
C
      IMPLICIT NONE
      REAL LOAD(101), TCEND, WIDTH(10), RSPACE(10), EFFDRN(10)
      REAL THETA, SLPLEN(10)
      REAL IRDGDX(10), QSOUT, DSLOST(10,100)
      REAL AVSOLE, QOUT
      INTEGER IPLANE, NPLANE

      .....
      END

C++ Bridge Test_Bridge.C

/******************************************************************************* 
 OMS jnisupport generated bridge - DO NOT EDIT (unless you are me)
 Java Component : gov.test.Test
 Creation Date  : 2/1/05 4:57 PM
 Jnisupport Version : 1.0
*******************************************************************************/
#include <oms.h>

// External (Native) Call Prototype
extern "C" void SLOSS(
	int*, // IPLANE
	double*, // LOAD
	double*, // TCEND
	double*, // WIDTH
	double*, // RSPACE
	double*, // EFFDRN
	double*, // THETA
	double*, // SLPLEN
	double*, // IRDGDX
	double*, // QSOUT
	double*, // DSLOST
	double*, // AVSOLE
	int*, // NPLANE
	double* // QOUT
);

// JNI Dispatcher
extern "C"  JNIEXPORT void JNICALL Java_gov_test_Test_SLOSS (
	JNIEnv *env, jobject obj,
	jobject IPLANE,
	jobject LOAD,
	jobject TCEND,
	jobject WIDTH,
	jobject RSPACE,
	jobject EFFDRN,
	jobject THETA,
	jobject SLPLEN,
	jobject IRDGDX,
	jobject QSOUT,
	jobject DSLOST,
	jobject AVSOLE,
	jobject NPLANE,
	jobject QOUT
) {
	GETATTR(int*, IPLANE)
	GETATTR(double*, LOAD)
	GETATTR(double*, TCEND)
	GETATTR(double*, WIDTH)
	GETATTR(double*, RSPACE)
	GETATTR(double*, EFFDRN)
	GETATTR(double*, THETA)
	GETATTR(double*, SLPLEN)
	GETATTR(double*, IRDGDX)
	GETATTR(double*, QSOUT)
	GETATTR(double*, DSLOST)
	GETATTR(double*, AVSOLE)
	GETATTR(int*, NPLANE)
	GETATTR(double*, QOUT)

	PRECALL(SLOSS)
	SLOSS(
		__IPLANE__, // IPLANE
		__LOAD__, // LOAD
		__TCEND__, // TCEND
		__WIDTH__, // WIDTH
		__RSPACE__, // RSPACE
		__EFFDRN__, // EFFDRN
		__THETA__, // THETA
		__SLPLEN__, // SLPLEN
		__IRDGDX__, // IRDGDX
		__QSOUT__, // QSOUT
		__DSLOST__, // DSLOST
		__AVSOLE__, // AVSOLE
		__NPLANE__, // NPLANE
		__QOUT__ // QOUT
	);

	POSTCALL(SLOSS)
	return;
}


// Reloadable dispatcher
extern "C"  JNIEXPORT void JNICALL Java_gov_test_Test_SLOSSdispatch (
JNIEnv * env, jobject obj, jobject * args) {
	Java_gov_test_Test_SLOSS(
		env,obj,args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13]
	);
	return;
};