Publicidad:
La Coctelera

un rato de sol

i will work harder, ja ja ja, no ahora en serio.

10 Diciembre 2008

clojure on grizzly

Clojure (http://clojure.org) es el lenguaje con el que paso más tiempo últimamente.
Es un Lisp-1, funcional (todo es inmutable), ejecutándose sobre la JVM con lo que supone poder acceder a la ingente cantidad de bibliotecas disponibles para Java, con interesantes abstracciones para la programación concurrente, con multimétodos y, por supuesto, con las características tradicionales de Lisp (defmacro!) pero con algunos paréntesis menos.


Por otro lado está grizzly (https://grizzly.dev.java.net/) un proyecto Java que ofrece un framework para la construcción de aplicaciones de red sobre las nuevas bibliotecas Java NIO. Grizzly está integrado en proyectos como Glassfish, donde se encarga de manejar las peticiones HTTP.

¿Podemos usar Clojure para servir aplicaciones web? pues por ahí anda Webjure, un miniframework web escrito en clojure, o se puede invocar a clojure desde un servlet, o implementar el servlet directamente en clojure... las opciones son varias, pero ¿por qué no conectar grizzly con clojure?


El elemento necesario para insertar código clojure en una petición recibida desde grizzly, es una implementación de una clase Adaptader. Como modelo, he modificado el código del adaptador de jruby para grizzly. Este adaptador conecta grizzly con los runtime de jruby configurados e implementa el procotolo Rack (http://rack.rubyforge.org/) que describe una interfaz de comunicación entre servidores web y frameworks de aplicaciones. Así que, siguiendo el ejemplo de jruby, tenemos la clase com.agh.webserver.ClojureAdpater que extiende GrizzlyAdapter
y que implementa el método public void service(GrizzlyRequest req, GrizzlyResponse res) donde se realiza la lógica de proceso de la petición.


Al usar el como base el código de jruby-grizzly, en ese método se construye un nuevo objeto que implementa la interfaz RackApplication que contiene el método RackResponse call(GrizzlyRequest request); como indica la especificación de Rack.
Esta clase hereda de la clase de DefaultRackApplication de jruby-rack con ligeras modificaciones. Esta clase abstracta procesa la petición de grizzly y extrae las variables de entorno que indica la especificación de Rack.


La implementación de esta clase abstracta se solicita desde el adaptador a través de una clase RackApplicationFactory que construye la implementación concreta de DefaultRackApplication para cada framework web. Como nosotros no tenemos framework web, simplemente se ha añadido la clase DefaultRackApplicationFactory que devuelve una subclase anónima de DefaultRackApplication que interpreta la URL de la petición como /directorio/script/función, donde directorio es el namespace de la función y script el nombre del script en ese namespace.

 public RackResponse callMethod(String cmd, final HashMap rackEnv) {
   
   ...
 
    File script = new File(filePath+".clj");
 
      if(script.exists()) {
        try {
          Properties props = System.getProperties();
          RT.loadResourceScript(suffix+".clj");
          RT.loadResourceScript(CLOJURE_RACK);
          Var form = RT.var("com.agh.webserver.rack", "rack-invokation-point");
          PersistentStructMap result = (PersistentStructMap) form.invoke(rackEnv,path[path.length-1]);
 
           ...
 

Como se puede ver, este script llama a la función rack-invokation-point, pasándole como argumentos el nombre de la función a invocar y el entorno de Rack construido. Esta función invoca a su vez a una macro que se encarga de la llamada y del procesamiento de la respuesta:

 (defmacro with-rack-response
   "Embeds a call to a function with a Rack request and response arguments. The
    function should receive two arguments -> the rack request and the rack
    response. Both arguments are references."
   [rack-request invoked-function]
   `(let [req# (ref ~rack-request)
          res# (ref (create-rack-response))]
      (do
        ((find-var (symbol (str "cgi/" ~invoked-function))) req# res#)
        @res#)))
 
 
 (defn rack-invokation-point [req function]
   (with-rack-response req function))
 

La clase Main es el punto de entrada de la aplicación que fija el contexto, el document root de la misma, el puerto de escucha, etc. a través de una subclase de SelectorThread, en nuestro caso el ClojureSelectorThread

 ClojureSelectorThread selectorThread = new ClojureSelectorThread();
 selectorThread.setRailsRoot("/Users/antonio/Desktop/clj-web-app/");
 selectorThread.setPort(8080);
 selectorThread.setAdapter(new ClojureAdapter("/", new ClojureRuntimeAsyncFilter()));
 try {
   selectorThread.initEndpoint();
   selectorThread.startEndpoint();
 } catch (IOException ex) {
    System.out.println(ex.getMessage());
 } catch (InstantiationException ex) {
     System.out.println(ex.getMessage());
 }
 

Ahora solo queda crear nuestra función clojure para ser invocada a través de grizzly, esta estará situada en el path cgi/cgi.clj a partir del directorio que hayamos indicado como document root para la aplicación en la clase Main. Por ejemplo:

 (ns cgi)
 
 (use 'com.agh.webserver.rack)
 
 (defn hello-complex [request resp]
   (render resp
           "<h1> Hola Grizzly!!</h1>"
           200
           {:Content-type "text/html"}))
 

Lanzamos nuestro servidor, y ya podemos probar a invocar nuestro script.

Aquí tenéis la URL del código en github por si queréis echarle un vistazo:

http://github.com/antoniogarrote/clojure-grizzly-trial/tree/master

Tags: clojure, grizzly, lisp

servido por Antonio 1 comentario compártelo

1 comentario · Escribe aquí tu comentario

sdfg

sdfg dijo

Rolex Replica and the animated Replica Rolex television satire show South Park.Her live Rolex shop peformances.

18 Diciembre 2009 | 05:09 AM

Escribe tu comentario


Sobre mí

Avatar de Antonio

un rato de sol

Barcelona/Salamanca, España
ver perfil »
contacto »
Trabajador del metal y del acero, en la gloriosa XING AG, escribo software con el que poder ganarme el jornal. En mi tiempo libre sigo tecleando código de bonitos colores a medio camino entre lo sublime y lo terrible. Últimamente me gustan mucho los gatos.

Fotos

Antonio Garrote Hernández todavía no ha subido ninguna foto.

¡Anímale a hacerlo!

Buscar

suscríbete

Selecciona el agregador que utilices para suscribirte a este blog (también puedes obtener la URL de los feeds):

¿Qué es esto?

Crea tu blog gratis en La Coctelera