SENDE YAZ , FARKIN OLSUN...

29 Temmuz 2010 Perşembe

Java ' da RMI (Remote Method Invocation)



Selamlar ,artık mümkün oldugunca Java üzerine de bişeyler yazmaya çalışıcam.Günümüzde Mesajlajma ve msn tarzı sohbet programlarının kullanımı cok yaygın oldugundan bu olayın temeliyle ilgili bi konudan bahsetmek istedim.Öncelikle RMI kısaltmasının Türkçe açılımı "Uzaktan Metod Çağırımı" demektir.Adından da anlaşılacağı üzere , iki ayrı objenin bir interface ( Arayüz ) aracılığıyla , birbirleri arasında server - client (sunucu - istemci) ilişkisi oluşturmada kullanılan bir yöntemdir.Daha genel olarak yazıcak olursak ; Bir cihaz üzerinde çalışan Java nesnelerinin, başka bir cihaz üzerinde çalışan diğer Java nesnesinin metodunu çağırmasını sağlar. Bu önemli özellik dağıtık uygulamalar geliştirilmesine izin verir.

Genel şablon şu şekildedir :




Çok basit bir RMI örneğini resimlli ve açıklamalı olarak paylaşmak istedim.

İlk olarak oluşturmamız gereken nesnelerimizi belirliyelim;

1)Server (Sunucu) görevi yapan objemiz;
2)Client (İstemci) görevi yapan objemiz;
3)Her iki taraf tarafından da kullanılabilen bir Interface (Arayüz);
4)ve bu interface' i (Arayüz) implment edicek olan objemiz.

İstersek arada baglantı saglicak olan interface'imizi implement etmek için ayrı bir nesne

oluşturmayıp diğer nesnemiz içinde de implement edebilirdik fakat kodun anlasılması

acısından ve temizliği acısından bu sekilde yazılması daha faydalı olucaktır.

Gelelim program tarafına ;

1.Kısım'da Server isimli class'ımızı yazalım ;

import java.rmi.registry.Registry;//Registry' mizi oluşturmak ve

import java.rmi.registry.LocateRegistry;//yerleştirmek için paketlerimizi dahil ettik

//Ben isim olarak ServerClass dedim;

public class ServerClass {

public ServerClass() {


try {//Try catch kullanımına kendimizi alıştırmamız lazım ki ne gibi hatalar aldıgımızı //görelim

Registry myregistry=LocateRegistry.createRegistry(1099);//Öncelikle kendimize Default olan

//1099 portunu ayırdık

myregistry=LocateRegistry.getRegistry();//Ve bu portu aldık.

myregistry.rebind("MesajServisi",new ImplementSender());//Bind(Baglamak) kelimesinden

//de anlaşıldığı gibi , MesajServisi ismini verdiğimiz sunucuya,interface'mizi implement eden

ImplementSender isimli nesneyle geçiş yapacagımızı belirttik.

System.out.println("Server is Working...");//Ve Server'ın Çalıştıgı uyarısı için bir output aldık.

} catch (Exception e) {//Try'ın içerisindeki olası bir Exception(İstisna) durumunda 'e' içerisine //gömülü hatayı getiricek.

System.out.println("Registry Olusturulan Kısımda Hata: "+e);//Hata Output'unu vericek
}
}

public static void main(String [] args) {


new ServerClass();//Ve burda objemizin bir instance(Örneğini) olusturarak server'ı calıstırdık.
}
}


2.Kısım'a gelicek olursak Client nesnesini oluşturucaz ;

//Her zamanki gibi , ilk olarak kullanacagımız tanımlı objeleri ve

// methodları barındıran paketlerimizi dahil ettik.

import javax.swing.*;

import java.rmi.Naming;

import java.rmi.RemoteException;

import java.net.MalformedURLException;

import java.rmi.NotBoundException;

//Ben isim olarak ClientClass dedim;

public class ClientClass//Direk olarak main method içerisinde interfaceimizin bir instance'ını
//oluşturduk ve Naming.lookup yaparak , yazdıgımız url'nin referansını döndürmesini sagladık
{

public static void main(String [] args)
{

try
{
SenderInterface senderinterface=(SenderInterface)Naming.lookup("rmi://127.0.0.1

/MessageService");//127.0.0.1 yerine localhost'da yazabilirdik,zaten o anlama geliyor.

//Cunku suan local de calıstırıyoruzki,mesajlaşmamızı görebilelim.

for(int i=0;i<6;i++)
{
//Burda ben sonlandırmak için kısa bi döngü olusturdum;

//Bunu siz istediginiz takdirde kullanıcılar cıkıs yapana kadar uzatabilirsiniz.Suan 6 kere

//mesajlaşıcaklar

StringFirstMessage=senderinterface.getData(JOptionPane.showInputDialog("Gonderilmek

İstenen Mesaj:\nKullanıcı 1 Mesaj Alanı:\n")); //1 nolu kullanıcının mesajı String

SecondMessage=senderinterface.getData(JOptionPane.showInputDialog("Gonderilmek

İstenen Mesaj:\nKullanıcı 2 Mesaj Alanı:\n"));//2 nolu kullanıcının mesajı
}
}

// import java.rmi.RemoteException;

// import java.net.MalformedURLException;

//import java.rmi.NotBoundException;

// Bize uyarı vermeleri için dahil ettiğimiz bu paketlerin sonunda Exception yazması demek;

//oluşacak Exception'ın kullanıcıya throw edilmesi (fırlatılması ) demek.Buyüzden hepsi

//için ayrı ayrı cacth yazmak zorundayız.

catch (RemoteException RMTException)
{
System.out.println("RemoteException Hatası: "+RMTException);
}
catch (MalformedURLException Murle
)
{ System.out.println("Malformed URL Exception Hatası : "+Murle);
}
catch (NotBoundException NotBound)
{
System.out.println("NotBoundException Hatası: "+NotBound);
}
}
}

Ve şimdide gelelim 3.Kısım'a: Interfacemizi oluşturalım ;

import java.rmi.*; //Ben isim olarak SenderInterface dedim;

public interface SenderInterface extends Remote{ //Remote method olmasından dolayı

//Java'da tanımlı Remote Class'ına extends olması (Yayılması) lazım.

public String getData(String text) throws RemoteException; //Burda ise her iki tarafından

//da kullanacagı methodu yazıyoruz fakat method'un içeriğini , Implement ettiğimiz yerde ,

//yani ImplementSender class'ımızda(Sabit bir isim değildir,kendi verdiğim isimdir)

//tanımlayacagız.Bir diğer nokta ise,görüldüğü gibi bu method da RemoteException içeriyor

//ve bu da methodu kullanacagımız yerde try catch yazmalıyız anlamına geliyor , ki

//herhangi bir exception durumunda bize exception bildirebilsin. İsterseniz throw etmesini

//istemiyorum ,bana bi exception bildirmesin diyebilirsiniz tabiki , ama yazarken

//karsılasılacak hataların cabuk cozulebilmesi acısından şart;
}

Ve son kısım 4.Kısım' da ise oluşturdugumuz Interface'i implement edicek Class'ı yazıyoruz;

import java.rmi.RemoteException;//Yine Exceptionlarımız var import

java.rmi.server.UnicastRemoteObject;//Bu sebepten catch kullanmayı //unutmayalım.

public class ImplementSender extends UnicastRemoteObject implements SenderInterface
{
//UnicastRemoteObjesinin , java içerisinde tanımlı olan constructor'ını kullanacagız ve bu

//yuzden extdends UnicastRemoteObject yazdık ve yazdığımız Interface'i implement

//edebilmesi içinde sonuna Implements keyword'unu yazıp yanına implement edeceği

//interface'in adını yazdık.

static int cnt=1;//Static olarak tanımlamamın sebebi , her

//initialize edildiğinde 1'e eşitlenmesini istemememin sebebi,1 iken 1.kullanıcı yazıcak ,

// 2 iken 2. kullanıcı yazıcak.Bu ornek kod oldugu için o kısımlar istendiği gibi değiştirilebilir

public ImplementSender() throws RemoteException
{
super();//UnicastRemoteObject isimli sistemde tanımlı olan objenin constructor'ını

//çağırdık.
}
public String getData(String text) throws RemoteException
{
//Az önce Interface'in içerisinde boş bıraktığımız methodumuzu işte tam burda //tanımlıyoruz. Amacımız yollanan mesajın interface methodu ile alınıp, daha sonra diğer // objenin bu methodu cagırmasıyla içerisinde tasıdıgı string'i return ettirip diger objeye //tasımak.

if(cnt==0) { System.out.println("1. Kullanıcıdan Mesaj Geldi : ===>"+text);
cnt++;
return text;
}
System.out.println("2.Kullanıcıdan Mesaj Geldi : ===>"+text);
cnt--;
return text;
}
}
Programımızın Çalıştırılmasına gelince , doğal olarak ilk önce Server'ımızı yani ServerClass'ımızı çalıştırıyoruz ve daha sonra ise ClientClass'ımızı çalıştırıyoruz.Ve karşımıza direk yollayacagımız metni isteyen kutu cıkıyor.

Alttaki Screen Shotlardan programın Çalışırken ki görüntüsüne bakabilirsiniz.



Ve işte Bu kadaaaaaar :) Bazı yerleri biraz fazla detaylı anlatmamın sebebi , daha alt seviyedeki
arkadaşların baktığı zaman "Burayı niye yazdık?" dememesi içindir.








Kodun Direk Olarak Çalıştırılabilir halini yorumsuz olarak alt kısıma koyuyorum.
Bu programın kodlarını yazarken IDE olarak Eclipse tercih edilmiştir.


import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;


public class ServerClass {

public ServerClass() {


try {

Registry myregistry=LocateRegistry.createRegistry(1099);
myregistry=LocateRegistry.getRegistry();
myregistry.rebind("MessageService",new ImplementSender());
System.out.println("Server is Working...");

} catch (Exception e) {

System.out.println("Registry Olusturulan Kısımda Hata: "+e);
}
}

public static void main(String [] args) {


new ServerClass();
}
}


import javax.swing.*;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.net.MalformedURLException;
import java.rmi.NotBoundException;


public class ClientClass
{

public static void main(String [] args)
{

try
{
SenderInterface senderinterface=(SenderInterface)Naming.lookup("rmi://127.0.0.1/MessageService");
for(int i=0;i<6;i++)
{
String FirstMessage=senderinterface.getData(JOptionPane.showInputDialog("Gonderilmek İstenen Mesaj:\nKullanıcı 1 Mesaj Alanı:\n"));
String SecondMessage=senderinterface.getData(JOptionPane.showInputDialog("Gonderilmek İstenen Mesaj:\nKullanıcı 2 Mesaj Alanı:\n"));
}
}
catch (RemoteException RMTException)
{
System.out.println("RemoteException Hatası: "+RMTException);
}
catch (MalformedURLException Murle)
{
System.out.println("Malformed URL Exception Hatası : "+Murle);
}
catch (NotBoundException NotBound) {
// TODO: handle exception
System.out.println("NotBoundException Hatası: "+NotBound);
}


}




}



import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;


public class ImplementSender extends UnicastRemoteObject implements SenderInterface {

static int cnt=1;
public ImplementSender() throws RemoteException{
// TODO Auto-generated constructor stub
super();
}
public String getData(String text) throws RemoteException{
if(cnt==1)
{
System.out.println("1. Kullanıcıdan Mesaj Geldi : ===>"+text);
cnt++;
return text;
}
System.out.println("2.Kullanıcıdan Mesaj Geldi : ===>"+text);
cnt--;
return text;
}

}

import java.rmi.*;



public interface SenderInterface extends Remote{

public String getData(String text) throws RemoteException;

}

Umarım faydalı bir makale olmustur.Daha sonra görüşmek üzere.
Sende Yaz , Farkın Olsun!!!