J.a.i.m’s Diary

Interfacing Delphi dan Java

Java sebagai bahasa pemrograman aplikasi bisnis enterprise menawarkan begitu banyak ragam alternatif solusi yang beberapa di antaranya sudah mencapai taraf kematangan yang cukup baik terutama untuk kebutuhan aplikasi berbasis multi-tier, sebut saja TopLink yang saat ini menjadi standar persistent API di java, kemudian Spring, Atomikos, dan begitu banyak lainnya yang tidak mungkin disebutkan satu persatu dalam blog ini. Java juga menarik digunakan sebagai sarana pemasaran karena plethoria-nya yang begitu luas. Sementara itu Delphi, khususnya untuk digunakan sebagai bahasa pemrograman untuk middleware belum memiliki ragam pilihan seperti yang terdapat di Java, namun demikian, karena sifatnya sebagai native code, Delphi memungkinkan kita membuat middleware server yang memiliki performa dan stabilitas yang mengungguli middleware sejenis yang dibuat dengan menggunakan Java.

Ragam solusi yang terdapat di java sangat menarik dan terlalu sayang untuk tidak dimanfaatkan, namun permasalahannya, bagaimana jika kita sudah memiliki sebuah middleware server yang dibangun dengan delphi? Memportingnya ke java jelas bukanlah sebuah solusi yang mudah karena itu bisa berarti menulis ulang keseluruhan sistem dari awal. Solusi yang paling memungkinkan tentunya adalah menginterfacekan middleware server yang dibuat dengan delphi tersebut dengn Java, dengan kata lain meng-embbed java virtual machine ke dalam middleware server Delphi sehingga memungkinkan kita memanfaatkan java dalam sistem yang kita buat dengan menggunakan Delphi.

Bagaimana Caranya?

Cukup sederhana sebenarnya, komunitas delphi, meskipun tidak sebesar komunitas java, namun tidak pula sekecil yang kita pikirkan. Solusi untuk menginterfacekan Delphi dengan Java dengan memanfaatkan JNI telah tersedia dan bisa dimanfaatkan untuk kebutuhan kita. Matthew Mead telah membuat translasi Java Native Interface Wrapper yang memungkinkan Delphi bisa melakukan interfacing dengan kode-kode yang ditulis dengan java. Yang kita butuhkankan hanyalah mendownload wrapper tersebut.
   

Kita perlu sedikit melakukan modifikasi pada file JNI.pas, mulai pada baris 89 dengan kode berikut:


  JNI_VERSION_1_5 = JInt($00010005);
  {$EXTERNALSYM JNI_VERSION_1_5}
  JNI_VERSION_1_6 = JInt($00010006);
  {$EXTERNALSYM JNI_VERSION_1_6}

{$DEFINE DYNAMIC_LINKING}

Strukturisasi class yang terdapat dalam wrapper tersebut bisa dikatakan cukup baik, kita hanya perlu memastikan hanya ada satu instance class TJavaVM dalam keseluruhan aplikasi kita. Barangkali akan timbul pertanyaan, middleware umumnya berbasis multithread, dan menggunakan single instance seperti itu tentunya akan beresiko tinggi, atau setidaknya menurunkan performa karena harus melakukan locking dan sinkronisasi setiap akan menggunakannya. Kita tidak perlu kuatir untuk hal ini karena kita tidak akan menggunakan object instance dari TJavaVM secara langsung, melainkan untuk tiap-tiap thread kita membuat satu instance dari class TJNIEnv dengan menggunakan TJavaVM sebagai referer.

Inisialisasi JavaVM

Mari kita lanjutkan dengan membuat inisialisasi TJavaVM pada class utama aplikasi, bisa main class, atau main server object class, bergantung pada bagaimana struktur class yang terdapat dalam middleware yang dibuat.


type
  TServerManager = class(TAbstractLifeCycle)
  ...
  private
    FJavaVM: TJavaVM;
    procedure InitializeVM(FEngine: TJavaVM);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    property JavaVM: TJavaVM read FJavaVM;
  end;

...
const
  CJVM_Path = 'C:\Java\jdk1.6.0_04\jre\bin\client\jvm.dll';

constructor TServerManager.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ...
  FJavaVM := TJavaVM.Create(JNI_VERSION_1_6, CJVM_Path);
end;

destructor TServerManager.Destroy;
begin
  FJavaVM.Free;
  ...
  inherited Destroy;
end;

procedure TServerManager.InitializeVM(FEngine: TJavaVM);
var
  Options: array [0..4] of JavaVMOption;
  VM_args: JavaVMInitArgs;
  Errcode: Integer;
begin
  Options[0].optionString := '-Djava.class.path=.'; // tambahkan library lain pada classpath jika diperlukan
  VM_args.version := JNI_VERSION_1_6;
  VM_args.options := @Options;
  VM_args.nOptions := 1;
  Errcode := FEngine.LoadVM(VM_args);
  if Errcode < 0 then
    Raise Exception.Create(Format('Error loading JavaVM, error code = %d', [Errcode]));
end;

Pastikan method InitializeVM dipanggil hanya sekali setelah object class utama itu di-create, namun jangan menggabungkannya pada constructor TServerEngine karena bisa menyebabkan memory leakage jika penanganan atas itu keliru.


begin
  FServerManager := TServerManager.Create(Self)
  FServerManager.InitializeVM(FServerManager.JavaVM);
end;

Seperti yang telah disebutkan sebelumnya, sebelum kita mulai melakukan invoking method java dari delphi, kita harus membuat terlebih dulu satu buah instance dari class TJNIEnv untuk tiap-tiap process thread dari middleware tersebut dengan menggunakan object instance TJavaVM sebagai referer.


type
  TServerCommandHandler = class(TBaseCommandHandler)
  ...
  private
    FJNIEnv: TJNIEnv;
    FServerManager: TServerManager;

    procedure SetServerManager(AValue: TServerManager);
  public   

    property JNIEnv: TJNIEnv read FJNIEnv;
    property Servermanager: TServerManager read FServerManager write SetServerManager;
  end;

procedure TServerCommandHandler.SetServerManager(AValue: TServerManager);
begin
   if AValue = FServerManager then
      exit;
   if AValue = nil then
   begin
      if Assigned(FJNIEnv) then
          FreeAndNil(FJNIEnv);
   end else
   begin
      if Assigned(FJNIEnv) then
          FreeAndNil(FJNIEnv);
      FJNIEnv := TJNIEnv.Create(AValue.JavaVM.Env);
   end;
   FServerManager := AValue;
end;

Invoking Java Method dari Delphi

Untuk melakukan pemanggilan atas method Java melalui delphi dari process thread tersebut, kita tinggal menggunakan object instance TJNIEnv yang telah dibuat sebelumnya. Implementasi pada bagian ini sangat beragam, dan bisa menjadi sangat kompleks bergantung pada tipikal task yang dikerjakan di sisi middleware yang dibuat, namun contoh yang paling sederhananya adalah sebagai berikut:


var
  Cls: JClass;
  Mid: JMethodID;
  JStr: JString;
begin
  Cls := FJNIEnv.FindClass('FunctionTest');
  if Cls = nil then
    LogAndRaise('Can''t find class: FunctionTest');
  Mid := FJNIEnv.GetStaticMethodID(Cls, 'sayHello', '(Ljava/lang/String;)Ljava/lang/String;');
  if Mid = nil then
    LogAndRaise('Can''t find method: sayHello');

   // Call the static method
  JStr := FJNIEnv.CallStaticObjectMethod(Cls, Mid, ['Hello World']);

  // Convert the returned JString to a Delphi string
  DataMessage.Reply(FJNIEnv.JStringToString(JStr));
end;

Kode java yang akan dipanggil dalam hal ini adalah sebagai berikut:


public class FunctionTest{

  public static String sayHello(String inputHello)
  {
    String hello = "Hello World";
    return hello;
  }
}

C.O.M.M.E.N.T.S:

Listed below are comments from my friends regarding to this entry. If you wish, you may also add a comment by clicking new comment.

  1. bang aku kopi ke blog ku ya
    thx

    Comment by Bagus Prasojo — 13 September, 2008 @ 12:02 am

  2. thanx buat kuliah gue ne..

    Comment by dochi — 27 October, 2008 @ 2:21 am

  3. mas bisa lihat contoh aplikasi nya g?
    trus aplikasinya apa cuman bisa dijalankan di windows saja?

    Comment by wanto — 7 January, 2010 @ 4:15 am

RSS feed for comments on this post. TrackBack URL

Leave a comment:








 

About Me

Jaimy Azle My name is
Jaimy Azle, hufflepuff, I am a software developer with Delphi and C/C++ as major programming language. Living in Ungaran, Jawa Tengah.

Search

Categories:

Tag Cloud

Archives:

Meta:


Get Firefox!
Perhatian: Informasi yang terdapat disini bener-bener hanya merepresentasikan cerita, pengalaman, ataupun pandangan yang merupakan opini pribadi dari saya sebagai ego. Segala hal yang bersifat pandangan ke depan sebenarnya lebih bersifat spekulatif dan bisa saja berobah meski saya bukan bunglon.