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:laborator07 [2015/12/02 02:03]
Andrei Roșu-Cojocaru [Utilizarea JAXB pentru conversia dintre clase Java și scheme XML]
laboratoare:laborator07 [2015/12/05 15:18] (current)
Andrei Roșu-Cojocaru
Line 67: Line 67:
 ===== Proiectarea serviciului web ===== ===== Proiectarea serviciului web =====
  
-Un serviciu web dezvoltat cu JAX-WS este o clasă Java adnotată cu însemnarea ​''​@WebService''​ din pachetul ''​javax.jws.WebService''​, aceasta fiind desemnată ca entitatea care deserveşte serviciul web respectiv (//eng.// endpoint). Aşadar, structura prin care este descris un serviciu web (SEI – Service Endpoint Interface / Implementation) este o intefaţă sau o clasă Java unde sunt declarate metodele pe care un client le poate invoca pentru un serviciu.+Un serviciu web dezvoltat cu JAX-WS este o clasă Java adnotată cu însemnarea ​[[https://​docs.oracle.com/​javaee/​7/​api/​javax/​jws/​WebService.html|javax.jws.WebService]], aceasta fiind desemnată ca entitatea care deserveşte serviciul web respectiv (//eng.// endpoint). Aşadar, structura prin care este descris un serviciu web (SEI – Service Endpoint Interface / Implementation) este o intefaţă sau o clasă Java unde sunt declarate metodele pe care un client le poate invoca pentru un serviciu.
  
 <note tip>Nu este obligatoriu să se definească o interfaţă (explicit) atunci când serviciul web este construit cu JAX-WS, întrucât funcţionalitatea sa este descrisă prin implementarea operaţiilor. Totuşi, folosind elementul ''​endpointInterface''​ în adnotarea ''​@WebService'',​ se poate defini explicit interfaţa, definindu-se metodele la care utilizatorul are acces.</​note>​ <note tip>Nu este obligatoriu să se definească o interfaţă (explicit) atunci când serviciul web este construit cu JAX-WS, întrucât funcţionalitatea sa este descrisă prin implementarea operaţiilor. Totuşi, folosind elementul ''​endpointInterface''​ în adnotarea ''​@WebService'',​ se poate defini explicit interfaţa, definindu-se metodele la care utilizatorul are acces.</​note>​
Line 107: Line 107:
  
 Structurile (clasele, interfeţele) care definesc un serviciu web folosind tehnologia JAX-WS trebuie să îndeplinească mai multe condiţii: Structurile (clasele, interfeţele) care definesc un serviciu web folosind tehnologia JAX-WS trebuie să îndeplinească mai multe condiţii:
-  * clasa care implementează serviciul web trebuie să fie adnotată cu însemnările ​''​javax.jws.WebService'' ​sau ''​javax.jws.WebServiceProvider''​;+  * clasa care implementează serviciul web trebuie să fie adnotată cu însemnările ​[[https://​docs.oracle.com/​javaee/​7/​api/​javax/​jws/​WebService.html|javax.jws.WebService]] sau [[http://​docs.oracle.com/​javaee/​7/​api/​javax/​xml/​ws/​spi/​Provider.html|javax.xml.ws.spi.Provider]];
   * clasa care implementează serviciul web poate referi în mod explicit interfaţa care descrie acest serviciu web prin elementul ''​endpointInterface''​ al însemnării ''​@WebService'',​ însă acest lucru nu este obligatoriu:​ dacă nu este întâlnit nici un element ''​endpointInterface''​ în însemnarea ''​@WebService'',​ interfaţa care descrie serviciul web este definită implicit;   * clasa care implementează serviciul web poate referi în mod explicit interfaţa care descrie acest serviciu web prin elementul ''​endpointInterface''​ al însemnării ''​@WebService'',​ însă acest lucru nu este obligatoriu:​ dacă nu este întâlnit nici un element ''​endpointInterface''​ în însemnarea ''​@WebService'',​ interfaţa care descrie serviciul web este definită implicit;
   * metodele ce implementează funcţionalitatea serviciului web trebuie să fie publice şi nu trebuie să fie declarate ca fiind ''​static''​ sau ''​final'';​   * metodele ce implementează funcţionalitatea serviciului web trebuie să fie publice şi nu trebuie să fie declarate ca fiind ''​static''​ sau ''​final'';​
-  * metodele ce implementează funcţionalitatea serviciului web, ce sunt accesibile utilizatorilor trebuie să fie adnotate cu însemnarea ​''​javax.jws.WebMethod''​+  * metodele ce implementează funcţionalitatea serviciului web, ce sunt accesibile utilizatorilor trebuie să fie adnotate cu însemnarea ​[[https://​docs.oracle.com/​javaee/​7/​api/​javax/​jws/​WebMethod.html|javax.jws.WebMethod]]
-  * metodele ce implementează funcţionalitatea serviciului web trebuie să aibă parametrii şi rezultate întoarse de tipuri compatibile cu JAXB;+  * metodele ce implementează funcţionalitatea serviciului web trebuie să aibă parametrii şi rezultate întoarse de tipuri compatibile cu JAXB; acestea pot fi adnotate cu însemnările [[https://​docs.oracle.com/​javaee/​7/​api/​javax/​jws/​WebParam.html|javax.jws.WebParam]],​ respectiv [[https://​docs.oracle.com/​javaee/​7/​api/​javax/​jws/​WebResult.html|javax.jws.WebResult]];
   * clasa care implementează serviciul web nu trebuie să fie declarată ca fiind ''​final''​ şi nu trebuie să fie abstractă;   * clasa care implementează serviciul web nu trebuie să fie declarată ca fiind ''​final''​ şi nu trebuie să fie abstractă;
   * clasa care implementează serviciul web trebuie să implementeze un constructor public implicit;   * clasa care implementează serviciul web trebuie să implementeze un constructor public implicit;
   * clasa care implementează serviciul web nu trebuie să conţină metoda ''​finalize()'';​   * clasa care implementează serviciul web nu trebuie să conţină metoda ''​finalize()'';​
-  * clasa care implementează serviciul web poate folosi adnotaţiile ​''​javax.annotation.PostConstruct'' ​sau ''​javax.annotation.PreDestroy'' ​pentru evenimente legate de ciclul de viaţă al serviciului web:+  * clasa care implementează serviciul web poate folosi adnotaţiile ​[[http://​docs.oracle.com/​javaee/​7/​api/​javax/​annotation/​PostConstruct.html|javax.annotation.PostConstruct]] sau [[http://​docs.oracle.com/​javaee/​7/​api/​javax/​annotation/​PreDestroy.html|javax.annotation.PreDestroy]] pentru evenimente legate de ciclul de viaţă al serviciului web:
     * metoda ''​@PreConstruct''​ va fi invocată înainte ca structura care implementează serviciul web să răspundă la cereri din partea clienţilor;​     * metoda ''​@PreConstruct''​ va fi invocată înainte ca structura care implementează serviciul web să răspundă la cereri din partea clienţilor;​
     * metoda ''​@PreDestroy''​ va fi invocată înainte ca structura care defineşte serviciul web să fie îşi încheie activitatea.     * metoda ''​@PreDestroy''​ va fi invocată înainte ca structura care defineşte serviciul web să fie îşi încheie activitatea.
  
-În exemplul de mai sus, clasa care implementează serviciul web, ''​BookManager'',​ este adnotată ca fiind descriind operaţiile acestuia prin însemnarea ''​@WebService(serviceName="​BookManager"​)''​. Clasa ''​BookManager''​ declară mai multe metode (''​getBooksList()'',​ ''​getBooksListWithStockpile()''​),​ fiecare fiind adnotate cu ''​@WebMethod(operationName=""​)''​ prin care acestea sunt făcute vizible către clienţi. Parametrii acestor metode accesibile la nivelul clienţilor trebuie să fie adnotate cu însemnarea ''​@WebParam(name=""​)'',​ putându-se specifica un nume sugestiv pentru semnificaţia argumentelor. Totodată, este necesar ca implementarea să conţină şi un constructor implicit care va fi apelat atunci când un client face o invocare pentru o metodă asociată serviciului web respectiv. Preluarea informaţiilor dintr-o sursă externă (fişier) pentru obţinerea acestui element trebuie să ţină cont de faptul că în urma operaţiei de dezvoltare (//eng.// deployment) a serviciului web, aplicaţia este plasată într-un context al serverului de aplicaţii care va pune la dispoziţie respectivul serviciu web, astfel încât amplasarea sursei externe trebuie să fie cunoscută ca locaţie (server web sau sistem de fişiere) în mod absolut şi nu relativ la adresa unde se găsesc clasele.+În exemplu, clasa care implementează serviciul web, ''​BookManager'',​ este adnotată ca fiind un serviciu web, descriind operaţiile acestuia prin însemnarea ''​@WebService(serviceName="​BookManager"​)''​. Clasa ''​BookManager''​ declară mai multe metode (''​getBooksList()'',​ ''​getBooksListWithStockpile()''​),​ fiecare fiind adnotate cu ''​@WebMethod(operationName=""​)''​ prin care acestea sunt făcute vizible către clienţi. Parametrii acestor metode accesibile la nivelul clienţilor trebuie să fie adnotate cu însemnarea ''​@WebParam(name=""​)'',​ putându-se specifica un nume sugestiv pentru semnificaţia argumentelor. Totodată, este necesar ca implementarea să conţină şi un constructor implicit care va fi apelat atunci când un client face o invocare pentru o metodă asociată serviciului web respectiv. Preluarea informaţiilor dintr-o sursă externă (fişier) pentru obţinerea acestui element trebuie să ţină cont de faptul că în urma operaţiei de dezvoltare (//eng.// deployment) a serviciului web, aplicaţia este plasată într-un context al serverului de aplicaţii care va pune la dispoziţie respectivul serviciu web, astfel încât amplasarea sursei externe trebuie să fie cunoscută ca locaţie (server web sau sistem de fişiere) în mod absolut şi nu relativ la adresa unde se găsesc clasele.
  
-Clasa ''​javax.xml.ws.Endpoint'' ​pune la dispoziție mai multe metode statice prin intermediul cărora poate fi gestionat un serviciu web. Un astfel de obiect asociază o implementare a unui serviciu web, a cărui stare poate fi publicat sau nepublicat. Totodată, el încapsulează mai multe metadate, cum ar fi documentele WSDL și schemele XML, pe care le generează în funcție de adnotările din clasele ce conțin implementarea serviciului web, în cazul că acestea nu sunt furnizate explicit.+Clasa [[http://​docs.oracle.com/​javaee/​7/​api/​javax/​xml/​ws/​Endpoint.html|javax.xml.ws.Endpoint]] pune la dispoziție mai multe metode statice prin intermediul cărora poate fi gestionat un serviciu web. Un astfel de obiect asociază o implementare a unui serviciu web, a cărui stare poate fi publicat sau nepublicat. Totodată, el încapsulează mai multe metadate, cum ar fi documentele WSDL și schemele XML, pe care le generează în funcție de adnotările din clasele ce conțin implementarea serviciului web, în cazul că acestea nu sunt furnizate explicit.
  
-Crearea și publicarea unui obiect de tip ''​Endpoint''​ se face prin metoda publică ''​publish()''​, care primește ca parametrii locația la care va fi disponibilă descrierea serviciului web (locația fișierului WSDL) precum și implementarea propriu-zisă a serviciului web:+Crearea și publicarea unui obiect de tip ''​Endpoint''​ se face prin una dintre implementările metodei publice [[http://​docs.oracle.com/​javaee/​7/​api/​javax/​xml/​ws/​Endpoint.html#​publish-java.lang.String-java.lang.Object-|publish()]], care primește ca parametrii locația la care va fi disponibilă descrierea serviciului web (locația fișierului WSDL) precum și implementarea propriu-zisă a serviciului web:
  
 <code java> <code java>
Line 137: Line 137:
 <note tip>​Metoda ''​publish()''​ nu este blocantă, astfel încât pot fi realizate și alte operații după crearea și publicarea unui serviciu web.</​note>​ <note tip>​Metoda ''​publish()''​ nu este blocantă, astfel încât pot fi realizate și alte operații după crearea și publicarea unui serviciu web.</​note>​
  
-<note tip>​Opțional,​ metoda poate primi niște parametri de tip ''​WebServiceFeature'' ​prin care se poate configura obiectul de tip ''​Endpoint''​.</​note>​+<note tip>​Opțional,​ metoda poate primi niște parametri de tip [[http://​docs.oracle.com/​javaee/​7/​api/​javax/​xml/​ws/​WebServiceFeature.html|javax.xml.ws.WebServiceFeature]] ​prin care se poate configura obiectul de tip ''​Endpoint''​.</​note>​
  
 <note tip>În situația în care se folosește un sistem de gestiune a securității,​ este necesar ca aplicația să dețină permisiunea ''​WebServicePermission("​publishEndpoint"​)'',​ în caz contrar generându-se o excepție de tip ''​SecurityException''​.</​note>​ <note tip>În situația în care se folosește un sistem de gestiune a securității,​ este necesar ca aplicația să dețină permisiunea ''​WebServicePermission("​publishEndpoint"​)'',​ în caz contrar generându-se o excepție de tip ''​SecurityException''​.</​note>​
  
-Un serviciu web care este publicat poate fi făcut indisponibil prin intermediul metodei ​''​Endpoint.stop()''​. +Un serviciu web care este publicat poate fi făcut indisponibil prin intermediul metodei ​[[http://​docs.oracle.com/​javaee/​7/​api/​javax/​xml/​ws/​Endpoint.html#​stop--|stop()]] a clasei ''​Endpoint''​.
  
 ===== Utilizarea JAXB pentru conversia dintre clase Java și scheme XML ===== ===== Utilizarea JAXB pentru conversia dintre clase Java și scheme XML =====
Line 203: Line 202:
  
 ^  Adnotare ​ ^  Descriere ​ ^ ^  Adnotare ​ ^  Descriere ​ ^
-''​@XmlRootElement(namespace="​..."​)'' ​| defineşte elementul rădăcină din cadrul schemei XML | +[[https://​docs.oracle.com/​javase/​7/​docs/​api/​javax/​xml/​bind/​annotation/​XmlRootElement.html|@XmlRootElement(namespace="​..."​)]]| defineşte elementul rădăcină din cadrul schemei XML | 
-''​@XmlElement'' ​| face conversia între o proprietate JavaBeans sau un câmp al unei clase şi un atribut XML | +[[https://​docs.oracle.com/​javase/​7/​docs/​api/​javax/​xml/​bind/​annotation/​XmlElement.html|@XmlElement]] | face conversia între o proprietate JavaBeans sau un câmp al unei clase şi un atribut XML | 
-''​@XmlAccesorType(XMLAccessType.PACKAGE|FIELD)'' ​| este aplicat unui pachet sau unei clase Java, specificând daca proprietăţile JavaBeans sau atributele vor fi serializate | +[[https://​docs.oracle.com/​javase/​7/​docs/​api/​javax/​xml/​bind/​annotation/​XmlAccessorType.html|@XmlAccesorType(XMLAccessType.PACKAGE|FIELD)]] | este aplicat unui pachet sau unei clase Java, specificând daca proprietăţile JavaBeans sau atributele vor fi serializate | 
-''​@XmlType(propOrder={"​atr<​sub>​1</​sub>​","​atr<​sub>​2</​sub>​",​...,"​atr<​sub>​n</​sub>​"})'' ​| permite stabilirea structurii documentului XML prin indicarea ordinii în care atributele clasei vor fi copiate |+[[https://​docs.oracle.com/​javase/​7/​docs/​api/​javax/​xml/​bind/​annotation/​XmlType.html|@XmlType(propOrder={"​atr_1","​atr_2",​...,"​atr_n"})]] | permite stabilirea structurii documentului XML prin indicarea ordinii în care atributele clasei vor fi copiate |
  
 JAXB pune la dispoziţie un utilitar pentru compilarea unei scheme XML într-o clasă Java – denumit ''​xjc''​ –, un utilitar de generare a unei scheme XML dintr-o clasă Java – denumit ''​schemagen''​ şi un cadru general de rulare. Astfel, se poate porni de la o definiţie a unei scheme XML (XSD – XML Schema Definition),​ creându-se obiecte JavaBeans corespunzătoare (folosind compilatorul pentru scheme XML ''​xjc''​) sau se poate porni de la obiecte JavaBeans creându-se definiţiile unei scheme XML corespunzătoare (folosind utilitarul ''​schemagen''​). ​ JAXB pune la dispoziţie un utilitar pentru compilarea unei scheme XML într-o clasă Java – denumit ''​xjc''​ –, un utilitar de generare a unei scheme XML dintr-o clasă Java – denumit ''​schemagen''​ şi un cadru general de rulare. Astfel, se poate porni de la o definiţie a unei scheme XML (XSD – XML Schema Definition),​ creându-se obiecte JavaBeans corespunzătoare (folosind compilatorul pentru scheme XML ''​xjc''​) sau se poate porni de la obiecte JavaBeans creându-se definiţiile unei scheme XML corespunzătoare (folosind utilitarul ''​schemagen''​). ​
Line 433: Line 432:
 De remarcat faptul că adnotarea ''​@XmlElement''​ va fi indicată pentru metoda getter asociată atributului respectiv şi nu pentru atributul în sine. De remarcat faptul că adnotarea ''​@XmlElement''​ va fi indicată pentru metoda getter asociată atributului respectiv şi nu pentru atributul în sine.
  
-<note tip>​Adnotarea ''​@XmlElement''​ se precizează pentru metodele getter întrucât acestea sunt publice, spre diferenţă de atributele în sine care au modul de acces privat. Într-o distribuţie anterioară a JAX-WS, adnotarea ​''​@XmlAttribute'' ​se definea pentru atributele clasei.</​note>​+<note tip>​Adnotarea ''​@XmlElement''​ se precizează pentru metodele getter întrucât acestea sunt publice, spre diferenţă de atributele în sine care au modul de acces privat. Într-o distribuţie anterioară a JAX-WS, adnotarea ​[[https://​docs.oracle.com/​javase/​7/​docs/​api/​javax/​xml/​bind/​annotation/​XmlAttribute.html|@XmlAttribute]] se definea pentru atributele clasei.</​note>​
  
-De asemenea, ​necesară asigurarea persistenţei pentru obiectele ​de tipul ''​ArrayList<​Interval>'' ​''​ArrayList<​ReservationData>'':​ ''​timetable''​ / ''​reservationData''​. Prin JAXB, starea acestor obiecte poate fi reţinută prin intermediul ​unor documente ​XML pe serverspecificându-se un mecanism ​de transformare. Astfel, se vor defini clasele ''​PersistentInterval''​ / ''​PersistentReservationData'',​ conţinând două atribute ''​ArrayList<​GregorianCalendar>'',​ respectiv două atribute ''​ArrayList<​Integer>''​ şi ''​ArrayList<​GregorianCalendar>''​ (pentru ​care este cunoscut mecanismul ​de transformare în document XML), adnotările în cadrul acestei clase (''​@XmlRootElement'',​ ''​@XmlElement''​indicând modul cum informaţiile din obiecte vor fi transpuse în documentul XML. Trebuie definite metode setter ​getter corespunzătoare pentru accesarea informaţiilor necesare. +Pot exista situații în care instanțale obiectelor serializabile,​ implicate în metodele expuse sub formă de servicii web ca parametri sau valori întoarse să trebuiască să fie salvate ​încărcate pe server sub forma unor fișiere ​XML, între invocări succesive ale acestora. O astfel ​de funcționalitate poate fi necesară în situația în care este utilizat un server ​de aplicații care nu menține obiectul asociat serviciului web și nici proprietățile pe care acesta le conține ​(acesta menținând o stare intermediară). În acest scop pot fi utilizate funcționalitățile puse la dispoziție de clasa [[http://docs.oracle.com/javaee/7/api/javax/xml/​bind/​JAXBContext.html|javax.xml.bind.JAXBContext]]. Aceste ​obiecte ​sunt de regulă instanțiate pe constructorul clasei care implementează metodele serviciului webfolosindu-se una dintre implementările metodei statice [[http://​docs.oracle.com/​javaee/​7/​api/javax/​xml/​bind/​JAXBContext.html#​newInstance-java.lang.Class...-|newInstance()]].
- +
-<file java PersistentInterval.java> +
-@XmlRootElement +
-public class PersistentInterval { +
- +
-    private int numberOfSeats;​ +
-    private ArrayList<​GregorianCalendar>​ startingIntervals;​ +
-    private ArrayList<​GregorianCalendar>​ endingIntervals;​ +
- +
-    @XmlElement +
-    public int getNumberOfSeats() { +
-        return numberOfSeats;​ +
-    }     +
- +
-    @XmlElement +
-    public ArrayList<​GregorianCalendar>​ getStartingIntervals() { +
-        return startingIntervals;​ +
-    } +
-     +
-    @XmlElement +
-    public ArrayList<​GregorianCalendar>​ getEndingIntervals() { +
-        return endingIntervals;​ +
-    } +
-+
-</file> +
- +
-<file java PersistentReservationData.java>​ +
-@XmlRootElement +
-public class PersistentReservationData {  +
-    +
-    private ArrayList<​Integer>​ customerIds; ​       +
-    private ArrayList<​GregorianCalendar>​ startingIntervals; ​    +
-    private ArrayList<​GregorianCalendar>​ endingIntervals;​ +
-    private ArrayList<​Integer>​ numberOfSeats;​ +
-     +
-    @XmlElement +
-    public ArrayList<​Integer>​ getCustomerIds() { +
-        return customerIds;​ +
-    } +
- +
-    @XmlElement +
-    public ArrayList<​GregorianCalendar>​ getStartingIntervals() { +
-        return startingIntervals;​ +
-    } +
- +
-    @XmlElement +
-    public ArrayList<​GregorianCalendar>​ getEndingIntervals() { +
-        return endingIntervals;​ +
-    } +
- +
-    @XmlElement +
-    public ArrayList<​Integer>​ getNumberOfSeats() { +
-        return numberOfSeats;​ +
-    } +
-+
-</file> +
- +
-Astfel un obiect de tipul ''​ArrayList<​Interval>'' ​''​ArrayList<​ReservationData>''​ pentru care nu era cunoscut modul de transformare în document XML este împărţit în obiecte de tipul ''​ArrayList<​GregorianCalendar>'',​ funcţionalitatea acestora fiind asemănătoare. Deşi modalitatea de transformare este cunoscută pentru clasa ''​Interval''​trebuie specificat mecanismul de transformare pentru tipul de date ''​ArrayList<​Interval>'',​ astfel încât operaţiile de împachetare şi despachetare să fie realizate pentru obiecte de acest felPentru uşurinţa accesului la datele conţinute în obiect, au fost definite două atribute corespunzătoare celor din clasa ''​Interval''​Similar pentru ''​ReservationData'' ​''​ArrayList<​ReservationData>''​. +
- +
-De remarcat faptul că adnotarea ''​@XmlElement''​ va fi indicată pentru metoda getter asociată atributului respectiv şi nu pentru atributul în sine. +
- +
-<note tip>​Adnotarea ''​@XmlElement''​ se precizează pentru metodele getter întrucât acestea sunt publice, spre diferenţă de atributele în sine care au modul de acces privatÎntr-o distribuţie anterioară a JAX-WS, adnotarea ''​@XmlAttribute''​ se definea pentru atributele clasei.</​note>​ +
- +
-Operaţiile asupra obiectelor ''​timetable''​ şi ''​reservationData''​ vor implica încărcarea,​ respectiv descărcarea lor din fişierele care le reţin starea.+
  
 <code java> <code java>
-JAXBContext ​contextPersistentInterval+JAXBContext ​contextBookInformation
-JAXBContext ​contextPersistentReservationData;+JAXBContext ​contextBookInformationDetailed;
  
-public ​Reservation() { +public ​BookManager() { 
-    try { +  try { 
-        ​contextPersistentInterval ​= JAXBContext.newInstance(PersistentInterval.class); +    ​contextBookInformation ​= JAXBContext.newInstance(BookInformation.class); 
-        ​contextPersistentReservationData ​= JAXBContext.newInstance(PersistentReservationData.class); +    ​contextBookInformationDetailed ​= JAXBContext.newInstance(BookInformationDetailed.class); 
-    } +  } catch (Exception exception) { 
-    ​catch (Exception exception) {  +    System.out.println("​An exception has occurred: " + exception.getMessage());​ 
-        System.out.println("​An exception has occurred: "​+exception.getMessage());​ +    if (Constants.DEBUG) ​{ 
-        if (Constants.DEBUG) +      exception.printStackTrace();​
-            exception.printStackTrace(); +
-    } +
-     +
-    if (new File("​timetable.xml"​).exists()) { +
-        timetable = unpackPersistentInterval("​timetable.xml"​);​ +
-        numberOfSeats = timetable.getNumberOfSeats();​ +
-    } else { +
-        timetable = new PersistentInterval();​ +
-        packPersistentInterval(timetable,​ "​timetable.xml"​);​ +
-    } +
-     +
-    if (new File("​reservationData.xml"​).exists()) { +
-        reservationData =  +
-        unpackPersistentReservationData("​reservationData.xml"​);​ +
-    } else { +
-        reservationData = new PersistentReservationData(); ​           +
-        packPersistentReservationData(reservationData,"​reservationData.xml"​);+
     }     }
 +  }
 +  // ...
 } }
 </​code>​ </​code>​
  
-Contextul JAXB referitor la persistenţă va fi iniţializat cu tipul de date pentru care se doreşte conversia. Obiectele ''​timetable''​ şi ''​reservationData''​ sunt încărcate din fişier în constructor (în condiţiile în care fişierul corespunzator există, altfel aceste obiecte ​sunt create împreună cu fişierele care le reţin starea)descărcarea stării în fişier urmând a fi realizată în cadrul operaţiilor ''​makeReservation()''​ ş''​cancelReservation()'',​ care acţionează asupra lor. +Operațiile ​de salvare / încărcare în / din fișier sunt realizate prin intermediul claselor [[http://​docs.oracle.com/​javaee/​7/​api/​javax/​xml/​bind/​Marshaller.html|javax.xml.bind.Marshaller]]respectiv [[http://​docs.oracle.com/​javaee/​7/​api/​javax/​xml/​bind/​Unmarshaller.html|javax.xml.bind.Unmarshaller]],​ instanțe ale acestora fiind furnizate prin intermediul metodelor [[http://​docs.oracle.com/​javaee/​7/​api/​javax/​xml/​bind/​Marshaller.html#​marshal-java.lang.Object-java.io.OutputStream-|marshal()]] ș[[http://​docs.oracle.com/​javaee/​7/​api/​javax/​xml/​bind/​Unmarshaller.html#​unmarshal-org.xml.sax.InputSource-|unmarshal()]].
- +
-Pentru aceasta, se vor implementa mecanismele corespunzătoare de împachetare şi despachetare puse la dispoziţie de contextul JAXB.+
  
 <code java> <code java>
-public final void packPersistentInterval(PersistentInterval ​object, String file) { +public final void packBookInformation(BookInformation ​object, String file) { 
-    try { +  try { 
-        Marshaller conversion = contextPersistentInterval.createMarshaller();​ +    Marshaller conversion = contextBookInformation.createMarshaller();​ 
-        conversion.marshal(object,​ new FileOutputStream(file)); ​              +    conversion.marshal(object,​ new FileOutputStream(file)); ​              
-    } +  } catch (Exception exception) { 
-    ​catch (Exception exception) { +    System.out.println("​An exception has occurred: " + exception.getMessage()); 
-        System.out.println("​An exception has occurred: "​+exception.printStackTrace()); +    if (Constants.DEBUG) ​{ 
-        if (Constants.DEBUG) +      exception.printStackTrace();​
-            exception.printStackTrace();​+
     }     }
 +  }
 } }
-    ​ +  
-public final void packPersistentReservationData(PersistentReservationData ​object, String file) { +public final void packBookInformationDetailed(BookInformationDetailed ​object, String file) { 
-    try { +  try { 
-        Marshaller conversion = contextPersistentReservationData.createMarshaller();​ +    Marshaller conversion = contextBookInformationDetailed.createMarshaller();​ 
-        conversion.marshal(object,​ new FileOutputStream(file)); ​              +    conversion.marshal(object,​ new FileOutputStream(file)); ​              
-    } +  } catch (Exception exception) { 
-    ​catch (Exception exception) { +    System.out.println("​An exception has occurred: " + exception.getMessage()); 
-        System.out.println("​An exception has occurred: "​+exception.printStackTrace()); +    if (Constants.DEBUG) ​{ 
-        if (Constants.DEBUG) +      exception.printStackTrace();​ 
-            exception.printStackTrace(); ​    +    ​}   
-    }+  ​}
 }        }       
-      +  
-public final PersistentInterval unpackPersistentInterval(String file) { +public final BookInformation unpackBookInformation(String file) { 
-    try { +  try { 
-        Unmarshaller conversion = contextPersistentInterval.createUnmarshaller();​ +    Unmarshaller conversion = contextBookInformation.createUnmarshaller();​ 
-        return (PersistentInterval)conversion.unmarshal(new FileInputStream(file));  ​+    return (BookInformation)conversion.unmarshal(new FileInputStream(file));  ​ 
 +  } catch (Exception exception) { 
 +    System.out.println("​An exception has occurred: " + exception.getMessage());​ 
 +    if (Constants.DEBUG) { 
 +      exception.printStackTrace();​
     }     }
-    catch (Exception exception) { +  ​
-        System.out.println("​An exception has occurred: "​+exception.printStackTrace());​ +  return null;
-        if (Constants.DEBUG) +
-            exception.printStackTrace(); ​    +
-    ​+
-    return null;+
 } }
-    ​ +  
-public final PersistentReservationData unpackPersistentReservationData(String file) { +public final BookInformationDetailed unpackBookInformationDetailed(String file) { 
-    try { +  try { 
-        Unmarshaller conversion = contextPersistentReservationData.createUnmarshaller();​ +    Unmarshaller conversion = contextBookInformationDetailed.createUnmarshaller();​ 
-        return (PersistentReservationData)conversion.unmarshal(new FileInputStream(file));  ​+    return (BookInformationDetailed)conversion.unmarshal(new FileInputStream(file));  ​ 
 +  } catch (Exception exception) { 
 +    System.out.println("​An exception has occurred: " + exception.getMessage());​ 
 +    if (Constants.DEBUG) { 
 +      exception.printStackTrace();​
     }     }
-    catch (Exception exception) { +  ​
-        System.out.println("​An exception has occurred: "​+exception.printStackTrace());​ +  return null;
-        if (Constants.DEBUG) +
-            exception.printStackTrace(); ​    +
-    ​+
-    return null;+
 } }
 </​code>​ </​code>​
Line 689: Line 607:
 Totodată, sunt generate şi clasele corespunzătoare obiectelor transmise ca parametrii sau rezultate întoarse, în care tipul atributelor este însă transformat astfel încât să poată fi transmise prin infrastructura de comunicaţie. ​ Totodată, sunt generate şi clasele corespunzătoare obiectelor transmise ca parametrii sau rezultate întoarse, în care tipul atributelor este însă transformat astfel încât să poată fi transmise prin infrastructura de comunicaţie. ​
  
-<​note>​Spre exemplu, în cazul claselor ''​Interval''​ / ''​ReservationData'',​ obiectele de tip ''​GregorianCalendar''​ sunt convertite în mod automat la tipul de date echivalent ''​XMLGregorianCalendar''​. +<​note>​Spre exemplu, în unei cazul unei proprietăți având tipul ''​String'' ​din cadrul unei clase serializabile,​ au loc următoarele transformări în momentul transmisiei ​prin infrastructura de comunicației: ''​String''​ → ''​xs:​string''​ → ''​String''​.</​note>​
- +
-Transformările suferite de un astfel de obiect la transferul său de la server, prin infrastructura de comunicație șpână la client sunt: ''​GregorianCalendar'' ​→ ''​xs:​dateTime''​ → ''​XMLGregorianCalendar''​. +
- +
-Transformările suferite de un astfel de obiect la transferul său de la clinet, ​prin infrastructura de comunicație și până la server sunt: ''​XMLGregorianCalendar''​ → ''​xs:​anySimpleType''​ → ''​java.lang.Object''​ → ''​GregorianCalendar''​.</​note>​+
  
 Invocările metodelor implementate în cadrul serviciului web se fac printr-un obiect local care funcţionează ca un delegat pentru serviciul la distanţă. Acesta este obţinut ca port al unei alte clase generate pe baza serviciului web în care sunt definite metodele, având denumirea sufixată de ''​_Service''​. Invocările metodelor implementate în cadrul serviciului web se fac printr-un obiect local care funcţionează ca un delegat pentru serviciul la distanţă. Acesta este obţinut ca port al unei alte clase generate pe baza serviciului web în care sunt definite metodele, având denumirea sufixată de ''​_Service''​.
Line 724: Line 638:
 Pe baza acestei descrieri, vor fi generate în mod automat clasele responsabile cu transportul parametrilor și valorilor întoarse ale metodelor accesibile la distanță. Pe baza acestei descrieri, vor fi generate în mod automat clasele responsabile cu transportul parametrilor și valorilor întoarse ale metodelor accesibile la distanță.
  
-În situația în care există mai multe servicii web care pun la dispoziție aceeași funcționalitate (aceleași metode accesibile la distanță),​ dar cu implementări diferite, există posibilitatea **invocării dinamice** (în momentul execuției),​ serviciul fiind obținut pe baza metodei statice ​''​create()'' ​din cadrul clasei ​''​Service''​, primind ca parametrii denumirea sa și locația la care este disponibil documentul WSDL ce îi descrie funcționalitatea:​+În situația în care există mai multe servicii web care pun la dispoziție aceeași funcționalitate (aceleași metode accesibile la distanță),​ dar cu implementări diferite, există posibilitatea **invocării dinamice** (în momentul execuției),​ serviciul fiind obținut pe baza metodei statice ​[[https://​docs.oracle.com/​javaee/​7/​api/​javax/​xml/​ws/​Service.html#​create-java.net.URL-javax.xml.namespace.QName-|create()]] din cadrul clasei ​[[https://​docs.oracle.com/​javaee/​7/​api/​javax/​xml/​ws/​Service.html|javax.xml.ws.Service]], primind ca parametrii denumirea sa și locația la care este disponibil documentul WSDL ce îi descrie funcționalitatea:​
  
 <code java> <code java>
Line 745: Line 659:
 </​code>​ </​code>​
  
-Ulterior, funcționalitatea îi poate fi invocată prin intermediul metodei ​''​getPort()'' ​a obiectului de tip ''​Service'',​ care primește ca parametru clasa pe care o reprezintă (la care va fi convertit):+Ulterior, funcționalitatea îi poate fi invocată prin intermediul metodei ​[[https://​docs.oracle.com/​javaee/​7/​api/​javax/​xml/​ws/​Service.html#​getPort-java.lang.Class-|getPort()]] a obiectului de tip ''​Service'',​ care primește ca parametru clasa pe care o reprezintă (la care va fi convertit):
  
 <code java> <code java>
Line 761: Line 675:
 ==== Dezvoltarea serverului ==== ==== Dezvoltarea serverului ====
  
-Se creează un proiect de tip Java Web → Web Application.+Se creează un proiect de tip //Java Web// → //Web Application//.
  
 {{ :​laboratoare:​laborator07:​netbeans_server01.png?​nolink&​600 }} {{ :​laboratoare:​laborator07:​netbeans_server01.png?​nolink&​600 }}
Line 902: Line 816:
  
 {{ :​laboratoare:​laborator07:​netbeans_client03.png?​nolink }} {{ :​laboratoare:​laborator07:​netbeans_client03.png?​nolink }}
- 
-<note tip>​Opțiunea //Clean// din meniul contextual asociat proiectului determină pierderea claselor generate.</​note>​ 
  
 De asemenea, este necesar să se bifeze opțiunea //Also replace local wsdl file with original wsdl located at://, astfel încât să se descarce definiția serviciului web (fișierul WSDL) de la locația în care a fost publicat de către server: De asemenea, este necesar să se bifeze opțiunea //Also replace local wsdl file with original wsdl located at://, astfel încât să se descarce definiția serviciului web (fișierul WSDL) de la locația în care a fost publicat de către server:
  
-{{ :​laboratoare:​laborator07:​netbeans_client04.png?​nolink&​600 ​}}+{{ :​laboratoare:​laborator07:​netbeans_client04.png?​nolink }}
  
 Clasele generate sunt vizibile în secțiunea //Generated Sources (jax-ws)//. Clasele generate sunt vizibile în secțiunea //Generated Sources (jax-ws)//.
  
-{{ :​laboratoare:​laborator07:​netbeans_client05.png?​nolink }+{{ :​laboratoare:​laborator07:​netbeans_client05.png?​nolink }
 + 
 +<note tip>​Opțiunea //Clean// din meniul contextual asociat proiectului determină pierderea claselor generate.</​note>​
  
 Operaţiile pot fi testate din consola serverului de aplicaţii GlassFish, disponibile la [[http://​localhost:​8080/​07-BookStore-JAXWS-Server/​BookManager?​Tester|]]. Invocarea unei funcţionalităţi în acest caz este întotdeauna însoţită de mesajele SOAP care sunt schimbate între client şi server, fiind descrise cererea (invocarea metodei din cadrul serviciului web) precum şi răspunsul (rezultatul execuţiei operaţiei respective în contextul serverului unde rulează serviciul web). Operaţiile pot fi testate din consola serverului de aplicaţii GlassFish, disponibile la [[http://​localhost:​8080/​07-BookStore-JAXWS-Server/​BookManager?​Tester|]]. Invocarea unei funcţionalităţi în acest caz este întotdeauna însoţită de mesajele SOAP care sunt schimbate între client şi server, fiind descrise cererea (invocarea metodei din cadrul serviciului web) precum şi răspunsul (rezultatul execuţiei operaţiei respective în contextul serverului unde rulează serviciul web).
  
-{{ :​laboratoare:​laborator07:​netbeans_client06.png?​nolink&​800 ​}}+{{ :​laboratoare:​laborator07:​netbeans_client06.png?​nolink }}
  
 Pentru exemplul considerat, în cazul metodelor ''​getBooksList()'',​ ''​getBooksListWithStockpile()''​ pot fi vizualizate referinţe (adrese) către obiecte de tip ''​BookInformation''​ / ''​BookInformationDetailed''​. În situația în care metodele ar fi primit ca parametri tipuri de date derivate din ''​java.lang.Object'',​ o astfel de consolă nu ar putea fi utilizată, întrucât ar trebui furnizate referințele către aceste obiecte. Pentru exemplul considerat, în cazul metodelor ''​getBooksList()'',​ ''​getBooksListWithStockpile()''​ pot fi vizualizate referinţe (adrese) către obiecte de tip ''​BookInformation''​ / ''​BookInformationDetailed''​. În situația în care metodele ar fi primit ca parametri tipuri de date derivate din ''​java.lang.Object'',​ o astfel de consolă nu ar putea fi utilizată, întrucât ar trebui furnizate referințele către aceste obiecte.
Line 984: Line 898:
 ===== Activitate de Laborator ===== ===== Activitate de Laborator =====
  
 +**0**. Să se cloneze în directorul de pe discul local conținutul depozitului la distanță de la [[https://​www.github.com/​aipi2015/​Laborator07]]. În urma acestei operații, directorul Laborator07 va trebui să conțină subdirectorul ''​labtasks'',​ fișierele ''​README.md''​ și ''​LICENSE''​.
 +
 +<​code>​
 +student@aipi2015:​~$ git clone https://​www.github.com/​aipi2015/​Laborator07.git
 +</​code>​
 +
 +**1**. Să se ruleze, folosind MySQL Workbench (sau alt utilitar similar), scripturile ''​Laborator07c.sql''​ și ''​Laborator07l.sql'',​ localizate în directorul ''​scripts''​ din cadrul proiectului ''​07-BookStore-JAXWS-Server''​. Acesta instalează baza de date ''​bookstore''​.
 +
 +<​note>​În cazul în care baza de date ''​bookstore''​ este deja instalată, nu mai este necesar să se ruleze acest script.</​note>​
 +
 +<note important>​Această operație poate dura o perioadă de timp îndelungată,​ în funcție de configurațiile mașinilor pe care se lucrează.</​note>​
 +
 +**2**. Să se modifice credențialele (nume de utilizator și parolă), astfel încât să se poată accesa informațiile din baza de date MySQL.
 +
 +==== Eclipse ====
 +
 +Este suficient să se modifice proprietățile ''​javax.persistence.jdbc.user'',​ respectiv ''​javax.persistence.jdbc.password''​ din fișierul ''​persistence.xml'',​ localizat în directorul ''​src/​META-INF'',​ întrucât în această situație este folosit un server local, iar accesul la sistemul de gestiune pentru baze de date se realizează din contextul acestuia.
 +
 +==== NetBeans ====
 +
 +În cazul în care accesul la sistemul de gestiune pentru baze de date se realizează din contextul unui server de aplicații (GlassFish 4.1), este necesar să se definească o resursă la nivelul acestuia, referința către aceasta fiind identificată prin intermediul JNDI (Java Naming and Directory Interface).
 +
 +În acest sens, în fișierul ''​persistence.xml''​ vor fi realizate următoarele modificări:​
 +  * atributul ''​transaction-type''​ din cadrul elementului ''​persistence-unit''​ va avea valoarea ''​JTA'';​
 +  * informațiile cu privire la conexiunea la sistemul de gestiune pentru baze de date vor fi specificate printr-o resursă JNDI, a cărui referință este indicată în cadrul elementului ''​jta-data-source'';​
 +  * nu mai sunt necesare proprietățile ''​javax.persistence.jdbc.url'',​ ''​javax.persistence.jdbc.user'',​ ''​javax.persistence.jdbc.password'',​ ''​javax.persistence.jdbc.driver'',​ acestea fiind conținute în resursa definită la nivelul serverului de aplicație;
 +  * în secțiunea de proprietăți,​ se va defini proprietatea ''​hibernate.transaction.jta.platform''​ cu valoarea ''​org.hibernate.service.jta.platform.internal.SunOneJtaPlatform''​.
 +
 +Definirea unei resurse JDBC în cadrul serverului de aplicație GlassFish implică [[https://​dev.mysql.com/​doc/​connector-j/​en/​connector-j-usagenotes-glassfish-config.html|următoarele etape]]:
 +
 +**a**. se accesează secțiunea //JDBC Connection Pools// disponibilă în //​Resources//​ → //JDBC// și se apasă butonul //New// pentru a se defini un nou set de conexiuni:
 +
 +{{ :​laboratoare:​laborator07:​netbeans_glassfish01.png?​nolink&​800 }}
 +
 +**b**. se specifică proprietățile:​
 +  * //Pool Name//, va avea o valoare definită de utilizator, spre exemplu: ''​MySQLConnectionPool'';​
 +  * //Resource Type//, trebuie să aibă valoarea ''​javax.sql.DataSource''​ selectată din lista de opțiuni;
 +  * //Database Driver Vendor//, trebuie să aibă valoarea ''​MySQL''​ selectată din lista de opțiuni;
 +
 +<note important>​Este necesar ca driver-ul de conexiune la sistemul de gestiune pentru baze de date (Connector/​J = mysql-connector) să se găsească în classpath-ul serverului de aplicații Glassfish: ''<​glassfish-install-directory>/​glassfish/​domains/<​domain-name>/​lib''​. Implicit, se va folosi ''​domain1''​ ca denumire a domeniului.</​note>​
 +
 +{{ :​laboratoare:​laborator07:​netbeans_glassfish02.png?​nolink&​800 }}
 +
 +Se apasă butonul //Next//.
 +
 +{{ :​laboratoare:​laborator07:​netbeans_glassfish03.png?​nolink&​800 }}
 +
 +În secțiunea //Aditional Properties//,​ trebuie specificate următoarele proprietăți:​
 +  * //​ServerName//​ cu valoarea ''​localhost'';​
 +  * //Port// cu valoarea ''​3306'';​
 +  * //User// cu valoarea numelui de utilizator prin intermediul căruia se va realiza conexiunea (''​root''​);​
 +  * //​Password//​ cu valoarea parolei prin intermediul căreia se va realiza conexiunea (''​StudentAipi2015''​);​
 +  * //​DatabaseName//​ cu valoarea bazei de date care va fi exploatată (''​bookstore''​).
 +
 +{{ :​laboratoare:​laborator07:​netbeans_glassfish04.png?​nolink&​800 }}
 +
 +Se apasă butonul //Finish//.
 +
 +Noul set de conexiuni va fi vizibil în secțiunea //​Resources//​ → //JDBC// → //JDBC Connection Pools//.
 +
 +{{ :​laboratoare:​laborator07:​netbeans_glassfish05.png?​nolink&​800 }}
 +
 +Se accesează resursa creată în panoul //​Advanced//​.
 +
 +{{ :​laboratoare:​laborator07:​netbeans_glassfish06.png?​nolink&​800 }}
 +
 +În secțiunea //​Connection Validation//​ se specifică următoarele proprietăți,​ necesare datorită faptului că driver-ul de conexiune la sistemul de gestiune pentru baze de date Connector/J nu suportă optimizarea interogărilor pentru validare:
 +  * //​Connection Validation//:​ ''​Required'';​
 +  * //​Validation Method//: se selectează valoarea ''​table''​ din lista de opțiuni;
 +  * //Table Name//: se introduce valoarea ''​DUAL''​.
 +
 +{{ :​laboratoare:​laborator07:​netbeans_glassfish07.png?​nolink&​800 }}
 +
 +Se apasă butonul //Save// astfel încât modificările realizate să fie preluate.
 +
 +Pentru a se verifica starea conectivității la sistemul de gestiune pentru baze de date, în panoul //​General//,​ se apasă butonul //Ping//. În situația în care rezultatul furnizat este //Ping Succeeded//,​ conexiunea a fost configurată corect.
 +
 +{{ :​laboratoare:​laborator07:​netbeans_glassfish08.png?​nolink }}
 +
 +**c**. se accesează secțiunea //JDBC Resources// disponibilă în //​Resources//​ → //JDBC// și se apasă butonul //New// pentru a se defini o nouă resursă:
 +
 +{{ :​laboratoare:​laborator07:​netbeans_glassfish09.png?​nolink&​800 }}
 +
 +**d**. se specifică proprietățile:​
 +  * //JNDI Name//, va avea o valoare definită de utilizator, spre exemplu: ''​jdbc/​MySQLDataSource'';​ aceeași valoare trebuie să fie specificată și în elementul ''​jta-data-source''​ din fișierul ''​persistence.xml'';​
 +  * //Pool Name//, va referi setul de conexiuni definit anterior (spre exemplu, ''​MySQLConnectionPool''​),​ disponibil într-o listă de opțiuni.
 +
 +{{ :​laboratoare:​laborator07:​netbeans_glassfish10.png?​nolink&​800 }}
 +
 +Se apasă butonul //Ok//.
 +
 +Noua resursă va fi vizibilă în secțiunea //​Resources//​ → //JDBC// → //JDBC Resources//​.
 +
 +{{ :​laboratoare:​laborator07:​netbeans_glassfish11.png?​nolink&​800 }}
 +
 +===== =====
 +
 +**3**. Să se ruleze proiectul corespunzător serverului (''​07-BookStore-JAXWS-Server''​).
 +
 +==== Eclipse ====
 +
 +Proiectul se rulează ca aplicație Java (//Run As...// → //Java Application//​). Nu este necesară definirea unei configurații de rulare dedicate, întrucât nu trebuie specificați nici argumente în linia de comandă și nici parametrii ai mașinii virtuale. Aplicația va rămâne în execuție întrucât metoda ''​Endpoint.publish()''​ creează o instanță a unui server local, prin intermediul căruia vor fi expuse metodele corespunzătoare serviciului web.
 +
 +==== NetBeans ====
 +
 +Proiectul este instalat la nivelul serverului de aplicații GlassFish 4.1 prin intermediul opțiunii //Deploy// disponibilă la nivelul meniului contextual asociat. Aceasta lansează în execuție serverul de aplicații (dacă acesta nu rulează deja) și copiază în contextul său resursele necesare astfel încât funcționalitățile corespunzătoare serviciului web să fie disponibile la distanță. O astfel de operație poate dura o perioadă de timp semnificativă.
 +
 +===== =====
 +
 +**4**. Să se ruleze proiectul corespunzător unuia dintre clienți (''​07-BookStore-JAXWS-Client-BookManager''​). Să se testeze funcționalitățile expuse prin intermediul serviciului web.
 +
 +Anterior, trebuie să se genereze clasele care conțin definiția serviciului web (clasa ''​_Service''​),​ definițiile metodelor la distanță (clasele ''​Operation'',​ respectiv ''​OperationResponse'',​ pentru fiecare funcționalitate în parte), definițiile entităților transmise ca parametrii sau valori întoarse ale acestora precum și fabrica de obiecte (clasa ''​ObjectFactory''​).
 +
 +==== Eclipse ====
 +
 +Este necesar să se ruleze script-ul ''​client[.bat|.sh]''​ care rulează comanda ''​wsimport''​ necesară generării claselor necesare pentru accesarea metodelor expuse prin intermediul serviciului web:
 +
 +<​code>​
 +wsimport -s ../src http://​localhost:​8080/​bookstore/​BookManager?​wsdl
 +</​code>​
 +
 +Se indică locația la care este publicat fișierul WSDL conținând definiția serviciului web precum și locația la care va fi plasat codul sursă, prin intermediul opțiunii ''​-s''​.
 +
 +==== NetBeans ====
 +
 +Este necesar să se creeze un client pentru serviciul web (definirea unei resurse de tip //Web Service Client// din secțiunea //New// a meniului contextual asociat proiectului). Aceasta va specifica adresa Internet la care a fost publicat fișierul WSDL ([[http://​localhost:​8080/​07-BookStore-JAXWS-Server/​BookManager?​wsdl]]). Ulterior, generarea codului sursă se face prin accesarea opțiunii //Refresh// din meniul contextual asociat referinței la serviciul web. Se va folosi opțiunea //Also replace local wsdl file with original wsdl located at//. Clasele generate vor fi evidențiate prin plasarea lor în secțiunea //Generated Sources (jax-ws)//.
 +
 +===== =====
 +
 +După ce au fost generate clasele necesare, astfel încât proiectele să nu mai aibă erori, rularea proiectului se face obișnuit (//Run As...// → //Java Application//,​ pentru Eclipse, respectiv //Run// folosind configurația de rulare implicită, pentru NetBeans).
 +
 +**5**. Să se expună metodele corespunzătoare clasei ''​BookPresentationManager''​ din pachetul ''​ro.pub.cs.aipi.lab07.businesslogic'',​ astfel încât acestea să fie accesibile la distanță prin intermediul unui serviciu web același denumire. Să se relanseze în execuție serverul, astfel încât acesta să expună și funcționalitățile serviciului web ''​BookPresentationManager''​.
 +
 +<​spoiler|Indicații de Rezolvare>​
 +a) Se adnotează clasa ''​BookPresentationManager''​ precum și metodele care vor fi expuse la distanță (cu parametrii lor):
 +  - clasa ''​BookPresentationManager''​ se adnotează folosind însemnarea ''​@WebService(serviceName = "​BookPresentationManager"​)'';​
 +  - metodele care vor fi expuse la distanță se adnotează folosind însemnarea ''​@WebMethod(operationName = "​..."​)'':​ <code java>
 +@WebMethod(operationName = "​updateBookPresentationPriceForBooksWithMultipleFormats"​)
 +@WebMethod(operationName = "​makeSupplyOrderBasedOnStockpile"​)
 +</​code>​
 +  - parametrii metodelor care vor fi expuse la distanță se adnotează folosind însemnarea ''​@WebParam(name = "​..."​)'':​ <code java>
 +public List<​BookPresentationInformation>​ updateBookPresentationPriceForBooksWithMultipleFormats(@WebParam(name = "​numberOfFormats"​) int numberOfFormats,​ @WebParam(name = "​amount"​) double amount);
 +public List<​SupplyOrderInformation>​ makeSupplyOrderBasedOnStockpile(@WebParam(name = "​stockpile"​) int stockpile);
 +</​code>​
 +
 +b) Se adnotează clasele ''​BookPresentationInformation''​ și ''​SupplyOrderInformation'',​ ale căror instanțe vor fi transmise prin rețea, sub formă de documente XML, astfel încât JAXB să cunoască mecanismul prin care obiectele Java pot fi transformate în scheme XML și invers:
 +  - clasele ''​BookPresentationInformation''​ și ''​SupplyOrderInformation''​ vor fi adnotate folosind însemnările ''​@XmlRootElement''​ și ''​@XmlType(name="​..."​)'':​ <code java>
 +@XmlRootElement
 +@XmlType(name="​BookPresentationInformation"​)
 +public class BookPresentationInformation extends PersistentEntity {
 +
 +  // ...
 +  ​
 +}
 +</​code>​
 +  - toate metodele de tip getter (cu excepția celei care furnizează identificatorul,​ ''​getId()''​) vor fi adnotate folosind însemnarea ''​@XmlElement''​.
 +
 +**Eclipse**
 +
 +c) Este necesar să se publice serviciul web ''​BookPresentationManager''​ printr-un apel al metodei ''​Endpoint.publish()''​. Pentru fiecare serviciu web publicat, trebuie să se folosească un port dedicat.
 +
 +<code java>
 +Endpoint.publish("​http://​localhost:​8081/​bookstore/​BookPresentationManager",​ new BookPresentationManager());​
 +System.out.println("​[BookPresentationManager] successfully registered!"​);​
 +</​code>​
 +
 +**NetBeans**
 +
 +c) Nu este necesar să se realizeze nici o acțiune suplimentară,​ întrucât clasele adnotate cu însemnarea ''​@WebService''​ sunt detectate automat ca servicii web (vizibile în secțiunea //Web Services//) al căror conținut este instalat în contextul serverului de aplicații în momentul în care se accesează opțiunea //Deploy//.
 +</​spoiler>​
 +
 +**6**. Să se construiască un client care să acceseze funcționalitățile corespunzătoare serviciului web ''​BookPresentationManager''​. Să se testeze metodele expuse la distanță prin intermediul serviciului web.
 +
 +<​spoiler|Indicații de Rezolvare>​
 +a) Se creează un proiect Java.
 +
 +b) Se generează definițiile de clase necesare pentru accesarea funcționalităților expuse de serviciul web.
 +
 +**Eclipse**
 +
 +În directorul ''​scripts''​ aferent proiectului,​ se creează un script ''​client[.bat|.sh]''​ care rulează comanda ''​wsimport''​ necesară generării claselor necesare pentru accesarea metodelor expuse prin intermediul serviciului web:
 +
 +<​code>​
 +wsimport -s ../src http://​localhost:​8081/​bookstore/​BookPresentationManager?​wsdl
 +</​code>​
 +
 +Se indică locația la care este publicat fișierul WSDL conținând definiția serviciului web precum și locația la care va fi plasat codul sursă, prin intermediul opțiunii ''​-s''​.
 +
 +**NetBeans**
 +
 +Este necesar să se creeze un client pentru serviciul web (definirea unei resurse de tip //Web Service Client// din secțiunea //New// a meniului contextual asociat proiectului). Aceasta va specifica adresa Internet la care a fost publicat fișierul WSDL ([[http://​localhost:​8081/​07-BookStore-JAXWS-Server/​BookPresentationManager?​wsdl]]). Ulterior, generarea codului sursă se face prin accesarea opțiunii //Refresh// din meniul contextual asociat referinței la serviciul web. Se va folosi opțiunea //Also replace local wsdl file with original wsdl located at//. Clasele generate vor fi evidențiate prin plasarea lor în secțiunea //Generated Sources (jax-ws)//.
 +
 +c) Se definește clasa ''​BookPresentationManagerClient''​ în pachetul ''​ro.pub.cs.aipi.lab07.main'',​ conținând metoda ''​main()'':​
 +  - se creează obiectele de tip ''​Service'',​ respectiv ''​port''​ corespunzătoare serviciului web: <code java>
 +BookPresentationManager_Service service = new BookPresentationManager_Service();​
 +BookPresentationManager port = service.getBookPresentationManagerPort();​
 +</​code>​
 +  - se accesează metodele la distanță, expuse prin intermediul serviciului web: <code java>
 +System.out.println("​Enter number of formats: ");
 +int numberOfFormats = Integer.parseInt(bufferedReader.readLine());​
 +System.out.println("​Enter percent amount: ");
 +double amount = Double.parseDouble(bufferedReader.readLine());​
 +port.updateBookPresentationPriceForBooksWithMultipleFormats(numberOfFormats,​ amount);
 +System.out.println("​Enter stockpile: ");
 +int stockpile = Integer.parseInt(bufferedReader.readLine());​
 +port.makeSupplyOrderBasedOnStockpile(stockpile)
 +</​code>​
 +
 +d) Pentru afișarea rezultatelor,​ poate fi util să se definească metoda ''​displayResults''​ care primește ca parametri o listă de obiecte (derivate din ''​PersistentEntity''​) precum și clasa care conține tipul propriu-zis,​ afișând conținutul tuturor câmpurilor,​ prin intermediul metodelor puse la dispoziție de pachetul [[https://​docs.oracle.com/​javase/​8/​docs/​api/​java/​lang/​reflect/​package-summary.html|java.lang.Reflect]].
 +</​spoiler>​
 +
 +**7**. (opțional) Să se expună metodele corespunzătoare clasei ''​WriterManager''​ din pachetul ''​ro.pub.cs.aipi.lab07.businesslogic'',​ astfel încât acestea să fie accesibile la distanță prin intermediul unui serviciu web având aceeași denumire. Să se relanseze în execuție serverul, astfel încât acesta să expună și funcționalitățile serviciului web ''​WriterManager''​.
 +
 +**8**. (opțional) Să se construiască un client care să acceseze funcționalitățile corespunzătoare serviciului web ''​WriterManager''​. Să se testeze acest metodele expuse la distanță prin intermediul serviciului web.
  
 ===== Resurse ====== ===== Resurse ======
Line 992: Line 1120:
 [[http://​www.oracle.com/​technetwork/​articles/​javase/​index-140168.html|Java Architecture for XML Binding (JAXB)]]\\ ​ [[http://​www.oracle.com/​technetwork/​articles/​javase/​index-140168.html|Java Architecture for XML Binding (JAXB)]]\\ ​
 [[http://​www.vogella.com/​tutorials/​JAXB/​article.html|JAXB - Tutorial]]\\ ​ [[http://​www.vogella.com/​tutorials/​JAXB/​article.html|JAXB - Tutorial]]\\ ​
-[[https://​dev.mysql.com/​doc/​connector-j/​en/​connector-j-usagenotes-glassfish-config.html|Using Connector/J with GlassFish]]+[[https://​dev.mysql.com/​doc/​connector-j/​en/​connector-j-usagenotes-glassfish-config.html|Using Connector/J with GlassFish]]\\  
 +[[https://​www-01.ibm.com/​support/​knowledgecenter/​SSAW57_8.5.5/​com.ibm.websphere.nd.doc/​ae/​twbs_devjaxwsendpt.html|Developing JAX-WS Web Services with Annotations]]
  
 ===== Soluții ===== ===== Soluții =====
  
-TODO+[[https://​github.com/​aipi2015/​Laborator07/​tree/​master/​solutions/​eclipse|Proiect Eclipse]]\\  
 +[[https://​github.com/​aipi2015/​Laborator07/​tree/​master/​solutions/​netbeans|Proiect NetBeans]]
laboratoare/laborator07.1449014632.txt.gz · Last modified: 2015/12/02 02:03 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