There is a good realtime JavaScript stack, composed by nodejs + express + mongoose + socket.io + angularjs, and I’m going to explain how to integrate these pieces of software to develop a simple web application. The application that I have developed is called VoteExpress, and through this application users are able to vote the team that they think that will win the next Brazil World Cup 2014. When a user votes for a team, every users connected to the page will be notified in realtime that someone has voted that team, and a pie chart will be automatically updated with the new results.

 

Demo Application    Source Code

 

We can bootstrap our application with the following skeleton: https://github.com/jlmonteagudo/node-express-moongose-min-bootstrap  This skeleton is based on the excellent project developed by Madhusudhan Srinivasa project: Nodejs Express Mongoose Demo, that use best practices developing nodejs web applications.

This is the main tree folder of the skeleton project:

  • app
    • controllers
    • models
  • config
    • config.js
    • db-fixture.js
    • express.js
    • routes.js
    • socket-io.js
  • public
  • server.js

 

The Back End

The back end will manage RESTFUL requests, and these requests will be done by an AngularJS application on the front end, which will be located in the public folder.

The only entity that our application will manage is Team. To manage this entity we only have to create its Schema, its controller and its routes.

Inside the app/models folder we will create team.js, where we will define our model through Moongose (Mongoose Quick Start):

 

var mongoose = require('mongoose')
   ,Schema = mongoose.Schema

var TeamSchema = new Schema({
  code: String,
  name: String,
  urlImage: String,
  votes: {type: Number, default: 0}
})

mongoose.model('Team', TeamSchema)

 

Next, we will create a controller in the folder app/controllers:

 

var mongoose = require('mongoose')
	, Team = mongoose.model('Team')

	exports.list = function(req, res) {
		Team.find({}, function(err, teams) {
	    	res.json(teams);
		});
	}

	exports.update = function(req, res) {
		var team = new Team(req.body);
		Team.update({ _id: team.id }, {votes: team.votes}, function (err, numberAffected, raw) {
			var socketIO = global.socketIO;
			socketIO.sockets.emit('team:updated', team);
			res.json(true);
		});
	}

 

In the controller we define the actions that we will do with our models. list will return a JSON of all the teams with its scores, and update will update the score of the team and will notify about this to all the clients connected to the application.

Finally we have to define the routes in the file config/routes.js:

 

module.exports = function (app) {
     var teams = require('../app/controllers/teams');
     app.get('/teams', teams.list);
     app.put('/teams/:id', teams.update);
}

The Front End

The front end is an AngularJS application that is located in the public/js folder. Its tree folder is as follow:

  • controllers
    • team.js
  • directives
    • chart.js
  • services
    • socketio.js
  • app.js

In app.js we only define the routes:

 

angular.module('voteApp', ['ngResource'])
	.config(function ($routeProvider) {
		$routeProvider
		.when('/', {
	    templateUrl: 'views/team/list.html',
        controller: 'TeamCtrl'
	});
});

 

In the controller we get all the teams that are inside the database, and we define the function vote that will be invoked when someone votes for a team. In the controller also is defined what to do when the server notify that a team has been updated. Here is the controller code:

 

angular.module('voteApp')
	.controller('TeamCtrl', function ($scope, $http, Socket, Team) {

		$scope.disableVote = false;

		//$scope.teams = Team.list();
		$http.get('/teams').success(function(data) {
		$scope.teams = data;
	});

	$scope.vote = function(team) {
		team.votes = team.votes + 1;
			$http.put('/teams/' + team._id, team).success(function(data) {
				$scope.disableVote = true;
			});
		};

	Socket.on('team:updated', function (team) {
		$http.get('/teams').success(function(data) {
			$scope.teams = data;
		});
		$.pnotify({title: 'Vote', text: '+1 vote for ' + team.name });
	});

});

 

We have defined a directive to render the chart (through Google Visualization API):

 

angular.module('voteApp')
	.directive('chart', function () {
		return {
			template: '<div id="chart"></div>',
				restrict: 'E',
				link: function postLink(scope, element, attrs) {

					scope.$watch('teams', function(newValue, oldValue, scope) {

						if (newValue === undefined) return;
						var chartTeams = newValue.map(function(team) {
							return [team.name, team.votes];
						});

						var data = google.visualization.arrayToDataTable(chartTeams, true);
						var googleChart = new google.visualization.PieChart(document.getElementById('chart'));
						googleChart.draw(data);

					});
				}
			};
		});

 

So, to render a chart inside a view we only have to insert the following code:

<chart></chart>

and that tag will render a Pie Chart through the Google Visualization API using the JSON document got from the server.

Finally, I have defined a service (services/socketio.js) that will be used to manage socket.io connections. The code is based on this article  http://www.html5rocks.com/en/tutorials/frameworks/angular-websockets/

 

Conclusion

As we have seen, this is a simple stack that we can use to create our real time applications. In the JavaScript ecosystem there are another systems that allow us to develop this kind of applications, but I think that this one is very flexible.

There are many alternatives to the stack that I have proposed in this article, and two of them that I think that are very interesting are sails.js and Meteor. Maybe I will translate the VoteExpress demo developed in this article to sails and meteor, so we can compare its features.

 

Disclaimer

There are some things in the code that I don’t like and I think that there would be a better way to code. I would be happy if you could propose a better solution.

The first one is that I have defined the socketIO variable as global in the voteExpress/config/socket-io.js file. I know I could pass the socketIO paramater to config/routes and from here to each controller, but I didn’t like the solution.

The second one is related to Angular. I have used Pines Notify, to notify that someone has voted for a team, and I call to it as a JQuery method inside the controller: $.pnotify({title: ‘Vote’, text: ‘+1 vote for ‘ + team.name }); I know that it is a bad practice to update the DOM from the controller, and that it is much better to do that through a directive. Do you have any sugestion to solve this subject in a better way?

En este post quiero mostrar lo sencillo que puede ser desarrollar aplicaciones que procesen información en tiempo real mediante la utilización de Node.js y websockets. En concreto, como ejemplo para esta demostración, he desarrollado una aplicación que captura vídeo a través de la cámara de tu dispositivo móvil y lo emite a través de una página web.

La aplicación está publicada en Heroku, una plataforma de cloud computing que permite publicar tu aplicación gratuitamente. Puedes probar la aplicación en la siguiente dirección: http://jlmonteagudo-cam.herokuapp.com/

El código fuente de la aplicación lo he subido a github y se puede acceder desde la siguiente URL: https://github.com/jlmonteagudo/jlmonteagudo-cam

 

Estructura de la aplicación

La aplicación está estructurada en tres piezas distintas:

- Página web que emite el vídeo: Esta página captura vídeo a través de la cámara de tu dispositivo móvil y lo envía mediante web sockets a un servidor. Utiliza el método getUserMedia de los navegadores para capturar el vídeo.

- Servidor: El servidor simplemente se encarga de recibir los frames que envía la página que emite el vídeo y hace un broadcast de estos frames a otra página web.

- Página web que visualiza el vídeo: Esta página web simplemente visualiza los frames enviados por el servidor.

 

Gráficamente la estructura sería la siguiente:

 

 

Emit.html

La página emit.html es la que se encarga de capturar el vídeo a través del dispositivo móvil y lo envía al servidor. El código principal de la página es el siguiente:

<video id = "video" autoplay="true" style="width: 680px; heigth: 320px;"></video>
<div id = "logger"></div>

<script type="text/javascript">

    var video = document.getElementById('video');
    var logger = document.getElementById('logger');
    var canvas = document.createElement('canvas');
    var context = canvas.getContext('2d');
    context.width = 120;
    context.height = 120;


    function log(message) {
       logger.innerHTML = logger.innerHTML + message + "<br/>";
    };


    if(navigator.getUserMedia) {
        navigator.getUserMedia('video', successCallback, errorCallback);

        function successCallback( stream ) {
        	log('Broadcasting...');
            video.src = stream;
        };

        function errorCallback( error ) {
            log('Error broadcasting: ' + error.code );
        };
    } else {
        log('Cannot access to the camera');
    };


    /* SOCKET.IO */

    var socket = io.connect(window.document.location.host);


    socket.on('connect', function () {
    	log('connected');
    });

    socket.on('disconnect', function () {
    	log('disconnected');
    });

    function emit(message) {
    	socket.emit('data', message);
    }

    /* END SOCKET.IO */

    function sendFrame(video, context) {
        context.drawImage(video, 0, 0, context.width, context.height);
        emit(canvas.toDataURL('image/webp'));
    }

    setInterval(function() { sendFrame(video, context); }, 1000);

</script>

El script primero comprueba si el navegador implementa el método getUserMedia, y en caso afirmativo al tag video se le asigna el flujo de datos que el navegador captura de la cámara del dispositivo:

    
video.src = stream;

A continuación el script configura la librería Socket.IO para conectarse al servidor al que tiene que enviar las capturas de vídeo. La función que se encarga de enviar las capturas de vídeo es la siguiente:

    
function emit(message) {
    socket.emit('data', message);
}

Para enviar las capturas de vídeo al servidor, el script utiliza un elemento canvas, que se crea a través de JavaScript, en el cual se dibuja cada segundo lo que el elemento video está emitiendo en ese momento:

    function sendFrame(video, context) {
        context.drawImage(video, 0, 0, context.width, context.height);
        emit(canvas.toDataURL('image/webp'));
    }

    setInterval(function() { sendFrame(video, context); }, 1000);

Display.html

La página display.html es muy sencilla y lo único que hace es conectarse al servidor y mostrar en un elemento img aquellas capturas que le llegan a la página a través de websockets:


<img src="" id="frame" style="width:680px; height:320px"/>
<div id="logger"></div>

<script type="text/javascript">

	var img = document.getElementById("frame");	
	var logger = document.getElementById('logger');

	/* SOCKET.IO */

	var socket = io.connect(window.document.location.host);

	socket.on('connect', function () {
		log('connected');
	});

	socket.on('disconnect', function () {
		log('disconnected');
	});

	socket.on('data', function(data) {
		img.src = data;
	});


	/* END SOCKET.IO */

	function log(message) {
	   logger.innerHTML = logger.innerHTML + message + "<br/>";
	};

</script>	

Servidor

El servidor está desarrollado con Node.js y es muy sencillo de implementar. Simplemente tenemos que crear una aplicación con el framework Express.js e importamos una librería que implementaremos a continuación (streamingService). Esta librería será la encargada de configurar Socket.IO para recibir las capturas de vídeo y distribuirlas a todos los clientes conectados al servidor. El código del servidor (casi en su totalidad generado por Express.js) es el siguiente:

var express = require('express')
  , routes = require('./routes')
  , http = require('http')
  , path = require('path')
  , streamingService = require('./lib/service/streamingService');


var server;
var clients = [];

var app = express();

app.configure(function(){
  app.set('port', process.env.PORT || 5000);
  app.set('views', __dirname + '/views');
  app.set('view engine', 'jade');
  app.use(express.favicon());
  app.use(express.logger('dev'));
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(path.join(__dirname, 'public')));
});

app.configure('development', function(){
  app.use(express.errorHandler());
});

app.get('/', routes.index);

server = http.createServer(app).listen(app.get('port'), function(){
  console.log("Express server listening on port " + app.get('port'));
});


streamingService.start(server);

Y por último, así es cómo quedaría la implementación de la librería streamingService:

var io = require('socket.io');

exports.start = function (server) {
	io = io.listen(server);
	io.set("transports", ["xhr-polling"]);

	io.sockets.on('connection', function (socket) {
	  console.log(socket);

	  socket.on('disconnect', function () {
	    console.log('User disconnected');
	  });

	  socket.on('data', function (data) {
	    socket.broadcast.emit('data', data);
	  });

	});

}

Como vemos, toda información que le llega al servidor, la librería hace un broadcast de esa misma información a todos los clientes. Otro punto a tener en cuenta es que Heroku, al igual que otras plataformas cloud computing, no soporta el uso de websockets, por ello es que hay que especificar que Socket.IO realice el transporte a través de xhr-polling.

Consideraciones

La cantidad de información que transmite esta solución de emisión de vídeo es relativamente elevada, ya que cada frame que emite la página emit.html al servidor pesa alrededor de 50K. Hemos configurado el sistema para que envíe únicamente un frame por segundo, ya que emitir más de 50K por segundo sería demasiado pesado. Es por esto que para probar el sistema es recomendable que el dispositivo que emite el vídeo esté conectado a una red ADSL o de alta velocidad y no a través de 3G, ya que de lo contrario la emisión no funciona correctamente.

Conclusión

Como hemos podido comprobar, las posibilidades que nos ofrece Node.js y Socket.IO son muy interesantes, y la combinación de ambas herramientas nos permite desarrollar aplicaciones que procesen información en tiempo real de forma muy sencilla.

Estoy actualizando www.dondeviajamos.com. Uno de los cambios que quiero hacer es relativo a la navegación, donde voy a reemplazar el clásico sistema de paginación por un sistema de scroll infinito, estilo Twitter. El scroll infinito se basa en que cuando un usuario visualiza la página y llega al final de la misma, ésta realiza automáticamente una petición AJAX al servidor para que éste le proporcione más registros. Estos registros serán procesados mediante Javascript para presentarlos en un formato de visualización determinado.

He estado intentando utilizar algún plugin que ya existiera, pero ninguno se ha adaptado fácilmente a mis necesidades, por lo que finalmente he decidio desarrollar el scroll infinito de forma manual. Es realmente sencillo, así que voy a explicar rápidamente cómo podemos implementar este sistema.

Codificación de la parte del servidor

El primer punto que necesitamos es que el servidor nos proporcione los nuevos registros en formato JSON. Esto es realmente sencillo con Grails:

def list() {
   params.max = Math.min(params.max ? params.int('max') : 20, 100)
   def results = Destino.list(params)

   withFormat {
      html { [destinoInstanceList: results, destinoInstanceTotal: Destino.count()] }
      json {
         render(contentType: "text/json") {
            destinos = array {
               for (d in results) {
                  destino (foto: getDestinoFoto(d), tituloMin: d.tituloMin, resumenMin: d.resumenMin)
               }
            }
         }
      }
   }
}

En el código anterior vemos que si el navegador solicita un documento HTML entonces simplemente retorna el listado de registros, y si el navegador solicita JSON entonces renderiza un objeto JSON a partir del mismo listado de registros. ¿Cómo sabe el controlador si tiene que devolver HTML o JSON? Si la solicitud es del siguiente tipo /destino/list entonces el servidor devuelve HTML. Si la solicitud es del siguiente tipo /destino/list.json entonces el servidor devuelve JSON.

Codificación de la parte del cliente

En primer lugar, tenemos que saber si el usuario ha hecho scroll y ha alcanzado el final de la página. Esto podemos saberlo mediante el siguiente código Javascript:

$(window).scroll(function () {
	if ($(window).scrollTop() >= $(document).height() - $(window).height()) {
            console.log("has llegado al final de la pagina");
	}
});

El siguiente paso es que cuando el usuario alcance el final de página entonces se realice una petición AJAX al servidor para que éste proporcione más registros. Para hacer la petición AJAX utilizaremos JQuery:

$.get( "${createLinkTo(dir:'destino',file:'list.json')}",
	{ offset: destinosOffset, max: MAX_DESTINOS },
	function(data) {
		var destinos = data.destinos;
		for (var i = 0, len = destinos.length; i < len; i++) {
			var html = '<div>' + destinos[i].tituloMin + '</div>';
			$('.content').append(html);
		}
	}
);

Al método GET sólo hay que pasarle tres parámetros: la URL del servidor, los parámetros que queremos enviar al servidor, y una función callback que se ejecutará una vez el servidor ha devuelto la información. El código Javascript completo de dondeviajamos quedaría del siguiente modo:

var destinosOffset = 0;
var MAX_DESTINOS = 20;

$(window).scroll(function () {
	if ($(window).scrollTop() >= $(document).height() - $(window).height()) {

		destinosOffset += MAX_DESTINOS;

		$.get( "${createLinkTo(dir:'destino',file:'list.json')}",
			{ offset: destinosOffset, max: MAX_DESTINOS },
			function(data) {
				var destinos = data.destinos;
				for (var i = 0, len = destinos.length; i &lt; len; i++) {
                                      var html = '<div>' +
                                                     '<a href="#"><img src="' + destinos[i].foto + '" /></a>' +
                                                     '<div>' +
                                                            '<h4><a href="#">' + destinos[i].tituloMin + '</a></h4>' +
                                                            '<hr/>' +
                                                            '<p>' + destinos[i].resumenMin + '</p>' +
                                                            '<hr/>' +
                                                     '</div>' +
                                                '</div>';

                                      $('.content').append(html);
				}
			}
		);

	}
});

Como vemos, es realmente sencillo implementar con Javascript un sistema de navegación basado en scroll infinito, sin necesidad de la utilización de plugins de terceros. Si alguien quiere que aclare algún punto que no ha quedado lo suficientemente claro, no tiene más que dejar un comentario.

Puedes ver la demo de las tablas en la siguiente dirección: http://jlmonteagudo.cloudfoundry.com/team

Puedes descargarte el código fuente en la siguiente dirección: jqgrid

En muchas de las aplicaciones web que desarrollamos tenemos la necesidad de mostrar la información en forma de tabla. Existe un plugin desarrollado con jQuery que podemos utilizar en nuestra aplicación para este propósito, independientemente del lenguaje de programación que utilicemos en nuestro servidor. El pugin en cuestión se llama jqGrid, y lo vamos a utilizar en combinación con Grails, como ya viene siendo habitual.

Una característica importante de jqGrid que cabe destacar es que no sólo permite mostrar información, sino que  permite agregar registros nuevos a la base de datos, consultarlos, actualizarlos y borrarlos.

jqgrid2

Quiero comentar que hoy en día ya existe un plugin para Grails que permite la utilización de jqGrid de forma sencilla. Sin embargo, he preferido demostrar el uso de jqGrid directamente porque, además de ser muy fácil utilizarlo, no estás supeditado a las actualizaciones del plugin de Grails para poder utilizar las últimas funcionalidades de jqGrid. Así, en el momento de escribir este post, la versión actual del plugin de Grails utiliza la versión 3.8 de jqGrid, pero la versión actual de jqGrid es la 4.1.1.

Para integrar jqGrid en nuestra aplicación Grails lo primero que tenemos que hacer es descargárnoslo desde su sitio web. Una vez descargado y descomprimido, tenemos que copiar los ficheros del directorio js (directorio i18n incluido) al directorio web-app/js de nuestra aplicación Grails. Lo mismo tenemos que hacer con el directorio css, copiamos los ficheros de la carpeta css de jqGrid al directorio web-app/css de nuestra aplicación Grails.

También nos tenemos que descargar uno de los muchos temas que puedes encontrar en la web jQuery UI, con el cuál conseguimos darle al grid un look & feel determinado. Una vez descargado y descomprimido el tema lo único que nos faltaría hacer sería copiar el contenido del directorio css, al directorio web-app/css de nuestra aplicación Grails.

A continuación, para utilizar el grid en una determinada página, tenemos que ir al GSP en cuestión y agregar las siguientes hojas de estilo:

&lt;link rel="stylesheet" type="text/css" media="screen" href="${resource(dir:'css/redmond',file:'jquery-ui-1.8.13.custom.css')}" /&gt;
&lt;link rel="stylesheet" type="text/css" media="screen" href="${resource(dir:'css',file:'ui.jqgrid.css')}" /&gt;

Por otra parte tendríamos que agregar los siguientes ficheros JavaScript:

&lt;g:javascript library="jquery-1.5.2.min" /&gt;
&lt;g:javascript library="i18n/grid.locale-es" /&gt;
&lt;g:javascript library="jquery.jqGrid.min" /&gt;

Y finalmente el siguiente código JavaScript:

&lt;script type="text/javascript"&gt;
	$(function(){
	  $("#teams").jqGrid({
		url:'${createLink(action: 'listJSON')}',
		datatype: 'json',
		mtype: 'GET',
		colNames:['Id','Code', 'Name','Won Leagues'],
		colModel :[
		  {name:'id', index:'id', width:55, align:'right'},
		  {name:'code', index:'code', width:90},
		  {name:'name', index:'name', width:400},
		  {name:'wonLeagues', index:'wonLeagues', width:100, align:'right'}
		],
		pager: '#pager',
		rowNum:5,
		rowList:[5, 10,20,30],
		sortname: 'id',
		sortorder: 'desc',
		viewrecords: true,
		gridview: true,
		caption: 'Equipos'
	  });
	});
&lt;/script&gt;

En este fragmento de código se configuran una serie de parámetros (documentación oficial de las opciones) del grid. Uno de los más importantes es el parámetro URL, donde se le asigna al grid una dirección desde donde éste obtiene la información que tiene que presentar.

En nuestro controlador Grails necesitamos una closure que busque en la base de datos la información y que la devuelva en formato JSON, que es el formato que hemos definido mediante el parámetro datatype del grid. A continuación se muestra la closue, cuyo código se basa en el código del plugin jqGrid de Grails:

	def listJSON = {

		def sortIndex = params.sidx ?: 'name'
		def sortOrder  = params.sord ?: 'asc'
		def maxRows = Integer.valueOf(params.rows)
		def currentPage = Integer.valueOf(params.page) ?: 1
		def rowOffset = currentPage == 1 ? 0 : (currentPage - 1) * maxRows

		def teams = Team.createCriteria().list(max: maxRows, offset: rowOffset) {
			order(sortIndex, sortOrder).ignoreCase()
		}

		def totalRows = teams.totalCount
		def numberOfPages = Math.ceil(totalRows / maxRows)

		def results = teams?.collect {
			[
				 cell: [it.id, it.code, it.name, it.wonLeagues],
				 id: it.id
			]
		}

		def jsonData = [rows: results, page: currentPage, records: totalRows, total: numberOfPages]
		render jsonData as JSON
	}

Esta closure recoge los parámetros enviados por el grid, y a partir de estos parámetros realiza la consulta en la base de datos.

En la aplicación mostrada existe un segundo grid más avanzado que, además de consultar la información de la base de datos, permite realizar operaciones CRUD sobre la entidad a representar. Este segundo grid tiene una barra de herramientas en su parte inferior a través de la cuál se pueden crear nuevos registros, actualizarlos y borrarlos. Además, en la cabecera, este grid contiene unos controles a través de los cuales se puede filtrar la información que se presenta. Para ver todas estas funcionalidades se recomienda revisar el código fuente que se adjunta más arriba.

Puedes ver la demo del chat en la siguiente dirección: http://jlmonteagudo.cloudfoundry.com/chat

Puedes descargarte el código fuente en la siguiente dirección: chat

Muchas de las aplicaciones con interfaces ricas que actualmente tenemos que desarrollar requieren actualizaciones automáticas, es decir, el servidor envía información al cliente, y éste actualiza los datos de su interfaz de forma automática. Este tipo de actualizaciones actualmente suelen llevarse a cabo a través de AJAX, y con AJAX podemos utilizar dos sistemas de comunicación diferente, pull y push.

Mediante pull, es el cliente quien solicita información al servidor, que puede estar programado para esta solicitud la realice cada cierto periodo de tiempo. Mediante push, el cliente se subscribe a un canal, y cada vez que éste se actualiza el servidor envía automáticamente la información a todos los clientes subscritos al canal.

Con este post quiero demostrar cuán sencillo y rápido es desarrollar un sistema con comunicación AJAX Push y con Grails. Una aplicación de chat nos sirve perfectamente para este cometido, ya que un cliente envía información al servidor y éste automáticamente envía esa misma información a cada uno de los clientes subscritos al canal.

Vamos a ver cómo con unas pocas líneas de Groovy, con el plugin Atmosphere de Grails y con un poco de Javascript podemos crear una aplicación de chat. Toda la documentación del plugin puedes consultarla en la siguiente dirección: https://docs.google.com/View?id=dfdr5d2x_14ccbgm8dm

Una vez creada la aplicación de Grails tenemos que instalar el plugin Atmosphere, que es un framework que nos permite establecer una comunicación Ajax Push:

grails install-plugin atmosphere

A continuación creamos un controlador que sólo necesita declarar una closure, en nuestro caso la closure broadcast. El plugin Atmosphere inyecta a todos los controladores de la aplicación el objeto Broadcaster, que como vemos en la aplicación se encarga de difundir un mensaje a todos los clientes subscritos al canal /atmosphere/chat (tan sólo con una línea de código):

class ChatController {

    def index = { }

    def broadcast = {
		broadcaster['/atmosphere/chat'].broadcast(params.data)
	}

}

Por otra parte, creamos un servicio en el que declaramos una propiedad estática llamada atmosphere, y dos closures onRequest y onStateChange:

class ChatService {

	static transactional = false
	static atmosphere = [mapping: '/atmosphere/chat']

	def onRequest = { event -&gt;
		event.suspend()
	}

	def onStateChange = { event -&gt;

		if (!event.message) return

		event.resource.response.writer.with {
			write "&lt;script&gt;parent.callback('${event.message}');&lt;/script&gt;"
			flush()
		}
	}

}

Lo importante aquí es saber que cuando algún cliente invoca la closure broadcast del controlador, se desencadena la ejecución de la closure onStateChange del servicio. Como vemos, esta closure llama el método javascript callback del cliente, que a continuación veremos cómo se define.

Finalmente, tenemos la siguiente página gsp, que es la que mediante Javascript envía la información al servidor y procesa la información recibida por el servidor:

&lt;html&gt;
  &lt;head&gt;
    &lt;title&gt;Chat - jlmonteagudo&lt;/title&gt;
    &lt;meta name="layout" content="main" /&gt;

   	&lt;link rel="stylesheet" href="${resource(dir:'css',file:'chat.css')}" type="text/css" /&gt;

	&lt;atmosphere:resources/&gt;
	&lt;script type="text/javascript"&gt;
		$(function(){

			function callback(response) {
				if (response.status == 200) {
					var data = response.responseBody;
					if (data.length &gt; 0) {
						var mensajeData = $.parseJSON(data);
						var chatValue = $('#chat').html();

						chatValue += "&lt;span class='chatUser'&gt;" + mensajeData.usuario + " dice:&lt;/span&gt; " + mensajeData.mensaje + "&lt;br/&gt;";
						$('#chat').html(chatValue);
						$("#chat").attr({ scrollTop: $("#chat").attr("scrollHeight") });
					}
				}
            		}

			$.atmosphere.subscribe('${resource(dir: '/atmosphere/chat')}',
				callback,
				$.atmosphere.request = {transport: 'streaming'});

			$('#buttonPost').click(function() {
				var data = '{"usuario":"' + $('#usuario').val() + '", "mensaje":"' + $('#mensaje').val() + '"}';
				$.get('${createLink(action: "broadcast")}?data=' + data);
				$("#mensaje").val('');
				$("#mensaje").focus();
			});

		});
	&lt;/script&gt;
  &lt;/head&gt;

  &lt;body&gt;

  	&lt;div id="pageBody"&gt;

		&lt;div class="contenedor"&gt;

		  	&lt;h3&gt;Sala de Chat - Grails y Ajax Push&lt;/h3&gt;

			&lt;div id="chat"&gt;
			&lt;/div&gt;

			&lt;div id="chatForm"&gt;

				&lt;table cellpadding="0" cellspacing="0"&gt;
					&lt;tr&gt;
						&lt;td&gt;&lt;label&gt;Usuario:&lt;/label&gt;&lt;/td&gt;
						&lt;td&gt;&lt;input type="text" id="usuario" name="usuario" value="" size="10"/&gt;&lt;/td&gt;
					&lt;/tr&gt;
					&lt;tr&gt;
						&lt;td&gt;&lt;label&gt;Mensaje:&lt;/label&gt;&lt;/td&gt;
						&lt;td&gt;
							&lt;input type="text" id="mensaje" name="mensaje" value="" size="40"/&gt;
							&lt;input type="submit" id="buttonPost" name="buttonPost" value="Enviar"/&gt;
						&lt;/td&gt;
					&lt;/tr&gt;
				&lt;/table&gt;
			&lt;/div&gt;

		&lt;/div&gt;

		&lt;div id="chatWarning"&gt;
			(*) Para probar el funcionamiento de la aplicación se recomienda abrir distintos navegadores y enviar mensajes desde cada uno de ellos.
		&lt;/div&gt;

	&lt;/div&gt;

  &lt;/body&gt;

&lt;/html&gt;

En esta página son tres las cosas que tenemos que tener en cuenta:

  • Al cargarse la página el cliente se conecta automática al canal /atmosphere/chat:
$.atmosphere.subscribe('${resource(dir: '/atmosphere/chat')}',
callback,
$.atmosphere.request = {transport: 'streaming'});
  • Al pulsar el botón Enviar, mediante Javascript se genera un mensaje JSON (que contiene el usuario que ha escrito el mensaje, así como el mensaje en sí), y se envía el JSON al servidor:
var data = '{"usuario":"' + $('#usuario').val() + '", "mensaje":"' + $('#mensaje').val() + '"}';
$.get('${createLink(action: "broadcast")}?data=' + data);
  • Finalmente, cuando el servidor envía información al cliente, se ejecuta la función Javascript callback, que proceso el mensaje JSON y lo agrega al div llamado chat.

Esta aplicación es extremadamente sencilla y en ningún momento pretende explotar todas las funcionalidades que el plugin ofrece, pero sirve para poder ver el tipo de aplicaciones que pueden desarrollarse con este framework.

En un post anterior publiqué información acerca de la publicación de una aplicación Grails en una plataforma de cloud computing. En este post voy a comentar lo sencillo que supone desplegar la misma aplicación (Gestión de Encuestas, http://encuestas.cloudfoundry.com) en Cloud Foundry.

A mediados de Abril de 2011 VMware anunció la disponibilidad de su plataforma PaaS, una plataforma que facilita en gran medida la publicación de aplicaciones Java, Rails y Node.js en la nube. Lo bueno de esta plataforma es que el desarrollador no se tiene que preocupar de otra cosa que no sea el diseño y la programación de su aplicación, ya que CloudFoundry no exige al programador adaptar su aplicación a la plataforma.

De momento, VMware permite testear su plataforma sin coste alguno, ya que actualmente se encuentra en fase beta. Para poder publicar tus aplicaciones en Cloud Foundry tienes que solicitar gratuitamente una cuenta en la web http://www.cloudfoundry.com/ y en unos días recibirás un mail con tus datos de acceso.

Una vez tienes tu cuenta, tienes varias opciones para poder interactuar con la plataforma. Puedes gestionar tus aplicaciones con el IDE STS, o bien directamente a través de un command line que puedes descargarte. Si tu aplicación está desarrollada con Grails, existe un plugin que te permite interactuar con la plataforma a través de la línea de comandos de Grails. Tengo que decir que tuve problemas a la hora de subir la aplicación a través del plugin de Grails, así que tuve que hacerlo a través del command line de Cloud Foundry.

Creo que, una vez más, SpringSource, de la mano de VMware, ha demostrado que se sabe adaptar mucho más rápido a las necesidades del mercado que los estándares de la plataforma Java (JEE7 tendrá soporte para la nube), ofreciendo soluciones que facilitan el trabajo del desarrollador.

En el siguiente artículo voy a detallar los pasos necesarios para desplegar en la nube una aplicación desarrollada con Grails. La aplicación es un sencillo gestor de encuestas que permite la creación y el borrado de las mismas, y que muestra al usuario un listado de todas las encuestas disponibles en el sistema. El usuario tendrá la posibilidad de votar en cualquiera de las encuestas existentes, y para poder crear nuevas encuestas el usuario tendrá que disponer de privilegios, accediendo al sistema con el usuario admin y el password monteagudo.

Os dejo a continuación el código fuente y la URL de la aplicación publica en la plataforma de cloud computing de Stax:

Código Fuente: encuestas

URL de la aplicación: http://encuestas.jlmonteagudo.staxapps.net/

Grails y la aplicación Gestión de Encuestas

En un principio mi idea era explicar en el artículo los pasos realizados para desarrollar la aplicación, pero, como asumo que cualquiera que tenga interés en la lectura de este artículo tiene conocimientos sobre cómo desarrollar una aplicación en Grails, me voy a ahorrar la explicación y me voy a centrar más en cómo desplegar una aplicación web en la nube. En cualquier caso, os dejo el código fuente de la aplicación, así cualquier persona que quiera probarla o quiera ver el código tiene la posibilidad de hacerlo.

Sin embargo, antes de empezar con el despliegue de la aplicación, me gustaría comentar algunos aspectos de Grails en general, y de la aplicación en particular.

Quiero aprovechar este artículo para destacar que Grails es una herramienta que permite mejorar notablemente la productividad de los desarrolladores. Esta es una característica muy importante, porque el éxito o el fracaso de un proyecto de desarrollo de software puede estar condicionado en gran medida por este factor, entre otros.

Además, Grails ofrece un extenso ecosistema de plugins que facilitan enormemente la integración de Grails con otras APIs o herramientas. En el caso concreto de la aplicación “gestión de encuestas”, durante su desarrollo he necesitado de una serie de funcionalidades que ya estaban implementadas en forma de plugins en Grails, por lo que, en este sentido, el desarrollo con Grails y su amplia gama de plugins me han ahorrado un tiempo considerable de desarrollo.

A continuación comento brevemente los plugins que he utilizado para el desarrollo de la aplicación “gestión de encuestas”:

  • Webflow:  webflow inicialmente formaba parte del core de Grails, pero a partir de la versión 1.2 se extrajo en forma de plugin, por lo que si quieres utilizar “conversaciones” dentro de tu aplicación tendrás que instalarlo. Este plugin nos permite crear flujos, donde se almacenan estados de la aplicación y en función de las entradas del usuario el programa pasará de un estado a otro.En “gestión de encuestas” se utiliza este plugin para crear la encuesta. De este modo, la aplicación permite ir añadiendo opciones a la nueva encuesta, opciones que ser irán almacenando en el ámbito del flujo, y que sólo se almacenarán en la base de datos cuando el usuario decida que no quiere agregar más opciones y que quiere grabar la encuesta.
  • Google Visualization: Google Visualization permite la elaboración de gráficos a partir de los datos proporcionados por una fuente de datos. Este plugin nos facilita enormemente la representación de la información en forma de gráficos, ya que simplemente pasando al control nuestra información en forma de lista, obtendremos la visualización de la lista en el tipo de gráfico que decidamos.
  • Shiro: Shiro es un framework que permite gestionar de forma sencilla la seguridad de una aplicación. Podemos comenzar a utilizar fácil y rápidamente Shiro instalando el plugin e invocando el comando grails quick-start. A pesar de su facilidad, Shiro nos proporciona gran flexibilidad que nos permite configurar la seguridad en base a las necesidades de la aplicación.

Proveedores de cloud computing

Tenemos distintos proveedores de cloud computing a través de los cuales podemos desplegar nuestras aplicaciones en la nube. En un principio, mi intención fue desplegarla en el servidor Google App Engine, pero por problemas con librerías utilizadas por el plugin webflow, no he podido instalar la aplicación con este proveedor. Un factor a tener en cuenta es que, si queremos que nuestra aplicación se ejecute en Google App Engine, vamos a tener que convertir nuestro modelo de datos a JPA, ya que Google sólo permite trabajar con este sistema de persistencia y con JDO.

Mi segunda opción era desplegar la aplicación con la solución de SpringSource Cloud Foundry. Actualmente este servicio lo ofertan en modo Beta, siendo gratuito el servicio en este modo. Al ser una solución perteneciente a SpringSource, imagino que el despliegue de aplicaciones basadas en el framework Spring estará bastante depurado, con lo que los problemas con esta plataforma deberían de ser mínimos. Para obtener acceso a este servicio hay que realizar una solicitud, pero ha pasado más de una semana desde que realicé la solicitud y lamentablemente ésta todavía no la he recibido. Updated: Mientras escribo este artículo he recibido la confirmación de Cloud Foundry que me permite registrarme para utilizar sus servicios. Próximamente publicaré la aplicación “gestión de encuestas” en Cloud Foundry y escrbiré un post acerca del proceso de publicación en esta plataforma.

Otra solución que me ofrecía el despliegue de la aplicación de forma gratuita (aunque en fase beta) es Stax, cuya infraestructura trabaja sobre el sistema Amazon EC2. Desplegar la aplicación con este proveedor no supone ninguna dificultad, aunque si nuestra cuenta es Beta, la aplicación se desactivará automáticamente entre 2 y 4 horas a lo largo del día. Posteriormente se volverá a activar de forma automática.

Despliegue de la aplicación con el proveedor Stax

El primer paso que tenemos que realizar es crearnos una cuenta a través de la web de Stax. El proceso es muy sencillo, y en cuestión de minutos tendremos acceso a la consola de administración de nuestra cuenta. La consola de administración también es extremadamente sencilla, y a través de ésta tendremos que crear una base de datos y una aplicación. Crear una aplicación tan sólo consiste en asignarle un nombre, y seleccionar el tipo de aplicación, que en nuestro caso es “Basic Servlet and JSP”.

A continuación tenemos que descargarnos e instalar el SDK de Stax. El proceso de instalación del SDK puede consultarse en la siguiente URL: http://wiki.stax.net/w/index.php/SDK, aunque básicamanente se trata de descomprimir el SDK en el directorio que deseemos. Conviene tener en cuenta crear una nueva variable de entorno llamada STAX_HOME que apunte al directorio en el que se ha instalado el SDK, así como agregar al PATH la variable STAX_HOME. En un principio el SDK simplemente lo utilizaremos para, mediante la ejecución de un comando, publicar la aplicación en Stax.

El siguiente paso que tendremos que realizar es configurar nuestra aplicación Grails para que acceda a la base de datos que hemos creado previamente a través de la consola. Para acceder a la base de datos vamos a utilizar un driver proporcionado por Stax, por lo que es necesario copiar el driver (podemos encontrarlo en la siguiente ubicación: STAX_HOME/lib/ stax-appserver-1.0.20100601-SNAPSHOT.jar) en el directorio lib de nuestra aplicación Grails. A continuación tendremos que modificar el fichero DataSource.groovy para configurar la conexión de la base de datos de producción:

production {

    dataSource {
         pooled = true
         driverClassName = "com.staxnet.jdbc.Driver"
         dbCreate = "update"
         url = "jdbc:stax://STAX_DB_NAME"
         username = "STAX_DB_USER"
         password = "STAX_DB_PASS"
     }
}

Tendrás que reemplazar los valores de STAX_DB-NAME, STAX_DB_USER y STAX_DB_PASS por los utilizados a la hora de crear la base de datos a través de la consola.

Finalmente, sólo nos queda publicar la aplicación. En primer lugar tendremos que generar el fichero war de nuestra aplicación mediante la ejecución del siguiente comando: grails war. Y por último, para desplegar la aplicación en Stax ejecutaremos el siguiente comando: stax app:deploy -a STAX_APPID [PATH_TO_WAR_FILE] . Hay que tener encuenta que STAX_APPID es el nombre de la aplicación que hemos creado con la consola, pero hay que anteponerle el nombre de usuario con el que te has registrado en Stax. Así, en mi caso, el valor de STAX_APPID corresponde a jlmonteagudo/encuestas.

Con estos simples pasos ya tienes tu aplicación Grails funcionando en una plataforma de cloud computing. Te recuerdo que si tu cuenta con Stax es Beta, tu aplicación se desactivará una vez al día durante unas horas. Sin embargo, creo que la plataforma de Stax es muy útil si lo que quieres es testear tu aplicación con en una plataforma de cloud computing.

Dentro del mundo del desarrollo de software somos conscientes de la importancia que el cloud computing está adquiriendo en nuestros días. Con el fin de experimentar los beneficios que esta nueva tendencia nos proporciona, he desarrollado una aplicación con Grails y la he alojado en una plataforma de cloud computing.

Podéis probar la aplicación en la siguiente URL: http://encuestas.jlmonteagudo.staxapps.net/

También os dejo unas capturas de pantalla por si no pudierais acceder a la aplicación:

Consulta de encuestas

Crear encuesta

En un principio he intentado desplegar la aplicación con Google App Engine. Grails dispone de un plugin que permite el despliegue de aplicaciones Grails en la plataforma de Google, pero lamentablemente me he encontrado con diversos problemas que me han impedido la publicación de la aplicación. Supongo que los problemas son debidos a bugs que contiene el plugin a la hora de integrarse con otra serie de plugins que utilizo en la aplicación, aunque esto todavía no puedo confirmarlo.

Posteriormente mi intención ha sido desplegar la aplicación en CloudFoundry, una plataforma adquirida por SpringSource. Inicialmente es necesario solicitar una invitación para crear una cuenta de usuario, pero ha pasado un día desde que realicé la solicitud y la invitación todavía no la he recibido. En cuanto reciba la invitación intentaré desplegar la aplicación y comentaré cómo ha sido el proceso.

Finalmente he escogido Stax para publicar la aplicación. Ha sido francamente rápida y sencilla la publicación de la aplicación con este proveedor. Es una plataforma que opera sobre el servicio Elastic Cloud Computing de Amazon (EC2), y que actualmente ofrecen una cuenta gratuita para poder testear su servicio. El problema es que, según he leído, cada 24 horas detienen la aplicación, por lo que imagino será necesario volver a arrancarla manualmente desde el panel de control que ofrecen.

La aplicación desarrollada es un simple gestor de encuestas. Para implementarla he utilizado Grails, porque considero que es uno de los frameworks Java más interesantes actualmente y que ofrece un alto grado de productividad. He utilizado diversos plugins, como web-flow, google visualization y shiro (para gestionar la seguridad), que han simplificado mucho el desarrollo. Durante estos días publicaré un artículo/tutorial en el que detallaré cómo he desarrollado la aplicación y donde explicaré cómo publicar la aplicación en la nube.

Cuando tenemos que desarrollar una aplicación web para la plataforma Java, la decisión más extendida hasta ahora ha sido diseñar una arquitectura web-céntrica en lugar de utilizar una arquitectura EJB-céntrica. En la mayoría de las ocasiones la decisión estaba justificada, ya que para qué vamos a utilizar un servidor de aplicaciones cargado de un montón de especificaciones que no vamos a utilizar, si un simple y ligero servidor Tomcat nos proporiona todo lo que necesitamos para desarrollar nuestra aplicación. Además, todos sabemos que la complejidad de desarrollar una aplicación EJB con sus fatídicos ficheros XML de despliegue, siempre ha sido más costoso y complejo que implementar una aplicación con el framework Spring, por ejemplo.

Sin embargo, con la llegada de JEE6 y su Web Profile, bien merece la pena dedicar el tiempo necesario para decidir qué framework o especificación es la más adecuada a la hora de diseñar y desarrollar una aplicación web. Personalmente considero que, si SpringSource no hubiera desarrollado Spring Roo, programar una aplicación web con NetBeans y utilizando el Web Profile podría ser bastante más productivo y ágil que desarrollarla con Spring. Al margen de lo anterior, aprovecho para comentar que soy fan de Grails, ya que éste me permite centrarme desde un principio en la lógica de negocio de la aplicación y no en la configuración de la misma.

Como sabemos, cada aplicación tiene unos requisitos y unas necesidades particulares y, dependiendo de éstas, será más conveniente un tipo de arquitectura u otra. Actualmente mis preferencias son, sin importar el orden, Grails, Spring Roo y JEE6. Conviene tener en cuenta que, a día de hoy, JEE6 es una opción muy atractiva porque nos ayuda a conseguir un nivel de productividad y una facilidad de uso muy interesantes. En próximos posts iré escribiendo sobre las nuevas características que hacen de JEE6 una plataforma muy tentadora.

Hace unos días, a través de no recuerdo qué agregador de blogs, mi navegador me dirigió a un interesante post titulado Starting with the Startup – Setting Up Development Environment. Este post me llevó a otras entradas del mismo blog, en las cuales se explican las decisiones adoptadas por un equipo técnico a la hora de definir los procesos de desarrollo que se van a seguir en el seno de la startup.

La primera decisión que tomaron fue el uso de SCRUM como metodología de desarrollo de software. La siguiente cuestión que abordaron fue acerca del entorno y frameworks de desarrollo que utilizaría el equipo y que les permitiera conseguir un nivel de productividad elevado.

A continuación comento las decisiones que en este sentido adoptaron:

- Framework web: Comenta el autor que inicialmente tenían dos opciones por las que decantarse; una era Grails y la otra era Wicket. La decisión final fue Grails. Personalmente, mis últimos proyectos los estoy realizando con Grails y tengo que decir que se consigue un aumento de productividad importante programando con este framework. También considero muy interesante tener presente en una elección de este tipo la herramienta Spring Roo, que también ayuda a aumentar la productividad notablemente, sin la necesidad de utilizar lenguajes dinámicos como Groovy.

- Sistemas de build: Grails dispone de comandos para hacer los build de forma muy sencilla, pero dado que tenían que integrar los builds de Grails con los de otros proyectos, decidieron utilizar otra herramienta. Finalmente tuvieron que decidir entre maven e ivy, y dado que el soporte de ivy por parte de Grails es mejor que el de maven, optaron por utilizar ivy como herramienta para hacer los build. Personalmente considero que una herramienta muy a tener en cuenta actualmente entre los sistemas de construcción, y a la cual espero dedicar un post en un futuro, es Gradle, que reúne lo mejor de Ant, Ivy y Maven.

- Integración contiua: Deciden utilizar Hudson como servidor de integración continua debido a su facilidad a la hora de instalarlo, debido a su potente interfaz de gestión y al número de plugins que tiene.

- Bug tracker: Dado que gran parte del equipo ha trabajado con Mantis, deciden utilizar esta herramienta para gestionar los bugs. Es una herramienta que, personalmente, no he utilizado, así que me la anoto para probarla en cuanto pueda.

- Repositorio de librerías: Como utilizan librerías externas para el desarrollo de sus proyectos, deciden utilizar una herramienta que les permita gestionar las dependencias de las mismas, seleccionando Nexus para tal propósito.

- Sistema de control de versiones: Han decidido utilizar el que probablemente sea el sistema de control de versiones más extendido del mercado,  Subversion, a pesar de la existencia de nuevos sistemas, tales como Git.

- IDE: A pesar de no tener expeirencia con el IDE elegido, el equipo de desarrollo ha decidido utilizar IntelliJ Idea dado que este IDE proporciona un buen soporte para Grails. La verdad es que personalmente estoy bastante satisfecho con SpringSource Tool Suite para programar con Grails.

¿Qué os parece el conjunto de herramientas comentado en este post para llevar a cabo el proceso de desarrollo de software? ¿Qué herramientas utilizáis vosotros que os faciliten el proceso de desarrollo y que os permitan obtener un alto nivel de productividad?