Bienvenidos a un lugar donde la programación, los vídeos, las divagaciones y las subnormalidad se combinan para demostrar que el caos puede ser bello.
Serabe Reloaded
Conecto ergo sum. Non conecto ergo urgueo.
"¡Un verdadero guerrero Klingon nunca utiliza comentarios en su código!"
Chiste de programadores Klingon.
New RMagick4J release.
RMagick aims to implement the ImageMagick funcionality and the C portions of RMagick for make it works in JRuby.
Current stable version: 0.3.5
Project URL: http://code.google.com/p/rmagick4j/
Installation: gem install rmagick4j
Google Summer of Code project should be thanked for making this new release possible.
In release 0.3.5 the following improvements have been made:
- Implemented Draw primitives (affice, arc, pattern, path).
- Improved Image and ImageList:
- Implemented more of Pixel (from_HSL, to_HSL, <=>, fcmp, intensity).
- Implemented the fill classes.
- Added a side-by-side (MRI vs JRuby) image testing tool named Bullseye.
- Added 680 color names. It can search, but not retrieve the name correctly capitalized.
- Changed gem name from RMagick4J to rmagick4j.
This version should allow Gruff Graphs and Ruports to largely work without issues. Please try out your applications with rmagick4j and help us provide feedback. It is our goal to make a fully-compatible implementation of RMagick4j in JRuby.
Ay, Serabe, que no haces nada ni tan siquiera regular.
Hoy me he tirado unas cuatro horas para encontrar un bug, uno de estos puñeteros bichos que te atrapan y te dejan cosas como estas:

Para que os hagáis una idea, tenía que ser esto:

Como se puede apreciar, son sensiblemente diferentes. Así que cuatro horas de mi vida han transformado lo primero, en lo segundo.
El problema venía en que, tal y como Tom (mi mentor del GSoC) propuso, se ha cambiado la clase PixelPacket de forma que ahora trabaja con enteros. El problema, mejor no os lo cuento que es más aburrido que lo anterior.
En fin, que hoy me voy a la cama con un ego más grande que el de Enrique Dans.
Tweets del 29-02-2008
- Tutorial de Threads de Control http://www.programacion.net/java/tutorial/threads/ #
- Ventanas translúcidas y con forma en Java http://tinyurl.com/37aoqy #
Tweets del 18-02-2008
- JUnit 4.x en Eclipse http://www.vogella.de/articles/JUnit/article.html #
Tweets del 11-02-2008
- Paintjam http://tinyurl.com/2q2dwf #
- Aficionado a LKan - Todo lo que no http://tinyurl.com/2av2e3 #
- Curso gratuito de Sun de NetBeans, JRuby, JavaFX y J2ME con certificado. http://tinyurl.com/26lehv #
- Puzzle Shift http://www.flashninjaclan.com/zzz883.php #
Powered by Twitter Tools.
Array de un tipo genérico.
En Java 5 (desconozco lo que pasa en Java 6, aún no está en Mac, por desgracia) no se pueden instanciar arrays de un tipo genérico, para ello hay que recurrir a un pequeño truco de casting. Suponiendo que la clase es, por ejemplo, Pila<T> la línea de código para declarar un array llamado stack de capacidad n es:
T[] stack = (T[]) new Object[n];
Saldrá un warning “Type safety: Unchecked cast from Object[] to T[]“, pero no hay nada de que preocuparse.
Comparativa I: Servidor en Java
Segunda entrega de esta comparativa. Le toca el turno al servidor echo. Este servidor constará de dos clases: EchoServer, la clase pública con el método main, y EchoConnection, que extiende la clase Thread y es la que realiza la mayor parte del trabajo.
EchoServer.
Aquí nos encontramos el método main(), el cual es muy, pero que muy simple:
public static final void main(String[] args){
new EchoServer();
}
El constructor de la clase es un poco más interesante, con él se explicará el funcionamiento básico de la clase ServerSocket del paquete java.net.
int port = 7777;
try{
ServerSocket server = new ServerSocket(port);
System.out.println(”Servidor a la escucha en el puerto: “+port);
El constructor de la clase ServerSocket recibe como parámetro el número del puerto en el que ha de escuchar. En el siguiente trozo de código se crea un bucle infinito y se lanzan hilos que manejen las peticiones recibidas. Para ello se utiliza el método accept() de la clase ServerSocket. Este método espera una conexión y devuelve el objeto Socket que la representa. Finalmente se capturan las excepciones.
while(true) new EchoConnection(server.accept());
}catch(Exception e){
System.out.println(”Error en el servidor.\n”+e.toString());
}
EchoConnection.
La clase EchoConnection extiende la clase Thread y contiene dos variables estáticas: connections y visits. Estas variables sirven para contabilizar el número de clientes totales y el de clientes conectados actualmente. Por otra parte, se declara una variable privada socket, en la que se almacena la conexión pasada al constructor. Dicho constructor, consta de la asignación del socket recibido al privado y de la sentencia que inicia el hilo (this.start()).
El último método a comentar es el método run(). Dicho método es rápido de explicar. En primer lugar, se aumenta el número de conectados y el de las visitas:
EchoConnection.connections++;
int numCliente = ++EchoConnection.visits;
Después se capturan los flujos de entrada y de salida:
BufferedReader entrada = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
PrintWriter salida = new PrintWriter(new OutputStreamWriter(this.socket.getOutputStream()),true);
Ahora se ha de realizar lo que se supone que debe hacer. Recibir una cadena…
String cadena = entrada.readLine();
…y reenviarla:
salida.println(cadena);
Para terminar, se cierran los flujos y el socket:
entrada.close();
salida.close();
this.socket.close();
Después se capturan las excepciones y en el finally se resta 1 al número de conectados.
El código completo se puede encontrar aquí.
Nota: el código no es todo lo limpio que debería ser. Todos los cierres deberían ir en el finally, por ejemplo.
Comparativa I: Cliente en Java.
En primer lugar, decir que no es un cliente “echo”, simplemente es un programita que nos pruebe que el servidor, lo que realmente interesa.
El cliente en sí, es sencillo a más no poder: crea una cantidad de hilos cada uno de los cuales pilla un mensaje aleatorio, lo envía y comprueba que lo recibido es igual al enviado. Esto será así para el resto de lenguajes, por lo que no lo volveré a escribir (que me canso).
Empecemos a ver código. Una vista previa del código fuente (se puede descargar aquí) nos desvelará que consta de tres clases (sólo una de ellas es pública, por lo que sólo necesitaremos un archivo): EchoClient, EchoClientThread y Mensaje. Comentaremos primero las dos primeras, por ser las más cortas y después la segunda, por ser la que realiza todo el trabajo.
EchoClient.
La clase EchoClient es pública y consta de una variable estática (el límite de hilos), limite, y el método main. Dicho método sólo consta de una línea de código, la cual lanza tantos hilos como lo indique la variable estática:
for(int i=0; i < EchoClient.limite; i++) new EchoClientThread();
Mensaje.
La clase Mensaje sólo contiene un método estático:
public static String aleatorio(){
String[] mensajes = {”Hola, Mundo.”,”Melón.”,”Larga y próspera vida.”,”La Quinta Raza.”,”So long, and thanks for all the fish.”,”Spain is different.”, “Com va això?”,”Bona tarda.”};
return mensajes[ (int) Math.round(Math.floor(Math.random() * mensajes.length)) ];
}
En la primera línea se crea un array de String con diferentes mensajes. En el segundo se genera un número aleatorio y se coge ese elemento del array.
EchoClientThread.
Esta clase extiende de Thread. Su constructor simplemente llama al constructor padre e inicia el hilo. El método run() simplemente tiene un bucle infinito que llama una y otra vez el método conectar(). Este método es el interesante, aparte de largo, por lo que vayamos por partes:
int port = 7777;
String server = “localhost”;
Declaramos dos variables, la primera es el puerto y la segunda el servidor al que nos conectaremos. Ahora entramos en un bloque try:
Socket s = new Socket(server,port);
BufferedReader entrada = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter salida = new PrintWriter(new OutputStreamWriter(s.getOutputStream()),true);
Aquí creamos el socket al servidor y puerto indicados anteriormente. Después se capturan los flujos de entrada y de salida.
String mensaje = Mensaje.aleatorio();
salida.println(mensaje);
Creamos un mensaje aleatorio y se envía al servidor.
String cadena = entrada.readLine();
System.out.println(cadena.equals(mensaje));
Se recoge la respuesta del servidor y se imprime true si es lo enviado o false si es distinto. Por último se cierra la conexión:
s.close();
Y se capturan los errores. Técnicamente el último close() tendría que ir en un finally, etc. pero como ejemplo va bien. Ahora ya sólo se necesita compilarlo. Próximamente, el servidor.
Redirección de salida en Java
En los exámenes de mis últimos alumnos, a los que aún debo matar por suspender, tenían que hacer un servidor. Dicho servidor debía tener una GUI básica para mostrar diversos mensajes. A pesar de que en este ejemplo no era necesario, me pregunté cómo hacer para poder poner dichos mensajes en el mismo TextComponent desde varias clases sin tener que ponerlo como variable de instancia en todas ellas.
La solución es sencilla, sólo se necesita crear una nueva clase que extienda de OutputStream y sobreescribir algunos métodos, básicamente, los de escritura. Lo primero, y suponiendo como nombre de clase TextComponentStream, es crear el constructor.
import java.io.*;
import java.awt.*;
public class TextComponentStream extends OutputStream{
private TextComponent tc;
public TextComponentStream(TextComponent tc){
super();
this.tc = tc;
}
Ahora sólo toca sobreescribir los métodos de escritura. OutputStream tiene tres métodos de escritura: write(byte[] b), write(byte[] b, int off, int len), write(int b). Este último hay que sobreescribirlo, aunque empezaremos por el primero. Para ello miramos en el API la clase String, y veremos que tiene un constructor al que se le pasa los argumentos del primer write y otro al que se le pasan los parámetros del segundo. Así tenemos:
public void write(byte[] b){
this.tc.setText(this.tc.getText()+(new String(b)));
}
public void write(byte[] b, int off, int len){
this.tc.setText(this.tc.getText()+(new String(b,off,len)));
}
Por último, write(int b) se implementaría así:
public void write(int b){
byte[] b1 = {(new Integer(b)).byteValue()};
this.write(b1);
}
}//Cerramos la clase.
Así ya está creada la clase. Ahora, para utilizarla desde cualquier lugar sólo hace falta redireccionar la salida estándar. Para ello se utilizará el método System.setOut(PrintStream p); de la siguiente manera:
System.setOut(new PrintStream(new TextComponent(tc)));
Siendo tc el TextComponent donde queremos mostrar los mensajes. Así, sólo se necesita poner System.out.println("Mensaje"); para que el mensaje se muestre en el TextComponent.
El operador ternario.
El operador ternario es un operador un tanto especial. Se encuentra en bastante lenguajes y, para mi sorpresa, poca gente que conozco sabe de qué se trata. Dicho operador es muy sencillo:
(condicion_booleana) ? si_true : si_false;
Como podéis comprobar es un sustituto del if para ciertos casos. Al igual que odio el switch, me encanta el operador ternario. Por ejemplo, las siguientes porciones de código en C# y Java:
if(condicion_booleana) System.Console.WriteLine("Login válido.") ;
else System.Console.WriteLine(”Login inválido.”);
if(condicion_booleana) System.out.println("Login válido.");
else System.out.println(”Login inválido.”);
por:
System.Console.WriteLine("Login "+((condicion_booleana)?"":"in")+"válido.");
System.out.println("Login "+((condicion_booleana)?"":"in")+"válido.");
respectivamente. A mis alumnos actuales (Jorge, Juan y Pablo) les dejó asombrados, aunque la verdad es que es algo que suelo utilizar siempre que puedo.
Otro ejemplo sería la creación de la cadena “Se ha realizado.”/”No se ha realizado”:
((condicion_booleana)?"S":"No s")+"e ha realizado."
Mañana más y mejor.
"No te preocupes por tus dificultades con las matemáticas, puedo asegurarte que las mías son mayores."
Albert Einstein