lunedì 29 dicembre 2008

Effective Java

Da qualche settimana siamo fermi sullo sviluppo del framework (e quindi anche la mia tesi), ne ho approfittato, oltre che per migliorare il prototipo già funzionanente presso un nostro cliente, e per implementare nuove features richieste dal cliente stesso, per studiarmi uno dei libri che mi ero ripromesso di studiare: Effective Java.
Interessante direi, molto utile in qualche consiglio, meno in altri, ma direi un must.
Alcuni dei consigli trovati nel libro li ho già "implementati" nel framework, migliorando alcuni aspetti che erano già stati realizzati. E sicuramente molti altri ci saranno in seguito utili.
Lo consiglio a tutti, soprattutto a chi come me non è espertissimo nella programmazione di grandi progetti.

martedì 25 novembre 2008

TeePee

Dopo un po' di giorni senza post, forse è il caso di aggiornare un po' chi segue questo blog (e guardando dalle statistiche di google analytics non siete nemmeno pochi, lasciatemi gongolare, dai).

Nell'ultimo mese ci siamo dati completamente allo sviluppo del framework che fino dall'inizio volevamo sviluppare. Prima d'ora era poco più che un abbozzo, ma l'esperienza fatta nello sviluppare l'applicazione che già dei clienti stanno usando, ci ha permesso di trovare i reali bisogni di cui necessitiamo, e le carenze dei framework esistenti.

Il mio collega e correlatore ha gettato le basi, su cui ho costruito il resto, sempre sotto la sua supervisione.
Abbiamo anche deciso di rendere disponibile questo core del framework, rilasciandolos su google code con licenza GNU Lesser General Public License.
Il tutto lo trovate qui: http://code.google.com/p/teepee/
Ovviamente attualmente non si trova molto online, tranne il codice nudo e crudo, ma presto, anche ai fini della tesi, rilasceremo i javadoc e qualche file esplicativo, oltre a quelche schema UML.

A tale proposito, qualcuno ha quelche strumento (opensource o freeware) da consigliare? Per ora ho provato 
  • violetUML, non male, ma di fatto non utile nei sequence diagram
  • ArgoUml, buono per il reverse enginering, mi ha generato tutti i diagramma di classe per tutti le classi del progetto, niente male, fa risparmiare tempo... ma poi poco usabile per creare i diagrammi
  • Visual Paradigm... niente male, ma a pagamento
  • StarUml... quello che sto usando ora, opensource, non male, ma i grafici non sono personalizzabili al 100%... alcune cose rimangono standard, come i punti di ancoraggio delle linee, frecce e simili.

mercoledì 8 ottobre 2008

Ancora su Orm

Sono riuscito nel tentativo del salvataggio di una chiamata con hibernate/orm... ho in pratica trovato il modo per superare, più o meno, le restrizioni evidenziate in questo post(Alcuni problemi con gli id composti e i valori di default con Hibernate).

In pratica ho usato degli DAO molto più semplici... che non considerano in pratica le relazioni molti a molti... in pratica, all'interno della classe che rappresenta la tabella nel database, ogni riferimento a chiavi esterne... è memorizzato come un campo qualsiasi, ignorando assolutamente se nei DAO esiste una classe che potrebbe sostiurire il campo.

In pratica, prima, per esempio, se nella tabella chiamata evavo un campo id_imp che era ovviamente una chiava esterna per la tabella imp, il DAO era costituito come un field costituito da un elemento stesso della classe Imp... che a suo volta però al suo interno aveva un ID composito rappresentato dalla classe ImpId... ed è questo che pareva creare dei problemi.

Ora, con questi nuovi DAO più semplici, in un caso come quello sopra, id_imp è rappresentato nella classe Chiamata dal field chiamato idImp rappresentato da una semplice stringa... posso quindi assegnarli una semplice stringa... che rappresenta poi l'id chiave esterna di imp (imp ha il campo id come stringa)
In pratica come dovrei fare se usassi SQL.

Così sono riuscito a memorizzare senza problemi una chiamata assegnando tramite gli strumenti di HIBernate tutti i valori che mi interessano.
In realtà qualcosa di diverso c'è... tutti i campi sono memorizzati come dati primitivi, String, char, int, date... cioè come la definzione del campo nel database... tranne alcuni (pochissimi) come per esempio HdTipoContab, che è memorizzato ancora come classe... questo perchè (credo) proprio al tabella hd_tipo_contab non ha id composto (come invece il 99% delle altre tabelle) e quindi è comuinque molto semplice usarlo... anche se ho dovuto aggiungere un costruttore alla classe così come era stata creata automaticamente.

Questi DAO semplificati li ho ottenuti usando sempre Hibernate Tool, plugin di Eclipse, selezionando perà nel file di configurazione hibernate.revenge.xml solo el tabelle vere e proprie, ignorando le varie view presenti nel database, e selezionando, all'atto della creazione del codice, nessuna opzione particolare (quindi non selezionando"generate basyc typed composite id", nè "Decect optimistic lock columns", nè "detect many-to-many tables"), e nella schermata exporters, non ho selezionato nessuna delle opzioni in alto (quindi non ho selezionato nè "Use java 5 sintax" nè "Generate EJB3 annotations") e come exporters ho selezionato "domain code" (che genera le classi java che poi utilizzo), "Hibernate xml mapping .hbm.xml" (che genera i file xml per specificare ogni singola classe), "DAO Code" (che a quanto pare genera delle classi java chiamata come le precedenti+home... non so esattamente a cosa siano necessari, pare sempre ad hibernate), sia "Hibernate Xml Configuration, cfg.xml" che genera un nuovo hibernate.cfg.xml con i riferimenti ai file .hbm.xml che vengono generati.

domenica 21 settembre 2008

OpenLaszlo e Flex

OpenLaszlo e Flex sono stati due dei framwerok di sviluppo di RIA che avevamo inzialmente preso in considerazione. Li scartammo quasi immediatamente per il legame che questi framweork hanno (o meglio, nel caso di Laszlo, avevano) con Flash e per lo sviluppo in Javascript/Actionscript, e non Java.

Flex è un framework rilasciato da Adobe per la creazione di ria con un linguaggio markup proprio, MXML, basato su XML, utilizzato per descrivere il layout dell'interfaccia utente e i comportamenti, mentre ActionScript 3, linguaggio di programmazione orientato agli oggetti, utilizzato per creare la logica client. Il tutto compilato poi per la creazione di oggetti SWF per l'esecuzione tramite Flash Player.

OpenLazlo oper in maniera piuttosto simile, anch'esso con un linguaggio simil XML condito con un linguaggio di programmazione, Javascript, anch'esso poi compilato in file SWF.
Attualmente però la nuova versione di OpenLaszlo supporta anche la possibilità di sviluppare ria anche senza l'uso di flash, ma con dhtml/ajax (come gwt, in poche parole), ma questo supporto è stato introdotto solo con la versione 4.1, rilasciata a Luglio 2008... decisamente molto più tardi di quando la nostra scelta di frawork base su cui lavolare è caduta su GWT.

E' comunque interessante dare uno sguardo a questa tecnologia.
Grossomdo il paradigma di programmazione non è così distante da GWT... si programma in un linguaggio, il framework mette a disposizione un compilatore che processa i file sorgente e produce del codice che verrà poi eseguito sul client.
Il linguaggio di programmazione usato per OpenLaszlo è un markup language, LZX, linguaggio risultante dalla fusione di aspetti dichiarativi, derivanti dall' XML, con altri tipici della programmazione imperativa Object-Oriented, derivanti da JavaScript. Nei file sorgenti di OpenLaszlo infatti si utilizza una sintassi molto simile a quella di un classico file XML, con riferimenti alle API messe a disposizione del framwork, con l'aggiunta di codice JavaScript.
Il compilatore poi, processando questi file sorgenti, crea un file SWT (quindi un file per Macromedia Flash), che possa quindi essere eseguito da qualsiasi browser con il Flash Player. Recentemente è stato anche introdotto il supporto per la compilazione di codice slegato da Flash,
generando quindi codice DHTML/AJAX.
Comunque sia, il codice simil-Javascript scritto nei file LZX non è quello eseguito dal browser, ma viene intepretato dal compilatore e resituito come codice actionscript di Flash, nel caso si vada poi ad utilizzare la tecnologia di Macoromedia, o generando del nuovo codice Javascript nel caso di utilizzo del classico AJAX.

Pro:
  • La realizzazione dell'interfaccia utente risulta abbastanza semplice da realizzare, lineare e abbastanza riusabile. Il tutto viene realizzato con una serie di tag LZX che definiscono i componenti dell'interfaccia, la loro posizione, e le loro carattaristiche, il tutto riutilizzabile con la logica della programmazione ad oggetti.
    Per esempio questo codice
    < canvas>
    <button onclick="vw.setWidth(200)">Expand
    Width</button>
    <button x="120"
    onclick="vw.setWidth(100)">Reset</button>
    <view id="vw" y="30" width="100" height="100">
    <!-- onwidth is sent anytime width is changed -->
    <handler name="onwidth">
    this.setAttribute('bgcolor', (this.width
    > 100 ? red : blue));
    </handler>
    </view>
    </canvas>
    permette la creazione di due pulsanti, e relativi eventi.
  • Ci sono a disposizione numerevoli componenti, personalizzabili e riusabili, e le api, lmanoe per quanto riguarda l'implementazione con flash, è ben supportata e testata
Contro
  • Per dare un minimo di interattività alla pagina bisogna comunque utilizzare dell'actionscript, quindi bisogna conoscere questo linguaggio
  • Il supporto DHTML non è ancora maturo... quindi si può produrre stabilmente solo con flash, e quindi ci si lega troppo a questo prodotto




Fonti:
OpenLaszlo White Paper: http://www.openlaszlo.org/whitepaper/LaszloWhitePaper.pdf

venerdì 29 agosto 2008

Gwt-Log

Una delle cose più noiose nel logging con applicazioni GWT è che, lato client, non si riesce ad usare nativamente la console di loggin, ne quella di GWT in Hosted mode, nè quella del server. Il che diventa noioso, poichè spesso si ha la necessita di avere un minimo di tracciabilità delle attività svolte dal codice, e si vuole subito avere un feddback con il loggin, ma con gwt, almeno lato client, sono sempre stato obbligare ad usare i fastidiosi "windows alert".
Certo, da una parte hanno la loro utilità, come quella di bloccare, di fatto, l'esecuzione dell'applicazione e questo può avere un suo aspetto positivo... ma sono troppo invadenti... e soprattutto se ce si li dimentica nel codice, passando poi il prodotto al cliente, si posson avere situazioni imbarazzanti.

Ho trovato, in questi giorni, una libreria davvero interessante per il loggin con GWT


Che gestisce in maniera del tutto trasparente il loggin su più livelli... infatti, lasciando fare tutto a lui (ci sono comunque dei setting da poter usare per disabilitare/abilitare i vari tipi di logger), si può avere il log lato server (anche gli errori lato client possono essere spediti in amniera del tutto trasparente al server con rpc), con la normale console errore del server (errori lato server, come con il normale System.out o System.err), sia nella console dell'Hosted Browser di GWT (come con il classico GWT.log)(client e server), sia un log da leggere con al console di FireBug (un ottima estensione di Fiorefox), sia con un interessante "finestrella div" che compare all'interno delal applicazione stessa, un div semitrasparente draggabile...
Insomma, si può fare veramente di tutto e con in pratica nessuna riga di codice particolare... si importa la libreria nel progetto, si inseriscono alcune righe nel file gwt.xml... e basta usare Log(stringa) e via che si logga dappertutto.
Stupendo.


Aggiornamento: Strani Errori
Ieri sembrava funzionare tutto perfettamente, mentre oggi, aggiornando il progetto a GWT 1.5, cambiando quindi librerie eccetera, ho forse commesso qualche errore... e non si compilava più il modulo gwt... continuava a lamentarsi che non trovava la libreria di gwt-log, in particolare che non trovava il file di confiugurazione gwt.xml del progetto gwt-log
L'errore era:
[echo] Module: com.fdlservizi.sse.HelpDeskGWT
[java] Loading module 'com.fdlservizi.sse.HelpDeskGWT'
[java] Loading inherited module 'com.allen_sauer.gwt.log.gwt-log'
[java] [ERROR] Unable to find 'com/allen_sauer/gwt/log/gwt-log.gwt.xml' on your classpath; could be a typo, or maybe you forgot to include a classpath entry for source?
[java] [ERROR] Line 7: Unexpected exception while processing element 'inherits'
[java] com.google.gwt.core.ext.UnableToCompleteException: (see previous log entries)
[java] at com.google.gwt.dev.cfg.ModuleDefLoader.nestedLoad(ModuleDefLoader.java:225)
[java] at com.google.gwt.dev.cfg.ModuleDefSchema$BodySchema.__inherits_begin(ModuleDefSchema.java:194)
[...]

Non so per quale motivo, ma ignorava totalmente la presenza della libreria, che invece avevo normalmente selezionato tar le librerie esterne in IntelliJ Idea.
Poi, guardando bene il forum di grails (in particolare questa discussione), non ho capito bene perchè, ho scoperto che dovevo inserire tale libreria nella directory /lib/gwt.
Cosa mai fatta, anche perchè eventualmente le librerie le avrei messe in /lib, dentro al quale la directory gwt non esisteva nemmeno.
Ora invece, con l file messo lì dentro, funziona senza problemi.... misteri di grails.

venerdì 22 agosto 2008

Alcuni problemi con gli id composti e i valori di default con Hibernate

Stamattina, dopo aver passato due giorni a studiarmi il "paradigma di programmazione" per le GUI usato in sap (potrebbe tornarci utili, è uno interessante punto di riferimento a cui potremmo ispirarci), sono tornato a fare qualche esperimento con Hibernate.
In particolare ho continuato a giocare con le select e gli insert con le nostre classi POJO create per ORM.

Ho generato una pagina gsp di esperimento, con alcuni tasti gwt che usano una rpc, che "stimola" sue servizi lato server, uno per la ricerca delle classi (sempre "chiamata") e una per salvarla.
Nessun problema nella ricerca di chiamata, sia con il findall, il list, il find, i criteria, eccetera...
Bhe, in realtà ci sono dei problemi quando nel database ci sono dei null di troppo... ma è un problema correlato a quello che descvrivo qui in seguito.

Infatti nel momento dell'inserimento abbiamo trovati i primi problemi. Essendo il nostro database costruito con delle doppie chiavi primarie (ogni tabella ha un id, nemmeno numerico autoincrementale, come sarebbe meglio fosse, ma come stringa, correlato sempre ad un altro campo presente in ogni tabella "az" che fa riferimento ad una tabella, az), ogni volta che noi abbiamo una chiave esterna, questa chiave esterna è anch'essa costruita con due campi... e anche al tabella a cui facciamo riferimento ha un id primario composto. Questo comporta che nel ricavare i dati di uno di queste colonne, devo fare un doppio passaggio. Nella colonna ricavo l'id delal classe associata, nella quale ricavo poi l'id, che è quello che viee di fatto immagazzinato nella colonna stessa.
Ma all'atto dell'inserimento questo doppio passaggio non funziona. In pratica non riesco a memorizzare i campi se sono chiavi secondarie esterne... e questo ovviamente è un grosso problema. Il fatto è che non tutto il database è costruito in maniera perfetta, per esempio la tabella chiamata non ha riferimenti di chiave secondarie che puntano ad azienda, altre colonne sì... quindi il toll per il reverse enginering è andato un po' in pappa e non riesce a gestire in maniera completa queste doppie chiavi.
Il tutto dovrebbe risolversi attuando una modifica al database che già volevamo attuare, cioè eliminare totalmente tutte le chiavi primarie composte con quel campo az, che di fatto non serve a nulla. Era stato introdotto tempo addietro quando il programma doveva essere multiazienda, cosa che è stata in seguito abbandonata.
Non toglieremo nella tabelle il campo az (presente in tutte) e nemmeno la tabella az (per retrocompatibilità, alcune query presenti qua e là nel programma fanno riferimento a questa colonna), ma modificheremo tutte le chiavi primarie, facendole diventare uniche e non più composte (composte cioè dal solo campo id) e elimineremo ogni chiave secondaria esterna, in ogni tabella, che faccia riferimento ad az.

Stamattina mi sono accorto però di un nuovo problema... la generazione automatica delle classi di dominio POJO, usate da Hibernate, non ha tenuto conto dei valori di default impostati nel database... essendo in sql server sono impostate con delle costraint di questo tipo
ALTER TABLE [dbo].[chiamata] ADD DEFAULT ('N') FOR [libretto]
in questo caso la colonna libretto della tabella chiamata è impostata con un valore di default = N (tra l'alro la colonna ha come proprietà il poter accettare valori null).
In hibernate di fatto non esistono modi per specificare nel file di mapping delle classi i valori di default... esisterebbe ma non è portabile sui vari databasi, prchè bisognerebbe specificare il formato di colonna, diverso per ogni tipologia di database, qundi da evitare.
Di fatto, in una situazione del genere, se si vuole memorizzare nel database una classe di dominio per la quale non si specificano valori per un determinato fields, se questo accetta nel mapping valori null, hibernate lo inizializza automaticamente con null... infatti hibernate, quando deve memorizzare una classe sul database, nella query sql insert, specifica tutti i campi della classe stessa che nella proprietà del mapping abbiano insert=true
Ovviamente, se questa proprietà non viene specificata, hibernate automaticamente le popola con il valore null se la proprietà stessa l'accetta, o con al string avuota nel caso sia specificata not null
Questo significa che di fatto vengono ignorati i valori di default specificati nel database, perchè di fatto al database arriva una query con quei campi specificati... quindi inserisce quelli e non i valori che lui ha come default.
Se per esempio voglio forzare il database ad inserire i valori di dafault, dovrei fare in modo che hibernate non gli passi proprio quel campo... cosa possibile da fare, basta specificare insert=false



facendo così hibernate ignora il campo libretto, e il database, non ricevendolo nella query insert, lo inserisce con il valore di default
Così facendo però non è possibile inserire alcun valore... quindi se io volessi, all'atto della insert, specificare un valore per quella propietà, di fatto questa viene ignorata.

Nel nostro caso, in effetti, c'è un modo molto semplice per risolvere il problema... basta mettere nel costruttore della classe di dominio il valore di default, o nel mio caso, dato che per le classi di dominio che vengono utilizzate anche lato client gwt, devo costruire una determinata classe che viene poi serializzata ed usata nel passaggio dati nella rpc, dichiaro quel dato field con il valore di default, così facendo, anche se lato client non viene specificato alcun valore, di fatto hibernate lo riceve con il valore preimpostato e lo passa al database.

public class DatiChiamata implements IsSerializable {
public String id;
public String apertaDa;
public String tipoChiamata;
public String gradoDisservizio;
[...]
public String noteAssegnazione;
public String libretto = "N";
[...]
}

giovedì 7 agosto 2008

JAVA DAO, ORM, POJO

Abbiamo deciso di approfondire lo studio di Hibernate, effettivamente potrebbe esserci molto di aiuto, sia per la normale interrogazione di database (sia in selezione che in salvataggio) sia perché potrebbe evitarci i problemi di compatibilità con i due database che vogliamo supportare: Oracle e SQL Server.

Abbiamo deciso di non affidarci totalmente a GORM (Grails Object Relational Mapping) perchè groovy si rileva meno performante in alcune condizioni, e abbiamo paura che sia limitante nel futuro.

Quindi la scelta ricade sulla creazione di un ORM tramite JAVA DAO (Java Data Access Object) create con delle classi java POJO (Plain Old Java OBject).
Questo significa mappare tutto il nostro database con delle semplici classi java che devvano rispecchiare determinate carrateristiche.
In particolare Hibernate non ha richieste eccessive, ma secondo la logica del convention over configuration, è sempre meglio cercare di rispettare più richieste possibili, tra le quali:

  • Ogni classe dovrebbe avere un suo identificare univoco, chiamato Id (e qui per noi è un problema... perchè in pratica ogni tabella del nostro database ha un id composto da due campi stringa... decisamente lontano dagli standard che prevedono un id numerico autoincrementale... lo so lo so)
  • Ogni classe dovrebbe prevedere un costruttore a zero argomenti, che sarà utilizzato da Hibernate per istanziare la classe
  • Tutti i campi della tabella dovrebbero essere trasformari in campi della classe. Quindi ogni classe dovrebbe avere una serie di campi da considerare persistenti (quindi direttamente mappabilis ul database), preferibilmente da settare come privati, e quindi definire i getter e i setter per ognuno di questi campi. In particolare ogni campo dopvra rispettare le classiche convenzioni ORM, quindi nel caso di un nome campo (o tabella) composto d apiù nomi uniti con l'underscore, si dovrà converire con nome univoco con le lettere maiuscole per ogni parola che lo compone... esempio il campo data_di_nascita sarà convertito in dataDiNascita. Inoltre per convenzione Hibernate si aspetta di trovare i getter e i setter così composti getDataDiNascita e setDataDiNascita.
  • Le classi non dovrebbero essere dichiarate final, o in tal caso caso, dovrebbero implementare un interfaccia che dichiara tutti i metodi pubblici.
  • Nel caso di id composti conviene dichiarare l'id della classe come istanza di un'altra classe, convenzionamente chiamata nomeclasseId, nella quale vengono specificati i singoli campi delal chiave primaria composta.

Ci siamo affidati, per la stesura di queste classid i dominio, ad Hibernate Tool, un plugin per Eclipse appositamente studiato dallo staff di hibernate.
Seguendo i consigli di questa pagina, abbiamo proceduto con questi passi
  • dopo aver installato il plugin per eclipse (semplicemente scompattato lo zip preso dalla pagina di cui supra), ho creato un progetto grails, vuoto, con la classica procedura (nuova directory, grails create-app)
  • Ho messo nella cartella lib del progetto il jar con il driver jdbs del database sqlserver (jtds-1.2.2.jar preso su sourceforge). Avviato eclipse ho importato il progetto appena creato.
  • tasto destro sul progetto, ho creato un nuovo file di configurazione per hibernate: File -> New -> Other -> Hibernate -> Hibernate Configuration File.
    Il file di configurazione l'ho salvato nella directory grails-app/config/hibernate
    Come dialect ho scelto SQL Server, che poi sarà salvato nel file come org.hibernate.dialect.SQLServerDialect
    Come classe del driver ho scelto net.sourceforge.jtds.jdbc.Driver
    Come connection url jdbc:jtds:sqlserver://localhost/Sacci_Gabry;instance=SQLEXPRESS (ho instalato il database in locale)
    Il resto ho lasciato in bianco
  • ancora tasto destro e quindi ho settato al configuarazione della console di Hibernate (File -> New -> Other -> Hibernate -> Hibernate Console Configuration)
    Ho lasciato tutto come proposto, inserendo però nel classpath la lib inserita prima nella directory lib del progetto (il driver jdbc)
  • ancora tasto destro e quindi ho creato un file per il reverse enginering (di fatto quello che poi creerà i file) [File -> New -> Other -> Hibernate -> Hibernate Reverse Engineering File(reveng.xml) ]
    Il file l'ho inserito come prima in grails-app/config/hibernate
    dopo aver selezionato la configurazione e aspettato che il database venisse letto, ho selezionato solo le tabelle del dbo
  • Fatto questo ho fatto partire la compilazione (Lunch -> Hibernate Code Generation -> Open Hibernate Code Generation Dialog)
    Come outpout folder ho scelto src\java, e come nome di package gorm
    Come exporter ho selezionato le domain code, hibernate xml mappings, hibernate xml configuration, e lo Schema Documentation (decisamente opzionale, ma carino, genera della documentazione html interessante e facile da consultae)
    La generazione del codice impiega un po' ad eseguirsi.
  • A questo punto bisogna spostare qualche file per seguire le convenzioni hibernate/grails
    Il file hibernate.cfg.xml appena generato, diverso dal precedente in quanto conteiene tutti i riferimenti ai file di maping, va spostato nella directori config/hibernate, sovrascrivendo quindi il precedente
    Tutti i file hbl.xml vanno spostati nella stessa directorty grails-app/config/hibernate
A questo punto tutto è pronto per lavorare... si possono visualizzare e quindi utilizzare le view di eclipse predisposte per hibernate, consultare il database, la session factory, fare query HQL ecc..

martedì 29 luglio 2008

Hibernate, session, Dynamic Methods + Inject

Ci siamo accorti che così come utilizziamo noi sql, creiamo una differente connessione al database per ogni servizio, cosa non molto gradevole in effetti.
Infatti, sino ad ora, abbiamo raramente usato GORM e Hibernate, data la "stramba" costruzione del database già esistente per il programma (id stringa, più campi per chiavi primarie, eccetera), e quindi risulta più "facile" usare sql diretto piuttosto che gorm e hibernate. Quindi usiamo groovy.sql.Sql per la creazione di query sql on the fly.
Abbiamo tentanto la strada della memorizzazione delle sessioni nella session http, cosa che funziona, ma rende poco pratica la gestione delle sessioni stesse, perchè ogni volta che serve richiamare la connessione, bisogna scrivere svariate righe di codice, per ogni metodo dei dervizi che utilizzano sql...
Per farlo abbiamo usato questa strategia: nella prima connessione al database creata, quella del login, creiamo un istanza SQL come normalmente si dovrebbe fare in ogni service
import groovy.sql.Sql
def sql = Sql.newInstance("jdbc:jtds:sqlserver://192.168.0.22/sacco;instance=SQLSSE", "sa", "fdl", "net.sourceforge.jtds.jdbc.Driver")
e poi la memorizziamo nella sessione come altre informazioni (user, profilo, eccetera)
def session = RCH.currentRequestAttributes().session
session.connessioneDB = sql
E il tutto sembra funzionare... per poi richiamare questa connessione sql, basta fare in ogni servizio
def session = RCH.currentRequestAttributes().session
def sql= session.connessioneDB
per poi usare l'oggetto sql normalmente (quindi sql.execute eccetera)
Questo portava anche al vantaggio si avere la stringa di connessione al database in uan sola classe, e non in ogni servizio (maggiore mantenibilità)

Abbiamo quindi provato un'altra strada... essendoci hibernate comodamente pronto nel framework grails, abbiamo provbato ad usare le sessioni di hibernate per fare una cosa simile, in più abbiamo provato ad utilizzare i metodi dinamici di groovy iniettando nei servizi un oggetto sql già pronto all'uso... il tutto funziona... solo che non usando nativamente hibernate (ma lo usiamo solo per ricavare connessioni e non per gestire gli accessi al database) pare che non si riescano a recuparare connessioni univoche... ma che hibernate ne crei una nuova ogni volta che viene invocato con il metodo che più avanti spieghiamo.
E' stato comunque interessante provare questo approccio perchè ci ha permesso di verificare la possibilità di iniettare metodi (e proprietà) in svariate classi (singole, nominali, tutti i servizi, i controller, le classi di dominio eccetera)... ed addirittura provare la creazione di plugin (che pare essere l'unica strada efficace per effettuare l'iniettamento di metodi dinamici)
Questo approccia, nonostante non persegue il fine di riutilizzare una connessione unica, ha il vataggio di mettere a disposizione l'oggetto sql ad ogni servizio, senza riga di codice alcuna, e di utilizzare il file DataSource.groovy normalmente presente nei progetti grails... così si possono utilizzare i tre environment di questo file (development, production, test)

Abbiamo quindi creato un nuovo plugin in (seguendo la procedura indicata qui: http://docs.codehaus.org/display/GRAILS/The+Plug-in+Developers+Guide), dentro al quale abbiamo inserito il seguente codice:

def doWithDynamicMethods = {applicationContext ->
System.err.println("il metodo dinamico è partito1");
def sf = applicationContext.sessionFactory
com.fdlservizi.sse.SSEService.metaClass.getDbConn = {->
def sessione = sf.currentSession
def connessione = sessione.connection()
return connessione
}
}

Il quale inietta nella classe SSEService il metodo gerDbConn. In Grails inoltre vige la convenzione che ad ogni metodo get e set, corrisponda immediatamente, anche se non dichiarata, la relativa proprietà... quindi, specificando per una determinata classe il metodo getProprietà e/o setProprietà, automaticamente si può richiamare il metodo getProprietà semplicemente definendo: def proprietà (oppure utilizzando direttamente proprietà)

La classe SSEService, posta nella directory src/groovy/com.fdlservizi.sse/ è così composta


package com.fdlservizi.sse

import groovy.sql.Sql
import java.sql.Connection

class SSEService {

Sql getSql(){
def globalSql = new Sql((Connection)dbConn)
globalSql.execute("set dateformat ymd")
System.err.println("connection = " + (Connection)dbConn);
return globalSql
}

Connection getConnection(){
System.err.println("connection = " + dbConn);
return dbConn
}

org.hibernate.impl.SessionImpl getDbSession(){
return dbSess
}
}

In questa classe, quindi, per quello detto prima, semplicemente richiamando "dbConn", è come se richiamassimo getDbConn iniettato dal plugin.
Questa classe la usiamo poi per estendere ogni servizio che intenda usare una connessione sql... in questo modo, all'interno del servizio, possiamo semplicemente usare la sintassi che fino a quel momento usavamo, senza mai dichiarare l'oggetto sql.... perchè di fatto iniettato nella classe che estendono, quindi ereditato

In ogni servizio infatti si può tranquillamente scrivere, per esempio
sql.eachRow("select * from imp_tipo")
e si sottoindente GetSql, che a sua volta, sottointende getDbConn, che a sua volta sottointende applicationContext.sessionFactory.currentSession.connection() che restituisce la connessione di hibernate (presa dal file DataSource.groovy)
Questo però, come detto prima, al contrario delle nostre aspettative, sembra aprire sempre nuove connessioni.
Inoltre, nella classe SSEService, facciamo ad ogni richiesta di connessione, l'esecuzione del setdateformat, necessario per l'esecuzione delle nostre query, anche questo vantaggio notevole, dato che senza questo accorgimento bisognava eseguirla, in ogni servizio che utilizzava le date (DateTime, TimeStamp) e simili nelle query.

Abbiamo comunque deciso di concetrarci ora allo studio del dialetto di Hibernate, per utilizzare direttamente le sue potenzialita, demandando l'uso di sql diretto solo nei momenti in cui sarà strettamente necessario. Questo ci permetterà, presumibilmente, di demandare ad hibernate la gestione del pool di connession al database e le differenze tra i due database che dovremmo abdare a supportare (sql server e oracle).

giovedì 26 giugno 2008

Versioning

Sto provando ora l'utilizzo delle versioni per i progetti grails.
Da riga di comando, si può manipolare il file application.properties, settando quindi la versione, con
grails set-version n
dove n sta per il numero di versione.
Questo va a modificare la proprietà app.version all'interno del file sopracitato.

Successivamente si può utilizzare questo numero, all'interno dei progetti grails, con

da un controller con
def version = grailsApplication.metadata['app.version']
Oppure con le righe

import grails.util.*
def grailsVersion = GrailsUtil.grailsVersion
Oppure, all'interno di pagine gsp, con



Una volta che è stata settata al versione dell'applicazione, la creazione del war con il comando
grails war
rifletterà questi cambiamenti, nominando il war come nomeapplicazione.n.war, dove n sarà il numero di versione (in realtà questo per ora non succede, non so perchè, rimane sempre con il numero di versione 0.1; sul forum mi hanno consigliato di usare il comando
grails clean prima di grails war, ma nulla)

Durante il deploy si può inoltre specificare la directory di deploy, in quanto, di default, viene messo in una directory con lo stesso nome del war.
Per farlo basta usare il comando
asadmin deploy --contextroot /HelpDesk nomewar

Prima però bisogna fare l'undeploy dell'eventuale app già installata in quella directory, lo si fa con
asadmin undeploy nomeapp
nel nostro caso

asadmin undeploy HelpDeskGwt.1.2.6

AGGIORNAMENTO del 1 Luglio
Ho trovato l'errore del war... era colpa mia, nel file di configurazione config.groovy avevo inserito una riga di codice:
grails.war.destFile = """HelpDeskGwt-0.1.war"""
e questo forzava il nome del war... ora funziona tutto

venerdì 13 giugno 2008

Anche in Italia si muove qualcosa

Negli ultimi giorni anche il gruppo (mailing list su yahoo gropuc: http://it.groups.yahoo.com/group/Grails-IT/) italiano di Grails si sta animando, e oggi è stato rilasciato un tutorial interessante (mannaggia... se ci fosse stato un mesetto fa, avrei faticato molto meno)

Questo il messaggio integrale

Ciao,

ieri è stato pubblicato su Mokabyte il primo articolo su Grails e Groovy.

http://www2.mokabyte.it/cms/article.run?articleId=DYG-V69-HKE-Z3O_7f000001_10553237_7391cad5

Per come è fatto Grails, una Demo vale più di mille parole. Anche
l'articolo riprende questa impostazione alla "sporchiamoci subito le
mani", nei prossimi numeri andrò più in profondità sui vari argomenti
chiave.

Ovviamente, qualsiasi domanda o suggerimento per i prossimi numeri è
bene accetto.

Buon weekend!

Brando

giovedì 12 giugno 2008

Alcuni Errori - bug risolti, da ricordare

Durante lo sviluppo della nostra interfaccia sono emersi dei comportamenti strani di Gwt o GET-EXT o grails...
Forse dipendenti dalla mia scarsa esperienza, o forse da veri e propri buchi... non so

Elenco qui quelli che ho risolto, così da ricordarmi in futuro


  • Normalmente grails si accorge di ogni modifica effettuata ai file sorgenti e tenta la ricompilazione dei file necessari. Non ne sappiamo bene i motivi, ma così come è impostato Grails e il plugin di gwt, se si modificano dei file lato client di gwt, non sempre parte la compilazione. O meglio, sembra partire sempre, ma sembra che non vengano cancellati i file che gwt ha creato la compilazione precedente. Di fatto quindi le modifiche non vengono prese.

    Ho perso ore prima di capire questo problema... e pensavo che none ro capace di programmare, non mi capacitavo del perchè non vedevo le modifiche che avevo progettato... ed ecco poi risolto l'arcano... il problema, almeno questa volta, non ero io.

    RISOLTO:
    Francesco ha trovato al soluzione... obbligare lo script del plugin di gwt a ricompilare tutto.
    Questo lo si ottiene aggiungendo alla riga 76 del filke _Internal.groovy del plugin il seguente codice
    gwtForceCompile = true
    Avendo quindi questo codice:modules.each { moduleName ->
     gwtForceCompile = true
    if (!gwtForceCompile &&
    GU.environment != GA.ENV_PRODUCTION &&
      neW File("${outputPath}/${moduleName}/${moduleName}.nocache.js").exists()) {
     // We can skip this module.
             return
     }

    In più, per evitare il problema derivante dal "Java Heap Speace" abbiamo modificato il comando
     java(classname: 'com.google.gwt.dev.GWTCompiler', fork: 'true')
    sempre nello stesso file con
     java(classname: 'com.google.gwt.dev.GWTCompiler', fork: 'true',maxmemory: "512m")

    Se si hanno poi dei problemi con il jar di getext (non ho capito bene in quali casi avviene il problema, ma in alcune circostanze è così) va aggiunta anche questa riga di codice
    pathElement(location: "${basedir}/lib/gwtext.jar")
    nella zona della dichiarazioni del classhpath

  • Mai modificare un file di servizio lato server quando l'applicazione è up, perchè se per caso si aggiorna la pagina dell'aplicazione, grails si accorge che qualcosa è stato modificato, tenta la ricompilazione ma CANCELLA deliberatamente i file del servizio lato client. Non so bene perchè succeda, forse è provocato dalla modifica al plug in che abbiamo fatto (che forza la compilazione del modulo gwt, per risolvere il baco di cui sopra). Bisogna prima fermare l'appplicazione, o distruggere il server, poi ricompilare.

  • Attenzione con la gestione degli ascoltatori dei pulsanti, se poi li si vogliono abilitare e disabilitare. Non so se è un paco gi GWT o GWT-EXT (i button e i listener che utilizzo sono di GWT-EXT) o se è un normale comportamento... sta di fatto che se si aggiunge un ascoltatore ad un pulsante con una ascoltatore anonimo (come quasi sempre si fa), se ad un certo punto lo si disabilita, pare scomparire l'ascoltatore associato, quindi anche se lo si riabilita, non ascolta più nulla.
    Nel mio codice infatti avevo questo

    salvaButton.addListener(new ButtonListenerAdapter(){
    public void onClick(Button button, EventObject e) {
    [...]
    }
    });

    Trasformato poi in

    salvaButton.addListener(new AscoltatoreBottoneSalva());

    private class AscoltatoreBottoneSalva extends ButtonListenerAdapter{
    public void onClick(Button button, EventObject e) {
    [...]
    }
    }

martedì 10 giugno 2008

Giornata di aggiornamenti

Stamane è giornata di aggiornamenti.
Novità non indifferente, in ufficio abbiamo aperto la nuova macchina del caffè, una gaggia, tutta automatica, con il caffè in grani... scusate se è poco... la macchinetta di prima quasi ci esplodeva in mano ogni volta che l'accendevamo...
Bella bella...
vabbhe, torniamo alle cose importanti (perchè, il caffè non lo è? sì, è essenziale nella vita di un programmatore, ma forse non ai fini di questo blog)

Stamattina ho aggiornato sia Grails che Groovy
Di Groovy è stata rilasciata la versione 1.5.6, avevo installato sino ad ora la 1.5.5... d fatto nulla di che, solo qualche bugfix e migliorie varie...
Di Grails è stata recentemente rilasciata la 1.0.3, con alcuni bug fix, il supporto al tipo Enum, e un nuovo modo operativo, l'interactive mode, e migliore supporto all'internalizzazione i18n.
Oltre aver installato grails ho anche aggiornato il nostro progetto con la nuova release, dopotutto è semplice... basta il comando grails update nella directory del progetto.

AGGIORNAMENTO di Giovedì 12
Oggi ho aggiornato anche gwt-ext, di cui hanno rilasciato al versione 2.0.4
Alcune importanti migliorie sono presenti in questo aggiornamento, come il supporto a firefox3, che con la nuova verisone, dava alcuni problemi (firefox3 è+ molto più compatibile agli standard w3c di firefox2 e ie7... questo per assurdo creava problemi).
In questo aggiornamento c'è anche una nuova componente, pagebus... non so esattamente cosa sia, non ho capito, si orienta su nuove tecnologie presenti in opera, firefox, e safari. Comunque proprio questo aggiornamento ha iniziato a crearmi dei problemi.
Non in fase di compilazione, tutto filava liscio, ma Intellij IDEA ha iniziatoa darmi strani errori... in tutti i file mi continuava a dire
class blabla is defined in module 'com.gwtext.Pagebus' witch is not inherited in in module 'nome dle modulo del mio progetto'
ho aggiunto questa riga

al file nomemodulo.gwt.xml

venerdì 6 giugno 2008

Rieccomi

Dopo quasi un mese senza aggiornamenti, rieccomi.
Ho avuto poco tempo da dedicare al blog, nonostante le mie intenzione, a causa del sovraccarico di lavoro che la consegna di un progetto che mi coinvolgeva in prima persona ha portato.
Infatti, proprio durante lo studio sulla possibile accoppiata Grails+GWT (e GWT-Ext) si è conretizzata la possibilità di utilizzare proprio queste tecnologie per lo sviluppo di uno dei lavori richiesti da un cliente della fdl servizi.
Bisognava infatti rivedere un "HelpDesk" (una sorta di gestioen di ticket-aiuto) per la gestione di una centrale termica di un noto ospedale milanese.
Il tutto ovviamente deve essere usufruibile via web, e quale migliore occasione per testare queste tecnologie?

Il risultato? decisamente buono
A parte molti problemi nati qua e là durante il percorso, e quasi integralmente risolti, abbiamo ottenuto un interfaccia fresca, veloce e razionale, molto più performante di quello che pensavamo. Le rpc di GWT, integrate lato server con servizi groovy-grails, hanno una risposta davvero buono e lo scambio di dati tra client e server, anche attraverso "internet" e non solo uan rete intranet, è davvero buona, anche quando si tratta di compilare una griglia con migliaia di stringhe al suo interno.

Presto metterò online alcuni stralci di codice, in particolare per quanto riguarda la realizzazione delle RPC (come mi è stato richiesto da altri ragazzi che mi hanno scritto via mail per problemi riguardati lo sviluppo di RPC in GWT).
Parlerò inoltre della delegazione, da preferire in alcuni casi all'ereditarietà... anche se questo pattern, risolvendomi alcuni problemi e semplificandomi alcuni dettagli, mi ha portato a problematiche che non ho ancora risolto, che spero di annullare ocn lo studio di alcuni pattern proposti dai libri che ho già nominato in passato sul blog.

mercoledì 7 maggio 2008

Grails + GWT

Ho finito di leggere ed applicare l'esempio del libro "Getting started with Grails"... sembra proprio essere un gran bel framwork, ottimo per lo sviluppo di service web, praticamente fa tutto lui e grazie alla convention over configuration il codice da scrivere è davvero poco. Eseguendo la logica del MVC sembra non sia difficile integrare, come parte "view" del client dei moduli GWT.

Quindi ora passo allo studio proprio dell'integrazione di Grails con GWT.
Esiste un plugin per grails, già esistente nella normale installazione di Grails: http://grails.org/GWT+Plugin

Purtroppo sul sito di codehouse il plugin, o meglio, l'integrazione effettiva di gwt e grails non sono ben documentate, anzi...
Per prima cosa l'installazione del plugin nei singoli progetti grails non è veloce, almeno la prima volta: eseguito nel progetto racetack, quello che ho creato studiando GSWG, il comando
grails install-plugin gwt
ho dovuto aspettare quasi 10 minuti prima che si "ripulisse la cache"... di cosa non so bene.

Ho quindi creato il modulo gwt, chiamandolo Racetrack, seguendo la classica regola dei nomi del package, quindi con il comando
grails create-gwt-module com.fdlservizi.Racetrack

Seguendo la logica che quella che voglio fare è una view al progetto già esistente e funzionante, ho creato la pagina hosting del modulo gwt pensandola proprio come una view al controller "race".
La convenzione del plug in di gwt vuole che con il comando grails create-gwt-page , dove è la pagina hosting con il relativo path, se la pagina è indicata come una gsp e come indirizzo ha una singola cartella, questa viene interpretata come un controller view, altrimenti viene trattata come una normale pagina web.
Quindi ho eseguito il comando
grails create-gwt-page race/gwt.gsp com.fdlservizi.Racetrack

Tutto ciò dovrebbe avermi creato i file di configurazione necessari per il funzionamento del modulo gwt, e la pagina hosting dove mettere poi i widget gwt.
Con il comando
grails run-gwt-client
parte l'esecuzione dell'hosted mode di gwt, quindi parte anche il "browser" interno di gwt... va però precisato, e io me ne sono accorto dopo un po' di imprecazione, che deve essere attivo il server web... quindi da IDEA prima faccio partire il progetto racetrack e poi eseguo il comando run-gwt-client (ovviamente questo e i comandi precedenti vanno fatti all'interno del path del progetto racetrack)


Edit 8 Maggio
Iniziano i primi problemi... in pratica, come indicato nella pagina del plugin di gwt, per poter usare map e list in gwt, bisogna specificare nel servizio di grails il tipo di ritorno di queste liste o mappe. In teoria questo lo si dovrebbe fare con @CollectionTypeArg e @MapTypeArg ma qui casca l'asino. Il mio ambiente non vede le classi per queste annotation... viene questo errore
"unable to find class for annotation"
Ho chiesto aiuto nella mailing list di Nabble Grails User
Vediamo se ottengo aiuto.

Edit
Pausa pranzo finita e per ora nessun aiuto. Ho cercato di arrangiarmi e qualcosa, forse, ho risolto. Smattendo a destra e a manca no trovato dove risiede la classe delle annotazioni del plug in di gwt... in pratica nella directory del porgetto, sotto plugin in, vi è la directory in cui vi sono due jar. Uno di questi è grails-gwt-util.jar
Ho importato questa libreria da IDEA, andando in Setting -> Project Setting -> Library -> Attach Classes -> e ho selezionato il jar di cui sopra.
Poi nel file in cui voglio usare le annotazioni ho importato il riferimento alle annotazioni con
import org.codehaus.groovy.grails.plugins.gwt.annotation.CollectionTypeArg
Non so se è il metodo corretto, nè perchè abbia dovuto farlo (presupponevo che il plugin di GWT almeno importasse le jar necessarie al suo funzionamento), ma sembra funzionare.

venerdì 2 maggio 2008

Si passa ad Intellij Idea

I problemi che ho esposto in questo post Lo Saffolding non funziona ho poi scoperto non dipendono dalla mia ignoranza in materia grails o java... ma dal plugin di eclipse per grails che funziona male... e corrompe i file e l'ambiente.

Quindi ho installato, per il momento la trial version, di Intellij Idea, (altro IDE per Java) che sembra avere un integrazione con grails molto molto migliore.

Installato intellij Idea, ho installato i plug in per grails e groovy (che si trovano praticamente comunque già elencati in IDEA) e di fatto ho tutto pronto per lavorare.
Da IDEA posso creare il progetto grails direttamente dall'IDE, senza quindi usare la riga di comando come ho fatto sino ad ora.

Abbiamo poi creato un repository di subversion... e qui magari creerò un post apposito per questo fantastico tools.

Ho ripreso poi, reiniziandolo da capo, il tutorial del libro Getting Started With Grails, ovviamente apportando le modifiche dovute al cambiamento di versione con grails, che mano a mano segnalo nel post apposito.

Ho usato, invece di MYSQL, sempre il database in Java che ha nativamente grails con se, con la differenza che invece di usare la memoria ram, uso file su disco... questo lo si ottiene semplicemente cambiando l'url di memorizzazione nel file DataSource.groovy da
url = "jdbc:hsqldb:mem:devDB"
a
url = "jdbc:hsqldb:file:devDB"

Una delle cose che attualmente pare non sia possibile fare direttamente da IDE e il comando grails generate-all per ripetere la compilazione dei controllers e per effettuare nuovamente lo scaffolding... questo attualmente lo sto eseguendo ancora da riga di comando


mercoledì 30 aprile 2008

Lo scaffolding non funziona

Grails sembra fare praticamente tutto, se si rispettano le varie convenzioni, in pratica si riescono a generare un sacco di file preimpostati... lo scaffolding dovrebbe, per esempio, generare delle pagine web per inserire/aggiornare le classi del dominio.
Come suggerisce Getting Started with Grails, ho isntallato mysql e la libreria per agganciarlo a java, e ho specificato nelal configurazione dell'applicazione racetrack di non usare il database "in memoria" ma mysql.
Qui arrivano i primi problemi... il libro è stato scritto per la versione di grails 0.3.9 mentre ora siamo alla 1.X
Quindi ho dovuto "aggiornare" il codice, il libro infatti dice di modificare il file DevelopmentDataSource in questo modo
class DevelopmentDataSource {
boolean pooling = true
String dbCreate = "update"
String url = "jdbc:mysql://localhost/racetrack_dev"
String driverClassName = "com.mysql.jdbc.Driver"
String username = "jason"
String password = ""
}

ma questo file non esiste... però all'interno della directory conf vi è il file DataSource.groovy che sembrerebbe integrare i vari ambienti, cioè sviluppo, produzione, test
ho modificato questo file così (seguendo un po' la logica e un po' quello che c'è scritto sul sito di groovy nella sezione getting started)
environments {
development {
dataSource {
dbCreate = "create-drop" // one of 'create', 'create-drop','update'
//url = "jdbc:hsqldb:mem:devDB"
//aggiunto qui sotto da gabriele, e quella sopra commentata
String url = "jdbc:mysql://localhost/racetrack_dev"
String driverClassName = "com.mysql.jdbc.Driver"
String username = "gabry"
String password = ""
}
}
test {
dataSource {
dbCreate = "update"
url = "jdbc:hsqldb:mem:testDb"
}
}
production {
dataSource {
dbCreate = "update"
url = "jdbc:hsqldb:file:prodDb;shutdown=true"
}
}
}

Fatto questo però, i problemi non finiscono. Infatti, così come sono messe le cose, dopo aver creato i controller con la riga di comando
grails create-controllers
sia per Race che per Registration (e sembra funzionare tutto), sostituendo dei due controller la riga
def index = { }
con la riga
def scaffold = Race
(o Registration per la classe RegistrationController), facendo partire
grails run-app
dovrebbe automaticamente crearmi le pagine per la gestione delle classi di dominio... ma puntato il browser su http://localhost:8080/racetrack vedo sì i link ai due controller, ma invece di mostrarmi la paginetta con le classi... mi mostra un noioso errore che non capisco come risolvere (incollato in fondo al topic).
Ho comunque chiesto aiuto nella community di Napple
Error with "Getting Started with Grails" sample: scaffold


Aggiornamento di martedì 2 Maggio
Ho scoperto che non sono l'unico ad avere questo problema, sempre nella mailing list di Nabble, ho trovato questo
Grails Scaffold Issues

Inoltre ho trovato una pagina del sito dell'autore di "Getting Started With Grails", Jason Rudolph, in cui sono state messe alcuni aggiornamenti al codice del libro, dovuti ai cambiamenti che mano a mano sono stati introdotti dalle varie versioni di Grails
http://jasonrudolph.com/gswg_faq.html

Grails Runtime Exception
Error Details
Message:
Caused by:
Class: Unknown
At Line: [-1]
Code Snippet:
Stack Trace

java.lang.NullPointerException

at org.codehaus.groovy.grails.scaffolding.TemplateGeneratingResponseHandler.handleResponse(TemplateGeneratingResponseHandler.java:104)

at org.codehaus.groovy.grails.scaffolding.DefaultGrailsScaffolder$ListAction.call(DefaultGrailsScaffolder.java:113)

at groovy.lang.Closure.call(Closure.java:287)

at org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsControllerHelper.handleAction(SimpleGrailsControllerHelper.java:503)

at org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsControllerHelper.executeAction(SimpleGrailsControllerHelper.java:394)

at org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsControllerHelper.handleURI(SimpleGrailsControllerHelper.java:233)

at org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsControllerHelper.handleURI(SimpleGrailsControllerHelper.java:154)

at org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsController.handleRequest(SimpleGrailsController.java:88)

at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)

at org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet.doDispatch(GrailsDispatcherServlet.java:251)

at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:809)

at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:476)

at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:431)

at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)

at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)

at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)

at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:367)

at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)

at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)

at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)

at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)

at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:268)

at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:126)

at org.codehaus.groovy.grails.web.util.WebUtils.forwardRequestForUrlMappingInfo(WebUtils.java:198)

at org.codehaus.groovy.grails.web.util.WebUtils.forwardRequestForUrlMappingInfo(WebUtils.java:185)

at org.codehaus.groovy.grails.web.mapping.filter.UrlMappingsFilter.doFilterInternal(UrlMappingsFilter.java:117)

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:75)

at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1089)

at org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter.parsePage(GrailsPageFilter.java:119)

at org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter.doFilter(GrailsPageFilter.java:82)

at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1089)

at org.codehaus.groovy.grails.web.servlet.filter.GrailsReloadServletFilter.doFilterInternal(GrailsReloadServletFilter.java:142)

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:75)

at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1089)

at org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:68)

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:75)

at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1089)

at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:96)

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:75)

at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:183)

at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:138)

at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1089)

at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:365)

at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)

at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)

at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)

at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)

at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)

at org.mortbay.jetty.Server.handle(Server.java:295)

at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:503)

at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:827)

at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:511)

at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:210)

at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:379)

at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:361)

at org.mortbay.thread.BoundedThreadPool$PoolThread.run(BoundedThreadPool.java:442)

martedì 29 aprile 2008

Getting Started with Grails

Dopo essermi ben ben infarinato con Groovy, è ora di passare a Grails, e quindi, dopo aver proceduto all'installazione e alla configurazione del framework, parto con lo "studiare" qualche libro si questo framework. Speriamo che alla fine di queste letture mi convinca (anzi, ci convinciamo) che sia proprio il prodotto che fa per noi.

Parto con la lettura di un libro trovato online, scaricabile anche gratuitamente sul sito dedicato al minibook: http://www.infoq.com/minibooks/grails oppure acquistabile online sul famoso servizio di POD (Printing On Demand): lulu.com (http://www.lulu.com/content/618462)

Come sempre, userò questo post per prendere appunti, ove necessario, su questo libro.

Sebbene Grails abbia un database embedded, validissimo per i primi esempi "al volo", il libro consiglia, per un qualcosa di più duraturo, un database come mysql, sebbene grails sia compatibile con molti altri, tra cui, per esempio, oracle.
Procedo quindi all'installazione di MySql 5.0 (per rendermi le cose semplici scarico l'autoinstallante, scegliendo l'installazione completa, lasciando le opzioni standard, compreso l'installare il servzio di windows per il server mysql, sulla porta 3306).

  • All'interno della definizione del dominio (cioè, in pratica, la definizione delle classi che definiscono di fatto il progetto) del progetto di esempio Racetrack, si definisce la classe Race. All'interno della stessa, nell'elenco dei fields, si ha questa
    static hasMany = [registrations:Registration]
    che permette di specificare la relazione uno a molti che intercorre tra Race e Registration. Quella riga di codice, infatti, dice a Grails che la classe Race avrà la proprietà registrations che memorizzerà una collezione di oggetti Registration. Non serve poi specificare di nuovo l'esistenza del field registrations, perchè è implicita nella riga sopracitata (Grails segue la logica del DRY - Don't Repeat Yourself).
    La definizione delle relazioni ha diverse configurazioni, specificate dal GORM (Grails Object Relational Mapping), tutte reperibili qui: http://grails.org/GORM+-+Defining+relationships
  • Grails considera tutti le propietà (fields) di una classe come obbligatori, cioè per ogni classe devono essere espressi. Se si vuole specificare che uno dei campi non è obbligatorio, va aggiunta nelle constrains l'opzione nullable=true per ogni campo che si vuole specificare come facoltativo
  • Sempre seguendo l'esempio di prima, se nella relazione tra due classi, come definita prima, una a molti tra Race e Registration (cioè una corsa a zero o più registrazioni ad essa associata) possiamo aggiungere il concetto che una Registration non esiste se non correlata ad una Race. Quindi nella classe Registration aggiungiamo questa riga di codice
    static belongsTo = Race
    Cioè creiamo la proprietà belongsTo che specifica appunto che l'istanza della classe Registration esiste solo se associata ad un'istanza della classe Race, e se cancelliamo la Race, si cancellano tutte le Registration ad essa associate.
  • Secondo la logica del Convention Over Configuration, non serve specificare che le due classi specificate prima sono classi da "memorizzare", perché per convenzione le classi del dominio, come quelle di cui sopra, realizzate nella directory Domain, hanno bisogno della persistenza, e Grails quindi la gestirà in maniera automatica (di default, tramite Hibernate).
  • Il concetto del flash message è stato introdotto per permettere il "passaggio di parametri" tra le pagine. Infatti, per memorizzare messaggi di errore/avviso, e per passarseli tra le pagine, non possiamo usare variabili normali di una classe, perchè scomparirebbero all'aggiornamento della pagina (a meno di memorizzarle fisicamente da qualche parte). Usando invece questa variabile automaticamente creata da grails, possiamo passare tra le pagine questi messaggi: flash.message = "bla bla".
    Ciò che viene memorizzato nella variabile flash è disponibile durante la richiesta nella quale viene memorizzata e la successiva, quindi anche, per esempio, dopo un redirect della pagina.

Cambiamenti da fare al codice del tutorial dovuti ad errori di stampa del libro o necessari per le nuove vesioni di Grails (il libro è stato scritto per grails antecedente lo 0.4 e io attualmente sto usando grails 1.0.x)
  • Pagina 13 (25 sul pdf)
    La proprietà optional non esiste più da grails 1.0, ora, per dichiarare opzionale un campo, va aggiunta la propietà nullable=true nelle constraints per quel dato campo.
    Quindi la riga
    static optionals = ["postalAddress", "gender"]
    non va scritta, e si aggiunge invece una constraints nella classe
    static constraints = {
    postalAddress(nullable:true)
    }

    ricordandosi ovviamente di mantenere questa constraints anche successivamente
  • Pagina 21 (33 sul pdf)
    Il file DevelopmentDataSource non esiste più
    Le configurazioni vanno tutte fatte nel file DataSource.groovy
    Oltretutto io ho deciso di non usare, almeno per ora, mysql, ma di usare HSQLDB, già integrato con grails... l'unica modifica che faccio al file è quella di non memorizzare in memoria principale il file, ma di memorizzarlo a disco.
    Quindi le configurazioni per il development che si vogliono introdurre vanno comunque fatte nel file DataSource.groovy all'interno di queste righe di codice
    [...]
    environments {
    development {
    dataSource {
    //dbCreate = "create-drop" // one of 'create', 'create-drop','update'
    dbCreate = "update"
    url = "jdbc:hsqldb:file:devDB"
    }
    }
    [...]
  • Pagina 25 (37 sul pdf), pagina 27 (39 sul pdf)
    La proprietà maxLength non esiste più, va sostituita da maxSize, così, per esempio la riga
    city(maxLength:30,blank:false)
    diventa
    city(maxSize:30,blank:false)
  • Pagina 35 (47 sul pdf)
    Il codice della pagina gjp è proposta è diverso, in realtà qui non c'è nulla da modificare poichè la pagina gsp è stata creata automaticamente dal framework, quindi già aggiornata al codice necessario per il funzionamento.
  • Pagina 36 (48 sul pdf)
    Il codice del controller a cui si fa riferimento è diverso, in realtà qui non c'è nulla da modificare poichè il controller è stata creato automaticamente dal framework, quindi già aggiornata al codice necessario per il funzionamento, con il comando "generate-all".
  • Pagina 40 (52 sul pdf)
    Il messaggio a cui si fa riferimento, default.invalid.max.length.message, in realtà è default.invalid.max.size.message, dato che, come spiegato prima, il
    maxLength e minLength sono sostituiti da maxSize e minSize.
  • Pagina 41 (53 sul pdf)
    Non serve più riavviare il server ad ogni cambiamento, grails si accorge da solo e basta salvare le modifiche, e se si ritorna sulla pagina web, riaggiornandola, le si ritrovano subito.
  • Pagina 41 (53 sul pdf)
    In realtà non servirebbe aggiungere questo segnale di avvertimento, perchè le nuove versioni di grails lo aggiungono in maniera automatica, sempre tramite un javascript onclick
  • Pagine 43-45 (55-57 sul pdf)
    In realtà anche qui pare non sia necessario aggiungere il flash.massage ad ogni azione, perchè già create in automatico dalla nuove versioni di Grails
  • Pagina 46 (58 sul pdf)
    Come indicato prima la pagina gsp è diversa, ma il codice da rimuovere è facilmente identificabile. Però, oltre rimuovere la colonna id effettivamente inutile, va conservato il link per leggere i dettagli della race. Questo link è proprio conservato nell'id, quindi cancelliamo pure la riga dell'id, ma modifichiamo anche quella del nome in modo da conservare questo link
    Cancelliamo quindi:
    ${race.id?.encodeAsHTML()}
    E modifichiamo la riga sotto da
    ${race.name?.encodeAsHTML()}
    a
    ${race.name?.encodeAsHTML()}
  • pagina 102 -103 (114-115 sul pdf)
    Il file di configurazione di log4j, log4j.production.properties, non si trova più in racetrack/web-app/WEB-INF. Tutte le configurazioni di log4j vanno inserite nel file Config.groovy che si trova in /grails-app/conf. Inoltre le modifiche da apportare sono diverse da quelle indicate nel libro.
    La parte dedicata a log4j del mio file Config.groovy è così diventata:

    log4j {
    appender.stdout = "org.apache.log4j.ConsoleAppender"
    appender.'stdout.layout'="org.apache.log4j.PatternLayout"
    appender.'stdout.layout.ConversionPattern'='[%r] %c{2} %m%n'
    appender.errors = "org.apache.log4j.FileAppender"
    appender.'errors.layout'="org.apache.log4j.PatternLayout"
    appender.'errors.layout.ConversionPattern'='[%r] %c{2} %m%n'
    appender.'errors.File'="stacktrace.log"
    rootLogger="error,stdout"

    appender.access="org.apache.log4j.FileAppender"
    appender.'access.file'="access.log"
    appender.'access.layout'="org.apache.log4j.PatternLayout"
    appender.'access.layout.ConversionPattern'='%d %p %x [%c] %m%n'


    logger {
    //grails="error"
    StackTrace="error,errors"
    grails.'app.controller.UserController'="warn,access"
    org {
    codehaus.groovy.grails.web.servlet="error" // controllers
    codehaus.groovy.grails.web.pages="error" // GSP
    codehaus.groovy.grails.web.sitemesh="error" // layouts
    codehaus.groovy.grails."web.mapping.filter"="error" // URL mapping
    codehaus.groovy.grails."web.mapping"="error" // URL mapping
    codehaus.groovy.grails.commons="info" // core / classloading
    codehaus.groovy.grails.plugins="error" // plugins
    codehaus.groovy.grails.orm.hibernate="error" // hibernate integration
    springframework="off"
    hibernate="off"
    }
    }
    additivity.StackTrace=false
    additivity.grails.app.controller.UserController=false
    }

lunedì 21 aprile 2008

Groovy Programming: An Introduction for Java Developers



Mi sono procurato questo libro, che viene pubblicizzato anche sul sito ufficiale di groovy. In questo post metterò via via i principali concetti, da tenersi bene a mente, che troverò nel libro. I codici presenti nel libro possono essere recuperati nella pagina web predisposta dall'autore.

  • Groovy è un linguaggio di scripting, nativamente compatibile con Java e le sue API (dato che sfruttano la stessa JVM, Java Virtual Machine). Può essere usato come collante per applicazioni create con Java, oppure il codice può essere "mischiato" con codice Java senza grossi problemi.
  • Linguaggi di scripting sono in particolare adeguati per le situazioni in cui bisogna integrare applicazioni già esistenti, manipolare una vasta varietà di entità dinamiche, applicazioni con interfaccia grafica, sono particolarmente adeguati per applicazioni medio-piccole.
  • I linguaggi come Java sono fortemente tipizzati, per garantire al sicurezza del codice e epr rende agevola la manutenzione di grosse applicazioni. Però così si rende il linguaggio poco adeguato per l'integrazione di componenti differenti, perchè spesso non si sa a priori il tipo di dati da associare ad una variabile, in questo vengono in soccorso i linguaggi di scrripting che spesso sono debolmente tipizzati, appunto come groovy. L'altro lato della medaglia è che con un linguaggio poco tipizzato codice che non solleva errori in compile time potrebbe sollevare eccezzioni, per problemi di tipo, a run time. Questo rende obbligatorio una intensa attività di test per questo tipo di applicazioni.
  • Tutto in groovy è un oggetto, quindi ogni variabili è un istanza di una certa classe.
  • Seguono la regola di cui sopra anche i numeri, quindi per esempio, per un dato integer, per esempio il valore 123, possiamo chiamare, per sapere il successivo, il metodo "next" delal classe integer: 123.next() ottenendo quindi 124. Oppure per sommare due numeri possiamo chiamare il metodo +, passando come parametro il secondo numero, quindi per esempio 123.+(56) oppure il metodo plus, 123.plus(56); fortunatamente groovy prevede l'overloading degli operatori, e quindi possiamo efefttuare la somma nella classica forma 123 + 56
    Da notare come la divisione di due integer risulti SEMPRE in un floating point.
    Da sottolineare come l'operazione modulo (mod oppure %) può essere chiamata solo su due integer
  • Sebbene non si debba definire il tipo di una variabile, al variabile stessa deve essere definita tramite la keyword def, in rpatica la prima volta che si usa una variabile bisogna dichiararla così
    def age
    oppure facendo subito un assegnamento
    def age = 25
  • Le stringe si possono specificare con apice singoli ('), apici doppi (") o addirittura triplici apici - cioè tre volte apici doppi - ("""); con apici tripli si possono specificare stringe multiriga. Con gli apici singoli di specificano stringhe letterali, con le altre due interpretate, cioè ogni espressione in questa forma ${expression} viene interpretata e viene scritto il risultato, cioè
    def age = 25
    ’My age is ${age}’ // My age is ${age}
    “My age is ${age}” // My age is 25
  • La comparazione tra stringhe è fatta in maniera molto simile ai classi metodi dei linguaggi di scripting, capitolo 3.5 e 3.6 del libro.
  • Evidentemente groovy (o java) è un po' cambiato da quando è stato fatto il libro. Nella parte dedicata all'I/O infatti, in uno degli esempi si da questo codice
    name = System.in.readLine()
    ma risulta deprecato, quindi va sostituito con
    name = new BufferedReader( new InputStreamReader(System.in) ).readLine()
  • I metodi sono definiti come le variabili con al parola riservata def, esempio
    def printName(name) {
    println “Name (at entry): ${name}”
    name = ‘John’
    println “Name (after assignment): ${name}”
    }

    seguono poi le regole classiche delle funzioni in java
  • interessante poi l'uso delle parentesi graffe come "funzione"... in pratica possiamo chiamare un pezzo di codice con un determinato nome e poi eseguirlo un po' come se fosse una funzione, qui sotto un esempio con verifica dello scope dei parametri

    def greeting = ‘Hello’
    def clos = {param -> println “${greeting} ${param}”}
    clos.call(‘world’)
    // Now show that changes to this variable change the closure.
    greeting = ‘Welcome’
    clos.call(‘world’)
    def demo(clo) {
    def greeting = ‘Bonjour’ // does not affect closure
    clo.call(‘Ken’)
    }
    demo(clos)

    e l'outupt è:

    Hello world
    Welcome world
    Welcome Ken
  • La gestione delle classi è praticamente identica a Java, quindi anche in Groovy ogni classe, per ogni fields, ha il setter preimpostato. Cioè, data una classe con un campo chiamato, per esempio balance, di cui creiamo un istanza chiamata, per esempio, acccount1, possiamo settare il fields sia con account1.balance=300 sia con account.setBalance(300).
  • Molte delle cose qui non scritte sono identiche o pressoché identiche a Java.
  • Il corrispettivo delle JSP per java, in Groovy viene indicato come GSP e il corrispettivo delle servlet viene soprannominato Groovlet, e il funzionamento ne è stato semplificato.
    Per ora non approfondisco le Groovlet, preferisco rimandare il tutto a quando mi metto a studiare Grails. Per quanto riguarda le GSP invece va sottolineato che sono un poco meno potenti delle JSP in quanto si riducono ad essere assimilate ad un template Framework. In partica si condisce una pagina html semplice con del codice groovy ( <% - %> ) per aggiungere contenuto dinamico, definito altrove (secondo la logica del MVC)

mercoledì 16 aprile 2008

Grails, Groovy On Rails

Non faccio a tempo a finire di studiare un framework, che già se ne trova un altro da analizzare... piuttosto impressionate come cosa.

Non riesco nemmeno a finire di comprendere, come si deve, enunciare che subito salta fuori Grails... un framework completo per lo sviluppo di RIC con il linguaggio Groovy, una sorta di semplificazione di Java (e totalmente compatibile con Java stesso).

Ho trovato il plug in per integrare groovy e eclipse
http://groovy.codehaus.org/Eclipse+Plugin
e sembra funzionare.
Così come l'integrazione con Eclipse del framework
http://grails.org/Eclipse+IDE+Integration
PS: ho attivato l'opzione "Disable Groovy Compiler Generating Class Files" per rendere automatiche alcune funzioni del plugin... da ricordare però che così non funziona il debugging.

giovedì 10 aprile 2008

Enunciate, Maven, GWT, forse Spring, qualcos'altro?

Mi sto studiando un po' Enunciate, alla fine sembrerebbe interessante e potrebbe servirci per velocizzare lo sviluppo dei Web Services, evitando di scrivere tanto codice piuttosto ridondante.

Facendo il primo tutorial, anzi, il secondo, mi sono trovato di fronte ad un po' di difficoltà... si integra maven, con GWT, con enunciate, e volendo pure con spring... quindi insomma, un po' difficile per me che non conosco bene praticamente nessuna di queste tecnologie.

Comunque, spulciando un po' nei readme di enunciate (nella release ci sono anche 3 esempi) e un po' spulciando in rete, ho trovato come fare.

Dalla directory principale del sample, dal prompt dei comandi, si lancia maven
mvn -Dgwt.home=/path/to/gwt/home package
ovviamente inserendo il path dell'installazione di gwt
Questo comanda chiede a maven di compilare il progetto... nel progetto infatti c'è già un file pom.xml bello pronto.

Altrimenti si può chiedere a maven di compilate, far partire il server jetty e pubblicare il tutto, così da renderlo accessibile in locale, con questo comando
mvn -Dgwt.home=/path/to/gwt/home jetty:run-war
e puntando il browser su http://localhost:8080/petclinic/petclinic.html (petclinic è il secondo il progetto che i tutorial di enunciate prendono in considerazione) si vede il tutto all'opera

Se in più si vuole creare i file per importare il tutto in eclipse, si usa il plugin eclipse di maven, digitando sempre dalla directory root del progetto
mvn eclipse:eclipse
In alcuni casi, non ho capito bene l'agoritmo però, bisogna controllare la path in eclipse... verificando che tutte le librerie siano importate in maniera corretta

Si può inoltre evitare di scrivere, via riga di comando, il parametro -Dgwt.home (quindi per esempio richiamando il comando con "mvn jetty:run-war") inserendo nel file di configurazione enunciate.xml questo parametro
gwtHome="c:\Programmi\GWT\gwt-windows-1.4.62"
rispettando ovviamente la path della propria installazione di gwt, all'interno della dichiarazione del modulo gwt. Per esempio, nel mio petclinic, il file enunciate.xml, è così composto

<enunciate>
<modules>
<gwt disabled="false"
gwtHome="c:\Programmi\GWT\gwt-windows-1.4.62"

rpcModuleName="org.codehaus.enunciate.samples.petclinic.PetClinic">
<app
srcdir="src/main/gwt-apps" javascriptstyle="PRETTY">

<module
name="org.codehaus.enunciate.samples.petclinic.app.PetClinicApp">
</app>
</gwt>
<amf disabled="true">
<app
srcdir="src/main/flex-apps" name="vets"
mainmxmlfile="src/main/flex-apps/org/codehaus/enunciate/samples/petclinic/flex/vets.mxml">
</amf>
</modules>
</enunciate>

Google App Engine

Ieri, mentre finivo di rivedermi JSON e il supporto di GWT verso questo sistema di "scambio messaggi", mi arriva un alert da google desktop... "Google lancia una nuova iniziativa: Google App Engine"

Si tratta di un iniziativa interessante, che in poche ore ha scosso un po' il mondo degli sviluppatori... basti pensare che il video rilasciato da google di presentazione di questa tecnologia, quando l'ho visionato per la prima volta io (penso davvero poco dopo che i due blog su google più visitati, Google Blogoscoped e Google Operating System, aveva 427 Views... dopo meno di 20 minuti, ne aveva più di 30mila



In pratica google mette a disposizione, inizialmente solo ai primi 10mila sviluppatori (speriamo io sia tra questi, intanto mi sono messo in lista) spazio web (inizialmente 500 MB), banda (non poca), cicli di CPU (non pochi) eccetera, per poter mettere online le proprie applicazioni e testarle, sia in privato, sia di diffonderle al pubblico. Il tutto reso davevro semplice dall'environment che hanno sviluppato. Infatti rilasciano anche un SDK per gli sviluppatori, con una buona documentazione, per rendere di fatto subito disponibili le proprie applicazioni online, con un sacco di strumenti di analisi. Il tutto sotto l'ottima tecnologia di google, con database e sistemi scalari (maggiore traffico ha la tua applicazione, maggiore risorse ti danno).
Il tutto inizialmente solo per il linguaggio Python, ma in futuro (prossima pare) anche in altri linguaggi di programmazione.

Nel frattempo è nata una discussione tra sviluppatori, proprio all'interno di youtube, nei commenti dei video, per chiedersi come mai google abbia lanciato questo sistema con il supporto al solo linguaggio phyton
Nel video, i tecnini di google, dichiarano che è perchè buona parte dell'infrastruttura di google è proprio fatta in phyton e perchè gli inventori di questo linguaggio di programmazione, se non ho capito male, lavorano proprio, da qualche mese, in google.
La domanda che molti si sono posti, comunque, è perchè non c'è sin dall'inizio Java tra i linguaggi supportati: dopotutto google ha recentemente lanciato, con discreto successo GWT e Android, entrambi applicazioni per lo sviluppo di RIC in Java... quindi?
Alcuni sviluppatori rispondono che... Java non è il futuro, troppo pesante e "lungo" da programmare... e Phython è molto meglio.
Bho, non ho le conoscenze sufficienti per giudicare... ma è strano che google prima lanci due importanti tecnologie per Java e poi la ignori... forse non si vuole legare troppo ad un linguaggio di programmazione?


Google App Engine: http://code.google.com/appengine/

martedì 8 aprile 2008

Enunciate

Non faccio nemmeno a tempo di finire di approfondire (se si può dire approfondire... diciamo rivedere) le GWT-RPC, che già mi trovo di fronte ad un nuovo framework da analizzare!!!

E sì, giusto ora ho finito i capitoli sull'RPC di GWT in Action, ma stamane Francesco mi ha presentato questo framwork, ENUNCIATE (http://enunciate.codehaus.org/index.html), framework per lo sviluppo di Web Service, che ne semplifica lo sviluppo, sfruttando le tecnologie esistenti per fornire uno stumento per il build, il package, la distribuzione ecc...

Ora mi rivedo meglio l'utilizzo di GWT-JSON, poi mi studio questo frework, sia sul sito http://enunciate.codehaus.org/getting_started.html sia sul blog dell'autore di enunciate: http://weblogs.java.net/blog/stoicflame/archive/2008/01/web_service_pro_1.html

giovedì 3 aprile 2008

GWT-RPC

Attualmente sono arrivato in una fase di stallo per lo studio di Maven: ho capito cosa è e grossomodo come funziona. Idem, grossomodo, per Spring: ho capito, grossomodo, cosa è e ho un infarinatura su come funziona.

Ora però mi sono reso conto che è inutile, o comunque troppo complicato, per me studiarmi l'integrazione tra GWT e Spring, che in effetti sembra essere una buona strada, se non so bene come si comportano le RPC in GWT.

Quindi ho deciso di ritornare sullo studio di GWT, in particolare sull'utilizzo delle sue RPC (GWT-RPC). Una volta studiate, se sarò in grado di utilizzarle in maniera decente, e potrò dire di conoscerle, forse potrò affrontare l'integrazione con Spring senza troppa difficoltà... e se voglio analizzare altri sistemi di dialogo Client-Server, per sapere che strada affrontare, è il caso che conosca bene le RPC per conoscerne vantaggi e svantaggi.

Ho trovato qualche altro tutorial in rete:

RPC To Java Tutorial
Ho provato ad usare questo tutorial. Molto semplice, con poche informazioni e non spiegato benissimo, da però alcuni accorgimenti interessanti per gli "niubbi" di Java e gwt
Ho voluto però implementarlo da zero. Non ho quindi usato il codice online, ma ho creato un progetto in Eclipse da zero e piano piano ho aggiunto il codice.
Nuovo progetto web dinamico
Ho poi aggiunto il modulo GWT (dal progetto, new -> other -> GWT Module)
Ho aggiunto poi il modulo per le rpc (in pratica crea le classi async, imple eccetera, sia per client che per server) (dal progetto, new -> other -> GWT Remote Service)
Ho aggiunto il codice del tutorial (rinominando però RPCImpl in RPCInterfaceImpl perchè mi pareva più conforme agli standard... usare il nome stesso, aggiungendo prima async e poi impl)
Ho rinominato anche il nome del modulo, ma nulla di che

però ho poi dovuto consultare il codice che veniva fornito, perchè ho dovuto aggiungere questa riga al file "nomemodulo".gwt.xml perchè la configurazione di eclipse non la crea

martedì 1 aprile 2008

ancora su Maven

Ho provato a fare il tutorial trovato in questa pagina, che spiega il triodo Maven-Spring-GWT (si dice triodo? vabbhe avete capito)
http://shinetech.com/pages/viewpage.action?pageId=1396
ma purtroppo non riesco a finirlo, in quanto una delle ultime parti mi da un errore strano
Non so se sia un errore di utilizzo di Spring o GWT... più probabilmente non so usare Maven
Ho creato una discussione nel gruppo di GWT-Maven
http://groups.google.com/group/gwt-maven/t/f29cc4c833d14ad9
Vediamo se otterrò rispsota
(EDIT: 2 aprile
ho ricevuto risposta, che ha risolto il problema... ma ora ottengo un altro build error... che scatole... vedremo se mi aiutano ancora)


Nel frattempo mi leggo un'altra guida su Maven... primi passi, quelli che servono a me
http://www.javajournal.it/blog/2006/11/21/primi_passi_com_maven_prima_parte_3.html
http://www.javajournal.it/blog/2006/11/24/primi_passi_com_maven_seconda_parte_3.html
http://www.javajournal.it/blog/2006/11/30/primi_passi_com_maven_terza_parte_3.html


Aggiornamento 14:43
Guida letta, facile, molto semplice... ho capito il contenuto e almeno ora ho un po' più chiare le dinamiche di maven. Ma è una guida semplice, che spiega meno di quello che mi serve per capire i tutorial maven-spring-gwt

Nel frattempo trovo qualcosa per l'integrazione di Maven ed Eclipse
http://www.jugsiracusa.it/pmwiki.php?n=KnowledgeBase.KBMavenEclipse
in realtà ho già installato un plug in per ecplise (M2Eclipse)... ma me ne installo un'altra che viene consigliata sul sito ufficiale di Maven (http://maven.apache.org/eclipse-plugin.html)

Continuo a Studiarmi Maven

giovedì 27 marzo 2008

Maven

Già nelle scorse settimane mi era più volte capitato di leggere qualcosa su Maven... alcuni tutorial e progetti che ho analizzato lo richiedevano o facevano riferimento a questo tool, ma ho sempre evitato di "sapere cosa fosse".

Leggendo però il tutorial (anzi, vedendo la videolezione e relativi source) per l'integrazione tra GWT e Spring si è resa necessario lo studio, anche solo approssimativo, di cosa sia Maven.

Copio la definizione trovata in questa pagina:
http://www2.mokabyte.it/cms/article.run?articleId=S85-L5J-HP3-86O_7f000001_30480431_0844866c

Maven è un uno strumento "intelligente" e di alto livello per la gestione dei progetti in termini di compilazione, assemblaggio, test, deployment, e così via.
Sembrerebbe qualcosa di fin troppo evoluto per quello che sto facendo ora, anche se probabilmente diventerà interessante e utile per ciò che implementeremo. E dato che per comprendere ed utilizzare alcuni tutorial devo saperlo utilizzare, forse è il caso che me los tudi almeno superficialmente.

Attualmente sto leggendo questi articoli: Maven: best practices per il processo di build e di rilascio dei progetti in Java
Sembrano fatti bene, la prima pagina me la sono letta e più o meno capita tutta: è un introduzione a cosa sia Maven e una semplificata analisi di confronto Maven VS Ant (uno strumento di build di progetti Java)