Pedro Martínez en el Summer of Code de Google
Junio 29th, 2005 - [Enlace local]
Pues sí, me acabo de enterar que Pedro Martínez Juliá, alumno de la facultad de Informática de la Universidad de Murcia, va a trabajar en el Summer of Code. En concreto, va a trabajar dentro del proyecto Mono, una implementación libre y multiplataforma de la plataforma .NET de Microsoft. La lista final la podéis encontrar aquí. En concreto a él le toca realizar controles Windows.Forms 2. ¡Enhorabuena, Pedro! A ver qué tal te va.

» Leer más, comentarios, etc...
libcult
Junio 29th, 2005 - [Enlace local]
Mi amigo Boris Kolpackov, uno de las personas más inteligentes que conozco, y por supuesto, uno de los que más C++ sabe, acaba de sacar a la luz su librería libcult, cuyo nombre podría indicar algún tipo de culto a C++, que por otro lado es verdad. En ella se pueden encontrar peripecias con el lenguaje C++ que es difícil encontrar en otro sitio. No he tenido tiempo de estudiar exactamente todo lo que ofrece: parsers, generadores de XDR, una librería de opciones de la línea de comandos muy bien diseñada, utilidades para obtener el tipo de una variable en tiempo de ejecución, etc. Lo verdaderamente interesante de ese código es que es realmente inteligente, aparte de útil. Como ejemplo, sacado de la documentación. Este ejemplo muestra muy bien la sencillez y potencia del diseño de la librería, en este caso, para manejar la línea de comandos:
namespace
{
extern Char const help[] = "help";
extern Char const version[] = "version";
extern Char const outdir[] = "outdir";
}
typedef
CLI::Options<help, Boolean,
version, Boolean,
outdir, String>
Options;
Int
main (Int argc, Char* argv[])
{
try
{
Options options (CLI::parse<Options> (argc, argv));
if (options.value<help> ())
{
cerr << "usage: " << argv[0] << " [–help] [–version] [–outdir <dir>]"
<< endl;
return 0;
}
if (options.value<version> ())
{
cerr << argv[0] << " 1.2.3" << endl;
return 0;
}
if (String dir = options.value<outdir> ())
{
cerr << "outdir: " << dir << endl;
}
}
catch (CLI::UnexpectedOption const& e)
{
cerr << "unexpected option " << e.option () <<endl;
}
catch (CLI::OptionFormat const& e)
{
cerr << "bad format for " << e.option () << endl;
}
}
» Leer más, comentarios, etc...
zxFortunes actualizado
Junio 23rd, 2005 - [Enlace local]
Como esta tarde no tenía muchas ganas de currar en serio, tocando acá y tocando allá, al final he cogido el zxFortunes y he hablilitado dos nuevas opciones:
No permitir citas repetidas. Ahora, una vez que se ha mostrado una cita, ésta ya no vuelve a aparecer hasta que se hayan mostrado todas o se cambie algo de la configuración. Ha sido muy fácil de añadir. Cuando se genera el fichero índice, si la opción de no repetidas está habilitada, se crea un nuevo fichero binario con una posición de tipo bool para cada cita. Cuando se saca una, se escribe true en la posición; si se saca una que ya lo había sido antes, pues se va recorriendo el archivo hasta encontrar un false o volver a llegar a la original. En este caso, se reinicia el fichero y se devuelve la original. Esto se realiza en dos métodos nuevos, “OnlyOneFortuneGetNextUnread” y “OnlyOneFortuneInit”, que se encuentran en FormFortunes.cs.
Firmas de correo con el formato de Opera. Ahora estoy usando el Opera para todo, y no soporta el tener un fichero de texto con la cita. Cada cuenta tiene su propio fichero con el pie, pero todo el asunto lo controla directamente el programa, y no te deja como opción dirigirlo a un fichero de texto. Pero como es ya clásico en este programa, un usuario avanzado puede hacer lo que quiera, así que abrimos el archivo opera6.ini que está en “System.Environment.SpecialFolder.ApplicationData” más “Opera\Opera\profile”. Allí buscamos la cadena “Mail Root Directory”, que indica la carpeta donde se encuentra almacenado el correo. Nos vamos a la misma y abrimos “accounts.ini”. Para cada cuenta hay una entrada llamada “Signature File” que contiene el nombre del fichero que se corresponde con la firma. Lo único que resta es guardar en todos y cada uno de esos ficheros nuestra cita en formato unicode. Esto se realiza en el método “ProcessOperaEmailSign()”.
Ahora la versión del programa es la 1.1 y se puede bajar de aquí.
» Leer más, comentarios, etc...
Sistemas de Tiempo Real y Lenguajes de Programación, Alan Burns y Andy Wellings
Junio 22nd, 2005 - [Enlace local]
84-7829-058-3
Real-Time Systems and Programming Languages, 3rd Edition, 1989, 2001
Como ya dije en un comentario anterior, nada nuevo bajo el sol. Comienza con una explicación de los términos más comunes aplicados a la programación en tiempo real, para luego ir detallando aspectos de la misma.
Cada capítulo empieza con un resumen de la terminología empleada, para luego entrar en detalles sobre el tema a tratar; desde mi punto de vista, la profundidad es escasísima salvo alguna excepción. Si lo que el autor cita es todo lo que se sabe en la actualidad sobre el punto tratado, poco estudiado está el tema. Quiero creer que es el autor el que no entra en detalles.
Luego se centra en la forma en que cada lenguaje de programación soporta el tema. Los lenguajes principalmente tratados son ADA, C con soporte POSIX y Java en tiempo real, aunque a veces entra a detallar elementos de otros lenguajes como Occam, Modula y otros todavía más extraños, cuando éstos destacan en algún punto. No conozco ADA, muy poco de Java, pero sí que conozco el C: muy poca profundidad en general. Si el lenguaje soporta la característica, la cita; si no, da unas breves indicaciones sobre cómo se podría implementar y termina.
Luego viene un resumen (quizás lo más valorable del libro), una bibliografía y ejercicios que no me he molestado en mirar salvo excepciones.
Lo cierto es que el libro es muy flojo en general, recorriendo rápidamente todos los temas y a veces yéndose por las ramas, como cuando se pone a desvariar sobre el tiempo, hablando en térmimos filosóficos. No lo recomiendo ni siquiera para un principiante, y menos aún para un profesional que se gane las habichuelas programando sistemas en tiempo real.
Lo más destacable es la explicacion sobre concurrencia, contención y bloqueos de procesos, con el tema de programación de bajo nivel; quizás se hubiera salvado el libro si hubiese tratado estos temas con más amplitud y profundidad.
Un extracto del índice: Fiabilidad y tolerancia a fallos, Excepciones y manejo de excepciones, Programación concurrente, Comunicación y sincronización basada en variables compartidas, Sincronización y comunicación basada en mensajes, Acciones atómicas, procesos concurrentes y fiabilidad, Control de recursos, Capacidades de tiempo real, Planificación, Sistemas distribuidos, Programación de bajo nivel, El entorno de ejecución, Un caso de estudio en Ada.
» Leer más, comentarios, etc...
Rendimiento C++/C#/Java en Windows y Linux
Junio 22nd, 2005 - [Enlace local]
He leído en el CUJ de Julio (C/C++ Users Journal) un artículo intitulado Micro Benchmarking C++, C#, and Java (sólo pasando por caja), lo que traducido al castellano podría ser algo así como “Pruebas de micro rendimiento para C++/C# y Java”.
El artículo es bastante corto y escueto; el autor indica qué elementos de juicio ha decidido, el hardware y las versiones de las herramientas. Los ensayos consisten en pruebas repetidas con pequeños bloques de código, como operaciones con enteros, en coma flotante, matrices, ordenación, instanciación, excepciones, tablas de dispersión y cosas así.
Este señor ha ejecutado los programas en Linux (Sun java 1.4.2 y 1.5, gcc, intel c, mono) y en Windows XP+SP2 (SUN java 1.4.2, java 5, net 2, net 1.1sp1, ms c++ 7.1). Las versiones java han sido verificadas tanto en el lado cliente como en el servidor.
Personalmente considero que, dado lo delicado del tema, el artículo es todo lo serio que puede ser.
RESULTADOS
En contra de mi opnión personal, y creo que en la de muchos, lo más destacable es la velocidad de Java, comparable a la de C++, tanto en ambas plataformas (excepto en rendimiento con operaciones de enteros del lado cliente, cosa que no entiendo) como en forma cruzada. Tan sólo tarda unos pocos milisegundos más en hacer las cosas. El .NET en general se queda después de Java (salvo excepciones con un rendimiento igual al ms c++ 7.1).
El ganador indiscutible es el GCC bajo Linux, que supera en rendimiento al C++ de Microsoft en casi todo (qué lástima que el autor no haya probado el gcc-win32), y el perdedor indiscutbile es Mono 1.0.6, con el peor rendimiento en casi todo (incluso dos y tres veces más lento que el más lento), seguido del lado cliente de Java, aunque sólo a veces.
TERRA INCOGNITA
Sabemos que Java es lento. No hay mas que instalar Eclipse para darse cuenta de ello. O cualquier otra aplicación grande. En mi experiencia personal es más lento que el .NET, por lo menos la sensación del usuario es esa. Sin embargo, en estos tests de rendimiento, gana. Y no es un problema de consumo de memoria, porque si tienes memoria suficiente (1,5 GB en mi caso), también lo es (me refiero con esto a que no tira de archivo de paginación, por lo que todo el asunto queda entre la RAM, la MMU y el procesador).
¿Dónde está, pues la lentitud en Java?
» Leer más, comentarios, etc...
Liderazgo técnico MOI - Motivación, Organización e Innovación
Junio 21st, 2005 - [Enlace local]
Liderazgo técnico es el proceso de crear un entorno en el cual la gente se siente y está autorizada. Vamos a ver como conseguimos esto a través de la motivación, la organización y la innovación.
» Leer más, comentarios, etc...
Las verdades en programación
Junio 21st, 2005 - [Enlace local]
Vía lightme llego hasta la web de Lars Wirzenius que nos explica las verdades sobre la programación y los programadores. Para pasar un buen rato:
This page contains a number of important programming truths that every budding programmer should know about. These truths are self-evident, and need no explanations.
If it compiles, it works.
If it compiles, it’s correct.
If it runs, it doesn’t have any bugs.
If it doesn’t have any immediately obvious bugs, it’s perfect.
If a bug doesn’t show, it doesn’t exist.
If it seems to work, it works.
Doing something right is easy. Avoiding errors only takes a bit of concentration.
The shorter the source code, the faster the program.
It’s obvious how to optimize a program.
Prorammers don’t make mistakes.
Run-time errors don’t occur.
Users don’t make mistakes.
I don’t make mistakes.
Errors of any kind are rare.
Error handling can be done in version 2.
It’s OK to crash on bad input.
It’s OK to give incorrect output on bad input.
Portability isn’t useful.
All the world’s a VAX. Or, these days, an MS-DOS box
The length of the feature list is important.
Speed is good, features are better.
Slowness can be fixed in hardware.
The bigger a program is, the better it is.
Random changes to a program fix bugs.
Testing takes only a short while.
Finding bugs is easy. Fixing bugs is trivial.
Bug-fixes don’t need to be tested.
Trivial changes of any kind don’t need to be tested.
The first approach, idea, or version is always the best.
A 1% crash rate is actually pretty darn good.
Code is self-evident. Comments aren’t needed.
Comments are meant for people other than the original author of the code.
Undocumented features are fun and useful.
It can always be fixed in the next version.
Surprised users are happy users.
Demonstrating for clients is the best debugging method.
» Leer más, comentarios, etc...
Ceklog » Programación
Las verdades en programación
Junio 21st, 2005 - [Enlace local]
Vía lightme llego hasta la web de Lars Wirzenius que nos explica las verdades sobre la programación y los programadores. Para pasar un buen rato:
This page contains a number of important programming truths that every budding programmer should know about. These truths are self-evident, and need no explanations.
If it compiles, it works.
If it compiles, it’s correct.
If it runs, it doesn’t have any bugs.
If it doesn’t have any immediately obvious bugs, it’s perfect.
If a bug doesn’t show, it doesn’t exist.
If it seems to work, it works.
Doing something right is easy. Avoiding errors only takes a bit of concentration.
The shorter the source code, the faster the program.
It’s obvious how to optimize a program.
Prorammers don’t make mistakes.
Run-time errors don’t occur.
Users don’t make mistakes.
I don’t make mistakes.
Errors of any kind are rare.
Error handling can be done in version 2.
It’s OK to crash on bad input.
It’s OK to give incorrect output on bad input.
Portability isn’t useful.
All the world’s a VAX. Or, these days, an MS-DOS box
The length of the feature list is important.
Speed is good, features are better.
Slowness can be fixed in hardware.
The bigger a program is, the better it is.
Random changes to a program fix bugs.
Testing takes only a short while.
Finding bugs is easy. Fixing bugs is trivial.
Bug-fixes don’t need to be tested.
Trivial changes of any kind don’t need to be tested.
The first approach, idea, or version is always the best.
A 1% crash rate is actually pretty darn good.
Code is self-evident. Comments aren’t needed.
Comments are meant for people other than the original author of the code.
Undocumented features are fun and useful.
It can always be fixed in the next version.
Surprised users are happy users.
Demonstrating for clients is the best debugging method.
» Leer más, comentarios, etc...
código escrito
Se busca lenguaje
Junio 20th, 2005 - [Enlace local]
LibreSintaxis claraEstricto en tipos de datosOrientado a objetosMultiplataformaCon IDEPara aplicaciones de escritorioQue nadie piense que no me gusta lo que uso, nada que ver. Simplemente me apetece aprender algo nuevo y me gustaría que cumpliera las características que comento....
» Leer más, comentarios, etc...
Home-made AOP
Junio 16th, 2005 - [Enlace local]
Hola, con estes post quiero proponeros una forma de hacer AOP sin necesidad de recurrir a ningún framework.
El ejemplo más claro de las ventajas de la AOP es la generación de “logs”
o trazas de nuestros programas. Lo que voy a ilustrar en el ejemplo
es cómo realizar logs de todos los accesos a los métodos de determinados
objetos. Estos objetos van a ser DAOs (Data Access Object).
Bien, vamos a suponer que tenemos un objeto Peronsa, una interfaz PersonaDao
y una implementación de esa interfaz: PersonaJdbcDao. El patrón DAO busca
encapsular la persistencia de nuestros objetos, es decir, el código necesario
para ‘hablar’ con la base de datos se encapsula en DAOs. Como hay muchos
mecanismos de persistencia hacemos una interfaz (PersonaDao) y una o varias
implementaciones (ej: PersonaJdbcDao usando el API JDBC). La responsabilidad
de instanciar una implementación concreta la delegamos a una factoría, así
que también haremos una clase llamada DaoFactory.
Esta es la clase Persona: (por simplicidad he puesto los campos públicos)
public class Persona {
public long dni;
public String nombre;
public String apellidos;
public String toString() {
return \"Persona{ dni: \"+dni+\"; nombre: \"+nombre+\"; apellidos: \"+apellidos+\" }\";
}
}
Esta es la interfaz PersonaDoa: (por simplicidad sólo habrá dos métodos)
public interface PersonaDao {
public void create(Persona persona);
public Persona read(long dni);
}
Esta es la implementación PersonaJdbcDao: (que realmente es un fake
).
public class PersonaJdbcDao implements PersonaDao {
/* simulación de una implementación de PersonaDao supuestamente usando Jdbc */
public void create(Persona persona) {
System.out.println(\"\tinsert into...\");
}
public Persona read(long dni) {
System.out.println(\"\tselect from...\");
Persona persona = new Persona();
persona.nombre = \"juan\";
persona.apellidos = \"herrero\";
persona.dni = dni;
return persona;
}
}
Esta es la factoría (que por el momento queda así):
public class DaoFactory {
public static PersonaDao createPersonaDao() {
return new PersonaJdbcDao();
}
}
Este es el código para probar lo que hemos programado:
public class Test {
public static void main(String[] args) {
PersonaDao personaDao = DaoFactory.createPersonaDao();
Persona persona = new Persona();
persona.dni = 1234;
persona.nombre = \"pepe\";
persona.apellidos = \"garcía\";
personaDao.create(persona);
Persona persona2 = personaDao.read(4321);
}
}
Lo ejecutamos y…
insert into... select from...
Lo que esperábamos. Ahora sin modificar el códgio de PersonaJdbcDao vamos a
hacer que antes y después de la ejecución del método se muestre información
sobre su invocación. Esto lo vamos a conseguir usando la clase java.lang.reflect.Proxy. Vamos a envolver en tiempo de ejecución un objeto
y podremos interceptar las llamadas a sus métodos.
Voy a implementar una clase: la calse LogWrapper que contendrá un método
decorate() al que se le pasará el objeto que se desea ‘envolver’ y
devolverá el objeto ‘envuelto’. Simplemente hay que crear un Proxy
usando el método Proxy.newProxyInstance(). Le pasaremos un ClassLoader,
un array de objetos Class[] para indicar qué métodos de qué clases queremos
interceptar (en nuestro caso las interfaces del objeto; que será sólo una: PersonaDao), y finalmente un objeto que implemente InvocationHandler.
Este último objeto tendrá un método invoke() que será llamado cada
vez que un método será interceptado; nos dará información sobre el
método que se ha invocado y los argumentos que ha recibido.
Veamos el código…
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class LogWrapper {
public static Object decorate(Object delegate) {
return Proxy.newProxyInstance(delegate.getClass().getClassLoader(),
delegate.getClass().getInterfaces(),
new WrapperHandler(delegate));
}
}
class WrapperHandler implements InvocationHandler {
private Object delegate;
WrapperHandler(Object delegate) {
this.delegate = delegate;
}
public Object invoke(Object proxy, Method method, Object args[]) throws Throwable {
/* hacer algo antes de la ejecución del método */
// muestro el nombre del método, la clase del que procede, y sus argumentos
String name = method.getDeclaringClass().getName()+\".\"+method.getName();
System.out.print(\"ejecutando \"+name+\"(\");
for (int i = 0; i < args.length; i++) {
if(i != 0)
System.out.print(\", \");
System.out.print(args[i]);
}
System.out.println(\")\");
/* ejecutar el método*/
Object result = null;
try {
result = method.invoke(delegate, args);
} catch(Throwable e) {
/* en caso de error */
// se produce una InvocationTargetException
// la causa real se obtiene con getCause()
Throwable cause = e.getCause();
System.out.println(\"se produjo una excepción: \"+cause);
throw cause;
}
/* hacer algo al final de la ejecución */
// muestro el valor devuelto por el método
if(method.getReturnType().equals(Void.TYPE))
System.out.println(\"saliendo de \"+name+\"(); el método devuelve void\");
else
System.out.println(\"saliendo de \"+name+\"(); el método devuelve \"+result);
/* devolver el resultado del método si todo ha ido bien */
return result;
}
}
Ahora modifico la factoría para envolver los DAOs…
public class DaoFactory {
public static PersonaDao createPersonaDao() {
return (PersonaDao) decorate(new PersonaJdbcDao());
}
private static Object decorate(Object object) {
return LogWrapper.decorate(object);
}
}
Vuelvo a ejecutar el código y…
ejecutando aop.PersonaDao.create(Persona{ dni: 1234; nombre: pepe; apellidos: garcía })
insert into...
saliendo de aop.PersonaDao.create(); el método devuelve void
ejecutando aop.PersonaDao.read(4321)
select from...
saliendo de aop.PersonaDao.read(); el método devuelve Persona{ dni: 4321; nombre: juan; apellidos: herrero }
He conseguido pues que el código que se encarga de hacer la traza del código esté centralizado: no esté disperso por el código y no sea intrusivo. Además lo puedo activar y desactivar modificando una sola línea de código. En el ejemplo los Daos no se han implementado de la mejor forma y la forma de generar la traza con los System.out.println() no es la más adecuada teniendo frameworks como Log4J
pero como ejemplo vale, no?
Qué os ha parecido? Se ha entendido? Sugerencias?
» Leer más, comentarios, etc...
Gimenoblog
Home-made AOP
Junio 16th, 2005 - [Enlace local]
Hola, con estes post quiero proponeros una forma de hacer AOP sin necesidad de recurrir a ningún framework.
El ejemplo más claro de las ventajas de la AOP es la generación de "logs" o trazas de nuestros programas. Lo que voy a ilustrar en el ejemplo es cómo realizar logs de todos los accesos a los métodos de determinados objetos. Estos objetos van a ser DAOs (Data Access Object).
Bien, vamos a suponer que tenemos un objeto Peronsa, una interfaz PersonaDao y una implementación de esa interfaz: PersonaJdbcDao. El patrón DAO busca encapsular la persistencia de nuestros objetos, es decir, el código necesario para 'hablar' con la base de datos se encapsula en DAOs. Como hay muchos mecanismos de persistencia hacemos una interfaz (PersonaDao) y una o varias implementaciones (ej: PersonaJdbcDao usando el API JDBC). La responsabilidad de instanciar una implementación concreta la delegamos a una factoría, así que también haremos una clase llamada DaoFactory.
Esta es la clase Persona: (por simplicidad he puesto los campos públicos)
public class Persona {
public long dni;
public String nombre;
public String apellidos;
public String toString() {
return "Persona{ dni: "+dni+"; nombre: "+nombre+"; apellidos: "+apellidos+" }";
}
}
Esta es la interfaz PersonaDoa: (por simplicidad sólo habrá dos métodos)
public interface PersonaDao {
public void create(Persona persona);
public Persona read(long dni);
}
Esta es la implementación PersonaJdbcDao: (que realmente es un fake :P ).
public class PersonaJdbcDao implements PersonaDao {
/* simulación de una implementación de PersonaDao supuestamente usando Jdbc */
public void create(Persona persona) {
System.out.println("\tinsert into...");
}
public Persona read(long dni) {
System.out.println("\tselect from...");
Persona persona = new Persona();
persona.nombre = "juan";
persona.apellidos = "herrero";
persona.dni = dni;
return persona;
}
}
Esta es la factoría (que por el momento queda así):
public class DaoFactory {
public static PersonaDao createPersonaDao() {
return new PersonaJdbcDao();
}
}
Este es el código para probar lo que hemos programado:
public class Test {
public static void main(String[] args) {
PersonaDao personaDao = DaoFactory.createPersonaDao();
Persona persona = new Persona();
persona.dni = 1234;
persona.nombre = "pepe";
persona.apellidos = "garcía";
personaDao.create(persona);
Persona persona2 = personaDao.read(4321);
}
}
Lo ejecutamos y...
insert into... select from...
Lo que esperábamos. Ahora sin modificar el códgio de PersonaJdbcDao vamos a hacer que antes y después de la ejecución del método se muestre información sobre su invocación. Esto lo vamos a conseguir usando la clase java.lang.reflect.Proxy. Vamos a envolver en tiempo de ejecución un objeto y podremos interceptar las llamadas a sus métodos.
Voy a implementar una clase: la calse LogWrapper que contendrá un método decorate() al que se le pasará el objeto que se desea 'envolver' y devolverá el objeto 'envuelto'. Simplemente hay que crear un Proxy usando el método Proxy.newProxyInstance(). Le pasaremos un ClassLoader, un array de objetos Class[] para indicar qué métodos de qué clases queremos interceptar (en nuestro caso las interfaces del objeto; que será sólo una: PersonaDao), y finalmente un objeto que implemente InvocationHandler. Este último objeto tendrá un método invoke() que será llamado cada vez que un método será interceptado; nos dará información sobre el método que se ha invocado y los argumentos que ha recibido. Veamos el código...
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class LogWrapper {
public static Object decorate(Object delegate) {
return Proxy.newProxyInstance(delegate.getClass().getClassLoader(),
delegate.getClass().getInterfaces(),
new WrapperHandler(delegate));
}
}
class WrapperHandler implements InvocationHandler {
private Object delegate;
WrapperHandler(Object delegate) {
this.delegate = delegate;
}
public Object invoke(Object proxy, Method method, Object args[]) throws Throwable {
/* hacer algo antes de la ejecución del método */
// muestro el nombre del método, la clase del que procede, y sus argumentos
String name = method.getDeclaringClass().getName()+"."+method.getName();
System.out.print("ejecutando "+name+"(");
for (int i = 0; i < args.length; i++) {
if(i != 0)
System.out.print(", ");
System.out.print(args[i]);
}
System.out.println(")");
/* ejecutar el método*/
Object result = null;
try {
result = method.invoke(delegate, args);
} catch(Throwable e) {
/* en caso de error */
// se produce una InvocationTargetException
// la causa real se obtiene con getCause()
Throwable cause = e.getCause();
System.out.println("se produjo una excepción: "+cause);
throw cause;
}
/* hacer algo al final de la ejecución */
// muestro el valor devuelto por el método
if(method.getReturnType().equals(Void.TYPE))
System.out.println("saliendo de "+name+"(); el método devuelve void");
else
System.out.println("saliendo de "+name+"(); el método devuelve "+result);
/* devolver el resultado del método si todo ha ido bien */
return result;
}
}
Ahora modifico la factoría para envolver los DAOs...
public class DaoFactory {
public static PersonaDao createPersonaDao() {
return (PersonaDao) decorate(new PersonaJdbcDao());
}
private static Object decorate(Object object) {
return LogWrapper.decorate(object);
}
}
Vuelvo a ejecutar el código y...
ejecutando aop.PersonaDao.create(Persona{ dni: 1234; nombre: pepe; apellidos: garcía })
insert into...
saliendo de aop.PersonaDao.create(); el método devuelve void
ejecutando aop.PersonaDao.read(4321)
select from...
saliendo de aop.PersonaDao.read(); el método devuelve Persona{ dni: 4321; nombre: juan; apellidos: herrero }
He conseguido pues que el código que se encarga de hacer la traza del código esté centralizado: no esté disperso por el código y no sea intrusivo. Además lo puedo activar y desactivar modificando una sola línea de código. En el ejemplo los Daos no se han implementado de la mejor forma y la forma de generar la traza con los System.out.println() no es la más adecuada teniendo frameworks como Log4J :P pero como ejemplo vale, no?
Qué os ha parecido? Se ha entendido? Sugerencias?
» Leer más, comentarios, etc...
WP-Morph 1.2
Junio 14th, 2005 - [Enlace local]
WP-Morph is now on version 1.2. You can download it here. And read the README. Even you can browse its source code This version has some improvements:
- More kind error message.
- $rnd_val is calculated automatically and stored in wp’s internal
database. No user interaction or configuration is needed now.
(Thanks to Denis de Bernardy <denis .at.semiologic.com> for suggesting
this.) - Little change in the javascript code in order to prevent possible
overflows.
Please, report any problems you encounter in it, as it is running this weblog.
» Leer más, comentarios, etc...
El futuro de Borland C++ Builder
Junio 13th, 2005 - [Enlace local]
No suelo entrar mucho en la web de Borland últimamente, pero resulta que han cambiado por completo la apariencia de la misma. Pero lo interesante no es eso, sino que me ha dado por navegar por ella y he encontrado una página que indica el soporte de los productos de C++ y he visto algo como Borland C++ 2005, que ya de por sí es algo un tanto intrigante.
Pero como antítesis a lo que diría cierto personaje de dibujos animados, eso no es todo, amigos, puesto que en la BDN acaban de publicar un corto vídeo mostrando funcionalidades del nuevo C++ Builder.
Entre lo que dicen, y lo que se deja ver, es otra vuelta de tuerca para la programación visual, pues al todavía no superado paradigma two-ways (el que haya manejado el entorno sabrá a lo que me refiero), añaden todas las funcionalidades del Visual Studio 2005 y, además, al fondo, se ve una pestaña con el texto refactoring, pestaña sobre la que no dicen nada.
¿Soportará el C++ Builder de Borland refactorización en C++, una cosa que al parecer Microsoft no ha conseguido? ?Seré tan pavo que volveré a pasar por caja despúes de haber parado con la versión 4.0?
El único inconveniente que veo es que sólo se trata de programación win32, no se nombra nada acerca de C++ sobre .NET
» Leer más, comentarios, etc...
El arte de programar
Wake On LAN y Magic Packet
Junio 13th, 2005 - [Enlace local]
Todos sabemos que podemos apagar el ordenador con un comando o bién con una combinación de pulsaciones de teclado o ratón, también hay programas que dado cierto evento hacen que se apague el sistema.
Esto no tiene ningún misterio, pero... ¿y si se trata de encenderlo?. Puede que con el solo hecho de pulsar el botón de encendido de la cpu nos sea suficiente (a veces con pulsar un botón del teclado o mover el ratón), sin embargo cuando no estamos físicamente presentes la cosa cambia: un cibercafe donde es más cómodo encender todos los ordenadores a la vez, o encender un ordenador remoto que por las noches se apaga para ahorrar electricidad, etc. Antiguamente los ordenadores se apagaban y punto, pero desde que irrumpió en el mercado el formato ATX de cajas y placas madre y con el estandar ACPI la cosa no ha hecho más que facilitarnos las cosas: ahora gracias a esos dos estandares somos capaces de apagar el ordenador por software, apagar el equipo ordenadamente por hardware, suspender, volver a reactivar, volver a encender, etc. En la parte que nos toca hay unos eventos que son capaces de encender un ordenador cuando este está apagado, y para la gestión remota de ese encendido se puede usar unos metodos denominados wake on ring, wake on modem (por modem) o wake on lan (por red).
Este artículo se centra en el método Wake On Lan (+ o - despertar por red). Este sistema se basa en que un ordenador cuando se apaga, no lo hace totalmente, sino que la fuente de alimentación sigue alimentando a la placa madre, y esta puede gestionar con muy bajo consumo los eventos que se den, como por ejemplo, encender el ordenador cuando recibe un paquete especial por la tarjeta de red. Este paquete, conocido como Magic Packet es muy simple y su formato consiste en 6 bytes con valor hexadecimal FF y otros 16 grupos de 6 bytes con la dirección MAC de la tarjeta de red. Da igual en que protocolo se envié ese paquete (IPX, TCP/IP, etc), con tal de que se envíe por toda la red. Así si se quiere encender un ordenador con una MAC 01:02:03.04:05:06 se enviaría un paquete con estos bytes en hexadecimal:
FFFFFFFFFFFF
010203040506010203040506010203040506010203040506
010203040506010203040506010203040506010203040506
010203040506010203040506010203040506010203040506
010203040506010203040506010203040506010203040506
El paquete debe enviarse a toda la red, por lo que hay que intentar que sea con el protocolo que se haga, este debe permitir enviar paquetes broadcast. Esto normalmente se puede conseguir con el protocolo IP, ya que poniendo como destinatario la dirección IP 255.255.255.255 debería llegar a todos los nodos de todas las redes que lo permitan. El TCP o UDP que venga por encima no es importante, aunque personalmente prefiero el UDP por no ser orientado a conexión. Por encima del UDP vendrá el magic packet. A continuación pongo un ejemplo de codigo fuente en varios lenguajes de programación para que podais probarlo (son tan cortos que no hacen falta comentarlos, tampoco tienen gestión de errores para su simplicidad), en vuestro caso solo tendrías que modificar el puerto (1976) y la dirección MAC (01:02:03:04:05:06):
C para Linux/Unix y Windows
#ifdef WIN32
#include <stdio.h>
#include <winsock2.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#endif
void main(void)
{
int conexion;
struct sockaddr_in direccion;
unsigned char buffer[102];
unsigned char mac[]={0x01,0x02,0x03,0x04,0x5,0x06};
int valor=1,contador;
#ifdef WIN32
WSADATA wsaData;
WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
#endif
for(contador=0;contador<6;contador++)
buffer[contador]=0xff;
for(contador=6;contador<102;contador+=6)
memmove(&buffer[contador],mac,6);
memset(direccion.sin_zero,0,8);
direccion.sin_family=AF_INET;
direccion.sin_addr.s_addr=htonl(INADDR_BROADCAST);
direccion.sin_port=htons(1976);
conexion=socket(AF_INET,SOCK_DGRAM,0);
valor=setsockopt(conexion, SOL_SOCKET, SO_BROADCAST, (char *)&valor, sizeof(int));
sendto(conexion,(char *)buffer,102,0,(struct sockaddr *)&direccion,sizeof(struct sockaddr_in));
#ifdef WIN32
WSACleanup();
#endif
}
Perl
use strict;
use IO::Socket::INET;
my $socket;
my $msg;
my $contador;
$socket=new IO::Socket::INET->new(PeerPort=>1976,
Proto=>'udp',
PeerAddr=>'255.255.255.255',
Broadcast=>1
);
$msg="";
for($contador=0;$contador<6;$contador++)
{
$msg.="\xff";
}
for($contador=0;$contador<16;$contador++)
{
$msg.="\x01\x02\x03\x04\x05\x06";
}
$socket->send($msg);
Java
import java.net.*;
import java.io.IOException;
public class Wol
{
public static void main(String args[])
{
byte mac[]={0x01,0x02,0x03,0x04,0x05,0x06};
byte buffer[]=new byte[102];
byte contador;
for(contador=0;contador<6;contador++)
buffer[contador]=(byte)0xff;
for(contador=6;contador<102;contador+=6)
System.arraycopy(mac,0,buffer,contador,6);
try
{
DatagramSocket udp=new DatagramSocket();
udp.setBroadcast(true);
udp.send(new DatagramPacket(buffer,102,InetAddress.getByName("255.255.255.255"),1976));
}
catch(java.net.SocketException se)
{
System.err.println(se);
}
catch(java.net.UnknownHostException ue)
{
System.err.println(ue);
}
catch(java.io.IOException ie)
{
System.err.println(ie);
}
}
}
Visual Basic (Para que funcione debeis insertar un control Winsock)
Dim buffer() As Byte
Dim contador As Byte
ReDim buffer(101) As Byte
For contador = 0 To 5
buffer(contador) = &HFF
Next
For contador = 6 To 101 Step 6
buffer(contador) = &H1
buffer(contador + 1) = &H2
buffer(contador + 2) = &H3
buffer(contador + 3) = &H4
buffer(contador + 4) = &H5
buffer(contador + 5) = &H6
Next
Winsock1.Protocol = sckUDPProtocol
Winsock1.RemoteHost = "255.255.255.255"
Winsock1.RemotePort = 1976
Winsock1.SendData buffer
Por supuesto no hay método que sirva para marcar todas las tarjetas a la vez, así que habrá que ir una por una mandando el magic packet para que se vaya encendiendo cada ordenador. La tarjeta de red de cada ordenador apagado compara todos los paquetes que le llegan del tráfico de red para ver si contiene 16 veces su dirección MAC y así mandar a la placa madre que encienda el ordenador.
Las tarjetas de red que vengan incorporadas ya de fábrica en la placa madre ya tienen esta función activada. Sin embargo las que estan sueltas en ranuras PCI o ISA, deben:
1) Permitir el wake on lan (no todas tienen un firware con esa posibilidad)
2) La placa madre debe tener un conector de 3 pines que permita este evento.
3) Un cable que vaya desde la tarjeta hasta la placa madre.
En ambos casos se debe activar en la BIOS el mantenimiento de energía y posteriormente el evento WAKE ON LAN.
En mi portatil no puedo probar esta característica (cuando se apaga este, la tarjeta ethernet incorporada también se apaga). En el ordenador de sobremesa no me ha funcionado (tampoco funcionan eventos como el de encender el ordenador con una pulsación del teclado) y con el servidor me ha funcionado perfectamente.
El Magic Packet también se puede hacer desde Internet:
Si teneis conexión directa solo debeis modificar vuestro programa para que apunte a vuestra IP pública de Internet (si no es fija podeis usar cosas como dyndns).
Si no teneis conexión directa o no quereis usar un programa, podeis hacerlo desde aquí.
Sin embargo, a no ser que tengais un router que este conectado a Internet y donde podais poner rutas estáticas con IP, puertos y direcciones MAC no podreis hacerlo funcionar, ya que el router (como el mio) borra de la tabla arp las relaciones MAC/IP cuando detecta que no hay tráfico en una tarjeta determinada, por lo que aunque reciba un paquete que luego deba reenviar a una ip interna, lo ignora al no encontrarlo en la tabla; tampoco tiene opción para redireccionarlo como broadcast dentro de la red si no sabe que hacer con el.
» Leer más, comentarios, etc...
Microsoft seguirá soportando las MFC
Junio 13th, 2005 - [Enlace local]
Steve Texeira, Director of Partner Strategy for Microsoft Visual C++ (lo que quiera que signifique), en un artículo recientemente publicado en la MSDN, afirma que Microsoft continuará ofreciendo soporte y mejorando las MFC, de modo que cuando llegue el nuevo Longhorn (¿llegará algún día, me pregunto yo?), existirá soporte para Avalon, encapsulándolo ala MFC.
También afirma que las clases de la MFC han sido actualizadas para soportar las nuevas caracteristicas de seguridad incluidas en la CRT (la biblioteca estándard de C, ya sabes: fopen, strlen, etc., etc..) y que se permite una interactuación sin problemas entre la tecnología .NET y el código nativo.
Todo esto, claro está, es lo que lleva/llevará el Visual Studio 2005 (quitando lo de Avalon); personalmente me parece una forma de tranquilizar un poco a los cienes y cienes de empresas y programadores que todavía usan las MFC para sus desarrollos, así como una declaración de intenciones bastante clara, pero como está escrita con ese tonillo comercial tan característico de Microsoft que personalmente a mi me pone los pellillos de la nuca de punta, considero que es un tanto poco creíble, más que nada porque hace poco uno de los bloggers de Microsoft, Larry Osterman, ponía en su blog algo sobre el tema, quizás advirtiéndonos de que no todo el monte es orégano.
Independientemente de las intenciones de Microsoft, el post de Larry es bastante intersante, y más todavía muchas de las respuestas, todas ellas bastante razonadas y razonables. Es casi un deber leer el hilo entero si estás interesado en el tema.
» Leer más, comentarios, etc...
knocte :: MonoTema
AntiFUD Mono/.NET
Junio 10th, 2005 - [Enlace local]
Éste es mi segundo AntiFUD, quizás debería crear una sección con este nombre :D El caso es que también me suele enfadar mucho los hilos de BarraPunto que se dedican a desprestigiar a la plataforma de desarrollo de Mono, por la única razón de que con ésta se intenta reutilizar/adaptar/imitar un lenguaje, un entorno de desarrollo y unas API's de Microsoft (pero que, deliberadamente, ha publicado
» Leer más, comentarios, etc...
Y si hablamos de...
… reuniones temáticas
Junio 8th, 2005 - [Enlace local]
Ivan comenta en este post lo interesante que podría ser sentarnos un día (aunque él hable de forma virtual, yo no) y charlar de algunos temas.
En los congreso de javaHispano yo nohe podido hacerlo nunca, pero la verdad es que me parece muy interesante la posibilidad de crear unas reuniones y encontrarnos físicamente para charlar de algún tema (un tema por jornada), alguna presentación, intercambiar experiencias, etc. A mi la verdad es que me encantaría. Y a ser posible hacerlo de forma itinerante.
¿Problema?, ¿vosotros os pediríais un día libre para ir, digamos, de Barcelona a Madrid, o de Madrid a Bilbao, o de Bilbao a Valencia, para una cosa así?. Porque yo hablo de algo mínimamente serio, no de simplemente quedar a las 20:00 después del trabajo, para eso no me muevo 400 km ;-). ¿Habría gente realmente interesada?.