POLO Analisi ed esempi di persistenza in Java La nostra società dispone di una metodologia, per la realizzazione di progetti Target Cross, che presentiamo di seguito.
Il Progetto Polo è un’applicazione CRM (Customer Relationship Managemen) in Java, in via di sviluppo tramite lavori di Tesi di studenti della facoltà di Ingegneria Informatica del Politecnico di Milano e Como. Inoltre è un progetto pubblicato su SourceForge [http://www.sourceforge.org] ed è fruibile da tutti con licenza GPL (General Public License).
Come nasce Polo nasce dall’esigenza delle aziende, con natura di tipo commerciale, che si avvalgono per la distribuzione di numerosi Agenti dei quali si vuole organizzare/programmare le diverse attività. Polo ha quindi 3 tipologie di utenza: - i singoli agenti - gli addetti al call center - l’amministratore del sistema
Gli utenti In particolare: i singoli agenti si collegano tramite computer portatile, smart phone al server centrale per aggiornare i loro appuntamenti o per inviare il resoconto delle attività svolte. - gli addetti al call center aggiornano in tempo reale gli appuntamenti degli agenti utilizzando dalle loro postazioni l’interfaccia web - l’amministratore del sistema gestisce i diversi gruppi utenti, le tipologie degli appuntamenti
Architettura
Componenti Modulo client sviluppato in J2ME Modulo server sviluppato in tecnologia J2EE Tecnologie impiegate: framework Struts, Hibernate,MeFast
Situazione attuale Modulo client sviluppato in J2ME Modulo server sviluppato in PHP. Esiste anche una versione Java, con modello dei dati DTO, con funzionalità limitate.
Migrazione Sviluppo e miglioramento del framework MeFast, per lo sviluppo rapido in J2ME Porting della parte server da PHP a Java Primo porting modello DTO verso l’utilizzo di Hibernate
Flusso Dati
Bisogna aver chiaro… Cos’è un oggetto? un oggetto è una "raccolta" di dati e procedure che agiscono sui dati. Le procedure vengono, in questo caso, indicate con il termine di metodi. L'unione di dati e metodi costituisce un mezzo più potente e preciso per rappresentare nel software gli oggetti del mondo reale.
Persistenza dei dati attuale Parte SERVER Attuale basata su DTO (Data Transfer Object) I DAO (Data Access Object) non sono altro che degli oggetti che forniscono all’esterno i metodi per l’accesso a dati persistenti. I dati vengono incapsulatati in altri oggetti detti DTO (Data Transfer Object) che veicolano l’informazione proveniente dalle sorgenti dati. Ciò avviene in maniera del tutto trasparente, ed un eventuale modulo delegato alla logica di business non si deve preoccupare dell’accesso ai dati in quanto manipola semplici oggetti. Infine va sottolineato che le eventuali eccezioni che possono essere sollevate in un tipico accesso a DBMS (quindi eccezioni SQL) sono completamente mascherate da eccezioni proprie dei DAO.
Esempio DTO 1/2 // da UtenteDto.java public class UtenteDto { private String nome; private String cognome; private String user; private String comune; private String provincia; public String getNome(){ return nome; } public void setNome(String nome){ this.nome=nome; public String getCognome(){ return cognome; public void setCognome(String cognome){ this.cognome=cognome; …
Esempio DTO 2/2 public UtenteDto getUtente(Integer id_utente) { String sql = "SELECT * FROM utente WHERE id=“+id_utente; try{ ResultSet rs = stmt.executeQuery(sql); if (rs.first()==false) {System.out.println("array non trovato");} else{ rs.first(); while(rs.isAfterLast() == false){ dt = new UtenteDto(); dt.setUser(rs.getString("user")); dt.setNome(rs.getString("nome")); dt.setCognome(rs.getString("cognome")); dt.setComune(rs.getString("comune")); dt.setProvincia(rs.getString("provincia")); rs.next(); } }catch (SQLException e) { System.out.println(e.getMessage()); return dt;
Persistenza dei dati finale Parte SERVER Finale basata su Hibernate Hibernate (spesso chiamato H8) è una soluzione Object-relational mapping (ORM) per il linguaggio di programmazione Java. È un software free, open source e distribuito sotto licenza LGPL. Hibernate fornisce un framework semplice da usare, che mappa un modello di dominio orientato agli oggetti in un classico database relazionale.
Hibernate 1/3 Hibernate non si occupa solo di mappare dalle classi Java in tabelle del database (e da tipi Java ai tipi SQL), ma fornisce anche degli aiuti per le query di dati, il recupero di informazioni e riduce significativamente il tempo che altrimenti sarebbe speso lavorando manualmente in SQL e con JDBC. I mappaggi oggetto/relazione vengono definiti in un documento XML. Il documento di mappaggio è progettato per essere leggibile e modificabile a mano. Il linguaggio di mappaggio è java-centrico, nel senso che i mappaggi sono costruiti intorno alle dichiarazioni delle classi persistenti, non sulle dichiarazioni delle tabelle.
Hibernate 2/3 Oggetti persistenti e collezioni: sono oggetti di corta durata, che contengono stato persistente e funzioni applicative. Potrebbero essere normali oggetti POJO/Javabeans, con l'unica particolarità che in un dato momento sono associati con (esattamente) una Session. Nel momento in cui la Session viene chiusa, verranno staccati e saranno liberi di essere usati in qualsiasi strato applicativo (ad esempio direttamente come oggetti di trasferimento dei dati da e allo strato di presentazione).
Hibernate 3/3 Le classi persistenti sono quelle che in un'applicazione implementano le entità del problema di business (ad esempio Customer e Order in una applicazione di e-commerce). Le classi persistenti hanno, come implica il nome, istanze transienti ed istanze persistenti memorizzate nel database. Hibernate funziona meglio se queste classi seguono alcune semplici regole, conosciute anche come il modello di programmazione dei "cari vecchi oggetti java" (in inglese e nel seguito si usa l'acronimo POJO che sta per "Plain Old Java Object").
Esempio Hibernate 1/2 // da Utente.hbm.xml <?xml version="1.0" encoding='UTF-8'?> <hibernate-mapping package="it.digi.polo.hibernate"> <class name="Utente" table="UTENTE"> <id name="idUtente" column="ID_UTENTE" type="java.lang.Integer"> <generator class=“native"/> </id> <property name="user" column="USER" type="java.lang.String" /> <property name="pass" column="PASS" type="java.lang.String" /> <property name="cognome" column="COGNOME" type="java.lang.String" /> <property name="nome" column="NOME" type="java.lang.String" /> <set name=“appuntamenti" inverse="true"> <key column="ID_UTENTE"/> <one-to-many class=“Appuntamenti"/> </set> </class> </hibernate-mapping>
Esempio Hibernate 2/2 In alternativa, esempio HQL: // da UtenteManagement.java public Utente getUtente(Integer id_utente) { try{ Session hibSession=HibernateSessionFactory.currentSession(); Utente user=(Utente)hibSession.get(Utente.class, id_utente); } catch (SQLException e) { System.out.println(e.getMessage()); } return user; In alternativa, esempio HQL: Query q = hibSession.createQuery("from Utente ut where ut.idUtente = ?"); q.setInteger(0, id_utente); Utente user = (Utente) query.uniqueResult();
Persistenza dei dati lato Client Per la memorizzazione dei dati da parte del modulo client (dispositivo mobile con risorse limitate) si è scelto di sviluppare un framework ad hoc: MeFast MeFast si occupa di strutturare/memorizzare le informazioni a partire da oggetti, in un file sequenziale e di recuperarne al suo interno, tramite una serie di filtri, i dati richiesti
Architettura MEFast
Esempio MEFast 1/4 // dalla Struct intervento_testata.struttura.Addelement(4,"key_attivita_id"); intervento_testata.struttura.Addelement(4,"key_cliente_id"); intervento_testata.struttura.Addelement(2,"data"); intervento_testata.struttura.Addelement(3,"ora_inizio"); intervento_testata.struttura.Addelement(3,"ora_fine"); intervento_testata.struttura.Addelement(1,"tipo_att_id"); intervento_testata.struttura.Addelement(1,"chiusa_aperta"); intervento_testata.struttura.Addelement(1,"nuovo"); intervento_testata.struttura.Addelement(1,"mod"); intervento_testata.struttura.Addelement(1,"del");
Esempio MEFast 2/4 //da DbWriter.java public void DbaddRecordSet(Recordset recordset){ byte[] raccolta; ByteArrayOutputStream strmBytes = new ByteArrayOutputStream(); DataOutputStream strmDataType = new DataOutputStream(strmBytes); try { for (int i = 0; i < recordset.size(); i++) { switch (Struttura.ReturnType(i)) { case 1: strmDataType.writeInt(Integer.parseInt( recordset.Campo(i).toString())); break; case 2: DateManager datemgr=new DateManager(); strmDataType.writeLong(datemgr.StrLong( recordset.Campo(i).toString()));
Esempio MEFast 3/4 case 3: HourManager hourmgr=new HourManager(); strmDataType.writeLong(hourmgr.H_StrLong( recordset.Campo(i).toString())); break; case 4: strmDataType.writeUTF( recordset.Campo(i).toString()); default: } strmDataType.flush(); raccolta= strmBytes.toByteArray(); Database.addRecord(raccolta, 0, raccolta.length); strmBytes.reset(); strmBytes.close(); strmDataType.close(); } catch (Exception e) { e.printStackTrace(); }
Esempio MEFast 4/4 //da XmlObj.java public Recordset[] XmlSelect(int inizio,int num,Struct strutt) throws DbException { struttura=strutt; Recordset [] Records = null ; e.printStackTrace(); } if(Records.length==0) { System.err.println("nn"); throw new DbException(2,"Nessun dato"); return Records;
Commento al codice La classe che legge l’xml ritorna un’ array di oggetti Recordset che possono essere scritti tramite il metodo Write() direttamente sul database. La classe di lettura riceve come parametro di ingresso la classe Struct che definisce i tipi dei campi che devono essere letti. La classe Struct in MeFast rappresenta il mappaggio del db, definisce i tipi dei dati e il nome dei campi
Insorgenza di problemi Mismatch del paradigma Problema della granularità Problema dell’identità
Mismatch del paradigma Problema riguardante la progettazione del modello di dati: svilupparlo seguendo il modello object-oriented o il modello relational-oriented, oppure, un modello di dati programmabile che riunisca entrambi? Problema risolto con l'Object Relation Mapping, realizzato tramite dei file hbm.xml, fra gli oggetti e le reali tabelle del database, creando vere e proprie associazioni anche fra collezioni di oggetti ad una singola istanza, senza l'aggiunta di ulteriore codice nei corrispondenti moduli.
Soluzione Vecchia versione Polo Nuova versione Polo: uso di Hibernate Popolamento manuale dei DTO attraverso interrogazione sql alla base dati (con Join tra tabelle) Nuova versione Polo: uso di Hibernate Utilizzo di oggetti POJO che permettono di persistere i dati nelle tabelle relazionali mappate attraverso un file XML Utilizzo di comodi metodi per recuperare Set di oggetti collegati (ovvero record di tabelle relazionate) Soluzione proprietaria (Client) Definizione strutture mediante mappaggio e interfaccia a file vari per recuperare, mediante chiavi, le dipendenze
Problema della granularità Riferito al problema della separazione degli attributi dello stesso oggetto su vari oggetti relazionali. Es. Oggetto Java Location, rappresentante tutto quello che concerne la propria ubicazione (paese, città, indirizzo, ecc..), che potrebbe essere rappresentato come una singola tabella, oppure splittato su n tabelle ognuna rappresentante un attributo dell'oggetto.
Soluzione Vecchia versione Polo Nuova versione Polo: uso di Hibernate Popolamento manuale dei DTO attraverso interrogazione sql alla base dati (con Join tra tabelle) Nuova versione Polo: uso di Hibernate Utilizzo di oggetti POJO che permettono di persistere i dati nelle tabelle relazionali mappate attraverso un file XML Utilizzo di comodi metodi per recuperare Set di oggetti collegati (ovvero record di tabelle relazionate) Soluzione proprietaria (Client) Definizione strutture mediante mappaggio e interfaccia a file vari per recuperare, mediante chiavi, le dipendenze
Problema dell’identità In SQL non esiste una metodologia che eguagli il metodo equals() oppure l'operatore ==. Nel linguaggio relazionale l'identità è determinata dalle Primary-Keys, o in maniera del tutto più approfondita guardando l'identità fra opportune Foreign-Keys.
Soluzione Vecchia versione Polo Nuova versione Polo Costruzione di metodi isEqual() che verificano tramite una query sql l’identità delle chiavi Nuova versione Polo Mappaggi xml delle chiavi della tabella Creazione di metodi per la verifica dell’uguaglianza Soluzione proprietaria (client) Definizione di metodi di verifica mediante il recupero di chiavi definite sui file. Metodi per scorrere il file sequenziale e trovare elementi con la chiave richiesta
Ora tocca a voi… Esercizio: date queste classi, relazionate fra di loro come in figura, provate a implementarne il codice e il relativo mappaggio Hibernate immaginando di avere a disposizione una base dati relazionale per memorizzare le informazioni
Riferimenti l.pelizzeni@digitelematica.it