martes, 12 de febrero de 2013

Compilación e instalación de servidor Apache en Redhat

Si pretendemos compilar he instalar un Servidor Web Apache (la versión que he instalado es la 2.4) en un sistema tipo Linux (en mi caso un Redhat 4 de 64 bits) recomiendo seguir las indicaciones de la Guía de Compilación e Instalación del Servidor HTTP Apache. Básicamente las indicaciones de la guía son correctas salvo en el apartado Requisitos donde falta indicar que son necesarios para compilar Apache: Apache Portable Runtime Project (APR), Apache Portable Runtime Project Utility y Perl Compatible Regular Expressions (PCRE).





sábado, 2 de febrero de 2013

Trabajando con Threads en Java. Caso 1

Bruce Eckel en su libro Thinking in Java en el capítulo sobre la concurrencia plantea un ejercio que resulta muy ilustrativo sobre sobre como funcionan los Threads en Java.

El enunciado del ejercicio es:


Implement a Runnable. Inside run( ), print a message, and then call yield( ). Repeat this three times, and then return from run( ). Put a startup message in the constructor and a shutdown message when the
task terminates. Create a number of these tasks and drive them using threads

La implementación es simple. En primer lugar definimos una clase Runnable que cumple con los requisitos pedidos.


package thinkinginjava.concurrency.exercise1;

public class RunnablePrinter implements Runnable {

private static int count = 0;

private final int id = count++;

public RunnablePrinter() {
System.out.println("Inicio RunnablePrinter. Id: " + id);
}

public void run() {

Thread t = Thread.currentThread();

System.out.println("#" + id + " Mensaje 1." + " Thread: " + t.getId());
Thread.yield();
System.out.println("#" + id + " Mensaje 2."  + " Thread: " + t.getId());
Thread.yield();
System.out.println("#" + id + " Mensaje 3. " + " Thread: " + t.getId());
Thread.yield();

System.out.println("Fin RunnablePrinter. Id: " + id);

return;
}

}

Y después creamos una clase de tipo main para lanzar los Threads.


package thinkinginjava.concurrency.exercise1;

public class RunnablePrinterMain {

public static void main(String[] args){

for(int i = 0; i < 10; i++)
new Thread(new RunnablePrinter()).start();


}

}


Hasta aquí nada especial. Ahora viene lo interesante, lancemos el main y veamos que sucede.

Una primera ejecución nos devuelve el siguiente resultado:


Inicio RunnablePrinter. Id: 0
Inicio RunnablePrinter. Id: 1
Inicio RunnablePrinter. Id: 2
#1 Mensaje 1. Thread: 8
#1 Mensaje 2. Thread: 8
#1 Mensaje 3.  Thread: 8
Fin RunnablePrinter. Id: 1
Inicio RunnablePrinter. Id: 3
#0 Mensaje 1. Thread: 7
#0 Mensaje 2. Thread: 7
#0 Mensaje 3.  Thread: 7
Fin RunnablePrinter. Id: 0
Inicio RunnablePrinter. Id: 4
#2 Mensaje 1. Thread: 9
#2 Mensaje 2. Thread: 9
#3 Mensaje 1. Thread: 10
#2 Mensaje 3.  Thread: 9
Inicio RunnablePrinter. Id: 5
#3 Mensaje 2. Thread: 10
#3 Mensaje 3.  Thread: 10
Fin RunnablePrinter. Id: 2
Inicio RunnablePrinter. Id: 6
#4 Mensaje 1. Thread: 11
Fin RunnablePrinter. Id: 3
#4 Mensaje 2. Thread: 11
#4 Mensaje 3.  Thread: 11
Fin RunnablePrinter. Id: 4
#5 Mensaje 1. Thread: 12
#5 Mensaje 2. Thread: 12
#5 Mensaje 3.  Thread: 12
Fin RunnablePrinter. Id: 5
Inicio RunnablePrinter. Id: 7
#6 Mensaje 1. Thread: 13
#6 Mensaje 2. Thread: 13
#6 Mensaje 3.  Thread: 13
Fin RunnablePrinter. Id: 6
Inicio RunnablePrinter. Id: 8
#7 Mensaje 1. Thread: 14
#7 Mensaje 2. Thread: 14
#7 Mensaje 3.  Thread: 14
Fin RunnablePrinter. Id: 7
Inicio RunnablePrinter. Id: 9
#8 Mensaje 1. Thread: 15
#8 Mensaje 2. Thread: 15
#8 Mensaje 3.  Thread: 15
Fin RunnablePrinter. Id: 8
#9 Mensaje 1. Thread: 16
#9 Mensaje 2. Thread: 16
#9 Mensaje 3.  Thread: 16
Fin RunnablePrinter. Id: 9

En este resultado se observa como se reparte el tiempo de CPU entre los distintos threads. La ejecución no es secuencial y esto se pone de manfiesto claramente en la primeras líneas del resultado anterior (marcadas en negrita), el thread 8 se ejecuta antes que el thread 8. Al cotrario de cono debería suceder en el caso de una ejecución secuencial.

Una segunda ejecución daría un resultado distinto al anterior.


Inicio RunnablePrinter. Id: 0
Inicio RunnablePrinter. Id: 1
#0 Mensaje 1. Thread: 7
#0 Mensaje 2. Thread: 7
#0 Mensaje 3.  Thread: 7
Fin RunnablePrinter. Id: 0
Inicio RunnablePrinter. Id: 2
#1 Mensaje 1. Thread: 8
#1 Mensaje 2. Thread: 8
#1 Mensaje 3.  Thread: 8
Fin RunnablePrinter. Id: 1
Inicio RunnablePrinter. Id: 3
#2 Mensaje 1. Thread: 9
#2 Mensaje 2. Thread: 9
#2 Mensaje 3.  Thread: 9
Fin RunnablePrinter. Id: 2
Inicio RunnablePrinter. Id: 4
#3 Mensaje 1. Thread: 10
#3 Mensaje 2. Thread: 10
#3 Mensaje 3.  Thread: 10
Fin RunnablePrinter. Id: 3
Inicio RunnablePrinter. Id: 5
#4 Mensaje 1. Thread: 11
#4 Mensaje 2. Thread: 11
#4 Mensaje 3.  Thread: 11
Fin RunnablePrinter. Id: 4
Inicio RunnablePrinter. Id: 6
#5 Mensaje 1. Thread: 12
#5 Mensaje 2. Thread: 12
#5 Mensaje 3.  Thread: 12
Fin RunnablePrinter. Id: 5
Inicio RunnablePrinter. Id: 7
#6 Mensaje 1. Thread: 13
#6 Mensaje 2. Thread: 13
#6 Mensaje 3.  Thread: 13
Fin RunnablePrinter. Id: 6
Inicio RunnablePrinter. Id: 8
#7 Mensaje 1. Thread: 14
#7 Mensaje 2. Thread: 14
#7 Mensaje 3.  Thread: 14
Fin RunnablePrinter. Id: 7
Inicio RunnablePrinter. Id: 9
#8 Mensaje 1. Thread: 15
#8 Mensaje 2. Thread: 15
#8 Mensaje 3.  Thread: 15
Fin RunnablePrinter. Id: 8
#9 Mensaje 1. Thread: 16
#9 Mensaje 2. Thread: 16
#9 Mensaje 3.  Thread: 16
Fin RunnablePrinter. Id: 9

Se observa que no podemos conocer apriori el reparto del tiempo de CPU entre los distintos thread.

miércoles, 25 de abril de 2012

Sobre variables estáticas en Java

La pasada semana leyendo el capítulo dedicado a la programación concurrente del expléndido libro de Bruce Ekell, Thinking in Java, me encontré con un ejemplo que me distrajo de mi lectura principal. En el ejemplo, Bruce pretendía ilustrar el uso de los Threads en Java usando una clase que implementaba una cuenta atrás.

package test.specifications;
    
public class LiftOff implements Runnable {
    
 protected int countDown = 10; // Default
 private static int taskCount = 0;
 private final int id = taskCount++;
    
 public LiftOff () {}
    
 public LiftOff(int countDown) {
  this.countDown = countDown;
 }
      
 public String status() {
  return "#" + id + "(" + (countDown > 0 ? countDown :
   "Liftoff!") + " ) , ";
 }
    
 public void run() {
  while (countDown-- > 0) {
   System.out.print( status() ) ;
   Thread.yield();
  }
 }
    
}
   

Bruce ilustraba el uso de la clase anterior con el código siguiente:

package test.specifications;

public class MoreBasicThreads {
   
    public static void main(String[] args){
        for(int i = 0; i < 5; i++)
            new Thread(new LiftOff()).start();
       
        System.out.println("Waiting for LiftOff");
    }

}
   

Atrajo mi atención el resultado obtenido al ejecutar el código anterior.


#0(9 ) , #4(9 ) , Waiting for LiftOff #3(9 ) , #2(9 ) , #1(9 ) , #4(8 ) , #1(8 ),
#4(7 ) , #3(8 ) , #4(6 ) , #0(8 ) , #4(5 ) , #3(7 ) , #1(7 ) , #2(8 ) , #1(6 ) , 
#3(6 ) , #4(4 ) , #0(7 ) , #4(3 ) , #3(5 ) , #1(5 ) , #2(7 ) , #1(4 ) , #3(4 ) , 
#4(2 ) , #0(6 ) , #4(1 ) , #3(3 ) , #1(3 ) , #2(6 ) , #1(2 ) , #3(2 ) , #3(1 ) ,
#4(Liftoff! ) , #0(5 ) , #0(4 ) , #0(3 ) , #0(2 ) , #0(1 ) , #0(Liftoff! ) ,
#3(Liftoff! ) , #1(1 ) , #2(5 ) , #1(Liftoff! ) , #2(4 ) , #2(3 ) , #2(2 ) , 
#2(1 ) , #2(Liftoff! ) , 
   

Lo que llamó mi atención de este resultado fue como el valor de la variable id, asignado a partir de la variable estática taskCount, cambiaba para las distintas instancias de la clase LiftOff. En un principio, confundido por la inicialización de la variable id (mediante asignación de la variable estática taskCount), esperaba que todos los valores de id fuesen iguales.

La evidencia del resultado y una mirada más en detalle me hicieron salir de mi error.

Para explicar este resultado, partimos de la definición de variables estáticas de la especificación de Java ( http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.1

If a field is declared  static , there exists exactly one incarnation of the field, no matter how many instances (possibly zero) of the class may eventually be created. A static field, sometimes called a class variable, is incarnated when the class is initialized

Efectivamente el valor de la variable taskCount es compartido por todas la instancias de la clase LiftOff, pero este valor se asigna a la variable final id y posteriormente se incrementa mediante el operador ++.
private final int id = taskCount++;

De esta forma la siguiente vez que se que se instancia la clase LiftOff, el valor de taskCount ha cambiado, con lo que a la variable id se le asigna el nuevo valor de la variable taskCount, valor distinto que al que se asigno a la variable id de la instancia anterior (de echo es el valor anterior incrementado en una unidad). Y así sucesivamente para las siguientes instancias.

Así que, aunque el resultado aparentemente parece contradecir la definición de variable estática mostrando valores distintos de taskCount para las distintas instancias de LiftOff, la realidad, descrita en los párrafos anteriores, es muy distinta y concordante con la especificación.


viernes, 2 de marzo de 2012

Como buscar una cadena de caracteres en un blob de Oracle

El requisito para realizar el procedimiento es que el campo blob donde queremos buscar contenga caracteres. Si este es nuestro caso y queremos localizar una determinada cadena de caracteres dentro de este campo, se sigue el procedimiento que paso a describir.

Oracle dispone de un paquete de utilidades para trabajar con objetos de tipo RAW denominado UTL_RAW, y este paquete contiene una función que permiter convertir un objeto tipo BLOB en otro tipo VARCAHR2:  UTL_RAW.CAST_TO_VARCHAR2([<objeto Blob>])

Utilizamos esta función para buscar una cadena de caracteres en un Blob mediante la siguiente SELECT:

select [<lista de campos a mostrar>] from [<tabla>] where utl_raw.cast_to_varchar2([<objeto Blob>]) like '%[<cadena a buscar>]%'



martes, 25 de octubre de 2011

Cómo exportar la configuración los Alias y los Drivers de SQuirreL SQL

En el presente artículo se indica como exportar los alias y los drivers de una instalación de SquirreL QSL e importarlos en otra.

Las definiciones de alias se guardan en los ficheros SQLAliases23.xml y SQLAliases23_treeStructure.xml, y las de los drivers en SQLDrivers.xml. La ubicación de estos ficheros se puede consultar en las preferencias globales de SQuirreL: File -> GlobalPreferences -> General -> User Directory.


Para exportar las definiciones de alias y drivers a otra instalación de SQuirreL, se copian los dos ficheros anteriores en el User Directory de la nueva instalación (sobreescribiendo los ficheros originales).

Hay que tener en cuenta que el fichero de definición de drivers hacer referencia a la ubicación física de los ficheros que contienen los drivers jdbc por lo que, para un correcto funcionamiento, en la nueva instalación estos ficheros deben encontrarse en la ruta referenciada por el fichero SQLDrivers.xml.

miércoles, 31 de agosto de 2011

Como usar los ficheros de log de Simantec LiveUpdate

El fichero de log de Symantec LiveUpdate Log.LiveUpdate para Windows XP se encuentra en la carpeta:

C:\Documents and Settings\All Users\Application Data\Symantec\LiveUpdate
 
y en Windows Vista en la carpeta:
 
C:\ProgramData\Symantec\LiveUpdate

Los mensajes de error presentes en el fichero de log puede ayudarnos a encontrar problemas de LiveUpdate. Una lista de los errores que podemos encontrar en el fichero de logs se encuentra en la dirección: https://kb.berkeley.edu/jivekb/entry.jspa?entryID=975

REFERENCIA


miércoles, 18 de mayo de 2011

Problemas al lanzar ejecutables descargados a una máquina Windows. Windows no tiene acceso al dispositivo, ruta de acceso o archivo especificado

En ocasiones, durante mi trabajo, me he encontrado con el problema de que después de descargarme un ejecutable a un equipo Windows, cuando lo lanzo me salta una ventana de error con el mensaje: Windows no tiene acceso al dispositivo ruta de acceso o archivo especificado. Puede ser que no tenga permisos apropiados para tener acceso al elemento.

El usuario de la sesión tiene permisos para lanzar el ejecutable, por lo que el problema no va por ahí. Y, si no son los permisos, ¿qué causa este problema?.

El causante de nuestros males en este caso es un componente de Windows denominado: Configuración de seguridad mejorada de Internet Explorer.

Y para resolver este problema, basta con quitar este componente. Para lo que iremos a: Agregar o quitar programas -> Agregar o quitar componentes de Windows y quitaremos el componente Configuración de seguridad mejorada de Internet Explorer.

Después reiniciaremos el equipo y ya podremos lanzar el ejecutable.

REFERENCIA


miércoles, 6 de abril de 2011

Como subir un fichero a SendSpace

Seguramente más de una vez te has encontrado con el problema de que quieres mandar un fichero de gran tamaño a un amigo o amigos (las fotos del último fin de semana, algún vídeo, ...) y no encuentras una forma sencilla de hacerlo.

Cuando el fichero es pequeño se puede enviar fácilmente por mail, pero cuando el tamaño supera los 10MB no podemos utilizar el mail para enviarlo y es cuando empiezan los problemas.

Para resolver estos problemas os muestro una forma sencilla de compartir ficheros de hasta 500MB de forma gratuita.

La solución la encontramos en la dirección: http://www.sendspace.com/ . Esta página ofrece un servicio de alojamiento de ficheros gratuitos para ficheros de hasta 500MB.

Para subir un fichero basta con seguir los pasos siguientes:

En primer lugar accedemos a la página http://www.sendspace.com/ y seleccionamos el fichero que queremos subir mediante el botón [<Browse...>].



Una vez seleccionado, el fichero nos aparecerá en el campo Selected file. Si lo deseamos podemos poner una descripción al fichero rellendo el campo Description. En el campo Recipient's email escribimos el mail de la persona a la que queremos enviar el fichero y en el campo Your email escribimos nuestra dirección de mail para que le persona que reciba el fichero sepa quién se lo ha mandado.


Una vez que tengamos rellenos los campos del formulario como se ha indicado anteriormente, pulsamos el botón [<Upload File>] para subir el fichero. Después de esto se nos mostrará una nueva pantalla con una barra donde se muestra el progreso de subida del fichero.




Cuando la barra del progreso llega al 100% se nos mostrara una nueva ventana informando de la finalización de la subida del fichero.


La dirección que pusimos en el campo Recipient's email recibirá una mail desde el que se podrá descargar el fichero que hemos subido.

Hay que tener cuidado porque el enlace al fichero que hemos subido caduca en una semana.


martes, 22 de febrero de 2011

Como exportar la configuración de Putty

La configuración de Putty se guarda en la entrada del registro: HKEY_CURRENT_USER\Software\SimonTatham
Por lo que para exportar la configuración de Putty de un equipo Windows a otro basta con exporta a un fichero esta clave en el equipo de origen e importarla en el equipo de destino.

Exportación de la entrada del registro

La forma más rápida de exportar la clave es mediante el comando: regedit /e [<fichero_exp_reg>] "HKEY_CURRENT_USER\Software\Simontatham"

Donde en el parámetro [<fichero_exp_reg>] se indica el fichero donde se va a guardar la exportación de la clave del registro. Por ejemplo, el comando: regedit /e "c:\tmp\putty.reg" HKEY_CURRENT_USER\Software\Simontatham, guardaría la clave del registro en el fichero c:\tmp\putty.reg

Importación de la entrada del registro

Copiamos el fichero resultante de la exportación del registro en el equipo donde queremos importar la configuración del Putty.

Para importar la clave en el registro, lanzamos el comando: REGEDIT /S [<fichero_exp_reg>]

Donde el parámetro [<fichero_exp_reg>] indica el fichero a importar.

Siguiendo con el ejemplo anterior, ejecutaremos el comando: regedit /S "c:\tmp\putty.reg", para importar en el registro el contenido del fichero c:\tmp\putty.reg.

REFERENCIA:

lunes, 24 de enero de 2011

Enlazar tú página web con tu cuenta de Twiteer

Para insertar una enlace a una cuenta de Twitter en una página web, basta con acceder a la URL http://www.blogger.com/post-edit.g?blogID=33890760&postID=1403070947896963248, elegir el icono que más nos guste y seguir las instrucciones.

Pero, veamos más en detalle que es lo que estamos haciendo.

Cuando hacemos click en el icono elegido, nos aparecerá una pequeña ventana donde se indica que para usar el botón tenemos copiar en el código de nuestra página web el código que nos muestra, por ejemplo:

<a href="http://www.twitter.com/[<cuenta_twitter>]"><img src="http://twitter-badges.s3.amazonaws.com/twitter-a.png" alt="Seguir a [<cuenta twitter>] en Twitter"/></a>

  • El tag <a> define una referencia a la cuenta de twitter indicada en el atributo href, donde el campo [<cuenta_twitter>] se sustituye por la cuenta a la que queramos enlazar.
  • El tag <img> inserta la imagén de Twitter en nuestra página web. El atributo alt se utiliza para indicar un texto alternativo a la imagén.

Referencias

domingo, 23 de enero de 2011

Mensaje de Vida

Mensaje de Facundo Cabral

Como los budistas, sé que la palabra no es el hecho,
si digo "manzana" no es la maravilla innombrable que
enamora el verano, Si digo "árbol", apenas
me acerco a lo que saben las aves; el caballo siempre
fue y será lo que es sin saber que así lo nombro.

Sé que la palabra no es el hecho, pero sí se que un
día mi padre bajó de la montaña y dijo unas palabras
al oído de mi madre, y la incendió de tal manera que
hasta aquí he llegado yo, continuando el poema que mi
padre comenzó con algunas palabras.

Nacemos para encontrarnos (la vida es el arte del
encuentro), encontrarnos para confirmar que la
humanidad es una sola familia y que habitamos un
país llamado Tierra. Somos hijos del amor, por lo
tanto nacemos para la felicidad (fuera de la felicidad
son todos pretextos), y debemos ser felices también
por nuestros hijos, porque no hay nada mejor que
recordar padres felices.

Hay tantas cosas para gozar y nuestro paso por la
Tierra es tan corto, que sufrir es una pérdida de
tiempo. Además, el universo siempre está dispuesto
a complacernos, por eso estamos rodeados de buenas
noticias. Cada mañana es una buena noticia. Cada niño
que nace es una buena noticia, cada cantor es una
buena noticia, porque cada cantor es un soldado menos,
por eso hay que cuidarse del que no canta porque algo
esconde.

Eso lo aprendí de mi madre que fue la primera buena
noticia que conocí.

Se llamaba Sara y nunca pudo ser inteligente porque
cada vez que estaba por aprender algo llegaba la
felicidad y la distraía, nunca usó agenda porque
sólo hacía lo que amaba, y eso se lo recordaba el
corazón.Se dedicó a vivir y no le quedaba tiempo para
hacer otra cosa.

De mi madre también aprendí que nunca es tarde, que
siempre se puede empezar de nuevo, ahora mismo, le
puedes decir basta a la mujer (o al hombre) que ya
no amas, al trabajo que odias, a las cosas que te
encadenan a la tarjeta de crédito, a los noticieros que
te envenenan desde la mañana, a los que quieren
dirigir tu vida, ahora mismo le puedes decir "basta"
al miedo que heredaste, porque la vida es aquí y ahora mismo.

Me he transformado en un hombre libre (como debe ser),
es decir que mi vida se ha transformado en una fiesta
que vivo, en todo el mundo, desde la austeridad del
frío patagónico a la lujuria del Caribe, desde la
lúcida locura de Manhattan al misterio que enriquece a
la India, donde la Madre Teresa sabe que debemos dar
hasta que duela.

Caminando comprobé que nos vamos encontrando con el
otro, lenta, misteriosa, sensualmente, porque lo que
teje esta red revolucionaria es la poesía. Ella nos
lleva de la mano y debajo de la luna, hasta los
últimos rincones del mundo, donde nos espera el
compinche, uno más, el que continúa la línea que será
un círculo que abarcará el planeta. Esta es la
revolución fundamental, el revolucionarse
instantáneamente para armonizar con la vida,
que es cambio permanente, por eso nos vamos
encontrando fatalmente para iluminar cada rincón.

Que nada te distraiga de ti mismo, debes estar atento
porque todavía no gozaste la más grande alegría ni
sufriste el más grande dolor. Vacía la copa cada noche
para que Dios te la llene de agua nueva en el nuevo día.

Vive de instante en instante porque eso es la vida. Me
costó 57 años llegar hasta aquí, ¿cómo no gozar y
respetar este momento?
Se gana y se pierde, se sube y se baja, se nace y se
muere. Y si la historia es tan simple, ¿por qué te preocupas tanto?.

No te sientas aparte y olvidado, todos somos la sal de
la Tierra. En la tranquilidad hay salud, como plenitud
dentro de uno. Perdónate, acéptate, reconócete y ámate,
recuerda que tienes que vivir contigo mismo por la
eternidad, borra el pasado para no repetirlo, para no
abandonar como tu padre, para no desanimarte como tu
madre, para no tratarte como te trataron ellos, pero
no los culpes porque nadie puede enseñar lo que no
sabe, perdónalos y te liberarás de esas cadenas.

Si estás atento al presente, el pasado no te
distraerá, entonces serás siempre nuevo. Tienes el
poder para ser libre en este mismo momento, el
poder está siempre en el presente porque toda la vida
está en cada instante, pero no digas "no puedo" ni en
broma porque el inconsciente no tiene sentido
de humor, lo tomará en serio y te lo recordará cada
vez que lo intentes.

Si quieres recuperar la salud abandona la crítica, el
resentimiento y la culpa, responsables de nuestras
enfermedades.

Perdona a todos y perdónate, no hay liberación más
grande que el perdón, no hay nada como vivir sin
enemigos. Nada peor para la cabeza y por lo tanto
para el cuerpo, que el miedo, la culpa, el sentimiento
y la crítica que te hace juez (agotadora y vana tarea)
y cómplice de lo que te disgusta.

Culpar a los demás es no aceptar la responsabilidad de
nuestra vida, es distraerse de ella.

El bien y el mal viven dentro de ti, alimenta más al
bien para que sea el vencedor cada vez que tengan que
enfrentarse. Lo que llamamos problemas son lecciones,
por eso nada de lo que nos sucede es en vano.

No te quejes, recuerda que naciste desnudo, entonces
ese pantalón y esa camisa que llevas ya son ganancia.
Cuida el presente porque en él vivirás el resto de tu
vida. Libérate de la ansiedad, piensa que lo que debe
ser será, y sucederá naturalmente.


Facundo Cabral


¿Quieres saber más sobre Facundo Cabral?