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