Jan 8, 2003

          onlsbc1, Red Hat Linux 8.0 のシステムでのJNIの実行
           ---  ネイティブ言語メソッドからJavaメンバ変数をアクセス#6
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                  (http://www-online.kek.jp/~inoue/para-CAMAC/
                                   Work/SBC-Java8.html)



                        高エネルギー加速器研究機構
                            素粒子原子核研究所
                         物理、オンライングループ
                                井上 栄二



	目的

	    SBC、PCM-9370にインストールしてある Red Hat Linux 8.0 のシステム上で
	  JNIを使ってネイティブ言語メソッドからJavaメンバ変数へのアクセスの
	    実行確認をする。


	(1). 構成
	(2). コンパイル
	(3). 実行

  --------------------------------------------------------------------


 (1). 構成

	テストに使用するマシンは onlsbc1 である。 このマシンはアドバンテク社の
	SBC、PCM-9370である。 動作している OSはRed Hat Linux 8.0 で、Javaの
	バージョンは1.4.1_01 である。 最終的にはコンパクトフラッシュ上に構成した
	Linuxシステムで実行できることを目指すのであるが、ソフトウェアの開発段階
	では 2.5" IDE ハードディスク上に構成したLinuxシステムを使ってテストを
	行うことにする。


 (2). コンパイル

   (2-1). Javaのチェック
[inoue@onlsbc1 inoue]$ java -version
java version "1.4.1_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-b01)
Java HotSpot(TM) Client VM (build 1.4.1_01-b01, mixed mode)
[inoue@onlsbc1 inoue]$


   (2-2).  実行環境

[inoue@onlsbc1 inoue]$ env
MANPATH=:/usr/java/man
HOSTNAME=onlsbc1.kek.jp
PVM_RSH=/usr/bin/rsh
TERM=vt100
SHELL=/bin/bash
JLESSCHARSET=japanese
HISTSIZE=1000
SSH_CLIENT=130.87.153.9 33055 22
QTDIR=/usr/lib/qt3-gcc3.2
SSH_TTY=/dev/pts/1
USER=inoue
LS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;0
1:or=01;05;37;41:mi=01;05;37;41:ex=01;32:*.cmd=01;32:*.exe=01;32:*.com=01;32:*.b
tm=01;32:*.bat=01;32:*.sh=01;32:*.csh=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:
*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*
.bz=01;31:*.tz=01;31:*.rpm=01;31:*.cpio=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;3
5:*.xbm=01;35:*.xpm=01;35:*.png=01;35:*.tif=01;35:
PVM_ROOT=/usr/share/pvm3
MAIL=/var/spool/mail/inoue
PATH=/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/usr/java/bin
:/home/inoue/bin
INPUTRC=/etc/inputrc
PWD=/home/inoue
LANG=ja_JP.eucJP
LAMHELPFILE=/etc/lam/lam-helpfile
SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpass
SHLVL=1
HOME=/home/inoue
XPVM_ROOT=/usr/share/pvm3/xpvm
LOGNAME=inoue
LESSOPEN=|/usr/bin/lesspipe.sh %s
G_BROKEN_FILENAMES=1
_=/bin/env
[inoue@onlsbc1 inoue]$


   (2-3).  Javaコードを書く

        この実行で使用するソースコードは、以下のURLから入手した。
	http://java.sun.com/j2se/1.4/ja/docs/ja/guide/jni/index.html

[inoue@onlsbc1 FieldAccess]$ pwd
/home/inoue/JNI/FieldAccess
[inoue@onlsbc1 FieldAccess]$ ls -l
合計 8
-rw-rw-r--    1 inoue    inoue         882  1月  8 10:14 FieldAccess.c
-rw-rw-r--    1 inoue    inoue         453  1月  8 10:13 FieldAccess.java
[inoue@onlsbc1 FieldAccess]$ cat FieldAccess.java
class FieldAccess {
  static int si;
  String s;

  private native void accessFields();
  public static void main(String args[]) {
    FieldAccess c = new FieldAccess();
    FieldAccess.si = 100;
    c.s = "abc";
    c.accessFields();
    System.out.println("In Java:");
    System.out.println("  FieldAccess.si = " + FieldAccess.si);
    System.out.println("  c.s = \"" + c.s + "\"");
  }
  static {
    System.loadLibrary("MyImpOfFieldAccess");
  }
}
[inoue@onlsbc1 FieldAccess]$

	参考.
	  1. シグナチャ
	  シグナチャの要素(クラス名や返り値、データ型など)に分解します。
	    メソッドの名前とパラメータの数と型の事をシグナチャといいます。
		例)(Ljava/lang/String;)V
			↓
	  	"L" と "java/lang/String" と "V" に分解します。
	    "L" はクラスを意味します。
	    "java/lang/String" はパス付きクラス名です。
	    "V" は返り値が void 型であることを意味しています。

	  2. メンバ変数の概要 
	    メンバ変数はクラス及びそのオブジェクトに属する変数でどのメソッド、
	    コンストラクタにも属しません。そのため、複数のメソッド、コンスト
	    ラクタで共通して使用したい変数にメンバ変数を使用します。逆に
	    各メソッド、コンストラクタに限定して使用する変数をローカル変数と
	    呼びます。


   (2-4).  Javaコードをコンパイルする

[inoue@onlsbc1 FieldAccess]$ ls -l
合計 8
-rw-rw-r--    1 inoue    inoue         882  1月  8 10:14 FieldAccess.c
-rw-rw-r--    1 inoue    inoue         453  1月  8 10:13 FieldAccess.java
[inoue@onlsbc1 FieldAccess]$ javac FieldAccess.java
[inoue@onlsbc1 FieldAccess]$ ls -l
合計 12
-rw-rw-r--    1 inoue    inoue         882  1月  8 10:14 FieldAccess.c
-rw-rw-r--    1 inoue    inoue         985  1月  8 10:20 FieldAccess.class
-rw-rw-r--    1 inoue    inoue         453  1月  8 10:13 FieldAccess.java
[inoue@onlsbc1 FieldAccess]$

	参考.
	  Javaクラス ディスアセンブラツール、Javapを使うとクラスファイルから
	 メンバ変数シグナチャを作成して表示できる。 これを使用することで手書き
	 でメソッドシグナチャを書く時のミスを減らすことができる。 javapコマンド
	  に付加する "-s"フラグは通常のJavaタイプより多くのシグナチャを出力
	 することを指示し、"-p"フラグはプライベートメンバも含めるように指示
	 していることを意味している。

[inoue@onlsbc1 FieldAccess]$ javap -s -p FieldAccess
Compiled from FieldAccess.java
class FieldAccess extends java.lang.Object {
    static int si;
        /*   I   */
    java.lang.String s;
        /*   Ljava/lang/String;   */
    FieldAccess();
        /*   ()V   */
    private native void accessFields();
        /*   ()V   */
    public static void main(java.lang.String[]);
        /*   ([Ljava/lang/String;)V   */
    static {};
        /*   ()V   */
}
[inoue@onlsbc1 FieldAccess]$


   (2-5).  .hファイルの生成

        C++言語のヘッダーファイルは、以下のようにjavahというコマンドで生成
        できる。 オプションには-jniを指定し、引数には項目(2-4)でコンパイルした
        クラスの拡張子を除いたものを指定する。

[inoue@onlsbc1 FieldAccess]$ javah -jni FieldAccess
[inoue@onlsbc1 FieldAccess]$ ls -l
合計 16
-rw-rw-r--    1 inoue    inoue         882  1月  8 10:14 FieldAccess.c
-rw-rw-r--    1 inoue    inoue         985  1月  8 10:20 FieldAccess.class
-rw-rw-r--    1 inoue    inoue         426  1月  8 10:34 FieldAccess.h
-rw-rw-r--    1 inoue    inoue         453  1月  8 10:13 FieldAccess.java
[inoue@onlsbc1 FieldAccess]$ cat FieldAccess.h
/* DO NOT EDIT THIS FILE - it is machine generated */

#include <jni.h>
/* Header for class FieldAccess */

#ifndef _Included_FieldAccess
#define _Included_FieldAccess
#ifdef __cplusplus
extern "C" {
#endif
/* Inaccessible static: si */
/*
 * Class:     FieldAccess
 * Method:    accessFields
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_FieldAccess_accessFields
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif
[inoue@onlsbc1 FieldAccess]$


   (2-6).  C言語のソースファイルの作成

[inoue@onlsbc1 FieldAccess]$ cat FieldAccess.c

#include <stdio.h>
#include <jni.h>
#include "FieldAccess.h"

JNIEXPORT void JNICALL
Java_FieldAccess_accessFields(JNIEnv *env, jobject obj)
{
  jclass cls = (*env)->GetObjectClass(env, obj);
  jfieldID fid;
  jstring jstr;
  const char *str;
  jint si;

  printf("In C:\n");

  fid = (*env)->GetStaticFieldID(env, cls, "si", "I");
  if (fid == 0) {
    return;
  }
  si = (*env)->GetStaticIntField(env, cls, fid);
  printf("  FieldAccess.si = %d\n", si);
  (*env)->SetStaticIntField(env, cls, fid, 200);

  fid = (*env)->GetFieldID(env, cls, "s", "Ljava/lang/String;");
  if (fid == 0) {
    return;
  }
  jstr = (*env)->GetObjectField(env, obj, fid);
  str = (*env)->GetStringUTFChars(env, jstr, 0);
  printf("  c.s = \"%s\"\n", str);
  (*env)->ReleaseStringUTFChars(env, jstr, str);

  jstr = (*env)->NewStringUTF(env, "123");
  (*env)->SetObjectField(env, obj, fid, jstr);
}
[inoue@onlsbc1 FieldAccess]$


   (2-7).  C言語のソースファイルをコンパイルしてシェアード・ライブラリを作成

[inoue@onlsbc1 FieldAccess]$ pwd
/home/inoue/JNI/FieldAccess
[inoue@onlsbc1 FieldAccess]$ ls -l
合計 16
-rw-rw-r--    1 inoue    inoue         882  1月  8 10:14 FieldAccess.c
-rw-rw-r--    1 inoue    inoue         985  1月  8 10:20 FieldAccess.class
-rw-rw-r--    1 inoue    inoue         426  1月  8 10:34 FieldAccess.h
-rw-rw-r--    1 inoue    inoue         453  1月  8 10:13 FieldAccess.java
[inoue@onlsbc1 FieldAccess]$ gcc -shared -I/usr/java/include -I/usr/java/include
/linux FieldAccess.c -o libMyImpOfFieldAccess.so
[inoue@onlsbc1 FieldAccess]$ ls -l
合計 24
-rw-rw-r--    1 inoue    inoue         882  1月  8 10:14 FieldAccess.c
-rw-rw-r--    1 inoue    inoue         985  1月  8 10:20 FieldAccess.class
-rw-rw-r--    1 inoue    inoue         426  1月  8 10:34 FieldAccess.h
-rw-rw-r--    1 inoue    inoue         453  1月  8 10:13 FieldAccess.java
-rwxrwxr-x    1 inoue    inoue        6148  1月  8 11:14 libMyImpOfFieldAccess.s
o
[inoue@onlsbc1 FieldAccess]$


 (3). 実行

[inoue@onlsbc1 FieldAccess]$ export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
[inoue@onlsbc1 FieldAccess]$ java FieldAccess
In C:
  FieldAccess.si = 100
  c.s = "abc"
In Java:
  FieldAccess.si = 200
  c.s = "123"
[inoue@onlsbc1 FieldAccess]$

	ok.  JNIを使ってネイティブ言語メソッドからJavaメンバ変数へのアクセスの
	実行は正常にできた。

---xxxx