En el último tutorial os conté un poquito de Scala:
https://adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=scala.
Ahora vamos a dar un pasito más intentando construir una aplicación Web y para ello probaré el framework Lift para ver que nos aporta. Vamos a ver lo siguiente:
- Como instalar Lift para Scala y trabajar desde la linea de comando.
- Como instalar el plugin de Maven para eclipse m2e y los arquetipos de Lift para scala. Con esto crearemos el esqueleto básico de un proyecto lift y lo usaremos dentro de Eclipse compilando y ejecutando con Maven.
- Interpretar el ejemplo Blank de Lift: nuestras primeras paginitas sobre el arquetipo.
Instalación de Lift
Antes de nada nos deberemos dar un paseo por su Web para ver los recursos disponibles
http://liftweb.net/.
Descargamos la última versión.
Estad atentos a la que os descargáis porque luego os puede dar algún quebradero de cabeza con los generadores de código y la documentación/ejemplos.
El modo más sencillo de trabajar es copiar un directorio (basic o blank) y copiarlo con otro nombre.
Así partimos de algo que funciona y no perdemos el original.
Vamos a seguir las instrucciones del propio manual de Lift
http://simply.liftweb.net/index-13.1.html#toc-Section-13.1
Descargamos y descomprimidos, ejecutamos el comando sbt. Yo estoy en Mac y sin problemas. Eso si, recordar el ./stb
Después ejecutamos el comando update en linea de comando.
Y por último, ejecutamos el comando jetty:run.
Por desgracia, no acaba de funcionar correctamente y da un error de memoria
java.lang.OutOfMemoryError: PermGen space.
Bueno, esto es sencillo de solucionar.
Vamos a cambiar los parámetros de arranque de la máquina virtual Java.
Vamos a nuestro directorio de trabajo en este caso liff_autentia.
Y editamos el fichero sbt y añadimos las entradas de tamaño.
java -Xmx712M -Xss2M
-XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256m -Xmx512M -Xss2M
-jar dirname $0
/sbt-launcher.jar "$@"
Volvemos a lanzar jetty:run
Ahora solamente tenemos que ir a http://localhost:8080/ y vemos el resultado de nuestro proyecto básico.
Podremos modificar el código y actualizar la aplicación Web usando el comando
~prepare-webapp.
Trabajando con Lift para Scala desde Eclipse con Maven
Bueno, trabajar desde la linea puede estar bien pero casi que prefiero trabajar en eclipse.
Podríamos importar el proyecto simplemente y configurarlo pero creo que si queremos afrontar proyectos a nivel profesional en el ecosistema Java es fundamental trabajar con Maven.
Como curiosidad en Mac ya viene instalado Maven. Si pulsamos mvn -version podemos comprobar la versión actual instalada.
Lo primero que haremos será descargar el plugin de Maven para eclipse, en este caso (que hay varios) el m2e.
Vamos al menú de ayuda, a instalar nuevo software. Insertamos la url del plugin http://m2eclipse.sonatype.org/sites/m2e
Después de aceptar, ya lo tenemos funcionando.
Ahora vamos a crear un nuevo proyecto de tipo Maven
Elegimos el workspace o entorno de trabajo por defecto y pulsamos continuar
Nos aparece un menú para elegir el arquetipo deseado. Empezará por lift. Como inicialmente no lo tendremos deberemos añadirlo.
En el botón configure nos aparece el menú de preferencias. Pulsaremos el botón
Add Remote Catalog (añadir catalogo remoto). En la captura de la pantalla veréis como tiene que quedar: Yo le he puesto Remore: Scala
Vamos a añadir la url donde se encuentran los arquetipos de Scala/Lift
http://scala-tools.org/repo-releases
Ojito que tenéis que esperar un poquito a que se baje e indexe la información de los
arquetipos.
Aquí ahora viene un punto crítico: fijaos bien en las versiones porque a mi me ha tocado
repetirlo varias veces hasta que me ha funcionado. Tienen que ser compatibles las versiones de Scala, del plugin de eclipse, de Lift, de la máquina virtual java y de los arquetipos.
Elijo la versión net.liftweb lift-archetype-blank_2.8.1 2.3. Ojo que en el catálogo tengo
seleccionado Nexus Indexer y como aparecen muchas opciones filtro por aquellos que tienen la palabra lift.
El la parte inferior derecha podemos
ver el avance.
Seguimos con la creación de nuestro proyecto donde le doy el GroupId Autentia y el ArtifactId AutentiaScalaLift
Durante un rato (también lo podemos ver en la barra inferior derecha) se descargan las
dependencias y se configura nuestro proyecto blank.
Es muy posible que aparezcan errores en el árbol de proyecto dentro de Eclipse (el icono al lado de los fuentes de Scala)
Ahora tenemos que pulsar el botón derecho en el proyecto y en la opción configure (configurar) incluimos Add Scala Nature. Desaparecerán los errores de proyecto.
Ahora vamos al menú run as y pulsamos la opción de configurar (lo podemos hacer tanto en release como en debug).
Pulsamos el botón derecho para añadir una nueva opción para nuestro proyecto.
Le damos el nombre que queramos y le asociamos el comando jetty:run
Pulsamos run y, después de un rato la primera vez para bajarse todas las dependencias y arrancar
…
Ya tenemos nuestra aplicación Blank funcionando.
Si nos fijamos en la librería Java utilizada en nuestro proyecto, estaba trabajando con Java 1.5. Voy a cambiar a Java 1.6 para asegurarme que no tengo ningún conflicto.
Solamente tenemos que pinchar en el botón derecho sobre jre library
Y elegimos la deseada. En este caso la JavaSE 1.6 instalada en MacOs.
Revisión del código generado
En Lift, como en otros frameworks,
Podemos devolver respuestas a tres niveles: Páginas html, respuestas de más bajo nivel con Rest y peticiones Ajax/Comet.
En este ejemplo simple solo veremos la respuesta HTML sobre una estructura básica. Podréis ver por en la documentación y arquetipos la estructura de un ejemplo MVC más realista con proyectos grandes.
Este primer ejemplo (Blank) es muy sencillito. Lo mejor que podéis hacer es verlo en detalle en la guía oficial: Exploring Lift
Todo, como siempre en una WebApp java, empieza en el fichero Web.xml. Veis como se inserta el filtro para acaparar todas las peticiones.
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <filter> <filter-name>LiftFilter</filter-name> <display-name>Lift Filter</display-name> <description>The Filter that intercepts lift calls</description> <filter-class>net.liftweb.http.LiftFilter</filter-class> </filter> <filter-mapping> <filter-name>LiftFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
Cuando llega una petición se interpreta la solicitada o por defecto se procesa index.html. Vamos a ver antes un fichero auxiliar para entenderlo todo mejor (es parecido al concepto de tiles)
Buscamos en el directorio templates-hidden el fichero default.html.
Tenemos una plantilla xhtml con un cuerpo con 3 etiquetas lift: bind, Menu y msg para ligar el contenido, el menú (uso del mapa de Lift) y los mensajes (de traza o error).
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:lift="http://liftweb.net/"> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> <meta name="description" content="" /> <meta name="keywords" content="" /> <title>Autentia:AutentiaScalaLift:0.0.1-SNAPSHOT</title> <script id="jquery" src="/wp-content/uploads/tutorial-data//classpath/jquery.js" type="text/javascript"></script> </head> <body> <lift:bind name="content" /> <lift:Menu.builder /> <lift:msgs/> </body> </html>
Podemos ver el código del html para comprobar su resolución.
Si intentáis abrir cualquier fichero y os lo resuelve (muestra con un editor visual o similar)
solo tenéis que pulsar el botón derecho y pulsar Open With y elegir el Text Editor.
En <lift:surround with="default" at="content"> estamos diciendo que vamos a procesar en
la plantilla default.html la etiqueta content.
Será resuelta la variable <b:time> por una clase java helloWorld que le va a inyectar el
valor. Hacemos las declaración de nodo como <lift:helloWorld.howdy>
<lift:surround with="default" at="content"> <h2>Welcome to your project!</h2> <p> <lift:helloWorld.howdy> <span>Welcome to AutentiaScalaLift at <b:time/></span> </lift:helloWorld.howdy> </p> </lift:surround>
Y en nuestro fuente la clase HelloWorld tiene un método howdy donde se vinculan a través de la clase Helpers:
package Autentia.AutentiaScalaLift { package snippet { import _root_.scala.xml.NodeSeq import _root_.net.liftweb.util.Helpers import Helpers._ class HelloWorld { def howdy(in: NodeSeq): NodeSeq = Helpers.bind("b", in, "time" -> (new _root_.java.util.Date).toString) } } }
El menú se resuelve a través de la clase boot (que realmente es la primera que tendríamos
que mirar aunque he preferido mostrarlo el último).
package bootstrap.liftweb import _root_.net.liftweb.common._ import _root_.net.liftweb.util._ import _root_.net.liftweb.http._ import _root_.net.liftweb.sitemap._ import _root_.net.liftweb.sitemap.Loc._ import Helpers._ /** * A class that's instantiated early and run. It allows the application * to modify lift's environment */ class Boot { def boot { // where to search snippet LiftRules.addToPackages("Autentia.AutentiaScalaLift") // Build SiteMap val entries = Menu(Loc("Home", List("index"), "Home")) :: Nil LiftRules.setSiteMap(SiteMap(entries:_*)) } }
Bueno, ya tenemos el framework lift de Scala funcionando dentro de eclipse y desde los arquetipos, por lo que poco ya nos podemos equivocar al montar la base.
Personalmente creo que antes de decantarme por un framework web voy a mirar alguno más (recordad cuando leáis esto que es Julio de 2011) porque, comparado con otros frameworks Java, me da la sensación de que Lift está en sus comienzos y quiero asegurarme de elegir el más maduro tanto en desarrollo como en facilidades y documentación.
Recursos interesantes:
http://www.assembla.com/spaces/liftweb/wiki/Using_Eclipse_with_Maven
http://www.build47.com/posts/scala-on-lift-setup-for-eclipse/