Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
laboratoare:laborator03 [2015/11/06 03:39]
Andrei Roșu-Cojocaru
laboratoare:laborator03 [2015/12/01 15:07] (current)
Andrei Roșu-Cojocaru
Line 24: Line 24:
 RMI - Remote Method Invocation este un mecanism care extinde funcţionalitatea RPC, permiţând invocarea unei metode a unui obiect care există într-un alt spaţiu de adresă, în contextul unei mașini virtuale diferite. ​ RMI - Remote Method Invocation este un mecanism care extinde funcţionalitatea RPC, permiţând invocarea unei metode a unui obiect care există într-un alt spaţiu de adresă, în contextul unei mașini virtuale diferite. ​
  
-<​note>​RPC - Remote Procedure Call reprezintă tehnologia pentru apelul unei metode la distanţă, mecanism din care RMI a fost inspirat, extinzând funcţionalitatea pe care acesta o pune la dispoziţie prin orientarea ​aceasta ​pe obiecte.</​note>​+<​note>​RPC - Remote Procedure Call reprezintă tehnologia pentru apelul unei metode la distanţă, mecanism din care RMI a fost inspirat, extinzând funcţionalitatea pe care acesta o pune la dispoziţie prin orientarea ​acesteia ​pe obiecte.</​note>​
  
 RMI implementează comunicaţia la distanţă doar între programe scrise în limbajul de programare Java. RMI implementează comunicaţia la distanţă doar între programe scrise în limbajul de programare Java.
Line 55: Line 55:
  
 Aplicaţiile distribuite trebuie să realizeze următoarele operaţii: localizarea obiectelor la distanţă, comunicarea cu obiectele la distanţă, încărcarea definiţiilor de clase pentru obiectele care sunt obţinute. Aplicaţiile distribuite trebuie să realizeze următoarele operaţii: localizarea obiectelor la distanţă, comunicarea cu obiectele la distanţă, încărcarea definiţiilor de clase pentru obiectele care sunt obţinute.
-  * //​localizarea obiectelor la distanţă//​ se poate face prin înregistrarea obiectelor "la distanţă"​ la serviciul de nume RMI (rmiregistry);​+  * //​localizarea obiectelor la distanţă//​ se poate face prin înregistrarea obiectelor "la distanţă"​ la serviciul de nume RMI (''​rmiregistry''​);
  
 <​note>​Alternativ,​ o aplicaţie poate transfera obiecte "la distanţă"​ prin intermediul unor invocări ale unor metode.</​note>​ <​note>​Alternativ,​ o aplicaţie poate transfera obiecte "la distanţă"​ prin intermediul unor invocări ale unor metode.</​note>​
Line 64: Line 64:
 {{ :​laboratoare:​laborator03:​RMI-architecture.png?​nolink&​700 }} {{ :​laboratoare:​laborator03:​RMI-architecture.png?​nolink&​700 }}
    
-Se observă că serverul foloseşte serviciul de nume (rmiregistry) pentru a înregistra un obiect pe care apoi clientul îl găseşte invocând acelaşi serviciu. Ulterior, clientul apelează o metodă a obiectului "la distanţă"​. Definiţiile de clase sunt obţinute pentru obiect de pe un server web (existent), în ambele direcţii (de la server spre client şi de la client spre server).+Se observă că serverul foloseşte serviciul de nume (''​rmiregistry''​) pentru a înregistra un obiect pe care apoi clientul îl găseşte invocând acelaşi serviciu. Ulterior, clientul apelează o metodă a obiectului "la distanţă"​. Definiţiile de clase sunt obţinute pentru obiect de pe un server web (existent), în ambele direcţii (de la server spre client şi de la client spre server).
  
 Unul dintre avantajele principale ​ puse la dispoziţie de mecanismul RMI este obţinerea definiţiei clasei unui obiect care nu este definit în maşina virtuală Java a clientului. Toate atributele şi metodele unui obiect, disponibile până acum într-o singură maşină virtuală, pot fi transmise către o alta, posibil la distanţă. Transmiterea obiectului se face prin clasa sa, astfel încât comportamentul nu se modifică atunci când acesta este transmis către altă maşină virtuală. Astfel, noi atribute şi comportamente sunt introduse într-o maşină virtuală aflată la distanţă, îmbogăţind astfel comportamentul aplicaţiei. Unul dintre avantajele principale ​ puse la dispoziţie de mecanismul RMI este obţinerea definiţiei clasei unui obiect care nu este definit în maşina virtuală Java a clientului. Toate atributele şi metodele unui obiect, disponibile până acum într-o singură maşină virtuală, pot fi transmise către o alta, posibil la distanţă. Transmiterea obiectului se face prin clasa sa, astfel încât comportamentul nu se modifică atunci când acesta este transmis către altă maşină virtuală. Astfel, noi atribute şi comportamente sunt introduse într-o maşină virtuală aflată la distanţă, îmbogăţind astfel comportamentul aplicaţiei.
Line 71: Line 71:
  
 Un obiect "la distanţă"​ implementează o interfaţă (vizibilă "la distanţă"​) având următoarele caracteristici:​ Un obiect "la distanţă"​ implementează o interfaţă (vizibilă "la distanţă"​) având următoarele caracteristici:​
-  * extinde interfaţa ​''​java.rmi.Remote''​; +  * extinde interfaţa ​[[https://​docs.oracle.com/​javase/​8/​docs/​api/​java/​rmi/​Remote.html|java.rmi.Remote]]; 
-  * fiecare metodă definită în interfaţă aruncă excepţia ​''​java.rmi.RemoteException''​, în plus faţă de alte excepţii;+  * fiecare metodă definită în interfaţă aruncă excepţia ​[[https://​docs.oracle.com/​javase/​8/​docs/​api/​java/​rmi/​RemoteException.html|java.rmi.RemoteException]], în plus faţă de alte excepţii;
  
 Obiectele "la distanţă"​ sunt tratate diferit (faţă de obiectele locale) prin mecanismul RMI atunci când sunt transmise de la o maşină virtuală la alta. Obiectele "la distanţă"​ sunt tratate diferit (faţă de obiectele locale) prin mecanismul RMI atunci când sunt transmise de la o maşină virtuală la alta.
Line 84: Line 84:
 ===== Noțiunea de serializare ===== ===== Noțiunea de serializare =====
  
-Tehnologia RMI foloseşte mecanismul de serializare a obiectelor din Java pentru a transmite obiecte prin valoare între maşini virtuale diferite. Pentru ca un obiect să fie considerat serializabil,​ clasa sa trebuie să implementeze interfaţa ​''​java.io.Serializable''​. +Tehnologia RMI foloseşte mecanismul de serializare a obiectelor din Java pentru a transmite obiecte prin valoare între maşini virtuale diferite. Pentru ca un obiect să fie considerat serializabil,​ clasa sa trebuie să implementeze interfaţa ​[[https://​docs.oracle.com/​javase/​8/​docs/​api/​java/​io/​Serializable.html|java.io.Serializable]]. 
  
 Există două tipuri de clase care pot fi folosite cu mecanismul RMI: Există două tipuri de clase care pot fi folosite cu mecanismul RMI:
Line 113: Line 113:
 ==== Exemplu ==== ==== Exemplu ====
  
-În cele ce urmează, implementarea unei aplicaţii distribuite folosind mecanismul RMI va fi ilustrată pe cazul particular al unui serviciu ​de rezervare a locurilor.+În cele ce urmează, implementarea unei aplicaţii distribuite folosind mecanismul RMI va fi ilustrată pe cazul particular al unei aplicații integrate pentru întreprinderi utilizată ​de o librărie virtuală.
  
-Rezervările pot fi realizate numai în cadrul unui program de funcționare (diferit pentru fiecare dată calendaristică în parte), serviciul fiind limitat la un anumit număr ​de locuri. Aceste ​informaţii sunt disponibile în fişierul ''​timetable.txt''​ din directorul ''​input''​ de pe sever, fiind încărcate la momentul lansării în execuţie a acestuia. În fişier se indică numărul ​de locuri disponibile, ​precum ​şi programul de funcţionare pentru fiecare zi în parte, respectând formatul ''​ZZ LL AAAA O1 M1 O2 M2''​ (unde ''​O1:​M1''​ reprezintă momentul de timp de la care se doreşte să se facă rezervarea, iar ''​O2:​M2''​ momentul de timp până la care aceasta este valabilă).+Aceasta oferă mai multe servicii, dedicate unor categorii diferite ​de utilizatori. Astfel, pot fi accesate ​informații cu privire la volumele comercializate, date privind formatele ​de prezentare ale acestora ​precum ​și aspecte ​care îi privesc pe scriitorii ​care au elaborat lucrările respective.
  
-Aplicaţia va avea arhitectura client-server şi are definite semnăturile pentru metodele pe care va trebui să le implementaţi.+Aplicaţia va avea arhitectura client-server şi implementează un model de comunicare strâns cuplat, în care apelurile metodelor este realizat în mod sincron.
  
-Pe server ​(''​ReservationImplementation.java''​) ​se vor reţine rezervările clienţilor fără a fi necesară asigurarea persistenţei (informaţiile sunt disponibile cât timp serverul rulează, pierzându-se ulterior). Tot aici vor fi implementate metodele din interfaţa pe care o cunoaşte şi clientul, fiind apelate în acest context.+Pe server se va realiza accesul la informațiile stocate în baza de date precum și prelucrarea acestora în funcție de necesități.
  
-Fiecare ​client (''​Client.java''​) poate realiza o rezervare specificând o perioadă de timp preferată (orice durată) şi un număr de locuri. Dacă perioada ​de timp se încadrează în orarul specificat şi în intervalul respectiv există un număr de locuri libere corespunzător cererii făcute, atunci rezervarea este realizată şi locurile respective marcate ca ocupate. Este reţinut ​totodată şi identificatorul clientului care a realizat rezervarea, astfel încât tot acesta să aibă posibilitatea de a o anula, dacă situaţia o impune. Informaţiile ​cu privire la rezervările pe care clientul doreşte să le realizeze ​sunt preluate ​de la tastatură, respectând acelaşi format ca şi în fişier (dată calendaristică,​ intervalul orar pentru rezervarea respectivă, numărul de locuri solicitat), fără a fi necesară dezvoltarea unei interfeţe grafice.+Un client ​poate accesa mai multe funcționalități,​ aparținând unor servicii diferite: 
 +  * serviciul de carte (''​BookManager''​) ​oferă informații cu privire la volumele comercializate;​ astfel, ​poate fi obținută lista tuturor lucrărilor care pot fi achiziționate din librărie, aceasta putând fi ulterior filtrată în funcție ​de stocul disponibil, datele accesate în această situație fiind mult mai detaliate:​ 
 +  * serviciul referitor la formatele ​de prezentare ale volumelor (''​BookPresentationManager''​) permite actualizarea prețurilor pentru o categorie de lucrări care se găsesc într-un anumit ​număr de formate de prezentare, oferind ​totodată posibilitatea de a realiza comenzi de aprovizionare pentru acele volume pentru care nu este întrunit un anumit stoc; 
 +  * serviciul de furnizare a informațiilor ​cu privire la scriitori (''​WriterManager''​) permite înlăturarea din baza de date a acelor autori ale căror lucrări nu sunt comercializate ​de librărie dar și filtrarea listei de înregistrări ​în funcție de numărul total de cărți publicate, numărul de cărți pe care le-au scris singuri sau numărul de cărți redactate în colaborare.
  
 ==== Clase și Interfețe "la distanță"​ ==== ==== Clase și Interfețe "la distanță"​ ====
  
-Protocolul care permite ca serverul să fie interogat cu cereri de către client care să fie rulate apoi de server iar rezultatul să fie întors la client este realizat prin intermediul ​unei interfeţe care descrie ​funcţionalitatea ​care poate fi accesată la distanţă.+Protocolul care permite ca serverul să fie interogat cu cereri de către client care să fie rulate apoi de server iar rezultatul să fie întors la client este realizat prin intermediul ​unor interfeţe care descriu ​funcţionalitatea ​ce poate fi accesată la distanţă. 
 + 
 +<file java *ManagerInterface.java>​ 
 +package ro.pub.cs.aipi.lab03.businesslogic;​
  
-<file java Reservation.java>​ 
 import java.rmi.Remote;​ import java.rmi.Remote;​
 import java.rmi.RemoteException;​ import java.rmi.RemoteException;​
-import java.util.ArrayList;+import java.util.List; 
 + 
 +import ro.pub.cs.aipi.lab03.result.*Information;
  
-public interface ​Reservation ​extends Remote { +public interface ​*ManagerInterface ​extends Remote { 
-    public ​ArrayList<Interval> getTimetable() throws RemoteException;​ +  public ​List<*Information> method1(int param) throws RemoteException;​ 
-    public ​int getAvailableSeats(Interval interval) throws RemoteException;​ +  public ​List<​*Information>​ method2(String param) throws RemoteException;​
-    public ​boolean makeReservation(int clientId, Interval interval, int numberOfSeats) throws RemoteException;​ +
-    public boolean cancelReservation(int clientId, Interval interval) throws RemoteException;​+
 } }
 </​file>​ </​file>​
 +
 +<note tip>Prin noteția * se înțelege faptul că acest caracter poate fi înlocuit cu orice unitate de gestiune a unui serviciu, respectiv cu orice entitate persistentă.</​note>​
  
 Prin extinderea interfeţei ''​java.rmi.Remote''​ se specifică faptul că metodele declarate de interfaţa ''​Reservation''​ vor putea fi apelate din altă maşină virtuală Java. Orice obiect care implementează interfaţa ''​Reservation''​ va putea fi considerat un obiect "la distanţă"​. Prin extinderea interfeţei ''​java.rmi.Remote''​ se specifică faptul că metodele declarate de interfaţa ''​Reservation''​ vor putea fi apelate din altă maşină virtuală Java. Orice obiect care implementează interfaţa ''​Reservation''​ va putea fi considerat un obiect "la distanţă"​.
Line 144: Line 151:
 Metodele definite în cadrul acestei interfeţe vor putea fi apelate din cadrul altei maşini virtuale ("la distanţă"​),​ prin urmare este obligatoriu să genereze excepţii de tip ''​java.rmi.RemoteException''​. O astfel de excepţie este aruncată de sistemul RMI dintr-un apel de metodă la distanţă pentru indicarea situaţiei în care a intervenit o eroare de comunicare sau de protocol. Codul sursă care apelează metode "la distanţă"​ trebuie să trateze o astfel de excepţie (prin prinderea ei sau transmiterea ei mai departe). Metodele definite în cadrul acestei interfeţe vor putea fi apelate din cadrul altei maşini virtuale ("la distanţă"​),​ prin urmare este obligatoriu să genereze excepţii de tip ''​java.rmi.RemoteException''​. O astfel de excepţie este aruncată de sistemul RMI dintr-un apel de metodă la distanţă pentru indicarea situaţiei în care a intervenit o eroare de comunicare sau de protocol. Codul sursă care apelează metode "la distanţă"​ trebuie să trateze o astfel de excepţie (prin prinderea ei sau transmiterea ei mai departe).
  
-Se observă că metodele ''​getAvailableSeats()''​, ''​makeReservation()''​ şi ''​cancelReservation()''​ au şi un parametru ​de tip ''​Interval''​, întoarcând un rezultat de tip ''​int''​/''​boolean''​. ​Pentru că ''​Interval'' ​nu reprezintă un tip de bază, ​el trebuie ​definit tot acum.+Se observă că metodele ''​method1()'' ​și ''​method2()''​ au parametri ​de tip date primitive, întoarcând un rezultat de tip ''​*Information''​, derivate din ''​PersistentEntity''​. ​Întrucât acestea ​nu reprezintă un tip de bază, ​ele trebuie ​să fie serializabile. Se pot defini ca serializabile tipurile de date ''​*Information'',​ fiind de asemenea posibil ca această proprietate să aparțină totodată clasei din care acestea sunt extinse. Proprietățile acestor clase nu trebuie să poată fi accesate decât prin intermediul unor metode de tip getter / setter.
  
-<file java Interval.java> +<file java *Information.java> 
-import java.io.Serializable; +public class *Information extends PersistentEntity implements ​Serializable ​{
-import java.util.GregorianCalendar;​+
  
-public class Interval implements Serializable {  +  ​private static final long serialVersionUID = 20152015L;
-    ​private static final long serialVersionUID = 2014L;  +
-    GregorianCalendar startingTime;​ +
-    GregorianCalendar endingTime;+
  
-    public Interval() { +  // .. 
-        ​startingTime = new GregorianCalendar();​ +} 
-        ​endingTime = new GregorianCalendar();​ +</​file>​
-    }+
  
-    public Interval(GregorianCalendar startingTime,​ GregorianCalendar endingTime) { +sau
-        this.startingTime = startingTime;​ +
-        this.endingTime = endingTime;​ +
-    } +
-    public void setStartingTime(GregorianCalendar startingTime) { +
-        this.startingTime = startingTime;​ +
-    } +
-  +
-    public GregorianCalendar getStartingTime() { +
-        return startingTime;​ +
-    }+
  
-    public void setEndingTime(GregorianCalendar endingTime) { +<file java PersistentEntity.java> 
-        this.endingTime = endingTime; +@Embeddable 
-    } +public ​class PersistentEntity implements Serializable ​{ 
-  +  // ..
-    ​public ​GregorianCalendar getEndingTime() ​{ +
-        ​return endingTime;​ +
-    }+
 } }
 </​file>​ </​file>​
Line 184: Line 173:
 Câmpul ''​serialVersionUID''​ e folosit în procesul de deserializare al obiectelor încât dacă atributul obţinut nu corespunde cu cel specificat în definiţia clasei, este aruncată o excepţie de tipul ''​InvalidClassException''​. Câmpul ''​serialVersionUID''​ e folosit în procesul de deserializare al obiectelor încât dacă atributul obţinut nu corespunde cu cel specificat în definiţia clasei, este aruncată o excepţie de tipul ''​InvalidClassException''​.
  
-Obiectele de tip ''​Interval''​ vor fi transmise între client şi server astfel încât ele trebuie să fie serializabile (asigurând astfel consistenţa informaţiilor reţinute în obiect indiferent de formatul de reprezentare din maşinile virtuale). De aceea, ​clasa ''​Interval'' ​implementează interfaţa ''​Serializable''​ (din pachetul ''​java.io''​) ​şi pune la dispoziţie un constructor de copiere şi metode de tip setter/​getter .+Obiectele de tip ''​*Information''​ vor fi transmise între client şi server astfel încât ele trebuie să fie serializabile (asigurând astfel consistenţa informaţiilor reţinute în obiect indiferent de formatul de reprezentare din maşinile virtuale). De aceea, ​toate clasele *Information ​implementează interfaţa ''​Serializable''​ (din pachetul ''​java.io''​) ​punând ​la dispoziţie un constructor de copiere şi metode de tip setter/​getter .
  
-Compilarea claselor se face în mod obişnuit:+Compilarea claselor ​care vor fi incluse în bibliotecile care vor fi expuse la distanță ​se face în mod obişnuit:
  
-<​code ​bash> +  * Linux <​code>​ 
-$ javac Reservation.java Interval.java+student@aipi2015:​~$ javac -cp ../​libs/​hibernate-jpa-2.1-api-1.0.0.Final.jar ro/​pub/​cs/​aipi/​lab03/​businesslogic/​*Interface.java ro/​pub/​cs/​aipi/​lab03/​general/​Constants.java ro/​pub/​cs/​aipi/​lab03/​entities/​PersistentEntity.java ro/​pub/​cs/​aipi/​lab03/​result/​*.java 
 +</​code>​ 
 +  * Windows <​code>​ 
 +C:​\Users\Aipi2015>​ javac -cp ..\\libs\\hibernate-jpa-2.1-api-1.0.0.Final.jar ro\\pub\\cs\\aipi\\lab03\\businesslogic\\*Interface.java ro\\pub\\cs\\aipi\\lab03\\general\\Constants.java ro\\pub\\cs\\aipi\\lab03\\entities\\PersistentEntity.java ro\\pub\\cs\\aipi\\lab03\\result\\*.java
 </​code>​ </​code>​
  
-Întrucât cele două clase sunt necesare atât pe client cât si pe server, ​acestea trebuie ​împachetate într-o arhivă Java (de tip jar) adăugată în classpath atât la compilare cât şi la rulare.+Clasele reprezentând interfețe care conțin metode la distanță, tipuri de date definite de utilizator, implicate în transferul de parametri sau valori întoarse în cazul metodelor la distanță precum și alte clase referite de acestea, ​sunt necesare atât pe client cât si pe server, ​fiind necesar să fie împachetate într-o arhivă Java (de tip .jar) adăugată în classpath atât la compilare cât şi la rulare. Aceasta se constituie în definiția de clase care va trebui să fie cunoscută de serviciul de nume pentru a putea fi încărcată atunci când este necesar să se acceseze funcționalitatea disponibilă la distanță.
  
-<​code ​bash> +<note tip>Se recomandă ca în cazul unor funcționalități diferite, accesate de diverși utilizatori,​ să se creeze definiții de clase separate, care vor fi expuse către serviciul de nume în mod distinct, astfel încât să poată fi accesate numai în funcție de drepturile stabilite în contextul aplicației integrate pentru întrerprinderi. În situația în care unele clase sunt accesate din arhive .jar diferite, se va construi și o arhivă cu resursele comune, aceasta putând fi partajată între toate entitățile implicate.</​note>​ 
-$ jar cvf reservation.jar Reservation.class ​Interval.class+  * Linux <​code>​ 
 +student@aipi2015:​~$ jar cvf bookstore-common.jar ro/​pub/​cs/​aipi/​lab03/​general/​Constants.class ro/​pub/​cs/​aipi/​lab03/​entities/​PersistentEntity.class 
 +student@aipi2015:​~$ jar cvf bookstore-bookmanager.jar ro/​pub/​cs/​aipi/​lab03/​businesslogic/​BookManagerInterface.class ro/​pub/​cs/​aipi/​lab03/​result/​BookInformation.class ro/​pub/​cs/​aipi/​lab03/​result/​BookInformationDetailed.class 
 +student@aipi2015:​~$ jar cvf bookstore-bookpresentationmanager.jar ro/​pub/​cs/​aipi/​lab03/​businesslogic/​BookPresentationManagerInterface.class ro/​pub/​cs/​aipi/​lab03/​result/​BookPresentationInformation.class ro/​pub/​cs/​aipi/​lab03/​result/​SupplyOrderInformation.class 
 +student@aipi2015:​~$ jar cvf bookstore-writermanager.jar ro/​pub/​cs/​aipi/​lab03/​businesslogic/​WriterManagerInterface.class ​ro/​pub/​cs/​aipi/​lab03/​result/​WriterInformation.class
 </​code>​ </​code>​
 +  * Windows <​code>​
 +C:​\Users\Aipi2015>​ jar cvf bookstore-common.jar ro\\pub\\cs\\aipi\\lab03\\general\\Constants.class ro\\pub\\cs\\aipi\\lab03\\entities\\PersistentEntity.class
 +C:​\Users\Aipi2015>​ jar cvf bookstore-bookmanager.jar ro\\pub\\cs\\aipi\\lab03\\businesslogic\\BookManagerInterface.class ro\\pub\\cs\\aipi\\lab03\\result\\BookInformation.class ro\\pub\\cs\\aipi\\lab03\\result\\BookInformationDetailed.class
 +C:​\Users\Aipi2015>​ jar cvf bookstore-bookpresentationmanager.jar ro\\pub\\cs\\aipi\\lab03\\businesslogic\\BookPresentationManagerInterface.class ro\\pub\\cs\\aipi\\lab03\\result\\BookPresentationInformation.class ro\\pub\\cs\\aipi\\lab03\\result\\SupplyOrderInformation.class
 +C:​\Users\Aipi2015>​ jar cvf bookstore-writermanager.jar ro\\pub\\cs\\aipi\\lab03\\businesslogic\\WriterManagerInterface.class ro\\pub\\cs\\aipi\\lab03\\result\\WriterInformation.class
 +</​code>​
 +
 +Astfel, au fost create arhive .jar conținând definiții de clase corespunzătoare diferitelor funcționalități (''​bookstore-bookmanager.jar'',​ ''​bookstore-bookpresentationmanager.jar'',​ ''​bookstore-writermanager.jar''​) precum și o bibliotecă comună pe care o partajează (''​bookstore-common.jar''​ - conținând informații generale despre diferite constante din sistemul informatic precum și clasa de baza ''​PersistentEntity''​).
  
 ==== Dezvoltarea serverului RMI ==== ==== Dezvoltarea serverului RMI ====
Line 212: Line 216:
 Obiectele locale sunt transmise prin valoare (este realizată o copie folosind mecanismul de serializare). Sunt copiate toate câmpurile care nu au precizat atributul ''​static''​ sau ''​transient''​. Orice modificare realizată în starea obiectului sunt reflectate doar în copie, dar nu şi în instanţa originală. Similar, schimbările asupra stării obiectului în instanţa originală nu vor fi reflectate în copie. Obiectele locale sunt transmise prin valoare (este realizată o copie folosind mecanismul de serializare). Sunt copiate toate câmpurile care nu au precizat atributul ''​static''​ sau ''​transient''​. Orice modificare realizată în starea obiectului sunt reflectate doar în copie, dar nu şi în instanţa originală. Similar, schimbările asupra stării obiectului în instanţa originală nu vor fi reflectate în copie.
  
-<file java Server.java>+<file java BookStore.java> 
 +package ro.pub.cs.aipi.lab03.main;​ 
 import java.rmi.registry.LocateRegistry;​ import java.rmi.registry.LocateRegistry;​
 import java.rmi.registry.Registry;​ import java.rmi.registry.Registry;​
 import java.rmi.server.UnicastRemoteObject;​ import java.rmi.server.UnicastRemoteObject;​
  
-public class Server {+import ro.pub.cs.aipi.lab03.businesslogic.*Manager;​ 
 +import ro.pub.cs.aipi.lab03.businesslogic.*ManagerInterface;​ 
 +import ro.pub.cs.aipi.lab03.general.Constants;​
  
-    ​public ​static void main (String[] args) { +public ​class BookStore ​{
-     +
-        if (System.getSecurityManager() == null) +
-            System.setSecurityManager(new SecurityManager());​+
  
-        try { +  public static void main(String[] args) { 
-            ​String ​serviceName = "​ReservationService";​ +    ​if ​(System.getSecurityManager() == null) { 
-            Reservation service = new ReservationImplementation(); +      System.setSecurityManager(new SecurityManager());
-            ​Reservation proxy = (Reservation)UnicastRemoteObject.exportObject(service, 0); +
-            Registry registry ​= LocateRegistry.getRegistry();​ +
-            registry.rebind(serviceName,​ proxy); +
-        } catch (Exception exception) { +
-            System.out.println("An exception has occurred: "​+exception.getMessage()); +
-            if (Constants.DEBUG) +
-                exception.printStackTrace();​ +
-        }+
     }     }
  
 +    try {
 +      Registry registry = LocateRegistry.getRegistry();​
 +      String *ManagerServiceName = Constants.*_MANAGER_SERVICE_NAME;​
 +      *ManagerInterface *ManagerService = new *Manager();
 +      *ManagerInterface *ManagerProxy = (*ManagerInterface)UnicastRemoteObject.exportObject(*ManagerService,​ 0);
 +      registry.rebind(*ManagerServiceName,​ *ManagerProxy);​
 +      System.out.format("​[%s] successfully bounded%n",​ Constants.*_MANAGER_SERVICE_NAME);​
 +    } catch (Exception exception) {
 +    System.out.println("​An exception has occurred: " + exception.getMessage());​
 +    if (Constants.DEBUG) {
 +      exception.printStackTrace();​
 +    }
 +  }
 } }
-</​file>​ 
- 
-<file java ReservationImplementation.java>​ 
-import java.rmi.RemoteException;​ 
-import java.util.ArrayList;​ 
- 
-public class ReservationImplementation implements Reservation { 
- 
-    public ReservationServer() {  
-        // ... 
-    } 
- 
-    public ArrayList<​Interval>​ getTimetable() throws RemoteException { 
-        // ... 
-    } 
- 
-    public int getAvailableSeats(Interval interval) throws RemoteException { 
-        // ... 
-    }    ​ 
-    ​ 
-    public boolean makeReservation(int customerId, Interval interval, int numberOfSeats) throws RemoteException { 
-        // ... 
-    }    ​ 
-    ​ 
-    public boolean cancelReservation(int customerId, Interval interval) throws RemoteException { 
-        // ... 
-    } 
-}    
 </​file>​ </​file>​
  
Line 271: Line 253:
  
   - Este creat şi instalat **un sistem de securitate** care protejează accesul la resursele sistemului de cod sursă (descărcat) care rulează în maşina virtuală Java. Acest sistem de securitate stabileşte dacă codul sursă poate să acceseze sistemul local de fişiere sau poate realiza alte operaţii privilegiate.\\ \\ În situaţia în care aplicaţia distribuită care foloseşte tehnologia RMI nu dispune de un sistem de securitate, nu vor fi descărcate clase (altele decât din sistemul de fişiere specificat în classpath) pentru obiectele primite ca argumente sau valori întoarse.\\ \\ Se asigură totodată faptul că operaţiile realizate de codul descărcat sunt conforme cu o politică de securitate.   - Este creat şi instalat **un sistem de securitate** care protejează accesul la resursele sistemului de cod sursă (descărcat) care rulează în maşina virtuală Java. Acest sistem de securitate stabileşte dacă codul sursă poate să acceseze sistemul local de fişiere sau poate realiza alte operaţii privilegiate.\\ \\ În situaţia în care aplicaţia distribuită care foloseşte tehnologia RMI nu dispune de un sistem de securitate, nu vor fi descărcate clase (altele decât din sistemul de fişiere specificat în classpath) pentru obiectele primite ca argumente sau valori întoarse.\\ \\ Se asigură totodată faptul că operaţiile realizate de codul descărcat sunt conforme cu o politică de securitate.
-  - Se creează ​o instanţă a clasei ​''​ReservationServer'' ​şi este exportată ​către serviciul de nume RMI folosindu-se metoda ''​UnicastRemoteObject.exportObject()''​ astfel încât ​obiectul ​să poată fi apelat ​de către clienţi de la distanţă. La întoarcerea din execuţia acestei metode, obiectul poate procesa apeluri "la distanţă"​. Cel de-al doilea argument al metodei ''​exportObject()''​ reprezintă un port TCP utilizat pentru ascultarea apelurilor metodelor la distanţă de către client. Valoarea 0, folosită în exemplul de faţă specifică utilizarea unui port anonim, ales de RMI sau de sistemul de operare.\\ \\ Este întors un ciot (//eng.// stub) ce are tipul ''​Reservation'',​ deci tipul interfeţei şi nu al clasei (pentru că ciotul implementează doar interfaţa "la distanţă"​).+  - Se creează instanţe ale claselor ​''​*Manager'' ​care sunt exportate ​către serviciul de nume RMI folosindu-se metoda ''​UnicastRemoteObject.exportObject()''​ astfel încât ​obiectele ​să poată fi apelate ​de către clienţi de la distanţă. La întoarcerea din execuţia acestei metode, obiectul poate procesa apeluri "la distanţă"​. Cel de-al doilea argument al metodei ''​exportObject()''​ reprezintă un port TCP utilizat pentru ascultarea apelurilor metodelor la distanţă de către client. Valoarea 0, folosită în exemplul de faţă specifică utilizarea unui port anonim, ales de RMI sau de sistemul de operare.\\ \\ Este întors un ciot (//eng.// stub) ce are tipul ''​*ManagerInterface'',​ deci tipul interfeţei şi nu al clasei (pentru că ciotul implementează doar interfaţa "la distanţă"​).
   - Înainte ca un client să poată invoca metodele unui obiect "la distanţă",​ trebuie să obţină referinţa spre acesta, operaţie ce poate fi realizată în acelaşi fel în care este obţinută o referinţă spre un obiect într-o aplicaţie (ca valoare întoarsă pentru o metodă sau ca un câmp al unei structuri de date care conţine referinţa).   - Înainte ca un client să poată invoca metodele unui obiect "la distanţă",​ trebuie să obţină referinţa spre acesta, operaţie ce poate fi realizată în acelaşi fel în care este obţinută o referinţă spre un obiect într-o aplicaţie (ca valoare întoarsă pentru o metodă sau ca un câmp al unei structuri de date care conţine referinţa).
  
 Mecanismul RMI pune la dispoziţie un tip particular de obiect "la distanţă"​ și anume serviciul de nume (RMI registry), pentru găsirea de referinţe către alte obiecte de acest tip prin specificarea unui nume. Un astfel de sistem este în mod obişnuit folosit doar pentru găsirea primului obiect solicitat de client, putând ajuta la găsirea altor obiecte. Mecanismul RMI pune la dispoziţie un tip particular de obiect "la distanţă"​ și anume serviciul de nume (RMI registry), pentru găsirea de referinţe către alte obiecte de acest tip prin specificarea unui nume. Un astfel de sistem este în mod obişnuit folosit doar pentru găsirea primului obiect solicitat de client, putând ajuta la găsirea altor obiecte.
  
-Interfaţa ​''​java.rmi.registry.Registry'' ​conţine specificaţiile pentru înregistrarea şi găsirea de obiecte "la distanţă"​ în serviciul de nume. Clasa ''​java.rmi.registry.LocateRegistry'' ​pune la dispoziţie metode statice pentru identificarea unei referinţe la distanţă într-o reţea anume (specificată prin adresă şi port). Metodele creează referinţa către obiectul "la distanţă"​ conţinând adresa de reţea specificată fără a se realiza comunicare la distanţă. De asemenea, clasa ''​java.rmi.registry.LocateRegistry''​ pune la dispoziţie metode statice pentru crearea unui serviciu de nume nou în maşina virtuală Java.+Interfaţa ​[[https://​docs.oracle.com/​javase/​8/​docs/​api/​java/​rmi/​registry/​Registry.html|java.rmi.registry.Registry]] conţine specificaţiile pentru înregistrarea şi găsirea de obiecte "la distanţă"​ în serviciul de nume. Clasa [[https://​docs.oracle.com/​javase/​8/​docs/​api/​java/​rmi/​registry/​LocateRegistry.html|java.rmi.registry.LocateRegistry]] pune la dispoziţie metode statice pentru identificarea unei referinţe la distanţă într-o reţea anume (specificată prin adresă şi port). Metodele creează referinţa către obiectul "la distanţă"​ conţinând adresa de reţea specificată fără a se realiza comunicare la distanţă. De asemenea, clasa ''​java.rmi.registry.LocateRegistry''​ pune la dispoziţie metode statice pentru crearea unui serviciu de nume nou în maşina virtuală Java.
  
 După ce obiectul "la distanţă"​ a fost înregistrat de sistemul de nume, clienţii de pe orice maşină îl pot căuta după nume, îi pot obţine referinţa şi pot apela metodele "la distanţă"​ de pe el. Serverele de pe o maşină pot partaja acelaşi serviciu de nume sau fiecare aplicaţie (de tip server) poate să îşi creeze şi să utilizeze propriul său sistem de nume. După ce obiectul "la distanţă"​ a fost înregistrat de sistemul de nume, clienţii de pe orice maşină îl pot căuta după nume, îi pot obţine referinţa şi pot apela metodele "la distanţă"​ de pe el. Serverele de pe o maşină pot partaja acelaşi serviciu de nume sau fiecare aplicaţie (de tip server) poate să îşi creeze şi să utilizeze propriul său sistem de nume.
Line 292: Line 274:
 Excepţiile ce pot fi aruncate de metoda ''​main()''​ sunt de tip ''​RemoteException'',​ generate fie de metoda ''​UnicastRemoteObject.exportObject()''​ sau de apelul ''​rebind()''​. Se poate realiza recuperarea din eroare (în caz că o excepţie a fost aruncată) prin reapelarea metodei care a generat-o sau prin folosirea unui alt server. Excepţiile ce pot fi aruncate de metoda ''​main()''​ sunt de tip ''​RemoteException'',​ generate fie de metoda ''​UnicastRemoteObject.exportObject()''​ sau de apelul ''​rebind()''​. Se poate realiza recuperarea din eroare (în caz că o excepţie a fost aruncată) prin reapelarea metodei care a generat-o sau prin folosirea unui alt server.
  
-După realizarea acestor operaţii, metoda ''​main()''​ se încheie. Nu este necesară definirea unui fir de execuţie care să ţină serverul în starea de rulare, pentru că atât timp cât există o referinţă către un obiect de tip ''​ReservationServer''​ într-o maşină virtuală (locală sau la distanţă),​ el nu va fi distrus de garbage collector. Mecanismul RMI menţine activ procesul asociat ​obiectului ​''​ReservationServer'',​ pentru că există o legătură către ​el în serviciul de nume, accesibilă la distanţă. Obiectul va fi distrus atunci când legătura dintre el şi serviciul de nume va fi eliberată şi nu vor mai exista clienţi la distanţă care să aibă referinţe către el. +După realizarea acestor operaţii, metoda ''​main()''​ se încheie. Nu este necesară definirea unui fir de execuţie care să ţină serverul în starea de rulare, pentru că atât timp cât există o referinţă către un obiect de tip ''​*Manager''​ într-o maşină virtuală (locală sau la distanţă),​ el nu va fi distrus de garbage collector. Mecanismul RMI menţine activ procesul asociat ​obiectelor ​''​*Manager'',​ pentru că există o legătură către ​acesta ​în serviciul de nume, accesibilă la distanţă. Obiectul va fi distrus atunci când legătura dintre el şi serviciul de nume va fi eliberată şi nu vor mai exista clienţi la distanţă care să aibă referinţe către el.
- +
-Compilarea claselor se face în mod obişnuit:​ +
- +
-<code bash> +
-$ javac –cp libs/​reservation.jar Server.java +
-</​code>​+
   
 Lansarea în execuţie nu poate fi realizată decât după: Lansarea în execuţie nu poate fi realizată decât după:
Line 305: Line 281:
 <note tip>​Parametrul port este opţional, el poate să nu fie menţionat, caz în care serviciul de nume foloseşte portul implicit 1099.</​note>​ <note tip>​Parametrul port este opţional, el poate să nu fie menţionat, caz în care serviciul de nume foloseşte portul implicit 1099.</​note>​
  
-    * Windows ​<​code ​bash> +    * Unix <​code>​ 
-> start rmiregistry [port] -J-Djava.rmi.server.useCodebaseOnly=false+student@aipi2015:​~$ ​rmiregistry [port] -J-Djava.rmi.server.useCodebaseOnly=false ​&
 </​code>​ </​code>​
-    * Unix <​code ​bash> +    * Windows ​<​code>​ 
-$ rmiregistry [port] -J-Djava.rmi.server.useCodebaseOnly=false ​&+C:​\Users\Aipi2015>​ start rmiregistry [port] -J-Djava.rmi.server.useCodebaseOnly=false
 </​code>​ </​code>​
   * specificarea unei politici de securitate, într-un fişier denumit ''​policy[.txt]'',​ codul sursă obţinând ​ permisiunile de care are nevoie pentru a putea rula: <file policy>   * specificarea unei politici de securitate, într-un fişier denumit ''​policy[.txt]'',​ codul sursă obţinând ​ permisiunile de care are nevoie pentru a putea rula: <file policy>
-grant codebase "​file://<​cale_absoluta>/ReservationServer/-" { +grant codebase "​file://<​absolute_path>/03-BookStore-RMI-Server/-" { 
-    permission java.security.AllPermission;​+  permission java.security.AllPermission;​
 }; };
 </​file>​ </​file>​
Line 320: Line 296:
  
 Lansarea în execuţie a serverului se face prin comanda: Lansarea în execuţie a serverului se face prin comanda:
-  * Windows ​<​code ​bash> +  * Linux <​code>​ 
-> java -cp .;libs/reservation.jar +student@aipi2015:​~$ ​java -classpath ​.:libs/bookstore-common.jar:​libs/​bookstore-*manager.jar:​... ​-Djava.rmi.server.codebase="file:///<absolute_path>/03-BookStore-RMI-Server/libs/bookstore-common.jar file:///<​absolute_path>/​03-BookStore-RMI-Server/​libs/​bookstore-*manager.jar ..." ​-Djava.rmi.server.hostname=localhost -Djava.security.policy=configuration/​policy ​ro.pub.cs.aipi.lab03.main.BookStore
-       -Djava.rmi.server.codebase=file://<​cale_absoluta>/ReservationServer/libs/reservation.jar +
-       -Djava.rmi.server.hostname=localhost +
-       -Djava.security.policy=configuration/​policy +
-       ​Server+
 </​code>​ </​code>​
-  * Linux <​code ​bash> +  * Windows ​<​code>​ 
-> java -cp .:libs/reservation.jar +C:​\Users\Aipi2015> java -classpath ​.;libs/bookstore-common.jar;​libs/​bookstore-*manager.jar;​... ​-Djava.rmi.server.codebase="file:///<absolute_path>/03-BookStore-RMI-Server/libs/bookstore-common.jar file:///<​absolute_path>/​03-BookStore-RMI-Server/​libs/​bookstore-*manager.jar ..." ​-Djava.rmi.server.hostname=localhost -Djava.security.policy=configuration/​policy ​ro.pub.cs.aipi.lab03.main.BookStore
-       -Djava.rmi.server.codebase=file://<​cale_absoluta>/ReservationServer/libs/reservation.jar +
-       -Djava.rmi.server.hostname=localhost +
-       -Djava.security.policy=configuration/​policy +
-       ​Server+
 </​code>​ </​code>​
  
-Proprietatea ''​java.rmi.server.codebase''​ specifică locaţia de unde pot fi descărcate definiţii pentru clasele provenind de la server. Dacă în locul unei arhive se specifică o ierarhie de directoare, aceasta trebuie încheiată prin caracterul ''​’/​’''​.+<note tip>Prin notația ... se înțelege faptul că în continuare pot urma și alte elemente de același tip.</​note>​ 
 + 
 +Proprietatea ''​java.rmi.server.codebase''​ specifică locaţia de unde pot fi încărcate definiţii pentru clasele provenind de la server. Dacă în locul unei arhive se specifică o ierarhie de directoare, aceasta trebuie încheiată prin caracterul ''​’/​’''​. În situația în care sunt incluse mai multe fișiere, acestea trebuie să fie delimitate prin separatorul spațiu. Pentru fiecare resursă trebuie indicat și protocoul prin care aceasta este accesată (''​file:​%%///​%%''​ sau ''​http:​%%//​%%''​).
  
 Proprietatea ''​java.rmi.server.hostname''​ specifică numele maşinii sau adresa care urmează a fi completată în obiectele de tip ciot care vor fi exportate. Aceeaşi valoare va fi folosită de clienţi când vor încerca să apeleze metodele la distanţă. Implicit, implementarea RMI foloseşte adresa IP indicată de ''​java.net.InetAddress.getLocalHost()''​. Totuşi, câteodată o astfel de adresă nu este întotdeauna potrivită pentru toţi clienţii şi un nume (al maşinii) este mai adecvat. Pentru ca numele sa fie vizibil de toţi clienţii, trebuie configurată proprietatea ''​java.rmi.server.hostname''​. Proprietatea ''​java.rmi.server.hostname''​ specifică numele maşinii sau adresa care urmează a fi completată în obiectele de tip ciot care vor fi exportate. Aceeaşi valoare va fi folosită de clienţi când vor încerca să apeleze metodele la distanţă. Implicit, implementarea RMI foloseşte adresa IP indicată de ''​java.net.InetAddress.getLocalHost()''​. Totuşi, câteodată o astfel de adresă nu este întotdeauna potrivită pentru toţi clienţii şi un nume (al maşinii) este mai adecvat. Pentru ca numele sa fie vizibil de toţi clienţii, trebuie configurată proprietatea ''​java.rmi.server.hostname''​.
   
-Proprietatea ''​java.rmi.policy''​ specifică politica ​care conţine permisiunile ce vor fi acordate.+Proprietatea ''​java.rmi.policy''​ specifică politica ​de securitatecare ​conţine permisiunile ce vor fi acordate.
  
 ==== Dezvoltarea clientului RMI ==== ==== Dezvoltarea clientului RMI ====
  
-Codul care apelează metodele unui obiect tip ''​Reservation''​ trebuie să obţină o referinţă către acesta. +Codul care apelează metodele unui obiect tip ''​*Manager''​ trebuie să obţină o referinţă către acesta.
- +
-Ulterior, va creea un obiect de tip ''​Interval''​ (eventual din parametrii specificaţi în linie de comandă) pe care îl va transmite ca argument metodelor ''​makeReservation()''​ sau ''​cancelReservation()''​.+
  
   - Ca şi în cazul serverului, iniţial se va instala **un sistem de securitate**,​ necesar pentru că în procesul de obţinere a referinţei către obiectul ciot corespunzător obiectului la distanţă se poate întâmpla să se descarce definiţii de clase de la server, lucru care este posibil doar în condiţiile existenţei unui sistem de securitate.   - Ca şi în cazul serverului, iniţial se va instala **un sistem de securitate**,​ necesar pentru că în procesul de obţinere a referinţei către obiectul ciot corespunzător obiectului la distanţă se poate întâmpla să se descarce definiţii de clase de la server, lucru care este posibil doar în condiţiile existenţei unui sistem de securitate.
-  - Clientul va **căuta** obiectul "la distanţă"​ specificând un nume (acelaşi folosit de server pentru a înregistra obiectul la serviciul de nume) – în acest sens, e folosită de asemenea metoda ''​LocateRegistry.getRegistry()''​ pentru a obţine referinţa la sistemul de nume RMI care rulează pe maşina server, parametrul cu care este apelat reprezentând numele maşinii pe care rulează obiectul de tip ''​Reservation''​. În mod implicit, se consideră că sistemul de nume RMI ascultă pe portul 1099. În plus, poate fi folosită o metodă supraîncărcată care să specifice şi portul, prin specificarea unui parametru de tip ''​int''​. Apoi este utilizată metoda ''​lookup()''​ pentru a căuta obiectul la distanţă prin nume în sistemul de nume de pe maşina server. +  - Clientul va **căuta** obiectul "la distanţă"​ specificând un nume (acelaşi folosit de server pentru a înregistra obiectul la serviciul de nume) – în acest sens, e folosită de asemenea metoda ''​LocateRegistry.getRegistry()''​ pentru a obţine referinţa la sistemul de nume RMI care rulează pe maşina server, parametrul cu care este apelat reprezentând numele maşinii pe care rulează obiectul de tip ''​*Manager''​. În mod implicit, se consideră că sistemul de nume RMI ascultă pe portul 1099. În plus, poate fi folosită o metodă supraîncărcată care să specifice şi portul, prin specificarea unui parametru de tip ''​int''​. Apoi este utilizată metoda ''​lookup()''​ pentru a căuta obiectul la distanţă prin nume în sistemul de nume de pe maşina server. 
-  - Se va crea un obiect de tip ''​Interval''​ (eventual din parametrii specificaţi în linia de comandă) şi se vor **apela metodele la distanţă**,​ afişându-se rezultatul.+  - Se vor **apela metodele la distanţă**,​ afişându-se rezultatul.
  
-<file java Client.java>+<file java *ManagerClient.java> 
 +package ro.pub.cs.aipi.lab03.main;​ 
 + 
 +import java.io.BufferedReader;​ 
 +import java.io.InputStreamReader;​
 import java.rmi.registry.LocateRegistry;​ import java.rmi.registry.LocateRegistry;​
 import java.rmi.registry.Registry;​ import java.rmi.registry.Registry;​
  
-public class Client ​{ +import ro.pub.cs.aipi.lab03.businesslogic.*ManagerInterface;​ 
-  +import ro.pub.cs.aipi.lab03.general.Constants;​ 
-    public static void main(String[] args) {    ​+import ro.pub.cs.aipi.lab03.general.Utilities;​ 
 +import ro.pub.cs.aipi.lab03.result.*Information;​ 
 + 
 +public class *ManagerClient ​{ 
 + 
 +  public static void main(String[] args) { 
 +    if (args.length != 1) { 
 +      System.out.println("​You must specify the IP address on which the rmiregistry runs!"​);​ 
 +      return; 
 +    } 
 +     
 +    if (System.getSecurityManager() == null) { 
 +      System.setSecurityManager(new SecurityManager());​ 
 +    }
     ​     ​
-        if (System.getSecurityManager() == null) +    ​try { 
-            System.setSecurityManager(new SecurityManager());​ +      String serviceName = Constants.SERVICE_NAME; 
-  +      Registry registry = LocateRegistry.getRegistry(args[0]);​ 
-        ​try { +      ​*ManagerInterface service ​= (*ManagerInterface) registry.lookup(serviceName);​ 
-            String serviceName = "​ReservationService"​; +      int option ​= -1; 
-            Registry registry = LocateRegistry.getRegistry(args[0]);​ +      do { 
-            ​Reservation reservation ​= (Reservation)registry.lookup(serviceName);​ +        Utilities.displayMenu();​ 
-             +        BufferedReader bufferedReader ​= new BufferedReader(new InputStreamReader(System.in)); 
-            ​int customerId ​= 0; +        ​option ​= Integer.parseInt(bufferedReader.readLine()); 
-            ​Interval interval ​= new Interval(); +        switch (option) { 
-            int numberOfSeats ​= 0; +          case Constants.OPTION_1: 
-  +            Utilities.displayResults(service.method1(), *Information.class); 
-            if (reservation.makeReservation(customerId,​interval,​numberOfSeats)) { +            ​break; 
-                ​System.out.println("The reservation has been made successfully"​); +          case Constants.OPTION_2: 
-            ​} else { +            Utilities.displayResults(service.method2(), *Information.class); 
-                ​System.out.println("The reservation has not been made successfully"​); +            ​break; 
-            ​} +          // ... 
-        } catch (Exception exception) {  +          case Constants.OPTION_QUIT:​ 
-            System.out.println("​An exception has occurred: ​"+exception.getMessage()); +            break; 
-            ​if (Constants.DEBUG) +          default: 
-                exception.printStackTrace();+            System.out.println("​You have entered an invalid option"); 
 +            ​break;
         }         }
 +      } while (option != Constants.OPTION_QUIT);​
 +    } catch (Exception exception) {
 +      System.out.println("​An exception has occurred: " + exception.getMessage());​
 +      if (Constants.DEBUG) {
 +        exception.printStackTrace();​
 +      }
     }     }
 +  }
 } }
 </​file>​ </​file>​
- 
-Compilarea claselor se face în mod obişnuit: 
- 
-<code bash> 
-$ javac –cp libs/​reservation.jar Client.java 
-</​code>​ 
  
 Lansarea în execuţie nu poate fi realizată decât după: Lansarea în execuţie nu poate fi realizată decât după:
   * pornirea serviciului de nume RMI pe maşina server;   * pornirea serviciului de nume RMI pe maşina server;
-  * lansarea în execuţie a aplicaţiei server ''​ReservationServer'';​ +  * lansarea în execuţie a aplicaţiei server ''​BookStore'';​ 
-  * specificarea unei politici de securitate, într-un fişier numit ''​policy[.txt]'',​ codul sursă obţinând ​ permisiunile de care are nevoie pentru a putea rula: <file policy>​ +  * specificarea unei politici de securitate, într-un fişier numit ''​policy[.txt]'',​ codul sursă obţinând permisiunile de care are nevoie pentru a putea rula: <file policy>​ 
-grant codebase "​file://<​cale_absoluta>/ReservationClient/-" { +grant codebase "​file://<​absolute_path>/03-BookStore-RMI-Client-*Manager/-" { 
-    permission java.security.AllPermission;​+  permission java.security.AllPermission;​
 }; };
 </​file>​ </​file>​
   
-Lansarea în execuţie a serverului ​se face prin comanda: +Lansarea în execuţie a clientului ​se face prin comanda: 
-  * Windows ​<​code ​bash> +  * Linux <​code>​ 
-> java -cp .;libs/reservation.jar +student@aipi2015:​~$ ​java -classpath ​.:libs/bookstore-common.jar:​libs/​bookstore-*manager.jar -Djava.rmi.server.codebase="file:///<absolute_path>/03-BookStore-RMI-Client-*Manager/libs/bookstore-common.jar file:///<​absolute_path>/​03-BookStore-RMI-Client-*Manager/​libs/​bookstore-*manager.jar" ​-Djava.security.policy=configuration/​policy ​ro.pub.cs.aipi.lab03.main.*ManagerClient
-       -Djava.rmi.server.codebase=file://<​cale_absoluta>/ReservationClient/libs/reservation.jar +
-       -Djava.security.policy=configuration/​policy +
-       ​Client <​rmiregistry_IP_address>​+
 </​code>​ </​code>​
-  * Unix <​code ​bash> +  * Windows ​<​code>​ 
-> java -cp .:libs/reservation.jar +C:​\Users\Aipi2015> java -classpath ​.;libs/bookstore-common.jar;​libs/​bookstore-*manager.jar -Djava.rmi.server.codebase="file:///<absolute_path>/03-BookStore-RMI-Client-*Manager/libs/bookstore-common.jar file:///<​absolute_path>/​03-BookStore-RMI-Client-*Manager/​libs/​bookstore-*manager.jar"​ -Djava.rmi.server.hostname=localhost ​-Djava.security.policy=configuration/​policy ​ro.pub.cs.aipi.lab03.main.*ManagerClient
-       -Djava.rmi.server.codebase=file://<​cale_absoluta>/ReservationClient/libs/reservation.jar +
-       -Djava.security.policy=configuration/​policy +
-       ​Client <​rmiregistry_IP_address>​+
 </​code>​ </​code>​
  
-Se observă că prin proprietatea ''​java.rmi.server.codebase''​ s-a precizat locaţia unde clientul îşi defineşte clasele, iar prin proprietatea ''​java.security.policy''​ s-a specificat fişierul care conţine permisiunile acordate pentru diferite coduri sursă.+Se observă că prin proprietatea ''​java.rmi.server.codebase''​ s-a precizat locaţia unde clientul îşi încarcă definițiile de clase, iar prin proprietatea ''​java.security.policy''​ s-a specificat fişierul care conţine permisiunile acordate pentru diferite coduri sursă.
  
 ===== Configurarea mediilor de dezvoltare integrate pentru specificarea parametrilor de rulare ===== ===== Configurarea mediilor de dezvoltare integrate pentru specificarea parametrilor de rulare =====
- 
-Proprietatea ''​codebase''​ din fişierul ce conţine politica de securitate (atât pentru server cât şi pentru client) trebuie să ofere permisiuni maxime (''​java.security.AllPermission''​) pentru toate clasele aflate în structura de directoare a serverului, respectiv a clientului. 
  
 Configuraţiile de rulare implică specificarea proprietăţilor Java ''​java.rmi.server.codebase''​ (ce indică spre arhivele .jar ce conţin definițiile de clase care trebuie încărcate de către server și de către client), ''​java.rmi.server.hostname''​ pentru server şi ''​java.security.policy''​ atât pentru server cât şi pentru client. Configuraţiile de rulare implică specificarea proprietăţilor Java ''​java.rmi.server.codebase''​ (ce indică spre arhivele .jar ce conţin definițiile de clase care trebuie încărcate de către server și de către client), ''​java.rmi.server.hostname''​ pentru server şi ''​java.security.policy''​ atât pentru server cât şi pentru client.
 +
 +Proprietatea ''​codebase''​ din fişierul ce conţine politica de securitate (atât pentru server cât şi pentru client) trebuie să ofere permisiuni maxime (''​java.security.AllPermission''​) pentru toate clasele aflate în structura de directoare a serverului, respectiv a clientului. De altfel, aceasta este opțională.
 +
 +<note tip>Nu este neapărat necesar ca proprietățile să fie specificate în cadrul configurațiilor de rulare, acestea pot fi precizate și în codul sursă (înainte de a se implementa politica de securitate):​
 +
 +<code java>
 +System.setProperty("​java.rmi.server.codebase",​ "​..."​);​
 +System.setProperty("​java.security.policy",​ "​..."​);​
 +</​code></​note>​
  
 ==== Eclipse Mars (4.5) ==== ==== Eclipse Mars (4.5) ====
Line 467: Line 455:
 {{ :​laboratoare:​laborator03:​eclipse05.png?​nolink&​700 }} {{ :​laboratoare:​laborator03:​eclipse05.png?​nolink&​700 }}
  
-==== NetBeans 8.02 ====+==== NetBeans 8.0.2 ====
  
-{{ :​laboratoare:​laborator04:​netbeans01.png?​nolink&​300 }}+Pentru a defini o configurație de rulare, se accesează lista de selecție conținând astfel de obiecte (în stânga pictogramei corespunzătoare acțiunii de rulare a proiectului) și se accesează opțiunea //​Customize...//​.
  
-{{ :​laboratoare:​laborator04:​netbeans02.png?​nolink&​700 }}+<note tip>În mediul integrat de dezvoltare NetBeans configurațiile de rulare sunt stocate în mod automat în preferințele proiectului,​ astfel încât acestea pot fi utilizate și atunci când proiectul este rulat pe mașini diferite.</​note>​
  
-{{ :​laboratoare:​laborator04:​netbeans03.png?​nolink&​300 }}+Pentru fiecare proiect pot fi definite mai multe configurații de rulare, acestea fiind încărcate în mod automat în momentul în care se modifică selecția care indică proiectul curent. După ce o astfel de configurație de rulare este aleasă din lista de opțiuni, lansarea în execuție a proiectului poate fi realizată prin accesarea pictogramei aferente acestei acțiuni.
  
-{{ :​laboratoare:​laborator04:​netbeans04.png?​nolink&​700 }}+=== Server ===
  
-===== =====+{{ :​laboratoare:​laborator03:​netbeans01.png?​nolink }}
  
-Nu este neapărat necesar ca proprietățile să fie specificate în cadrul ​configurațiilor de rulare, acestea pot fi precizate și în codul sursă (înainte ​de a se implementa ​politica de securitate):+Pentru server se definesc următoarele ​proprietăți: 
 +  * denumirea ​configurației de rulare; 
 +  * clasa principală a proiectului;​ 
 +  * argumentele ​în linia de comandă; 
 +  * argumentele cu care se rulează mașina virtuală:​ 
 +    * calea (classpath) conține toate bibliotecile accesate ​de aplicație;​ 
 +    * proprietăți de sistem: 
 +      * ''​java.rmi.server.codebase'':​ indică locațiile la care se găsesc bibliotecile care conțin definițiile de clase care vor fi încărcate pentru ​a fi expuse la distanță;​ 
 +      * ''​java.rmi.server.hostname'':​ precizează adresa IP la care este disponibil serverul; 
 +      * ''​java.security.policy'':​ definește locația la care se găsește fișierul ce conține ​politica de securitate ​în privința accesului la codul sursă.
  
-<code java> +{{ :​laboratoare:​laborator03:​netbeans02.png?​nolink&​800 }} 
-System.setProperty("java.rmi.server.codebase", "file:///​.."​); + 
-System.setProperty("​java.security.policy", "​configuration/​policy"​);​ +=== Client === 
-</​code>​+ 
 +{{ :​laboratoare:​laborator03:​netbeans03.png?nolink }} 
 + 
 +Pentru server se definesc următoarele proprietăți:​ 
 +  * denumirea configurației de rulare; 
 +  * clasa principală a proiectului;​ 
 +  * argumentele în linia de comandă; 
 +  * argumentele cu care se rulează mașina virtuală:​ 
 +    * calea (classpath) conține toate bibliotecile accesate de aplicație;​ 
 +    * proprietăți de sistem: 
 +      * ''​java.rmi.server.codebase''​: indică locațiile la care se găsesc bibliotecile care conțin definițiile de clase, acestea fiind încărcate pentru a cunoaște funcționalitățile care pot fi accesate la distanță; 
 +      * ''​java.security.policy'':​ definește locația la care se găsește fișierul ce conține politica de securitate în privința accesului la codul sursă. 
 + 
 +{{ :​laboratoare:​laborator03:​netbeans04.png?​nolink&​800 }}
  
 ===== Activitate de Laborator ===== ===== Activitate de Laborator =====
Line 505: Line 515:
 student@aipi2015:​~$ ./​startRmiRegistry.sh student@aipi2015:​~$ ./​startRmiRegistry.sh
 </​code>​ </​code>​
 +
 +<note tip>În situația în care scriptul nu are drepturi de execuție, acestea vor fi acordate <​code>​
 +student@aipi2015:​~$ chmod +x startRmiRegistry.sh
 +</​code></​note>​
 +
   * Windows <​code>​   * Windows <​code>​
 C:​\Users\Aipi2015>​ startRmiRegistry.bat C:​\Users\Aipi2015>​ startRmiRegistry.bat
Line 513: Line 528:
 Precizarea căii către directorul ''​bin''​ al SDK-ului Java în variabila de mediu ''​PATH''​ se realizează astfel: ​ Precizarea căii către directorul ''​bin''​ al SDK-ului Java în variabila de mediu ''​PATH''​ se realizează astfel: ​
   * Linux <​code>​   * Linux <​code>​
-export PATH=$PATH:/​usr/​local/​java/​jdk1.8.0_60+export PATH=$PATH:/​usr/​local/​java/​jdk1.8.0_60/bin
 </​code> ​ </​code> ​
   * Windows: //Computer Properties//​ → //Control Panel Home/​Advanced System Properties//​ → //System Properties/​Advanced/​Environment Variables// → //System Variables / Path / Edit// <code bash>   * Windows: //Computer Properties//​ → //Control Panel Home/​Advanced System Properties//​ → //System Properties/​Advanced/​Environment Variables// → //System Variables / Path / Edit// <code bash>
Line 569: Line 584:
     * ''​java.security.policy''​ - locația la care se găsește fișierul ce definește politica de securitate (pot fi folosite locații relative);     * ''​java.security.policy''​ - locația la care se găsește fișierul ce definește politica de securitate (pot fi folosite locații relative);
  
-**4**.+**4**. Să se ruleze, în ordine, proiectele corespunzătoare serverului, respectiv clientului, prin intermediul configurațiilor de rulare definite anterior. Să se testeze funcționalitățile disponibile,​ verificându-se conectivitatea dintre server și client. 
 + 
 +**5**. Să se expună metodele corespunzătoare clasei ''​BookPresentationManager'',​ astfel încât acestea să fie accesibile la distanță:​ 
 + 
 +**a)** Să se definească interfața ''​BookPresentationManagerInterface''​ în pachetul ''​ro.pub.cs.aipi.lab03.businesslogic'';​ aceasta trebuie să fie derivată din ''​java.rmi.Remote'',​ iar metodele sale, vizibile în contextul altor mașini virtuale, trebuie să poată genera excepția ''​java.rmi.RemoteException'';​ 
 + 
 +**b)** Să se modifice clasa ''​BookPresentationManager''​ astfel încât să implementeze interfața accesibilă la distanță, schimbându-se și semnăturile metodelor pe care le conține; 
 + 
 +**c)** Să se modifice clasele entitate ''​BookPresentationInformation'',​ respectiv ''​SupplyOrderInformation''​ din pachetul ''​ro.pub.cs.aipi.lab03.result''​ astfel încât obiectele acestora să poată fi transmise prin rețea, ca parametri sau ca valori întoarse ale obiectelor accesibile la distanță. În acest sens, acestea trebuie să implementeze interfața ''​java.io.Serializable''​. 
 + 
 +**d)** Să se expună, în clasa ''​ro.pub.cs.aipi.lab03.bookstore.main.BookStore'',​ funcționalitățile definite de interfața ''​BookPresentationManagerInterface'',​ ca serviciu accesibil prin intermediul ''​rmiregistry'',​ identificarea sa fiind realizată prin intermediul unei denumiri. 
 + 
 +**e)** Să se modifice scriptul de creare ''​makeJars [.sh|.bat]''​ astfel încât: 
 +  - să construiască arhiva ''​bookstore-bookpresentationmanager.jar''​ care conține interfața ''​BookPresentationManagerInterface''​ și clasele entitate ''​BookPresentationInformation'',​ respectiv ''​SupplyOrderInformation'';​ 
 +  - să copieze aceste biblioteci în calea corespunzătoare proiectului care le va încărca pentru a le accesa funcționalitățile (după ce se creează un astfel de proiect). 
 +Să se ruleze acest script pentru a se crea resursele necesare rulării atât a serverului cât și a clientului. 
 + 
 +**f)** Să se actualizeze configurația de rulare a serverului:​ 
 +  - acesta va include la cale biblioteca conținând definițiile de clase necesare expunerii noii funcționalități;​ 
 +  - proprietatea ''​java.rmi.server.codebase''​ va referi, de asemenea, definițiile de clase corespunzătoare noii funcționalități,​ care vor fi încărcate astfel încât să fie accesibile la distanță. 
 + 
 +**6**. Să se construiască un client care să acceseze numai funcționalitățile corespunzătoare interfeței ''​BookPresentationManagerInterface''​. 
 + 
 +Acesta: 
 +  * va crea un sistem de securitate, în cazul în care nu există; 
 +  * va obține o referință către ''​rmiregistry'',​ folosind adresa IP transmisă ca parametru la rulare; 
 +  * va căuta serviciul ''​BookPresentationManagerInterface''​ accesibil prin intermediul aceleiași denumiri, primind o referință către obiectul delegat care încapsulează funcționalitățile ce pot fi invocate la distanță;​ 
 +  * va defini un meniu în mod text pentru a se putea apela metodele pe care interfața le expune. 
 + 
 +Să se relanseze în execuție serverul, prin intermediul noii configurații de rulare. Să se testeze funcționalitățile disponibile în cadrul interfeței ''​BookPresentationManagerInterface''​. 
 + 
 +**7**. (opțional) Să se expună metodele corespunzătoare clasei ''​WriterManager'',​ astfel încât acestea să fie accesibile la distanță. 
 + 
 +**8**. (opțional) Să se construiască un client care să acceseze numai funcționalitățile corespunzătoare interfeței ''​WriterManagerInterface''​. 
 + 
 +Să se relanseze în execuție serverul, prin intermediul noii configurații de rulare. Să se testeze funcționalitățile disponibile în cadrul interfeței ''​WriterManagerInterface''​.
  
 ===== Resurse ====== ===== Resurse ======
Line 575: Line 625:
 [[http://​docs.oracle.com/​javase/​tutorial/​rmi/​index.html|The Java Tutorials - Trail: RMI]]\\ ​ [[http://​docs.oracle.com/​javase/​tutorial/​rmi/​index.html|The Java Tutorials - Trail: RMI]]\\ ​
 [[http://​www.oracle.com/​technetwork/​java/​javase/​tech/​index-jsp-136424.html|Remote Method Invocation Home]]\\ ​ [[http://​www.oracle.com/​technetwork/​java/​javase/​tech/​index-jsp-136424.html|Remote Method Invocation Home]]\\ ​
-[[http://​www.genady.net/​rmi/​v20/​downloads.html|RMI Plug-in for Eclipse v2.0]]+[[http://​www.genady.net/​rmi/​v20/​downloads.html|RMI Plug-in for Eclipse v2.0]]\\  
 +[[http://​docs.oracle.com/​javase/​7/​docs/​technotes/​guides/​rmi/​codebase.html|Dynamic Code Downloading using Java RMI]]
  
 ===== Soluții ===== ===== Soluții =====
  
-TODO+[[https://​github.com/​aipi2015/​Laborator03/​tree/​master/​solutions/​eclipse|Proiect Eclipse]]\\ 
 +[[https://​github.com/​aipi2015/​Laborator03/​tree/​master/​solutions/​netbeans|Proiect NetBeans]]
laboratoare/laborator03.1446773994.txt.gz · Last modified: 2015/11/06 03:39 by Andrei Roșu-Cojocaru
CC Attribution-Share Alike 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0