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;
}
}
My name is 
bang aku kopi ke blog ku ya
thx
Comment by Bagus Prasojo — 13 September, 2008 @ 12:02 am
thanx buat kuliah gue ne..
Comment by dochi — 27 October, 2008 @ 2:21 am
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