Feb 04

Simplemente, las cosas no funcionan

 

Por la mañana me caí de la cama, como siempre, sobre las cinco de la madrugada y, como siempre, lo primero que hice fue encender el ordenador. Internet no me iba. Las lucecillas del cable-modem de ONO daban que no había red. Duró la avería menos de un minuto, pero volvió a repetirse a los diez minutos y así tres o cuatro veces.

Por otro lado, mi ordenador, todavía en garantía, tiene estropeado el grabador de DVD. A veces lee, a veces no, pero nunca graba. Como tengo otro instalado y me da pereza ir a la tienda a que lo cambien (como digo, todavía está en garantía), así sigue, estropeado. Seguro que el que me funciona se estropea cuando se acabe la garantía y no me quedará más remedio que echar pestes de mi pereza y comprar otro.

Luego fuí al curro y allí, cada vez que abro eclipse, lo cierro, abro el correo, lo cierro, compilo, me eternizo esperando. Mi ordenador no es especialmente viejo, pero se ha ido degradando y va muy lento. A veces, hasta diez minutos de espera a que eclipse acabe de cerrar. Así que en una de esas esperas, decido ir a llenar mi botellita de agua a una de las fuentes que hay por la empresa. Dicha fuente tiene la palanquita de sacar agua rota, pero funciona. Eso sí, en vez de chorro de agua, sale un chorrito fino, porque algo hay mal.

De vuelta al ordenador y como no ha terminado de cerrar eclipse (y no responde nada mientras tanto) decido irme a tomar un café a una de las máquinas de café. Una "fuera de servicio", la otra se traga la moneda y no da nada, y de la tercera consigo sacar un café.

Por cierto, la tele recién comprada hace cosas raras con el TDT integrado. De vez en cuando la pantalla se queda negra durante un segundo. Como pasa más con unas cadenas que con otras y la señal que tengo no es muy allá (la tele analógica se veía con algo de nieve), pienso que no es que la tele esté mal, sino símplemente que el decodificador integrado es un asquito.

Y viendo el percal de cómo son las cosas hoy en día, donde prima más sacar beneficio rápido sacando productos malos y baratos pronto, de usar y tirar, con piezas de "plasticucho" que se rompen a la más mínima y calidad sobre todo deficiente…. ¿por qué iba a ser menos el software que hacemos? Proyectos sobre dimensionados con plazos escasos y escasez de gente,  principalmente novatos recién salidos que son más baratos y tira pa’lante.

En fin, hay días que es mejor no levantarse de la cama (y menos a esas horas), y hay días en que realmente me apetece cambiar de profesión y dedicarme a algo que no tenga nada que ver. No sé, pastor de ovejas quizás.

Feb 03

Jugando con Openmap

 

A principios de semana me salió la necesidad de hacer un algoritmo que sobre la tierra me dijera lo siguiente: Supongamos que sobre un punto de la tierra trazamos un rumbo siguiendo un azimuth determinado (ángulo respecto al Norte, en sentido horario). Se trata de saber si ese rumbo pasa o no pasa por una determinada zona geográfica, definida como un polígono cerrado sobre la superficie de la tierra.

Si suponemos tierra plana, el tema es relativamente sencillo sabiendo un poco de matemáticas y de geometría. Pero si las distancias son algo grandes, no vale suponer tierra plana. Debemos meternos con trigonometría esférica, vectores o cualquier otro artilugio de matemáticas. Como me daba pereza desempolvar los apuntes de matemáticas, me dediqué a buscar por ahí y me encontré con Openmap.

Openmap es una librería java pensada para dibujar mapas y sobre ellos, dibujar lo que queramos. Podríamos, por ejemplo, dibujar nuestro polígono y el rumbo desde el punto en cuestión. La librería viene muy completita, de forma que con un simple new OpenMap(), sin parámetros, se lanza una aplicación con el mapa mundo por defecto, opciones de zoom, de dibujar día y noche, etc, etc. Pero por supuesto, también tiene todo el conjunto de clases necesario para que nosotros podamos hacer nuestro mapa a medida. Cargamos un mapa en formato shapefile, definimos nuestros menús y barras de herramientas, etc.

Pero eso no es lo que a mí me venía bien, puesto que no quiero pintar un mapa. Lo que a mí me venía bien es que tiene clases de sobra para el cálculo de "cosas" sobre la superficie de la tierra. Hay clases capaces de decirte la distancia en km de dos puntos sobre la tierra, de decirte si dos segmentos sobre la superficie de la tierra se cortan, hay clases de zonas geográficas poligonales … y clases para saber si un segmento corta a una zona poligonal.

Total, que lo que yo imaginaba iban a ser un par de días de echar cuentas arriba y abajo, probar, volver a probar y echar humo por la cabeza, al final ha sido una mañana de jugar con Openmap y aproximádamente diez líneas de código java para mi algoritmo, usando las clases de Openmap. La única "pega" que le veo es cargar con un Openmap.jar sólo para echar unas cuentas….

 

Feb 02

Cosillas con la clase File de Java

 

El otro día, tratando de hacer un test automático, me encontré con una cosa de la clase File de java que no sé si está bien o soy yo que soy demasiado enrevesado haciendo las cosas.

Supongamos que hay un fichero.txt que está en un directorio que existe, tanto el fichero como el directorio. Pero tenemos la mala suerte de que nuestro programa se está ejecutando en otro directorio que no es en el que está el fichero. Posiblemente no es la forma correcta de hacerlo, pero se me ocurrió que mi programa podía cambiarse de directorio usando la propiedad "user.dir" de la clase System.

System.setProperty("user.dir", "/directorio");

y ahora, para ver si el fichero existe, sólo tengo que hacer esto

File fichero = new File("fichero.txt");
if (fichero.exist()) {
    ….

Pues bien, resulta que NO existe. Bueno, será que File no lee la propiedad "user.dir" para ver el directorio de ejecución, o bien la lee muy al principio y luego no la cambia. No me gusta, pero puede ser así y tendría su razón de ser. Sin embargo, no es del todo así. Si en el código anterior hacemos esto

System.out.println(fichero.getCanonicalPath());
System.out.println(fichero.getAbsolutePath());

pues resulta que sale

/directorio/fichero.txt

o sea, que para los métodos getCanonicalPath() y getAbsolutePath() sí recarga la propiedad "user.dir".

Bueno, seguramente soy un poco enrevesado, pero esto me parece una pequeña incongruencia de File. O lee "user.dir" siempre, o no lo lee nunca. No parece lógico que el constructor o el método exist() no lo lea, pero los getCanonicalPath() y getAbsolutePath() sí.

Lo del enrevesamiento tiene una pequeña explicación. La aplicación en ejecución se ejecuta en un determinado directorio y busca los ficheros con path relativos, leídos de una propiedad (aplicacion.path.fichero=path/relativo/fichero.txt). Pero cuando desde maven compilo, los test se ejecutan en el directorio raíz del proyecto maven. Mi idea era hacer un test que leyera la propiedad y comprobara que el fichero existe. Para ello, tenía que llevar el directorio de ejecución del test al equivalente de la aplicación debajo de la estructura de directorios de maven (/proyecto_maven/src/main/config) y a partir de ahí usar la propiedad con el path relativo (directorio/fichero.txt)

Al final lo he solucionado con un new File("/proyecto_maven/src/main/config", "directorio/fichero"), que posiblemente sea una opción más correcta que andar jugando con el "user.dir"

Jan 29

Jugando con Apache Pivot

 

Esta mañana he estado jugando un poco con Apache Pivot. Es una librería puramente java para hacer aplicaciones ricas de internet (RIA). Normalmente yo me dedico a aplicaciones de escritorio, no de internet, pero tenía curiosidad por ver cómo era y si se podría aprovechar en una aplicación de escritorio.

La librería contiene básicamente todos los componentes habituales para hacer ventanas, clases java estilo Button, TableView, TextInput, etc. Las ventanas pueden construirse o bien usando un fichero xml en el que se indica qué componentes llevan dichas ventanas, o bien directamente desde código java, con un main(). Estos componentes tienen su aspecto propio, que no es el de SWING ni el del sistema operativo en el que corramos la aplicación. Aunque no lo he probado, aparentemente facilita mucho cosas como drag&drop o los efectos de aparición y desaparición de ventanas suavemente, degradados, transparencias, etc.

Pero lo que más me ha llamado la atención es la forma de rellenar u obtener datos de un formulario. Es algo detrás de lo que ando mucho tiempo y no he llegado a conseguir. Lo llaman "data binding" y consiste en lo siguiente:

  • Por un lado tienes tu formulario. A cada uno de los campos de dicho formulario lo identificas con una clave. Por ejemplo, si hacemos una ventana para pedir nombre y apellidos, podemos poner dos TextInput a los que identificaremos con las claves nombre y apellidos.
  • Por otro lado, podemos tener un Java Bean normalito, con dos atributos privados que se llamen igual que las claves del formulario, es decir, un atributo nombre y otro apellidos. Por supuesto, los correspondientes métodos get() y set().

Pues bien, el formulario (clase Form de Apache Pivot)  tiene métodos load() y store(), que directamente son capaces de extraer los atributos del Java Bean y meterlos en el formulario y al revés, haciendo coincidir clave con atributo. Permite además formularios anidados, que corresponden con Java Beans anidados.

En cuanto a las tablas (clase TableView), también es bastante sencilla. Al definir la tabla damos a cada columna un identificador, que luego correspoderá con el atributo del Java Bean. Así, siguiendo el ejemplo, nuestra tabla tendría dos columnas identificadas por nombre y apellidos. Nos basta ahora meter en el TableView usando el método setTableData() una List de nuestros Java Bean. La tabla se rellena solita.

Y más cosas interesantes. En las aplicaciones es importante validar los datos que se introducen. de forma que un TextInput, por ejemplo, sólo admita números entre 1 y 10,. Pues esto también está bien contemplado. Los TextInput tienen un setValidator() en el que podemos pasar una clase encargada de validar el dato según lo va escribiendo el usuario (el TextInput permanece rojo hasta que contiene un dato válido). La librería tiene ya hechos un montón de Validators habituales, como números en un rango determinado. También es interesante saber que si nuestro Java Bean tiene por ejemplo un atributo double (que no sea String), no tenemos que hacer nada especial, el formulario sabe convertirlo a texto para mostrarlo en el TextInput o reconstruirlo a partir del texto introducido por el usuario para devolver un double. Tanto los métodos load() y store() de la clase Form se "tragan" perfectamente atributos de varios tipos estándar de java, no sólo String.

Bueno, ahora sólo me queda buscar o hacer algo perecido a todo esto, pero con los componentes SWING normales de java, para poder empezar a usarlo sin tener que cambiar TODA la interface de un sólo golpe.

Dec 20

Idiotizados con los televisores planos

 

Hace once años, con el piso recién comprado, decidí comprar un televisor grande. De aquella, compré un televisor de tubo de formato 4:3 de 28" y de aquella intentaron ya venderme uno de tubo panorámico. Pregunté a la señora de la tienda si en esas televisones panorámicas no se veía a la gente ensanchada. Ella contestó, llena de sabiduría, "es que es el futuro". Yo, por supuesto, me negué a ver a la gente ensanchada aunque fuera el futuro y me compré la de 4:3

Hace un par de semanas, esa televisión de tubo, comprada hace once años, hizo "pluf", se apagó y empezó a oler a quemado. Así que tocó renovarse y comprar una de esas televisiones planas que hay ahora, formato panorámico. Dicho y hecho, el Lunes pasado estrenamos nuestra tele.

Llegó a casa, la desmontamos, la enchufamos, jugamos con ella un rato a sintonizar canales, poner DVDs y "asombrarnos de lo bien que se ve". Una hora después de tener la tele funcionando, llegué a la conclusión de que nos han idiotizado. Y una semana después de tener la tele, me he reafirmado en la idea.

Idiotización 1

El primer motivo de idiotización es el siguiente. Durante los días que estuvimos sin tele, la echábamos de menos. Hay costumbres adquiridas, como sentarse en el sillón y coger el mando a distancia para hacer zapping justo después de comer o cenar. Al no tener tele, llegabas al sillón y te faltaba algo. Parece que no podíamos vivir sin tele.

Sin embargo, con la tele recién comprada y diez minutos después de haberla instalado y probado… ¡¡ nadie hacía caso a la tele !!. Las niñas se fueron a su cuarto a jugar, mi mujer a hacer sus cosas y yo al ordenador. Un aparato tan caro y nos ha durado la novedad diez minutos. Y si no está ese ruido de fondo que es el televisor encendido, lo echamos de menos.

Idiotización 2

Nos han metido el formato panorámico hasta por las orejas y si la tele no tiene FULL HD (Alta definición a tope), es una caca de tele. Así que compramos teles panorámicas, cuanto más grandes mejor y cuanta más definición tengan mejor …. pero la realidad es dura:

  1. La inmensa mayoría de las cadenas y programas no se emiten en panorámico, así que las opciones que tenemos de uso de nuestra tele panorámica son:
    • Usar media tele, poniéndola en 4:3 y dejando franjas negras a los lados.
    • Dejarla en 16:9 para que ocupe todo el ancho, con lo que vemos a la gente ensanchada. Al menos quedamos bien con los amigos, ya que después de una sesión de tele y acostumbrarnos a la gente ensanchada, inevitablemente les preguntaremos a nuestros amigos si han adelgazado.
    • Poner 16:9 y zoom vertical, para que la imagen ocupe todo el ancho, pero sin ver a la gente ensanchada. Eso sí, entonces salen todos con el flequillo recortado, ya que cae fuera de la pantalla.
  2. Tampoco emiten en alta definición, por lo que lo normal es que en una tele tan grande y con tanta definición, la imagen se vea fatal, como un DivX de baja calidad o incluso borroso. De hecho, un compañero me avisó, si lo primero que haces al ver una tele de estas es ver una cadena de televisión normal, quedarás decepcionado y pensarás que la tele se ve fatal, pero no es la tele, es la señal emitida.
  3. Y lo más mejor de todo, dentro de una misma cadena, cada programa se emite en un formato distinto y el no va más son los anuncios. Cada 20 segundos, cambia el formato de la imagen. E incluso teniendo tele panorámica y emitiendo la película en panorámico, muchas veces se ven las franjas horizontales negras arriba y abajo. ¿Tendremos que ver las películas en teles todavía más panorámicas?

Y así estamos, después de once años en el que ver a la gente ensanchada era el futuro, según la señora de la tienda, se ve que ese futuro aún no ha llegado y le queda un poco. Eso sí, cuando la señal se emite realmente en formato 19:6 y con alta definición, o se pone un DVD (y supongo que un Blue Ray mejor), entonces sí se ve realmente bien. Desgraciadamente, son pocas las ocasiones.

Nov 27

Personalización de la página 404

 

La página 404 es la página de error que presenta un sitio web cuando se busca en él una página que no existe. Suele ser buena idea poner en esa página algún texto o algunos enlaces de forma que el usuario que ha terminado en ella, tenga una forma de llegar a donde pretendía llegar y, en plan webmaster egoísta, conseguir que no se vaya de nuestro sitio y siga navegando por él.

Google nos ofrece lo que llama widget 404, un trozo de código que podemos poner en nuestra página 404 y nos mostrará una caja de búsqueda de google, rellena con las palabras significativas de la URL fallida y que busca en el sitio web.

Aunque hace tiempo que la conocía, me he decidido a ponerla, y puedes ver el resultado si pinchas el enlace a http://www.chuidiang.com/esto-no-existe.html.

Nov 26

Excedido el límite de transferencia mensual

 

En su día tenía mi página web en geocities, sitio gratuito, pero con un límite de transferencia mensual pequeño (no recuerdo cuánto). Con el tiempo empecé a superar ese límite y empecé a obtener mensajes de error al visitar la página, estilo "este sitio está temporalmente suspendido porque ha superado el límite de transferencia…."

Así que me fui a un hosting de pago. Los 20 Gigas de transferencia mensual que me daban me parecía algo parecido a infinito comparado con el límite de geocities  Y así fue desde Marzo del 2006 hasta hoy …. en el que me ha vuelto a aparecer un mensaje "este sitio está temporalmente suspendido…..". Hoy he superador el límte de 20 Gigas de transferencia mensual y sólo estamos a día 26.

Ampliar el plan del hosting me sale unos dolares más caro y la otra opción es buscarse otro hosting con un precio similar y más transferencia. Pero la verdad es que en este hosting me va bien y el servicio técnico suele solucionarme los problemas e incluso contestar a las dudas. Así que me decidí, quizás un poco precipitadamente, a pedirles el siguiente plan, con 30 Gigas de transferencia mensual. Fue cuestión de menos de una  hora, desde que mandé el correo hasta que mi sitio tenía el nuevo plan y estaba otra vez en funcionamiento.

Y digo que quizás me precipité porque luego, investigando los logs de acceso, he visto que hay páginas que enlazan directamente a imágenes en mi sitio, en concreto, los de taringa a imágenes de mi página de efectos ópticos. Supongo que no es ese el único caso y espero que tampoco sea el motivo principal por el que excedo el límite de tráfico, pero la solución es sencilla. Basta configurar el servidor para que no admita enlaces directos a las fotos y, de hecho, las imágenes que faltan en el enlace de taringa son las que estaban descargadas directamente de mi página.

En fin, antes usaba un 10% del espacio de disco duro que tenía disponible en el hosting (1 Giga) y ahora tengo el doble de disco (2 Gigas), así que sólo uso un 5%. Tendré que ponerme las pilas y liarme a escribir tutoriales para amortizar el nuevo plan de hosting.

Nov 25

Archiva vs Nexus

 

En su día nos instalamos un repositorio propio para nuestros jar, de forma que estuvieran accesibles para todos los desarrolladores. Para ello usamos archiva, y ha funcionado más o menos bien con sus cosillas. Hace además las veces de proxy con los repositorios de maven que hay por internet. De esta forma, cada desarrollador únicamente debe configurar maven para que busque los jars en el repositorio de archiva y es este el que se encarga de acceder a internet y buscarlos si es necesario.

No hace mucho descubrí que había otra herramienta similar llamada nexus. Como archiva nos hacía cosas raras de vez en cuando (no traía las cosas de los repositorios de internet, no sé muy bien si por culpa de archiva o de nuestra conexión a internet, que va con proxy autentificado. También dejaba ficheros tmp vacíos en el repositorio de vez en cuando). Así que hoy me he decidido a instalar nexus y probar.

La instalación sencilla, un zip que te bajas, desempaquetas y tienes los scripts necesarios de windows, linux, solaris… para instalar nexus como servicio y arrancarlo y pararlo. Eso sí, hay dos versiones, la gratis con menos posibilidades de autentificación/seguridad, y la de pago que tiene de todo. La gratis en principio tiene lo necesario: gestión de usuarios y permisos propia, funciones de proxy y repositorios propios.

La interface web mucho mejor que la de archiva. Bastante más bonita y agradable. Rápidamente me puse en ella a configurar nuestros repositorios, tanto los propios, como los repositorios que son proxy de los estándar de internet (que ya vienen configurados los de maven central, apache y codehaus).

Y vamos a las cosas que me han gustado y que me han decidido a intentar el cambio en serio:

  1. Es más estricto que archiva con los SNAPSHOTS y las releases. Archiva permite subir y bajar jars snapshots y no snapshots de repositorios snapshots y no snapshots indistintamente. Somos los desarrolladores los que tenemos que tener cuidado de dónde subimos los jar. Nexus es más estricto, si intentamos subir un jar no snapshot a un repositorio que hemos marcado como snapshot, protesta. Y al revés también.
  2. Permite programar tareas de mantenimiento periódicas y entre ellas, la que veo más útil en nuestro caso: permite que se limpien automáticamente las versiones snapshots más antiguas o indicar cuántos snapshots quieres como máximo por cada jar. En un entorno de desarrollo como el nuestro en el que Hudson genera y sube muchos snapshots gigantes todas las noches, una limpieza periódica se hace imprescindible.
  3. Cuando configuras un repositorio como proxy de uno externo, tienes más visibilidad de si tiene o no conexión con el repositorio externo, si se ha bajado algo de él y qué se ha bajado.

Para ser justos, estoy comparando una versión antigua de archiva, que instalé hace mucho, con la última de nexus. Es posible que las versiones más modernas de archiva hayan mejorado o permitan hacer estas cosas que digo que hace nexus.

Nov 20

Sobre constructores, atributos y herencias.

 

Un pequeño "bug" con el que me he tropezado el otro día. Supón una clase padre abstracta en la que desde el constructor se llama al método abstracto.

public abstract ClasePadre {
   public ClasePadre() {
      …
      inicializa();
      …
   }

   public abstract void inicializa() {
   }
}

Ahora imagina que hacemos una clase hija, mal hecha, tal que así

public class ClaseHija extends ClasePadre {
   private UnAtributo atributo = null;

   @Override
   public void inicializa() {
         …
         atributo = new UnAtributo();
         …
      }
   }
}

Simplemente hemos sobreescrito el método inicializa() que nos obliga el padre y lo aprovechamos para inicializar un atributo que inicialmente es null. A partir de aquí, nuestro código se fia de que ese atributo esté inicializado. Pues bien, está mal. Veamos el orden de construcción cuando hacemos new ClaseHija()

  1. Primero java llama al constructor del padre. Este llama a inicializar() y se crea el atributo de la clase hija.
  2. Luego java asigna a los atributos de la clase hija los valores definidos al declararlos, o sea, pone atributo a null.
  3. Finalmente java llama al constructor de la clase hija.

El punto 2 es el que nos da los problemas, resulta que en el punto 1 se inicializa atributo dándole un valor y en el paso 2 se vuelve a poner a null. ¡¡ El atributo queda sin inicializar a pesar de que le hemos hecho un new !!. Nos costó un buen rato dilucidar por qué algo de lo que se hacía el new, un rato después era null.

Pues bien, esto nos ha pasado, y nos ha pasado por pasar de las métricas. Hay una que dice ConstructorCallOverridableMethod, en la que salta un error si un constructor llama a un método que no es final, es decir, que las clases hijas podrían sobreescribir y hacer que la clase padre no quedara bien inicializada. Esto no es exactamente así en este ejemplo, pero está claro que no es buena idea que un constructor llama a métodos que se pueda o, como en este ejemplo, se deban sobreescribir.

Nov 15

Efecto del crackeo del sitio

 

Como comenté hace unos días, me habían crackeado el sitio y habían metido spam. Google me sacó de los buscadores durante unos días hasta que solucioné el problema. Desde entonces vigilo el sitio y, toco madera, de momento no ha vuelto a suceder. De todas formas, ahí va el efecto en las visitas al desaparecer de google. El gráfico corresponde al foro, donde el efecto es más drástico, ya que apenas hay enlaces exteriores a post del foro y casi todas las visitas provienen de los buscadores.

efecto en las visitas al desaparecer del buscador google