1. Elosztott alkalmazásarchitektúrák
Manapság nem lehet olyan alkalmazást írni, ami ne
igényelne valamilyen hálózati
kommunikációt. A kommunikációt
sokféle szinten lehet végezni. A magas szintű
kommunikációs keretrendszerekben általában
a következő elemek találhatók:
- Prezentációs protokol, amelyik képes
bonyolult adatstruktúrákat is átvinni
- Leírónyelv, amely a hálózati
szolgáltatásokat írja le kliensek
részére
- Katalógus, amiben meg lehet keresni a
szolgáltatásokat, illetve a szolgáltatások
eléréséhez szükséges
információkat (pl. szerver név)
A Jáva a következő magas szintű kommunikációs
keretrendszereket támogatja.
- Elosztott objektumorientált architektúrák:
RMI, RMI-IIOP, Java-IDL, web services
- Elosztott többrétegű alkalmazásmodel:
Enterprise JavaBeans (EJB)
Ebben a fejezetben az első ponttal foglalkozunk. Mint később
látni fogjuk, az EJB még egy ennél is magasabb
absztrakció, ami még azt is eltakarja, hogy az
alkalmazás esetleg több gépen
szétszórva lehet. Az EJB szinte biztosan
felhasznál elosztott objektumorientált megoldást.
Az alábbi képen az elosztott objektumorientált
modellek általános elemei láthatók.
- Az első lépés a szerveroldali objektum ill. az
szerverének megkeresése az objektumkatalógusban.
Az elosztott objektumorientált modellek azt
ígérik, hogy nem kell foglalkozzunk olyan
transzport-specifikus jellemzőkkel, mint cím, port, stb., az
alkalmazáskód ugyanaz marad, ha az egyes elemeket
más számítógépre mozgatjuk. Kell
tehát egy katalógus, ami megmondja, melyik objektum
milyen gépen található. A katalógus
tárolhat még fejlettebb keresést elősegítő
tulajdonságokat, pl. objektum neve, verzió, üzleti
kategória, stb. Mindenképpen tárolja azonban az
objektum fizikai eléréséhez szükséges
adatokat, pl. szerver címe, portja. Ha a kliens tudja valamilyen
módon a távoli objektum
elérhetőségét, ez a lépés elmaradhat.
- A kliens a kliensoldali csonk (stub)
meghívásával éri el a szerveroldali
objektumot. A kliensoldali csonk szerkezete megegyezik a hívni
kívánt objektummal, de metódusainak
hívásai a keretrendszerbe vezetnek. A csonkot a
keretrendszer állítja elő, amikor a kliens sikeresen
keresett ki egy távoli objektumot a katalógusból.
- A csonk hívása a keretrendszerbe vezet. A
keretrendszer egy kérést küld a szerveroldali
keretrendszernek, ennek hálózati paramétereit a
katalógusból vette. Eközben gondoskodik a
paraméterek bájtsorozattá
alakításáról (szerializáció),
ami bonyolult objektumstruktúrák esetén nem is
olyan egyszerű. A kérés tartalmazza a szerveroldali
objektum azonosítóját, a meghívni
kívánt metódust paramétereit.
- A fogadó keretrendszer megkapja a kérést
és elemzi a paramétereket. Megkeresi a
hívandó objektumhoz tartozó szerveroldali csonkot
(skeletont), létrehozza a hívási
paramétereket (eközben esetleg a kliensoldali bonyolult
objektumstrukúrák pontos másolatát kell
létrehozza) és meghívja a szerveroldali csonk
kért metódusát. A csonk
implementációja megkeresi, esetleg
létrehozza a meghívandó objektumegyedet
és meghívja a metódust.
- Ezek után a metódus visszatérési
értékével ugyanez történik
visszafelé, kivéve, hogy a szerveroldali objektum
metódusának futásánál
fellépett esetleges kivételt is vissza kell adni a
kliensoldalnak.
- A kliensoldali csonk visszatér a
visszatérési értékkel. A kliens úgy
érezheti, hogy egyszerűen egy helyi metódust
hívott meg. Látható azonban, hogy a
procedúra meglehetősen bonyolult és nem meglepő, hogy egy
távoli metódus meghívása kb. egy
nagyságrenddel lassabb a helyi hívásnál
és ennek oka nem elsősorban a hálózati
kommunikáció időigénye.
A következőkben a Jáva által kínált
négy elosztott objektumorientált alkalmazásmodellt
tekintünk át.
2. Remote Method Invocation (RMI)
Az RMI a Jáva első elosztott objektumorientált modellje.
A JDK 1.1 óta része minden sztenderd Jáva
környezetnek, kicsi és programozni egyszerű.
Általános elterjedtsége és egyszerű
használata miatt ez a legnépszerűbb modell jelenleg.
Az RMI egy saját protokollt használ, amelyik a CORBA
GIOP-ra hasonlít. A protokollüzenetben a
meghívandó objektum szerveroldali csonkjának
referenciája, a meghívandó metódus neve
és a szerializált paraméterek vannak.A
szerializáció az java.io.ObjectInputStream és
java.io.ObjectOutputStream formátumát használja. A
szerializált paraméterek magukkal viszik a
típusukat (osztályukat) is és az osztály
annotálva lehet azzal az URL-lel, ahonnan az osztály
letölthető. Ez lehetővé teszi a paraméterekhez
tartozó osztályok dinamikus
letöltését: ha egy paraméter típusa
pl. example.MyClass, az RMI üzenet fogadójának
szüksége van erre a .class fájlra. Ha ez a
lokális CLASSPATH-ről nem elérhető, megnézi az
URL-t az osztály annotációjában
található URL-t és letölti onnan. Ez a
dinamikus RMI osztályletöltés. Az osztály
birtokában aztán a paraméterobjektum
helyreállítható a távoli gépen
(szerver a kérésnél, kliens a
válasznál). A dinamikus
osztályletöltés biztonsági
problémákat vethet fel, mert pl. egy rosszindulatú
kliens olyan paramétertípust adhat át, amelynek
letöltendő osztályába gonosz dolgokat művelő
konstruktort tehet. Amikor a szerver létrehozza a
paraméterobjektumot, a konstruktor letöltődik és
lefut a szerveroldalon. Nyilván ilyen biankó csekket nem
akarunk adni. A dinamikus osztályletöltés csak akkor
engedélyezett, ha az RMISecurityManager aktív. A
programozó leszármaztathat az RMISecurityManager-től,
hogy saját biztonsági szabályait
megvalósíthassa.
Az RMI szolgáltatásleírásra magát a
Jávát használja. Az RMI interfészeket
Jáva interfészosztályok írják le.
Habár az RMI elvileg alkalmas nem Jáva
kliensekkel/szerverekkel való együttműködésre,
valójában egy nem Jáva kliens/szerver
implementálása nagyon nehéz lenne. Én nem
tudok esetről, amikor az RMI-t nem Jávás
kommunikációs partnerrel együtt
használták volna.
Az RMI egy nagyon egyszerű katalógust használ, ezt
registry-nek hívják. Az RMI registry-ben URL-hez lehet
regisztrálni távoli objektum referenciákat. A
registry használója pl. megszerezheti a
"/merohely/15" névhez tartozó távoli
objektum referenciát.
Nézzünk most egy egyszerű példát.
Először a távoli objektum Jáva
interfészét kell megvalósítsuk.
Adder.java:
import
java.rmi.Remote;
import
java.rmi.RemoteException;
public
interface Adder extends Remote {
int
add( int i1, int i2 ) throws RemoteException;
}
A távoli objektumnak egy metódusa van. Ennek
RemoteException-t kell dobnia, mert a távoli metódus
hívása esetleg hibás is lehet (pl. nem sikeres a
kommunikáció a szerverrel). A távoli
interfészt implementálni kell.
AdderImpl.java:
import
java.rmi.Naming;
import
java.rmi.RemoteException;
import
java.rmi.RMISecurityManager;
import
java.rmi.server.UnicastRemoteObject;
public class
AdderImpl extends UnicastRemoteObject implements Adder {
public
AdderImpl() throws RemoteException {
super(); // Inicializáld az UnicastRemoteObject-et
}
public int
add( int i1, int i2 ) {
return
i1+i2;
}
public static
void main( String args[] ) {
// RMISecurityManager-t beállítja, különben a
dinamikus osztálybetöltés
// nem működik.
if( System.getSecurityManager() == null ) {
System.setSecurityManager( new RMISecurityManager() );
}
try {
// Ez maga a szerveroldali objektumegyed
AdderImpl obj = new AdderImpl();
// A
registry-ben a /Adder névhez rendeljük
Naming.rebind( "/Adder", obj );
System.out.println( "AdderServer bound in registry" );
}
catch (Exception e) {
System.out.println( "AdderImpl err: " + e.getMessage() );
e.printStackTrace();
}
// A program tovább fut, mert az UnicastRemoteObject
szálakat indított
}
}
Ez az objektum definiálja magát a távolról
elérhető metódust. Érdekes, hogy ez a
metódus nem dob RemoteException-t, hiszen ez nem végez
hálózati kommunikációt. RemoteException-t a
csonkok dobhatnak.
Ezek után nézzük a klienst, ami használja a
távoli objektumot.
import
java.rmi.Naming;
import
java.rmi.RemoteException;
public class
AdderClient {
public static
void main( String args[] ) {
//
Távoli objektum referencia, igazabol a csonkra mutat
Adder
obj = null;
try {
// A
távoli objektum referenciáját a registry-ből
vesszük
obj = (Adder)Naming.lookup( "/Adder" );
int result = obj.add( 23,34 );
System.out.println( "Result: "+result );
}
catch (Exception e) {
System.out.println( "AdderClient exception: " + e.getMessage() );
e.printStackTrace();
}
}
}
A Jáva források lefordítása után a
csonkokat is generálnunk kell az rmic programmal, amit az
objektum implementációján futtatunk (rmic
AdderImpl). Ezek után a szerver elindítható.
java -Djava.rmi.server.codebase=file:///mydir/rmi/
-Djava.security.policy=file:///mydir/rmi/rmi.policy AdderImpl
Minthogy a dinamikus osztálybetöltést
engedélyeztük (RMISecurityManager), meg kell adnunk a
letöltési kódbázist és a policy-t is.
Nincs időnk most kitérni a Jáva policy
megoldására, a legegyszerűbb policy a következő
(mindenkinek mindent megenged).
grant {
permission java.security.AllPermission;
};
Az RMI nagyon egyszerű, de eléggé korlátozott. Az
RMI szerver teljesítménye viszonylag kicsi és nem
skálázódik (RMI szerverekből nem lehet
szervercsoportot (cluster) szervezni). RMI praktikusan csak Jáva
kliens/szerver között használható.
3. Java-IDL
Az legnépszerűbb elosztott objektumorientált
alkalmazásmodel a CORBA. A CORBA különböző
programozási nyelveken írt objektumokat képes
összekötni. Ehhez két eszköze van:
- Az interfészleírásokat nyelvfüggetlen
módon írja le. Az CORBA IDL (Interface Definition
Language) nyelvet csak interfészleírásokra
használják.
- A CORBA keretrendszerek (ORB, Object Request Broker)
közötti kommunikáció
szabványosítva van, ez a General Inter-ORB Protocol
(GIOP). A TCP felett használt GIOP profilt Internet Inter-ORB
Protocolnak (IIOP) hívják.
Az ORB és az objektumimplementáció
közötti interfészt szabványosítani kell,
különben egyik ORB-ra írt programok nem fognak futni
egy másik ORB-on. Ezt az interfészt minden nyelvre
megcsinálják. A Jáva leképezést
Java-IDL-nek hívják. A Java-IDL tehát CORBA
Jávából való használatának
szabványos módja.
Az első lépés a távoli interfész
megírása IDL nyelven. Példa:
AdderInterface.idl:
// IDL interface
for the adder object
interface
AdderInterface {
long add( in long n1, in long n2 );
};
Megjegyzendő, hogy az IDL long típusa a 32 bites előjeles
egész számot jelenti, ami a Jávában int-nek
felel meg. Az IDL-t az ORB-hoz tartozó eszköz dolgozza fel,
amely az ORB-hez illeszkedő csonkokat és egyéb
segítő osztályokat gyárt belőle. Ezeknek nem kell
szabványosaknak lennie, hiszen egy másik ORB-hez
újragenerálhatók az IDL-ből.
Nézzük most a szerver kódot!
import
org.omg.CosNaming.*;
import
org.omg.CosNaming.NamingContextPackage.*;
import
org.omg.CORBA.*;
import
org.omg.PortableServer.*;
import
org.omg.PortableServer.POA;
// Servant az
objektum, ami a távoli interfészt implementálja.
// CORBA
szerver annyi servant-et gyárt, amennyire szüksége
van
// Az
AdderInterfacePOA interface-t az IDL fordító
generálta
class
AdderServant extends AdderInterfacePOA {
// Methods
from the IDL
public
int add(int i1, int i2) {
return i1 + i2;
}
}
// Ez az
alkalmazás, ami létrehozza és regisztálja
az objektumot az ORB-nál
public class
AdderServer {
public static void main(String args[]) {
try {
ORB orb = ORB.init( args, null);
POA rootpoa = POAHelper.narrow( orb.resolve_initial_references(
"RootPOA" ) );
rootpoa.the_POAManager().activate();
//
Létrehozza a servant-et és regisztrálja az
ORB-nál
AdderServant adderimpl = new AdderServant();
org.omg.CORBA.Object ref =
rootpoa.servant_to_reference( adderimpl );
AdderInterface href = AdderInterfaceHelper.narrow(ref);
//
Regisztrálja az objektumot a katalógusban. Először
lekéri a katalógus gyökeréhez
// tartozó objektumot, aztán regisztrálja az
objektumot.
org.omg.CORBA.Object objRef =
orb.resolve_initial_references("NameService");
NamingContextExt ncRef = NamingContextExtHelper.narrow( objRef );
// Az "Adder"
névhez köti a távoli objektumot
String name = "Adder";
NameComponent path[] = ncRef.to_name( name );
ncRef.rebind(path, href);
System.out.println("AdderServer ready and waiting ...");
//
Végtelen ciklus, kérésekre vár
orb.run();
} catch ( Exception e ) {
System.err.println("ERROR: " + e);
e.printStackTrace(System.out);
}
System.out.println("AdderServer Exiting ...");
}
}
Az RMI-vel összehasonlítva feltűnhet, hogy a CORBA
felkészült arra, hogy a távoli objektumot több
példányban, esetleg több gépen kell
létrehozni. Ez is azt mutatja, hogy a CORBA-t sokkal magasabb
követelmények kielégítésére
tervezték, mint az RMI-t. Természetesen a valódi
minőségi jellemzők az ORB-tól függenek, a JDK-ba egy
nagyon egyszerű ORB van beépítve.
A CORBA-nak nincs az RMI dinamikus
osztályletöltéshez hasonlító
metódusa. Erre az egységesített CORBA
típusrendszer miatt nincs szükség, mert a CORBA
absztrakt típusokból a paraméterek és
visszatérési értékek típusa
generálható, a típusok ekvivalensek lesznek a
hívó és hívott oldalán, még
ha esetleg nem is pontosan ugyanazok. Az ORB-vel kapcsolatot
tartó osztályokat sem lehet letölteni, mert ezek
ORB-ként különbözhetnek.
A CORBA sztenderd katalógusszolgáltatását
CosNaming-nek hívják, ami maga is egy CORBA objektum. Az
RMI registry-hez képest a legnagyobb különbség,
hogy a CosNaming hierarchikus névstruktúrával
rendelkezik, hasonlatosan pl. egy fájlrendszer
könyvtáraihoz és a fájlaihoz.
Lássuk most a klienst!
import
org.omg.CosNaming.*;
import
org.omg.CosNaming.NamingContextPackage.*;
import
org.omg.CORBA.*;
public class
AdderClient {
public
static void main(String args[]) {
try{
// Az ORB
létrehozása és inicializálása
ORB orb = ORB.init(args, null);
// CosNaming
objektum megszerzése
org.omg.CORBA.Object objRef = orb.resolve_initial_references(
"NameService" );
NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);
// Megszerzi
az távoli objektum kliensoldali csonkját a
katalógusból
String name = "Adder";
AdderInterface adderimpl =
AdderInterfaceHelper.narrow(ncRef.resolve_str(name));
System.out.println("Obtained a handle on server object: " + adderimpl);
System.out.println( "add: "+adderimpl.add( 1,2 ) );
} catch (Exception e) {
System.out.println("ERROR : " + e) ;
e.printStackTrace(System.out);
}
}
}
A Java-IDL nyilvánvalóan a bonyolultabb rendszer.
A legnagyobb előnye egyben a legnagyobb hátránya is: a
fejlesztőknek új nyelvet (IDL) kell megtanulniuk és
bonyolult adattípusok IDL-re való
leképezése nem egyszerű feladat. Cserébe a
Java-IDL jóval nagyobb
skálázhatóságot és
stabilitást ad és lehetővé teszi, hogy a
kommunikáló feleket különböző nyelveken
implementáljuk. A sokféle ORB implementáció
közül mindenféle igényt
kielégítőt lehet találni és maga a JDK is
tartalmaz egy kis ORB-t.
4. RMI-IIOP
A Java-IDL-ben IDL-lel kell dolgozni és ez jelentősen
csökkenti a vonzerejét. A CORBA stabilitását
és skálázhatóságát és
az RMI egyszerűségét az RMI-IIOP-ben
ötvözték. Az RMI-IIOP az RMI programozási
modellt ülteti a CORBA tetejére és igyekszik a
CORBA-ból minnél több részletet elrejteni.
A távoli interfészt az RMI-hez hasonlóan
definiáljuk, az IDL-lel nem szükséges foglalkozni.
AdderInterface.java
import
java.rmi.Remote;
public interface AdderInterface extends java.rmi.Remote {
public int add( int i1, int i2 ) throws java.rmi.RemoteException;
}
A távoli objektum implementációja
valójában a CORBA servant.
AdderImpl.java:
import
javax.rmi.PortableRemoteObject;
public class
AdderImpl extends PortableRemoteObject implements AdderInterface {
public AdderImpl() throws java.rmi.RemoteException {
super(); // Inicializálja a
PortableRemoteObject-et
}
public int add( int in1, int in2 ) throws java.rmi.RemoteException {
return in1+in2;
}
}
Továbbra is szükségünk van egy
szerveralkalmazásra, amely a távoli objektumot
létrehozza és bejegyzi a katalógusban. Az RMI-IIOP
elfedi a CosNaming katalógust a jól ismert JNDI API-jal.
AdderServer.java:
import
javax.naming.InitialContext;
import
javax.naming.Context;
public class
AdderServer {
public static void main(String[] args) {
try {
//
Létrehozza a servant-et
HelloImpl helloRef = new HelloImpl();
// A
JNDI-t használja az objektum
regisztrálására
Context initialNamingContext = new InitialContext();
initialNamingContext.rebind("AdderService", helloRef );
System.out.println("Adder server: Ready...");
} catch (Exception e) {
System.out.println("Trouble: " + e);
e.printStackTrace();
}
}
}
A kliens is a JNDI-t használja, amikor megszerzi a távoli
objektum referenciáját.
AdderClient.java:
import
java.rmi.RemoteException;
import
java.net.MalformedURLException;
import
java.rmi.NotBoundException;
import
javax.rmi.*;
import
java.util.Vector;
import
javax.naming.NamingException;
import
javax.naming.InitialContext;
import
javax.naming.Context;
public class
AdderClient {
public static void main( String args[] ) {
Context ic;
Object objref;
AdderInterface ai;
try {
ic = new InitialContext();
// JNDI-t
használja a távoli objektum csonkjának
megszerzésére
objref = ic.lookup("AdderService");
System.out.println("Client: Obtained a ref. to Adder server.");
// Megfelelő
típusúra alakítja a referenciát és
meghívja a metódust
ai = (AdderInterface) PortableRemoteObject.narrow(
objref, AdderInterface.class);
int result = ai.add( 3,7 );
System.out.println( "Result: "+result );
} catch( Exception e ) {
System.err.println( "Exception " + e + "Caught" );
e.printStackTrace( );
return;
}
}
}
Az RMI-IIOP előnye, hogy a CORBA infrastruktúrát
úgy használja fel, hogy közben annak
bonyolultságát nagyban elrejti. Ugyan az RMI-IIOP CORBA
típusleképezést végez, nem lehet
garantálni, hogy egy létező CORBA interfésszel
megegyező IDL-t generáljon. Az rmic eszköz viszont
megkérhető, hogy IDL-t generáljon egy új
interfészből, tehát nem Jáva rendszerrel
való kapcsolat is megoldható.
5. JAX-RPC
Az Internet szükségessé tette az Internet
infrastruktúrán hatékonyan futtatható,
interoperábilis elosztott alkalmazásmodel
kifejlesztését. Különböző, csak
részben műszaki okok miatt egy teljesen új keretrendszert
fejlesztettek erre, ez a web services architektúra (a
webszolgáltatás nem túl jó név, jobb
híján az angol nevet fogom használni). A web
services modell három kulcstechnológiából
áll.
- Simple Object Access Protocol (SOAP). Ez egy XML alapú
protokol, ami alkalmas bonyolult típusok
leírására. A SOAP sokféle modellben
használható. A dokumentum model pl. nem kliens-szerver
kommunikációra való, ezt a SOAP dokumentumot
ágensek adogatják tovább, mindegyik feldolgozza
és megváltoztathatja. Ehhez gyakran e-mail protokollokat
használnak. A mi szempontukból fontosabb az RPC modell,
ami megfelel a kliens-szerver kérés-válasz
modellnek.
- Web Services Description Language (WSDL). Ez egy XML alapú
leírónyelv. A WSDL dokumentum birtokában a kliens
képes egy, a szervernek megfelelő kérést
küldeni és fel tudja dolgozni a szerver
válaszát.
- Universal Description, Discovery & Integration (UDDI). Ez a
katalógus. Az UDDI katalógus elsősorban üzleti
azonosítókat tartalmaz (szolgáltatás
kategória, postacím, stb.), ezek alapján
kikereshető a szolgáltatás WSDL dokumentumának
címe.
Ezen írás kereteit meghaladja a web services protokollok
ismertetése. Itt csak egy egyszerű SOAP RPC példát
mutatok be. Ez jó barátunk, az add
szolgáltatás hívását mutatja be. A
párbeszéd HTTP tetején zajlik.
Íme a kérés:
<?xml
version="1.0" encoding="UTF-8"?>
<soapenv:
Envelope xmlns:soapenv=http://schemas.xmlsoap.org/soap/envelope/
xmlns:xsd=http://www.w3.org/2001/XMLSchema
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<ns1:add
soapenv:encodingStyle=http://schemas.xmlsoap.org/soap/encoding/
xmlns:ns1="urn:Calculator">
<ns1:arg0 xsi:type="xsd:int">3</ns1:arg0>
<ns1:arg1 xsi:type="xsd:int">4</ns1:arg1>
</ns1:add>
</soapenv:Body>
</soapenv:Envelope>
És a válasz:
<?xml
version="1.0" encoding="UTF-8"?>
<soapenv:Envelope
xmlns:soapenv=http://schemas.xmlsoap.org/soap/envelope/
xmlns:xsd=http://www.w3.org/2001/XMLSchema
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<ns1:addResponse
soapenv:encodingStyle=http://schemas.xmlsoap.org/soap/encoding/
xmlns:ns1="urn:Calculator">
<ns1:addReturn xsi:type="xsd:int">7</ns1:addReturn>
</ns1:addResponse>
</soapenv:Body>
</soapenv:Envelope>
A Jáva több web services-szel kapcsolatos API-t
nyújt. SOAP with Attachments (SAAJ) dokumentum
stílusú SOAP üzenetek feldolgozására
való, a Java API for XML Registries (JAXR) pedig a
katalógus elérésére való. A lecke
témájához igazodva itt csak a
kérés-válasz API-t mutatom be, ez a JAX-RPC.
A JAX-RPC modellben ugyanazt kell tenni, mint az eddigi modellekben:
távoli interfészt deklarálni,
megvalósítani annak
implementációját, majd meghívni azt a
kliensből. Az egyetlen (habár drámai) kivétel,
hogy a JAX-RPC jelenlegi implementációi nem
képesek a katalógust használni. Ez azért
van, mert a WSDL fájlokat a JAX-RPC implementációk
kapásból nem képesek felhasználni, csak
előfordítás után, Jáva interfészeket
pedig nem lehet az UDDI katalógusban tárolni. Ez sajnos
azzal jár, hogy a JAX-RPC kliensekben általában
benne van a szerver címe (vagy legalábbis nem a
katalógusból veszik).
A távoli interfész és az
implementáció nem tartogat meglepetéseket. A
távoli interfész:
import
java.rmi.Remote;
import
java.rmi.RemoteException;
public
interface AdderIF extends Remote {
public int add( int in1, int in2 ) throws
RemoteException;
}
És az implementáció:
public class
AdderImpl implements AdderIF {
public int add( int in1, in2 ) {
return in1+in2;
}
}
Ezek után az implementációtól függő
eszközökkel "összehozzák" ezt a két
osztályt egy szervlet-képes webszerverrel. Ez
változatos módokon történhet, az Apache Axis
esetén egyszerűen odaadják a Jáva forrást a
JAX-RPC keretrendszernek és az legyártja a
szükséges interfészosztályokat. A Sun JAX-RPC
megoldása WAR fájlt gyárt, amelyet bármely
szervlet konténerre telepíteni lehet. Ugyanezek az
eszközök legyártják a kliens
részére is a szükséges
illesztőosztályokat. Mint előbb láthattuk, maga a JAX-RPC
nem biztosítja ezen osztályok dinamikus
letöltését, ezeket be kell építeni a
kliensbe. A kliens ezeket használja fel, amikor meghívja
a szolgáltatást.
public class
AdderClient {
private String endpointAddress;
public static void main(String[] args) {
// A szerver
címe indítási paraméter
System.out.println( "Szerver cím = " + args[0]);
try {
Stub stub = createProxy();
stub._setProperty
(javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY, args[0]);
AdderIF ai = (AdderIF)stub;
int result = ai.add( 5,6 );
System.out.println( "Result: "+return );
} catch (Exception ex) {
ex.printStackTrace();
}
}
private static Stub createProxy() {
return (Stub)( new MyAdderService_Impl().getAdderIFPort() );
}
}
A web services megoldás mögött felsorakozott az
egész iparág, gyakorlatilag az egyetlen megoldás,
ami pl. Jáva és Microsoft termékek
összekötésére alkalmas. Ugyanakkor a SOAP
meglehetősen bőbeszédű, ugyanaz az alkalmazás SOAP-ban
4-5-ször nagyobb forgalmat generálhat, mint CORBA-ban. A
web services katalógusszolgáltatásának
használata még nem terjedt el. A web services
alkalmazásokhoz webszerver is kell, ez nagy forgalom
esetén elég drága mulatság lehet. Ebben a
pillanatban a web services megoldásokat különböző
platformokon futó megoldások
integrálására használják. Idő kell,
hogy kiderüljön, képes-e beváltani az
ígéreteit.