CORBA piemēri

Aprakstīsim visas Java IDL aplikācijas veidošanas stadijas.
Definēt attālināto interfeisu
Attālinātā objekta interfeisu apraksta ar OMG ieviesto IDL, nevis Javu
Kompilēt attālināto interfeisu
pēc tam izmanto "idltojava" kompilatoru, kas ģenerē visus Javas izejas tekstus - gan stabam, gan skeletam, kā arī infrastruktūru, kas piekonektēsies pie ORB.
Implementēt serveri
Servera kodā pašam jādefinē sava interfeisa metodes balstoties uz "idltojava" ģenerēto skeletu. Servera pusē ir arī kods, kurš nodrošina ORB piestartēšanu un klienta izsaukuma gaidīšanu.
Implementēt klientu
Klients izmanto ģenerēto stabu. Arī klients piestartē ORB, sameklē serveri, izmantojot Java IDL vārdu servisu, iegūst attālinātā objekta referenci un izsauc tā metodi.
Piestartēt aplikācijas
Kad klients un serveris ir gatavs, jāpiestartē vārdu serviss, tad serveris, tad klients.

IDL fails Hello.idl

module HelloApp
{
  interface Hello
  {
    string sayHello();
  };
};

Modulis ir "namespace" - apkopo radniecīgus interfeisus. Pēc "idltojava" moduļi pārtop par Javas pakešu deklarācijām.

IDL interfeiss ir analoģisks Javas interfeisam. Tas satur operācijas - darbības, ko serveris apsolās veikt, ja klients tās izsauks.

Kompilējam to ar komandu:

idlj -fall Hello.idl

Rodas sekojoši faili:

  • HelloApp/Hello.java - Javas interfeiss
  • HelloApp/HelloOperations.java - lai varētu mantot visas operācijas
  • HelloApp/_HelloImplBase.java - servera puses skelets; speciāli "Hello" IDLam ģenerēta abstrakta klase, no kuras mantos HelloServant
  • HelloApp/_HelloStub.java - klienta puses stabs;
  • HelloApp/HelloHelper.java - klase, kas pārveido CORBAS objektu references vajadzīgajā formā
  • HelloApp/HelloHolder.java - klase, kas nodrošina out un in/out parametru nodošanas paradigmas, kuras Java tīrā veidā neatbalsta

Servera un klienta implementācijas

HelloServer.java

// The package containing our stubs.
import HelloApp.*;

// HelloServer will use the naming service.
import org.omg.CosNaming.*;

// The package containing special exceptions thrown by the name service.
import org.omg.CosNaming.NamingContextPackage.*;

// All CORBA applications need these classes.
import org.omg.CORBA.*;

public class HelloServer {
  public static void main(String args[]) {
    try{
    
      // Create and initialize the ORB
      ORB orb = ORB.init(args, null);
      
      // Create the servant and register it with the ORB
      HelloServant helloRef = new HelloServant();
      orb.connect(helloRef);
      
      // Get the root naming context
      org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
      NamingContext ncRef = NamingContextHelper.narrow(objRef);
      
      // Bind the object reference in naming
      NameComponent nc = new NameComponent("Hello", " ");
      NameComponent path[] = {nc};
      ncRef.rebind(path, helloRef);
      
      // Wait for invocations from clients
      java.lang.Object sync = new java.lang.Object();
      synchronized(sync){
        sync.wait();
      }
      
    } catch(Exception e) {
        System.err.println("ERROR: " + e);
        e.printStackTrace(System.out);
      }  
  }
}

class HelloServant extends _HelloImplBase
{
  public String sayHello()
  {
    return "\nHello world!!\n";
  
  }
}

HelloClient.java

import HelloApp.*;           // The package containing our stubs.
import org.omg.CosNaming.*;  // HelloClient will use the naming service.
import org.omg.CORBA.*;      // All CORBA applications need these classes.


public class HelloClient
{
  public static void main(String args[])
  {
    try{
      
      // Create and initialize the ORB
      ORB orb = ORB.init(args, null);
      
      // Get the root naming context
      org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
      NamingContext ncRef = NamingContextHelper.narrow(objRef);
      
      // Resolve the object reference in naming
      NameComponent nc = new NameComponent("Hello", " ");
      NameComponent path[] = {nc};
      Hello helloRef = HelloHelper.narrow(ncRef.resolve(path));
      
      // Call the Hello server object and print results
      String Hello = helloRef.sayHello();
      System.out.println(Hello);      
          
    } catch(Exception e) {
        System.out.println("ERROR : " + e);
        e.printStackTrace(System.out);
      }  
  }
}

Kā palaist aplikāciju

Pirmajā DOS lodziņā palaižam vārdu servisu (naming service):

c:\corba\hello>tnameserv -ORBInitialPort 1050
Initial Naming Context:
IOR:000000000000002849444c3a6f6d672e6f72672f436f734e616d696e672f4e616d696e67436f
6e746578743a312e3000000000010000000000000054000101000000000c3139342e382e33392e34
30000802000000000018afabcafe00000002d3b156d5000000080000000000000000000000010000
0001000000140000000000010020000000000001010000000000
TransientNameServer: setting port for initial object references to: 1050
Ready.

(noklusētais ports ir 900). IOR (Interoperable Object Reference) - vārdu serviss.

Otrajā DOS lodziņā palaižam serveri:

c:\corba\hello>java HelloServer -ORBInitialHost localhost -ORBInitialPort 1050

Trešajā DOS lodziņā palaižam klientu:

c:\corba\hello>java HelloClient -ORBInitialHost localhost -ORBInitialPort 1050

Hello world!!

Stringota objektreference

Lai klients sauktu CORBA servera metodes, tam jāiegūst no tā reference. To var izdarīt caur vārdu servisu, bet var apmainīties ar referenci arī citādi - to ar kādu citu protokolu nododot no servera objektam kā stringu.

HelloServer.java

// The package containing our stubs.
import HelloApp.*;

// HelloServer will use the naming service.
//import org.omg.CosNaming.*;

// The package containing special exceptions thrown by the name service.
//import org.omg.CosNaming.NamingContextPackage.*;

// All CORBA applications need these classes.
import org.omg.CORBA.*;

import java.io.*;

public class HelloServer 
{
  public static void main(String args[])
  {
    try{
    
      // Create and initialize the ORB
      ORB orb = ORB.init(args, null);
      
      // Create the servant and register it with the ORB
      HelloServant helloRef = new HelloServant();
      orb.connect(helloRef);
      
      // Get the root naming context
//      org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
//      NamingContext ncRef = NamingContextHelper.narrow(objRef);
      
      // Bind the object reference in naming
//      NameComponent nc = new NameComponent("Hello", " ");
//      NameComponent path[] = {nc};
//      ncRef.rebind(path, helloRef);

      String ior = orb.object_to_string(helloRef);

	  String filename = 
//			System.getProperty("user.home")+
//            System.getProperty("file.separator")+
			"HelloIOR";

      FileOutputStream fos = new FileOutputStream(filename);
      PrintStream ps = new PrintStream(fos);
      ps.print(ior);
      ps.close();
      
      // Wait for invocations from clients
      java.lang.Object sync = new java.lang.Object();
      synchronized(sync){
        sync.wait();
      }
      
    } catch(Exception e) {
        System.err.println("ERROR: " + e);
        e.printStackTrace(System.out);
      }  
  }
}

class HelloServant extends _HelloImplBase
{
  public String sayHello()
  {
    return "\nHello world!!\n";
  
  }
}

HelloClient.java

import HelloApp.*;           // The package containing our stubs.
//import org.omg.CosNaming.*;  // HelloClient will use the naming service.
import org.omg.CORBA.*;      // All CORBA applications need these classes.

import java.io.*;

public class HelloClient
{
  public static void main(String args[])
  {
    try{
      
      // Create and initialize the ORB
      ORB orb = ORB.init(args, null);
      
      // Get the root naming context
//      org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
//      NamingContext ncRef = NamingContextHelper.narrow(objRef);
      
      // Resolve the object reference in naming
//      NameComponent nc = new NameComponent("Hello", " ");
//      NameComponent path[] = {nc};
//      Hello helloRef = HelloHelper.narrow(ncRef.resolve(path));

      String filename = 
//		System.getProperty("user.home")+
//		System.getProperty("file.separator")+
		"HelloIOR";
      FileInputStream fis = new FileInputStream(filename);
      java.io.DataInputStream dis = new java.io.DataInputStream(fis);
      String ior = dis.readLine();

      org.omg.CORBA.Object obj = orb.string_to_object(ior);
      Hello helloRef = HelloHelper.narrow(obj);
      
      // Call the Hello server object and print results
      String Hello = helloRef.sayHello();
      System.out.println(Hello);      
          
    } catch(Exception e) {
        System.out.println("ERROR : " + e);
        e.printStackTrace(System.out);
      }  
  }
}

Kā palaist aplikāciju

Pirmajā DOS lodziņā palaižam serveri:

c:\corba\hellostring>java HelloServer -ORBInitialPort 1050

Otrajā DOS lodziņā palaižam klientu:

c:\corba\hellostring>java HelloClient -ORBInitialPort 1050

Hello world!!

Izpildes laikā izveidojas fails HelloIOR; tas izmainās, ja serveri pārstartē.

Persistenti serverobjekti

Ja CORBA serveris beidz darbu, tad tā reference ir jāiegūst no jauna. Tomēr serveris var savu stāvokli noglabāt datubāzē vai failā un no jauna piestartējoties to atkal atjaunot.

Servera un klienta implementācijas

Hello.idl

module HelloApp
{
    interface Hello
    {
        exception cantWriteFile{};
        exception cantReadFile{};

        string sayHello(in string message)
                raises (cantWriteFile);

        string lastMessage()
                raises (cantReadFile);
    };
};

HelloServer.java

import java.io.*;
import HelloApp.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;
 
class HelloServant extends _HelloImplBase
{
    public String sayHello(String msg)
        throws HelloApp.HelloPackage.cantWriteFile
    {
        try {
                synchronized(this) {
                   File helloFile = new File("helloStorage.txt");
                   FileOutputStream fos = new FileOutputStream(helloFile);
                   byte[] buf = new byte[msg.length()];
                   msg.getBytes(0, msg.length(), buf, 0);
                   fos.write(buf);
                   fos.close();
                }
        } catch(Exception e) {
                throw new HelloApp.HelloPackage.cantWriteFile();
        }
        return "\nHello world !!\n";
    }
       
    public String lastMessage()
        throws HelloApp.HelloPackage.cantReadFile
    {
        try {
                synchronized(this) {
                   File helloFile = new File("helloStorage.txt");
                   FileInputStream fis = new FileInputStream(helloFile);
                   byte[] buf = new byte[1000];
                   int n = fis.read(buf);
                   String lastmsg = new String(buf);
                   fis.close();
                   return lastmsg;
                }
        } catch(Exception e) {
                throw new HelloApp.HelloPackage.cantReadFile();
        }
    }
}

public class HelloServer {
 
    public static void main(String args[])
    {
	try{
	    // create and initialize the ORB
	    ORB orb = ORB.init(args, null);
 
	    // create servant and register it with the ORB
	    HelloServant helloRef = new HelloServant();
	    orb.connect(helloRef);
 
	    // get the root naming context
	    org.omg.CORBA.Object objRef = 
		orb.resolve_initial_references("NameService");
	    NamingContext ncRef = NamingContextHelper.narrow(objRef);
 
	    // bind the Object Reference in Naming
	    NameComponent nc = new NameComponent("Hello", "");
	    NameComponent path[] = {nc};
	    ncRef.rebind(path, helloRef);
 
	    // wait for invocations from clients
            java.lang.Object sync = new java.lang.Object();
            synchronized (sync) {
                sync.wait();
            }
 
	} catch (Exception e) {
	    System.err.println("ERROR: " + e);
	    e.printStackTrace(System.out);
	}
    }
}

HelloClient.java

import HelloApp.*;
import org.omg.CosNaming.*;
import org.omg.CORBA.*;
 
public class HelloClient 
{
    public static void main(String args[])
    {
	try{
	    // create and initialize the ORB
	    ORB orb = ORB.init(args, null);
 
            // get the root naming context
            org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
            NamingContext ncRef = NamingContextHelper.narrow(objRef);

            // resolve the Object Reference in Naming
            NameComponent nc = new NameComponent("Hello", "");
            NameComponent path[] = {nc};
            Hello helloRef = HelloHelper.narrow(ncRef.resolve(path));
 
	    // call the Hello server object and print results
	
	    String oldhello = helloRef.lastMessage();
            System.out.println(oldhello);
            String hello = helloRef.sayHello(args[0]);
            System.out.println(hello);
 
	} catch (Exception e) {
	    System.out.println("ERROR : " + e) ;
	    e.printStackTrace(System.out);
	}
    }
}

"idlj" rīks tāpat kā agrāk ģenerē 6 failus, bet papildus tiem arī pa 3 failiem katram izņēmumam:

IDL jēdziens

Javas jēdziens

module

package

interface (non-abstract)

signature interface and an operations interface, helper class, holder class

interface (abstract)

signature interface, helper class, holder class

constant (not within an interface)

public interface

boolean

boolean

char, wchar

char

octet

byte

string, wstring

java.lang.String

short, unsigned short

short

long, unsigned long

int

long long, unsigned long long

long

float

float

double

double

fixed

java.math.BigDecimal

enum, struct, union

class

sequence, array

array

exception

class

readonly attribute

accessor method

readwrite attribute

accessor and modifer methods

operation

method

Ko mēs vēl neesam parādījuši:

  • IDL parametru "out", "in/out" nodošanas mehānismu
  • Citus parametrus nekā String
  • Callback funkcijas starp Javas klientu un CORBA serveri

Bibliogrāfija

Šie un citi piemēri atrodami arī http://java.sun.com/j2se/1.3/docs/guide/idl/index.html

CORBAs alternatīvas

CORBA un soketi

java.net pakete implementē URL objektu manipulācijas un Berkeley sockets.

  1. Izveido soketa galapunktu ar socket konstruktoru
  2. Izveido servisa portu
  3. Klausās pēc pieprasījumiem
  4. Klients pievienojas serverim
  5. Serveris akceptē konekciju
  6. Zema līmeņa tīklošanās
  7. Serveris aizver pavedienu, klients aizver savu konekciju

Trūkumi: par parametru nodošanu (parameter marshalling) jārūpējas pašam, nav interfeisu aprakstu ar IDL.

CORBA un HTTP/CGI

HTTP ir vājš bezkonekciju protokols (interfeiss aprobežojas ar URL pieprasīšanu un formu datu nosūtīšanu), toties HTTP strādā visur - arī tur kur CORBA nav atļauts.

Trūkumi: HTTP/CGI ir lēns, nesaglabā sesijas stāvokli, nenodrošina parametru nodošanu, interfeisu aprakstu, parametru datu tipu korektību, transakcijas.

CORBA un Servleti

Servleti var savstarpēji un ar Java apletiem sazināties arī ar CORBA (tā līdz ar soketiem, HTTP un RMI ir viena no komunikāciju metodēm).

Salīdzinot ar HTTP/CGI, servleti var būt vairākas reizes ātrāki par CGI, bet arī vairākas reizes lēnāki par soketiem vai CORBA. Tie arī ļauj saglabāt stāvokli.

CORBA un RMI

RMI-IIOP faktiski ir tas pats, kas sazināšanās ar CORBA (IDL vietā stājas Javā definēti interfeisi). Java-Sun definējuši savu iekšējo protokolu priekš RMI - Java Remote Messaging Protocol (JRMP). Tas nenodrošina Javas iespēju sazināties ar citvalodu klientiem, parametru nodošanu ar out vai in/out metodēm. Toties ar RMI var ne vien izmantot stabu kā servera klases referenci, bet arī apmainīties ar Javas objektiem.


Lapa mainīta 2004-12-02 22:00:22