Archivo

Archive for 23 mayo 2010

JQL (Java Query Language)

Hace un tiempo atrás conocí YQL, un servicio de Yahoo! que permite hacer consultas tipo SQL a sus APIs o a sitios webs… Buscando algo así para Java no encontré nada parecido, por lo que empece a hacerlo yo. El resultado fueron unas cuantas lineas de código que permiten filtrar ,manipular y unificar datos de páginas Web , simplemente con una consulta tipo SQL muy similar a YQL.

Por ejemplo si quisiera filtar los datos de una página web debería usar una conexión, obtener la página , filtarla usando expresiones regulares y devolver los datos que quisiera. Con ésta librería es tan simple como crear una consulta SQL:

Ejemplo:
Acá obtengo los resultados de búsqueda de goear.com

//Creo la consulta SQL
String sql = "SELECT href,title FROM html WHERE url='http://goear.com/search.php?q=rafaga' AND xpath=\"//a[@class='b1']\"";
//Creo un objeto de la clase JQL y le paso como parametro la query sql y el tipo que quiero que devuelva (JSON)
JQL jql = new JQL(sql,JQLResultType.JSON);
//Agrego un listener para que sea lanzado cuando me devuelva los resultados
jql.addJQLResultListener(new JQLResultListener() {
	//Implemento el método jqlResult para obtener los resultados
	public void jqlResult(JQLResultEvent event) {
	    //Imprimo los resultados de mi consulta
	    System.out.println(event.getJqlResult());
	}
});
//creo un hilo y le paso como parametro el objeto JQL
Thread th = new Thread(jql);
//lanzo el hilo
th.start();

Simplemente Selecciono el href y el titulo de los links de goear donde la url de donde sacare esos datos sea la página de goear y le paso el xpath de donde están los elementos que quiero obtener. Al hacer correr ese codigo me devuelve un String con JSON listo para ser manipulado:

run:
{
        "query": {
        "count": "10",
        "created": "2010-05-23T10:19:48Z",
        "lang": "en-US",
        "diagnostics": {
                "url": {
                        "execution-time": "4072",
                        "proxy": "DEFAULT",
                        "content": "http://goear.com/search.php?q=rafaga"
                }
        },
        "results": {
                "a": [
                        {"href":"listen/c77464e/rafaga-radio-andalucia-(1)-radio-andalucia-informacion","title":"Escuchar Rafaga Radio Andalucia (1) de radio andalucia informacion"},
                        {"href":"listen/6d87274/una-rafaga-de-amor-rafaga","title":"Escuchar Una rafaga de amor de rafaga"},
                        {"href":"listen/fd1b84c/una-rafaga-de-amor-rafaga","title":"Escuchar Una Rafaga De Amor de rafaga"},
                        {"href":"listen/3b043de/jambo-jambo---rafaga-sunshine-rafaga-sunshine","title":"Escuchar JAMBO JAMBO - Rafaga Sunshine de rafaga sunshine"},
                        {"href":"listen/1dbcd0b/una-rafaga-de-amor-rafaga","title":"Escuchar una rafaga de amor de rafaga"},
                        {"href":"listen/71b1c55/una-rafaga-de-amor---calidad-media---faviomundo.pe.kz-rafaga","title":"Escuchar Una Rafaga De Amor - Calidad Media - FavioMundo.Pe.Kz de rafaga"},
                        {"href":"listen/9ff4361/una-rafaga-de-amorr-rafaga","title":"Escuchar una rafaga de amorr de rafaga"},
                        {"href":"listen/b9cdad7/rafaga-feat-korekt---sabes(((-www.robney.com.pe-)))-rafaga-feat-korekt---sabes","title":"Escuchar Rafaga Feat Korekt - Sabes((( wWw.Robney.CoM.Pe ))) de Rafaga Feat Korekt - Sabes"},
                        {"href":"listen/1286fa6/rafaga---mentirosa-(danny-romero-remix)-rafaga---mentirosa-(danny-romero-remix)","title":"Escuchar Rafaga - Mentirosa (Danny Romero Remix) de Rafaga - Mentirosa (Danny Romero Remix)"},
                        {"href":"listen/b229d9c/no-te-vallas-remix-rafaga-dj-efexts-rafaga-dj-efexts","title":"Escuchar No Te Vallas Remix Rafaga Dj Efexts de Rafaga Dj Efexts"}
                ]
        }
        }
}

La librería solo es un prototipo de lo que va a ser. La idea es poder obtener Objetos Java como Map o Document para manipularlo aun mas fácil desde Java.

Además se podrá definir el método HTTP de la consulta (GET o POST) para aumentar aun mas su funcionalidad. La idea es poder hacer la mayoría de los comando SQL que funcionen en JQL.

Bueno acá les dejo el link de la librería si quieres aportar:
http://kenai.com/projects/javaquerylanguage/

PD: El código esta muy desordenado D:

Saludos!

ACTUALIZACIÓN 01 (25/05/2010):
– Puede devolver Map y String con JSON.
– Ordenado el Código y programado Orientado a Objetos.
– Mejorado el codigo para parsear las consultas

Categorías:Java, Proyectos Etiquetas: , , , ,

Administrar Remotamente un Equipo Vía Web [Java+HTML+JQuery=Remote Control]

El otro día hablando con @PabloVidela y @DavidAcevedo… y Acevedo, salió la idea de administrar un computador remotamente vía Web.

¿Cual es la idea?

Poder acceder a un computador remotamente vía web, pudiendo ver el escritorio e ir navegando por él solo con el navegador…

Seguro que la idea ya está desarrollada por alguna otra persona, pero igual lo investigue.

Para poder hacer ésto, es necesario que el computador que se quiera acceder tenga algún software que cree una especie de servidor para poder conectarse a el por algún cliente.

Primero que todo crearemos el servidor. Java Tiene una clase para poder crear un servidor web rápidamente, su nombre es HttpServer (Nombre Original xD). Para que sea un servidor web debemos poner a escuchar el puerto 80, en código para ésto seria así:

 HttpServer server = HttpServer.create(new InetSocketAddress(80), 0);

Supongamos que a el servidor queremos acceder con la siguiente dirección:

http://localhost:80/hola?action=view

de eso podemos sacar los siguientes términos:

http://host:puerto/path?parametros

Ahora debemos manipular los paths de nuestro servidor.Cuando llame a algun path el servidor deberá hacer alguna tarea.

Para manipular los paths debemos implementar la interface HttpHandler

//## Implementar interface HttpHandler
public class Servidor implements HttpHandler  {
    //## Constructor
    public Servidor() {
            //## Creo el Servidor en el puerto 80
            HttpServer server = HttpServer.create(new InetSocketAddress(80), 0);
            //## llamo al metodo createContext para poder hacer alguna funcionalidad al llamar al path "/get"
            server.createContext("/get", this);
            server.

    }
    //## Implementamos el Método handle de la interfaz HttpHandler
    public void handle(HttpExchange he) throws IOException {
        //## Acá agregamos la funcionalidad para los paths
        //...
    }
}

Ahora tenemos dos cosas que programar.

  • Capturar una imagen del escritorio: Con esto tendremos, en una imagen, lo que el servidor esta haciendo, las ventanas abiertas y todo lo que se pueda ver en el escritorio.
  • Clickear en un punto dado: con esto podremos, clickear en el escritorio segun parametros X e Y.

La primera tarea que programaremos es que al llamar a la URL

http://servidor:80/get

nos devuelva una imagen del escritorio del servidor.
Para eso usaremos la clase Robot de java. Esta clase se utiliza para generar eventos nativos de entrada del sistema a efectos de la automatización de pruebas, demos autoejecutables, y otras aplicaciones donde el control del ratón y el teclado es necesario. (API Java).

Con el siguiente método capturaremos el escritorio en una imagen

package servtest;

import java.awt.AWTException;

import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;

/**
 *
 * @author Esteban Fuentealba
 */
//## Creamos una Clase llamada ScreenShot
public class ScreenShot {

    public ScreenShot() {
    }
    public Image get() throws AWTException {
        //## Creamos una instancia a la Clase RObot
        Robot robot = new Robot();
        //## Tomamos una fotografía (Screen Shot) del Escritorio
        BufferedImage bufferedImage = robot.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
        //## Retornamos una Image
        return Toolkit.getDefaultToolkit().createImage(bufferedImage.getSource());
    }

}

Ahora, con una imagen podríamos obtener las coordenadas de un punto específico y simular un click dependiendo de esas coordenadas, para eso utilizaremos la siguiente Clase:

package servtest;

import java.awt.AWTException;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.InputEvent;

/**
 *
 * @author Esteban Fuentealba
 */
public class PCControl {
    private Robot robot;
    public PCControl() throws AWTException {
        robot = new Robot();
    }
    //## Metodo que clickea en un Punto pasado como parametro
    public void click(Point punto) {
        //Movemos el mouse a la posición X e Y
        robot.mouseMove(punto.x, punto.y);
        //Simulamos el click
        robot.mousePress(InputEvent.BUTTON1_MASK);
        robot.mouseRelease(InputEvent.BUTTON1_MASK);
    }
}

Bueno teniendo esas dos funcionalidades crearemos el programa en Si

package servtest;

import servtest.utils.ImageUtils;
import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.awt.AWTException;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import servtest.utils.Utils;

/**
 *
 * @author Esteban Fuentealba
 */
public class Servidor implements HttpHandler  {
    //## Main
    public static void main(String[] args) {
        if(args.length > 0) {
            if(Utils.isNumber(args[0])) {
                new Servidor(Integer.parseInt(args[0]));
            }
        } else {
            System.out.println("Falta el numero del puerto");
        }

    }
    //## Constructor con parametros, recibe el puerto que se quiere escuchar, donde se accederá
    public Servidor(int puerto) {
        try {
            //Ponemos a escuchar el puerto
            HttpServer server = HttpServer.create(new InetSocketAddress(puerto), 0);
            // Creamos un Context para manipular el path /get
            server.createContext("/get", this);
            // Creamos otro Context para manipular el path /click
            HttpContext conClick = server.createContext("/click", this);
            // el context tendrá además parametros, los cuales filtraremos y manipularemos con la clase ParameterFilter
            conClick.getFilters().add(new ParameterFilter());
            server.setExecutor(null); // creates a default executor
            //Iniciamos el servidor
            server.start();
            System.out.println("[INFO] Server ON ");
        } catch (IOException ex) {
            Logger.getLogger(Servidor.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    //## Constrctor por defecto, escucha el puerto 8080
    public Servidor() {
        this(8080);

    }
    //Implemento un metodo de la interface HttpHandler
    public void handle(HttpExchange he) throws IOException {
        System.out.println("[INFO] Connected ["+he.getRemoteAddress()+"] , Path: "+he.getHttpContext().getPath());
        //## Agrego una condición para ver que path fue llamado
        //## Si se llamo la url "http://miip:puerto/get" hare lo siguiente
        if(he.getHttpContext().getPath().equals("/get")) {
            try {
                //Creo un Objeto ScreenShot
                ScreenShot ss = new ScreenShot();
                //Capturo la imagen y la combierto a BufferedImage
                BufferedImage bimg = ImageUtils.toBufferedImage(ss.get());
                //Creo un objeto ByteArrayOutputStream
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                //Escribo el BufferedImage en el ByteArrayOutputStream con el formato png para poder obtener el peso de la imagen
                ImageIO.write(bimg, "png", out);
                //Envio una cabecera con el codigo 200 (OK) y el peso de la imagen al cliente
                he.sendResponseHeaders(200, out.size());
                //Obtengo el OutputStream para poder enviar la imagen al cliente
                OutputStream os = he.getResponseBody();
                //Escribo la BufferedImage al cliente.
                ImageIO.write(bimg, "png", os);
                //cierro la conexión
                os.close();
            } catch (AWTException ex) {
                Logger.getLogger(Servidor.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else if(he.getHttpContext().getPath().equals("/click")) {
            try {
                //Obtenemos los parametros
                Map<String, Object> params = (Map<String, Object>) he.getAttribute("parameters");
                //tomamos la posicion X e Y obtenidas de los parametros
                int x=  Integer.parseInt(params.get("x").toString());
                int y= Integer.parseInt(params.get("y").toString());
                //Creamos un Objeto PCControl
                PCControl control = new PCControl();
                //llamamos al metodo click y le pasamos como parametro un punto con las coordenadas obtenidas por parametros
                control.click(new Point(x, y));

                System.out.println("[INFO] ["+he.getRemoteAddress()+"] Click <x:" + params.get("x") + " y:" + params.get("y")+">");
                //## Enviamos cabeceras para evitar el cache en los navegadores
                he.getResponseHeaders().add("Pragma", "no-cache");
                he.getResponseHeaders().add("Cache-Control", "no-cache");
                //## Enviamos todo al cliente
                he.getResponseBody().flush();
                //## Cerramos la conexion
                he.close();
            } catch (AWTException ex) {
                Logger.getLogger(Servidor.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}

Con eso ya tenemos listo nuestro servidor. que tendrá dos “funcionalidades” que se accederán por:

http://ipservidor:puerto/get

Obtiene una imagen del escritorio

http://ipservidor:puerto/click?x=posX&y=posY

Hace un click en un punto dado

Ahora crearemos el Cliente que accederá al servidor, Para eso usaremos JQuery y la tecnología AJAX

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
	<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
	<head>
		<!-- Agregamos el framework JQuery -->
		<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
		<script type="text/javascript">
			/*
				Declaramos una variable con la ip del servidor y el puerto que está escuchando
				Ejemplo:
					var uri = "127.0.0.1:80";
			*/
			var uri = "ipservidor:80";
			/*
				Al cargar toda la pagina ejecuto el codigo
			*/
			$(document).ready(function() {
				/*
					Agrego al elemento con la id box un elemento html "img"
				*/
				$('#box').html(
					/*
						agrego una imagen llamando al servidor (ScreenShot)
					*/
					$('<img>').attr('id','desktop').attr('src','http://'+uri+'/get').mousemove(function(e) {
						/*
							Agrego un evento javascript a la imagen, al mover el mouse sobre ella me muestra la posicion en un div con id "status"
						*/
						var mouseX = e.pageX - $(this).attr('offsetLeft');
                        var mouseY = e.pageY - $(this).attr('offsetTop');
						$('#status').html(mouseX+', '+ mouseY+ ' %, %'+$(this).width());
					}).click(function(e) {
						/*
							Agrego un evento javascript a la imagen, al clickear la imagen se conecte via AJAX al servidor
							y le pase las coordenadas del click que hice en la imagen para que el servidor ejecute un click en la maquina
						*/
						var imgObj = $(this);
						var mouseX = e.pageX - $(this).attr('offsetLeft');
                        var mouseY = e.pageY - $(this).attr('offsetTop');
						$.ajax({
							url: 'http://'+uri+'/click?x='+mouseX+'&y='+mouseY,
							success: function(data) {
								$('#desktop').attr('src','http://'+uri+'/get?r='+Math.random());
								console.log('sus');
							},
							error: function(XMLHttpRequest, textStatus, errorThrown) {
								$('#desktop').attr('src','http://'+uri+'/get?r='+Math.random());
								console.log('err');
							}
						});
					})
				);
			});
		</script>
	</head>
	<body>
		<span id="status"></span>
		<div id="box"></div>
	</body>
</html>

Con eso ya podemos acceder remotamente ha algún PC vía web.

Esto es solo una idea ustedes pueden modificarlo y arreglarlo a su gusto. Se podria implementar para escribir desde la web, refrescar cada X segundos, etc.

Codigo FuenteServTest.EstebanFuentealba.rar

Para correr el servidor en CMD o Terminal escriban

java -jar ServTest.jar 80

ServTest.jar se encuentra en la carpeta dist

Espero que les sirva, Saludos!

Categorías:Proyectos Etiquetas: , , ,