Sunday, September 30, 2007

Part 1: Java Programming Using RMI (Remote Method Invocation)

Reference : http://java.sun.com

Aplikasi RMI biasanya mencakup dua program berupa server dan client.program pada server membuat remote objects kemudian membuat referensi ke object dan menunggu client untuk memanggil methods pada server.program pada client menentukan referensi ke satu atau lebih remote objects pada server dan kemudian memanggil methods2 pada server yang bisa terakses.RMI pada intinya merupakan sebuah mekanisme dimana server dan client berkomunikasi dan saling memberikan informasi, RMI sering kali dikaitkan dengan sistem terdistribusi.

ilustrasi di bawah ini menunjukkan applikasi terdistribusi menggunakan RMI :


registri digunakan untuk menentukan referensi ke remote object. Kemudian server memanggil registri untuk mencocokkan nama dengan remote object, client mencari remote object berdasarkan namanya pada server registri dan kemudian memanggil method pada object tersebut. Ilustrasi di atas juga menunjukkan bahwa sistem RMI menggunakan web server untuk meload class, dari server ke client dan dari client ke server sesuai dengan object yang dibutuhkan.

Keuntungan dari Dynamic Code Loading
Salah satu keunikan dari RMI adalah kemampuannya untuk mendownload object class jika class belum didefinisikan pada Java Virtual Machine penerima, tanpa ada perubahan ketika object dikirimkan ke Java Virtual Machine penerima. Object yang didownload secara dinamis dapat digunakan untuk sebuah aplikasi.

Remote Interface, Objects, dan Methods
Seperti aplikasi java pada umumnya, aplikasi RMI terdiri dari interface dan class. Interface mendefinisikan method sedang class mengimplementasikan methods yang didekrarasikan pada interface.
Agar object dapat menjadi remote object harus mengimplementasikan remote interface, yang mempunyai karakteristik sebaagai berikut:
1. Remote interface menurunkan sifat dari interface java.rmi.Remote.
2. Setiap method dari interface mendeclarasikan java.rmi.RemoteException menggunakan klausa throws

Membuat aplikasi terdistribusi menggunakan RMI
Membuat aplikasi terdistribusi menggunakan RMI mangikuti langkah-langkah umum sbb:
1. Mendesain dan mengimplementasikan aplikasi terdistribusi
2. Mengkompile source
3. Membuat class yang dapat diakses melalui netwotk
4. Menjalankan aplikasi

Membuat code RMI server
Mendesain Remote Interfce
Pada pembuatan aplikasi terdistribusi kali ini akan membuat sebuah "compute engine". Inti dari compute engine adalah sebuah protokol yang dapat menerima tugas/permintaan yang dikirim ke compute engine, kemudian compute engine menjalankan permintaan/tugas tersebut, dan hasil dari permintaan/tugas yang di jalankan akan dikembalikan lagi ke client. Komunikasi untuk protokol ini diilustrasikan sebagai berikut:

Pada aplikasi compute engine ini menggunakan 2 interface yaitu:
1. Compute.java --> merupakan compute engine remote interface yang digunakan untuk menangani permintaan/tugas yang dikirim ke compute engine (server)
2. Task.java --> merupakan client interface yang mendefinisikan bagaimana compute engine mengeksekusi tugas/permintaan yang dikirim oleh client.

compute.Compute interface mendefinisikan bagian dari compute engine yang dapat diakses secara remote. Berikut adalah source code untuk Compute interface:

package compute;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Compute extends Remote {
T excecuteTask(Task t) throws RemoteExcepation;
}

Dengan menurunkan interface java.rmi.Remote, Compute interface menandakan bahwa method pada interface ini dapat dipanggil dari Java Virtual Machine yang lain secara remote. Semua object yang mengimplementasikan interface ini akan dapat menjadi remote object. Dari kode Compute.java diatas terlihat bahwa method executeTask harus melemparkan sebuah exception yaitu java.rmi.RemoteException karena method ini merupakan bagian dari remote interface, sedangkan fungsi dari java.rmi.RemoteException ini digunakan untuk melemparkan exception jika terjadi kesalahan/kegagalan komunikasi antara client dengan server, exception kesalahan akan ditangani menggunakan klausa try-catch.

Interface yang kedua yaitu Task interface, interface ini digunakan sebagai parameter method executeTask pada Compute interface. compute.Task interface digunakan untuk menjembatani antara compute engine dengan task-task/tugas-tugas dari compute engine. Berikut adalah source code dari Task interface:

package compute;

public interface Task {
T execute();
}

Task interface mendefinisikan method tunggal yaitu execute tanpa parameter dan tidak melemparkan exeption apapun. Karena dalam interface Task tidak menurunkan interface Remote, Method ini juga tidak perlu melemparkan exception java.rmi.RemoteException karena exeption ini sudah ditangani oleh interface Compute.

Task interface mempunyai tipe parameter T, yang merupakan tipe dari hasil computasi/perhitungan. Method execute pada interface ini mengembalikan nilai berupa hasil dari perhitungan dimana bertipe T.

Sedangkan pada interface Compute, method executeTask akan mengembalikan hasil dari instance interface Task (dimana Task merupakan parameter dari method executeTask).

Implementing Remote Object
Pada bagian ini akan menjelaskan bagaimana mengimplemantasikan class untuk compute engine. Secara umum ada tiga tahapan dalam mengimplementasikan interface yang telah kita buat ke dalam sebuah class:
1. Mendeklarasikan remote interface yang telah diimplementasikan
2. Mendefinisikan construktor untuk setiap remote object
3. Mengimplementasikan setiap method yang telah dideklarasikan pada remote interface

Program RMI server perlu membuat inisial remote object dan mengexport inisial tersebut ke RMI runtime, yang akan membuat server dapat menerima pemanggilan secara remote terhadap method-method yang ada di server. Langkah inisialisasi:
1. Membuat dan menginstall security manager
2. Membuat dan mengexport satu atau lebih remote object
3. Lakukan register paling sedikit satu remote object dengan menggunakan RMI registri (atau menggunakan naming service yang lain, seperti JNDI) untuk bootstrap.

Berikut adalah source code untuk ComputeEngine.java:

package engine:

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import compute.Compute;
import compute.Task;

public class ComputeEngine implements Compute {
public ComputeEngine() {
super();
}

public T executeTask(Task t) {
return t.execute();
}

public static void main(String[] args) {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}
try {
String name = "Compute";
Compute engine = new ComputeEngine();
Compute stub =
(Compute)UnicastRemoteObject.exportObject(engine,0);
Registry registry = LocalRegistry.getRegistry();
registry.rebind(name, stub);
System.out.println("Compute Engine bound");
}catch (Exception e) {
System.out.println("Compute Engine exception");
e.printStackTrace();
}
}
}


Membuat program pada client
Program pada client akan lebih complex karena harus memanggil compute engine kemudian juga harus mendefinisikan task/tugas yang akan dikerjakan oleh compute engine.

Program pada client mempunyai dua class, yang pertama adalah class ComputePi yang akan mancari dan memanggil Compute object. Sedang yang kedua adalah class Pi yang mengimplementasikan Task interface dan mendefinisikan tugas/pekerjaan yang akan diselesaikan oleh compute engine.
Tugas dari class Pi adalah untuk menghitung nilai dari pi.

Code yang digunakan untuk memanggil method Compute object harus mereferensi ke object tersebut, membuat Task object, dan kemudian melakukan request yang berupa task/tugas.

Berikut adalah source code dari ComputePi:

package client;

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.math.BigDecimal;
import compute.Compute;

publi class ComputePi {
public static void main(String[] args) {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}
try {
String name = "Compute";
Registry registry = LocateRegistry.getRegistry(args[0]);
Compute comp = (Compute) registry.lookup(name);
Pi task = new Pi(Integer.parseInt(args[1]));
BigDecimal pi = comp.executeTask(task);
System.out.println(pi);
} catch (Exception e) {
System.err.println("ComputePi exception:");
e.printStackTrace();
}
}
}


Source code untuk class Pi:

package client;

import compute.Task;
import java.io.Serializable;
import java.math.BigDecimal;

public class Pi implements Task, Serializable {

private static final long serialVersionUID = 227L;

/** constants used in pi computation */
private static final BigDecimal FOUR =
BigDecimal.valueOf(4);

/** rounding mode to use during pi computation */
private static final int roundingMode =
BigDecimal.ROUND_HALF_EVEN;

/** digits of precision after the decimal point */
private final int digits;

/**
* Construct a task to calculate pi to the specified
* precision.
*/
public Pi(int digits) {
this.digits = digits;
}

/**
* Calculate pi.
*/
public BigDecimal execute() {
return computePi(digits);
}

/**
* Compute the value of pi to the specified number of
* digits after the decimal point. The value is
* computed using Machin's formula:
*
* pi/4 = 4*arctan(1/5) - arctan(1/239)
*
* and a power series expansion of arctan(x) to
* sufficient precision.
*/
public static BigDecimal computePi(int digits) {
int scale = digits + 5;
BigDecimal arctan1_5 = arctan(5, scale);
BigDecimal arctan1_239 = arctan(239, scale);
BigDecimal pi = arctan1_5.multiply(FOUR).subtract(
arctan1_239).multiply(FOUR);
return pi.setScale(digits,
BigDecimal.ROUND_HALF_UP);
}
/**
* Compute the value, in radians, of the arctangent of
* the inverse of the supplied integer to the specified
* number of digits after the decimal point. The value
* is computed using the power series expansion for the
* arc tangent:
*
* arctan(x) = x - (x^3)/3 + (x^5)/5 - (x^7)/7 +
* (x^9)/9 ...
*/
public static BigDecimal arctan(int inverseX,
int scale)
{
BigDecimal result, numer, term;
BigDecimal invX = BigDecimal.valueOf(inverseX);
BigDecimal invX2 =
BigDecimal.valueOf(inverseX * inverseX);

numer = BigDecimal.ONE.divide(invX,
scale, roundingMode);

result = numer;
int i = 1;
do {
numer =
numer.divide(invX2, scale, roundingMode);
int denom = 2 * i + 1;
term =
numer.divide(BigDecimal.valueOf(denom),
scale, roundingMode);
if ((i % 2) != 0) {
result = result.subtract(term);
} else {
result = result.add(term);
}
i++;
} while (term.compareTo(BigDecimal.ZERO) != 0);
return result;
}
}

5 comments:

  1. aseek,.. ada yg mahir java
    ntar saya diajari yap!

    sesama fren kan saling membantu
    :D

    ReplyDelete
  2. wew g semahir itu tapi klo mau diskusi bikin kelompok belajar boleh juga tuh soalnya aq jg baru pemula hehe.. benar sesama teman harus salaing membantu..

    ReplyDelete
  3. Wah Bagus nih Bagi2 ilmunya .....ane jg mau .....aq jg baru belajar ttg pemrograman java........boleh lah di transfer tuh mas ilmunya ...hehhe.......klo mau bikin aplikasi kasir ya terhung kejaringan itu ..kita harus sediain ap aj tuh mas biar bisa terhubung.....kasir --> komputer konsumen......masih binggun nih mas...tlong pencerahannya .....

    ReplyDelete
  4. kalo bikin aplikasi semacam POS/Point Of Sale kayak gitu cukup nyiapin satu mesin server database bisa diinstall database tergantung selera mau make database yang mana. Truss kalo masalah jaringan tinggal bagaimana tipologinya biasanya yang umum pake star... sedang di sisi aplikasi sendiri sudah ada API yang menangani koneksi kedatabase baik via internet maupun localhost... soo tunggu apa lagi langsung dibikin saja

    ReplyDelete
  5. permisi gan, saya ada sedikit tulisan mengenai protokol websocket menggunakan bahasa java berikut gan: http://datacomlink.blogspot.co.id/2015/11/script-java-websocket-rfc-6455-server.html ditunggu feedback-nya ya gan, semoga menambah wawasan bersama.. terima kasih gan..

    ReplyDelete