Aunque no sepamos lo que significan las siglas RIA todos tenemos claro lo que es una aplicación Flash. Navegando por internet  encontramos continuamente este tipo de animaciones. Podemos encontrar desde simulacros del temido Test teorico de conducción hasta una explicación del funcionamiento de los misiles interceptores Patriot.
Las aplicaciones Adobe Flash permiten una interfaz de usuario (drag and drop, sonidos, efectos gráficos, animaciones) que serian muy dificiles de conseguir mediante HTML y Javascript, incluso utilizando librerias de alto nivel como Prototype. Adobe proporciona a los desarrolladores un entorno de programación (basado en el lenguaje ActionScript 3) para crear aplicaciones Flash. Este entorno es muy popular y dispone de herrramientas para coordinar eficientemente el trabajo de los diseñadores (Adobe Photoshop, Ilustrator, sonidos) y el de los programadores. Las aplicaciones Flash también son populares entre los internautas que no dudan en bajarse el plug-in de Flash en su navegador.

La popularidad de Flash hace que sea un nicho apetecible para la competencia de Adobe. Así, han surgido otras alternativas que pretenden hacerse un hueco en el mercado: Microsoft ha lanzado Silverlight. Los desarrolladores de Flash no van a cambiar de plataforma sino perciben  una razón convincente. Al lanzar Silverlight Microsoft ofreció a los desarrolladores gráficos a pantalla completa que utilizaban la GPU (tarjeta de aceleración gráfica). Adobe tomó nota y ofrecerá esta caracteristica en la próxima release de Flash.

Figura1. Ejemplos de aplicaciones Flash

Figura1. Ejemplos de aplicaciones Flash

En este artículo (escrito en Marzo de 2009) veremos que características ofrece JavaFX y como se posiciona frente a sus competidores (Adobe Flash y Microsoft Silverlight). Aunque la primera release oficial JavaFX 1.5 (Marina) estará disponible en Junio de 2009, actualmente podemos ya trabajar con Java FX 1.1.

Para ello vamos a la página oficial de Java Fx y nos bajamos JavaFX 1.1 junto con el entorno de desarrollo Netbeans. Una vez instalado el entorno, creamos un proyecto (File >> New Project ),  le añadimos un fichero FX (Empty JavaFX file) y  podemos hacer una primera prueba arrastrando un rectangulo de la paleta ´Basic Shapes´ sobre el editor:
Editor JavaFX Netbeans

Figura2. Editor JavaFX Netbeans

Observamos que al soltar el Rectangulo, el entorno incorpora automaticamente todos los imports necesareos. Si ejecutamos el proyecto (Boton derecho >> Debug ) obtenemos una ventana sin título en la que tenemos el Rectangulo creado en las coodenadas [10,10]:
Figura 3. Ejecución de un proyecto JavaFX

Figura 3. Ejecución de un proyecto JavaFX

! Hemos ejecutado nuestra primera prueba con JavaFX !
Hay que tener en cuenta algunas consideraciones: El lenguaje utilizado no es Java sino JavaScript FX, un nuevo lenguaje declarativo que se ejecuta sobre la máquina virtual de Java. La razón de utilizar un nuevo lenguaje es la de simplificar la vida al desarrollador con una sintaxis más directa y adecuada para aplicaciones multimedia. Se trata por tanto de un DSL (Domain Specific Language ) especializado en animaciones interactivas. Veamos a continuación las principales caracteristicas del lenguaje.

Lenguaje JavaFX Script


A continuación veremos un resumen de las caracteristicas del lenguaje Java FX Script. Para una visión mas amplia se recomienda consultar los excelentes tutoriales de Sun así como otros tutoriales .
El lenguaje incorpora los siguientes tipos básicos: String, Boolean, Number e Integer. Las variables se declaran mediante la palabra clave var. Veamos los siguientes ejemplos:
var x:Number = 0.9;
var name:String = "David";
var y:Integer = 0;
var flag:Boolean = true;
var numbers:Number = [1,2,3,4,5];

En JavaFX no es obligatorio declarar el tipo una variable en su declaración. Así, podemos escribir el fragmento anterior de la siguiente forma:

var x = 0.9;
var name = "David";
var y = 0;
var flag = true;
var numbers:Number = [1,2,3,4,5];

Los operadores de  Java &&, || y ! tienen su equivalente en JavaFX: and, or y not. Por ejemplo:

(5 ==5 and 6 ==6 ) // retorna true

  if ( codebase == "" or codebase.startsWith("file:") )

 not (5 == 4) // => true

El manejo de arrays se simplifica con las facilidades que incorpora el lenguaje:

def days = ["Lunes","Martes","Miercoles","Jueves","Viernnes","Sab","Dom"];
println(days[0]); // Lunes
println(days[1]); // Martes
println(days[2]); // Miercoles
println(days[3]); // Jueves
println(days[4]); // Viernes
println(days[5]); // Sab
println(days[6]); // Dom
x = [1,2,3];
insert 10 as first into x; // ->[10,1,2,3]
insert 6 after x[. == 2]; // => [10,1,2,6,3]

Para determinar el tamaño de la secuencia utilizaremos la palabra reservada sizeof:
println(" {sizeof days}); // => 7
Podemos darle la vuelta a una sequencia con reverse:
var nums = [1..5];
reverse nums; // => [5, 4, 3, 2, 1]
 

A diferencia de Java, JavaFX soporta blocks. Los blocks (tambien llamadas closures) son muy populares en lenguajes de scripting como SmallTalk o Ruby, permiten realizar una select sobre un array con una sintaxis muy compacta. Veamos un ejemplo:

var lista = [1,2,7,3,30,15,14,6,4];
var menores_de_10 = lista[n|n < 10]; //selecciona los numeros menores de 10
println("Resultado: {menores_de_10}"); =>  1 2 7 3 6 4
var pares = list[ n | n mod 2 == 0];
println("Pares: {pares}"); //  =>  2 30 14 6 4
Tambien podemos escribir una expresion equivalente:
for (i in lista){
    if (i < 10) print(i)
} // => 1 2 7 3 6 4
Para crear una clase que modeliza una direccion postal (con los atributos calleciudadprovinciacodigoPostal y un método print() para imprimir una representacion del objeto) escribiremos:
 DireccionPostal {
     var calle: String;
     var ciudad: String;
     var provincia: String;
     var codigoPostal: String;
     function print() {
            println("Calle: {calle} Ciudad: {ciudad} Provincia: {provincia} CodigoPsotal: {codigoPostal} ");
      }
  }
Instanciar un objeto de la clase DireccionPostal es tan sencillo como:
var direccionPostal = DireccionPostal {
 calle: "Avenida de Logroño"
 ciudad: "Madrid"
 provincia: "Madrid"
 codigoPostal: "28042"
}
println (direccionPostal.print()) ;
A diferencia de Java, las funciones en JavaFX son entidades de primer orden . ¿Qué significa esto? Muy sencillo, con el lenguaje Java FX podremos hacer cosas que antes eran imposibles en Java como pasar una funcion como un parámetro a otra función o devolverla como tipo de retorno en otra función. Veamos un ejemplo:
function addN(n: Number): function(:Number): Number {
 function(x: Number): Number { x + n }
}
var addTen = addN(10);
println(addTen(3)); // => 13.0
Analizemos el código anterior. Atención a la signatura de la función addN() esta función acepta un parámetro del tipo Number y devuelve una función con signatura
function (:Number).
En la siguiente linea, la funcion resultante de addN(10) es asignada a la variable addTen. La variable addTen es una función que puede ser invocada como cualquier otra función. Mas adelante en el código de ejemplo veremos como se utiliza esta caracteristica de JavaFX.

Manos a la obra

Una vez vistas las principales caracteristicas del lenguaje podemos escribir una aplicación a modo de ejemplo. Se trata de escribir una aplicación que presente al usuario la hora del amanecer y el ocaso en nuestra ciudad. La aplicación final tiene el siguiente aspecto:

fig4

Veamos paso por paso como construir la aplicación. En primer lugar necesitaremos los datos de la hora de amanecer y ocaso en nuestra ciudad.
Para obtener estos datos utilizaremos un Servicio Web de Yahoo: Yahoo Weather Web Service. Un cliente puede lanzar una peticion GET contra este servicio y obtendrá un XML como el de la siguiente figura:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<rss version="2.0" xmlns:yweather="http://weather.yahooapis.com/ns/rss/1.0"
 xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">
<channel>
 <title>Yahoo! Weather - Sunnyvale, CA</title>
 <link>http://us.rd.yahoo.com/dailynews/rss/weather/Sunnyvale__CA/
 *http://weather.yahoo.com/forecast/94089_f.html</link>
 <description>Yahoo! Weather for Sunnyvale, CA</description>
 <language>en-us</language>
 <lastBuildDate>Tue, 29 Nov 2005 3:56 pm PST</lastBuildDate>
 <ttl>60</ttl>
 <yweather:location city="Sunnyvale" region="CA" country="US"></yweather:location>
 <yweather:units temperature="F" distance="mi" pressure="in" speed="mph"></yweather:units>
 <yweather:wind chill="57" direction="350" speed="7"></yweather:wind>
 <yweather:atmosphere humidity="93" visibility="1609" pressure="30.12" rising="0"></yweather:atmosphere>
 <yweather:astronomy sunrise="7:02 am" sunset="4:51 pm"></yweather:astronomy>
 <image>
 <title>Yahoo! Weather</title>
 <width>142</width>
 <height>18</height>
 <link>http://weather.yahoo.com/</link>
 <url>http://l.yimg.com/a/i/us/nws/th/main_142b.gif</url>
 </image>
 <item>
 <title>Conditions for Sunnyvale, CA at 3:56 pm PST</title>
 <geo:lat>37.39</geo:lat>
 <geo:long>-122.03</geo:long>
 <link>http://us.rd.yahoo.com/dailynews/rss/weather/
 Sunnyvale__CA/*
 http://weather.yahoo.com/ forecast/94089_f.html
 </link>
 <pubDate>Tue, 29 Nov 2005 3:56 pm PST</pubDate>
 <yweather:condition text="Mostly Cloudy" code="26" temp="57" date="Tue, 29 Nov 2005 3:56
 pm PST"></yweather:condition>
 <description><![CDATA[
 <img src="http://l.yimg.com/a/i/us/we/52/26.gif" /><br />
 <b>Current Conditions:</b><br />
 Mostly Cloudy, 57 F<p />
 <b>Forecast:</b><BR />
 Tue - Mostly Cloudy. High: 62 Low: 45<br />
 Wed - Mostly Cloudy. High: 60 Low: 52<br />
 Thu - Rain. High: 61 Low: 46<br />
<br />
<a href="http://us.rd.yahoo.com/dailynews/rss/weather/Sunnyvale__CA/*http://weather.yahoo.com/forecast/94089_f.html">Full Forecast at Yahoo! Weather</a><BR/>
 (provided by The Weather Channel)<br/>]]>
 </description>
 <yweather:forecast day="Tue" date="29 Nov 2005" low="45" high="62" text="Mostly Cloudy"
 code="27"></yweather:forecast>
 <yweather:forecast day="Wed" date="30 Nov 2005" low="52" high="60" text="Mostly Cloudy"
 code="28"></yweather:forecast>
 <guid isPermaLink="false">94089_2005_11_29_15_56_PST</guid>
 </item>
</channel>
</rss>

De esta respuesta solo nos interesan dos datos. Para obtener la hora del amanecer y del ocaso, buscaremos el nodo <yweather:astronomy> y recogeremos los valores (señalados en negrita) de los atributos  sunrise y sunset. JavaFX puede realizar esta tarea facilmente con la clase javafx.io.http.HttpRequest, que modeliza una petición, y javafx.data.pull.PullParser un parseador.Para poder personalizar la aplicación al lugar donde vivimos simplemente adaptaremos la petición GET. Esta petición contiene dos partes, una URL base que es siempre la misma:

http://weather.yahooapis.com/forecastrss?
y dos parámetros:
p = SPXX0050 para indicar la localidad (Barajas en este caso) de la que solicitamos datos
u=c donde indicamos que queremos las unidades de temperatura en grados Celsius
En nuestro caso (Barajas) la petición GET es la siguiente:
http://weather.yahooapis.com/forecastrss?p=SPXX0050&u=c
Nota. Para obtener el codigo de localidad correspondiente a la ciudad donde vives podemos consultar en la página Weather Yahoo . Allí introducimos el nombre de nuestra ciudad en la casilla de búsqueda. En la pàgina resultante, la parte final de la URL corresponde al código que necesitamos. Por ejemplo si buscamos el código correspondiente a Sabadell:


Pulsamos en el botón GO y obtenemos la siguiente página:


Por tanto, el código para esta localidad es p = SPXX0066.

Asi pues, creamos una nueva clase JavaFX que llamaremos  Main.fx. En primer lugar podemos declarar como String la url obtenida:
var url = "http://weather.yahooapis.com/forecastrss?p=SPXX0050&u=c";

También declaramos otras variables que utilizaremos posteriormente:
def sceneWidth = 425;
def sceneHeight = 300;
var amanecer: String; //hora del amanecer
var ocaso: String;  // hora del ocaso
Las variables sceneWidht y sceneHeight estan definidas como constantes (def) ya que la anchura y la altura de la aplicación en número de pixels depende de los graficos de mapa de bits y no van a cambiar durante la aplicación. Por contra las variables amanecer y ocaso van a ser modificadas durante la vida de la aplicación, y por tanto se debe utilizar var.
También declaramos una instancia de HttpRequest que modeliza la petición al servicio web de Yahoo:
    HttpRequest {
        location: url
        onDone: function() {
            print ("done");
            // Para simular un web service lento
            Thread.sleep(1000);
            resultado = " Amanecer:  {amanecer} \n  Ocaso: {ocaso}" ;
        }
        onInput: function(input) {
            try {
                PullParser {
                    input: input
                    onEvent: function(event) {
                        if ((event.type == PullParser.START_ELEMENT) and (event.qname.prefix == "yweather")) {
                            if (event.qname.name == "astronomy") {
                                amanecer = event.getAttributeValue(QName{name: "sunrise"
                                });
                                println("amanecer =  {amanecer}");
                                ocaso = event.getAttributeValue(QName{name: "sunset"
                                });
                                println("   ocaso =  {ocaso}");
                            }
                        }
                    }
                }.parse()
            }  finally {
                input.close();
            }
        }
    }
Notar que las clase de JavaFX HttpRequest dispone del método callback onInput() que se activará en cuanto el cliente reciba una respuesta del servicio web. Dado que el servicio web devuelve un XML, utilizaremos la clase PullParser para parsear esta respuesta. Para parsear la respuesta, buscaremos el nodo “yweater” y una vez encontrado recuperamos los valores de los atributos sunrise y sunset. De esta forma obtendremos los valores buscados.
Es importante notar que en la clase PullParser, el metodo callback onEvent es una funcion
Cuando inicializamos la clase PullParser, al callbalck onEvent le asignamos una función que detectará los eventos de parseo (inicio de nodo XML, fin de nodo XML).
La definición de los elementos gráficos es más sencilla. Asi para definir el rectangulo superior escribimos:
var topRectangle: Rectangle = Rectangle {
    translateX: 0
    translateY: 10
    width: sceneWidth - 2
    height: 60
    stroke: Color.DARKBLUE
    strokeWidth: 1
    arcWidth: 32
    arcHeight: 32
    fill: LinearGradient {
        endY: 0
        stops: [
            Stop {
                offset: 0
                color: Color.DARKBLUE
            }
            Stop {
                offset: 1
                color: Color.LIGHTBLUE
            }
        ]
    }
}
Para conseguir un relleno con un degradado lineal, utilizamos la clase LinearGradient. El degradado horizontal empieza con un azul oscuro y finaliza en un azul claro.
Finalmente, “maquetamos” todos los elementos gráficos definidos mediante el siguiente código:
Stage {
     title: "  Amanecer y Ocaso en Barajas  "
    width: sceneWidth
    height: sceneHeight
    style: StageStyle.TRANSPARENT
    scene: Scene {
        width: sceneWidth
        height: sceneHeight
        content: Group {
            content: bind [  topRectangle, text, rightRectangle, textResult, bottomRectangle, solView ]
            clip: Rectangle {
                width: sceneWidth
                height: sceneHeight
                arcWidth: 32
                arcHeight: 32
            }
        }
        fill: Color.TRANSPARENT
    }
}
Podeis consultar código completo de la aplicacion. También podeis ejecutar la aplicación pulsando el siguiente enlace 

Despliegue de aplicaciones JavaFX: Standalone, applet y mobile

Todos los proyectos JavaFX pueden ser deplegados de tres formas:
- Como una aplicación (Standalone)
- Como un applet WebStart integrado dentro del navegador (Web Start Execution)
- Como una aplicación para un telefono movil compatible con JavaFX (Run in Mobile Emulator)
Para elegir uno de los tres despliegues vamos a propiedades del proyecto y elegimos en la pestaña Run, el Modelo de Ejecución (Standart Execution, Run in Browser o Run in Mobile emulator).
Figura 4. Despliegue de un proyecto JavaFX

Figura 4. Despliegue de un proyecto JavaFX

Si elegimos el despliegue en teléfono movil tendremos que utilizar el emulador incluido en la plataforma (los primeros telefonos compatibles con JavaFx de LG y Sony-Ericsson estaran disponibles en Junio de 2009) :
Figura 5. Emulador JavaFX para terminal movil

Figura 5. Emulador JavaFX para terminal movil

Conclusiones

Java FX Script es un lenguaje declarativo, estaticamente tipado, orientado a objetos y funcional. Está diseñado especificamente para escribir aplicaciones gráficas. El Kit de desarrollo proporciona una libreria multimedia muy completa. La guerra para atraer a los usuarios avanzados de ActionScript 3 (Adobe Flash) ha empezado, pero esta vez Sun dispone de un buen arsenal.

Recursos

Galeria de Java FX Samples en el portal de SUN

Documentación sobre el API de JavaFX 1.1