AOP con Spring framework

Introducción

¿Qué es AOP?

Aspect-Oriented Programming (AOP) es un paradigma de programación que nos permite separar «aspectos» o «intenciones» de nuestro software en diferentes módulos según su responsabilidad. De esta manera puede verse como otra herramienta para poder diferenciar en nuestro código las diferentes necesidades, encapsulando los diferentes conceptos como ser los requerimientos funcionales, seguridad, profiling de tiempos, transaccionabilidad contra una base de datos, logging, entre otros.

En Wikipedia ofrecen una definición bastante completa de los términos básicos utilizados en el mundo AOP:

  • Aspect (Aspecto) es una funcionalidad transversal (cross-cutting) que se va a implementar de forma modular y separada del resto del sistema. El ejemplo más común y simple de un aspecto es el logging (registro de sucesos) dentro del sistema, ya que necesariamente afecta a todas las partes del sistema que generan un suceso.
  • Join point (Punto de Cruce o de Unión) es un punto de ejecución dentro del sistema donde un aspecto puede ser conectado, como una llamada a un método, el lanzamiento de una excepción o la modificación de un campo. El código del aspecto será insertado en el flujo de ejecución de la aplicación para añadir su funcionalidad.
  • Advice (Consejo) es la implementación del aspecto, es decir, contiene el código que implementa la nueva funcionalidad. Se insertan en la aplicación en los Puntos de Cruce.
  • Pointcut (Puntos de Corte) define los Consejos que se aplicarán a cada Punto de Cruce. Se especifica mediante Expresiones Regulares o mediante patrones de nombres (de clases, métodos o campos), e incluso dinámicamente en tiempo de ejecución según el valor de ciertos parámetros.
  • Introduction (Introducción) permite añadir métodos o atributos a clases ya existentes. Un ejemplo en el que resultaría útil es la creación de un Consejo de Auditoría que mantenga la fecha de la última modificación de un objeto, mediante una variable y un método setUltimaModificacion(fecha), que podrían ser introducidos en todas las clases (o sólo en algunas) para proporcionarlas esta nueva funcionalidad.
  • Target (Destinatario) es la clase aconsejada, la clase que es objeto de un consejo. Sin AOP, esta clase debería contener su lógica, además de la lógica del aspecto.
  • Proxy (Resultante) es el objeto creado después de aplicar el Consejo al Objeto Destinatario. El resto de la aplicación únicamente tendrá que soportar al Objeto Destinatario (pre-AOP) y no al Objeto Resultante (post-AOP).
  • Weaving (Tejido) es el proceso de aplicar Aspectos a los Objetos Destinatarios para crear los nuevos Objetos Resultantes en los especificados Puntos de Cruce. Este proceso puede ocurrir a lo largo del ciclo de vida del Objeto Destinatario:
    • Aspectos en Tiempo de Compilación, que necesita un compilador especial.
    • Aspectos en Tiempo de Carga, los Aspectos se implementan cuando el Objeto Destinatario es cargado. Requiere un ClassLoader especial.
    • Aspectos en Tiempo de Ejecución.

AOP con Spring Framework

Spring Framework nos ofrece un potencial muy interesante, utilizando el framework de AOP AspectJ, y permitiéndonos usarlo declarando beans muy similares a los tradicionales, y ofreciendo la suficiente flexibilidad para la gran mayoría de los escenarios.
Podemos modificar o agregar comportamiento de nuestros beans en diferentes momentos de la invocación:

  • Antes de invocar a un metodo.
  • Luego de invocar un método, si retornó OK.
  • Luego de invocar un método, si lanzó excepción.
  • Reemplazar la ejecución de un método.

Ejemplos de uso

A continuación veremos algunos casos de uso típicos en los que AOP aplica como solución.

Transaccionabilidad contra una base de datos

Escribí otro post que se centra en este tema, y uno de los enfoques que plantea para resolver esta problemática es definir las transacciones de forma declarativa utilizando AOP.

Profiling

Supongamos que queremos medir y enviar a un log el tiempo que demora la invocación a un conjunto de métodos de nuestras clases. Una opción sería agregar un cronómetro en cada uno de los métodos a monitorear -tomando el tiempo al iniciar, y tomando nuevamente el tiempo en un finally antes de retornar-. Otra opción es crear un aspecto al cual le especificamos qué métodos serán los que tiene que cronometrar.

Definiremos entonces una clase totalmente aislada del resto de la lógica de nuestro sistema, encargada de iniciar un cronómetro, ejecutar el método, parar el cronómetro y enviar a System.out el tiempo insumido.

<br />
package demo.aop;</p>
<p>import org.<br />
aspectj.lang.ProceedingJoinPoint;<br />
import org.springframework.util.StopWatch;</p>
<p>public class AopProfiler {</p>
<p>	public Object doProfile(ProceedingJoinPoint call) throws Throwable {</p>
<p>		StopWatch clock = new StopWatch(&quot;Started profiling&quot;);</p>
<p>		try {<br />
			clock.start(call.toShortString());<br />
			return call.proceed();<br />
		} finally {<br />
			clock.stop();<br />
			System.out.println(clock.prettyPrint());<br />
		}<br />
	}<br />
}<br />

Utilizando Spring y AspectJ, la única restricción impuesta a la clase que define el aspecto es que tenga un método que recibe un objeto de tipo ProceedingJoinPoint y que lance Throwable; no son importantes ni el nombre de la clase ni el del método.

La configuración de los beans en Spring quedaría de la siguiente forma:

<br />
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br />
&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;<br />
	xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;<br />
	xmlns:aop=&quot;http://www.<br />
springframework.org/schema/aop&quot;<br />
	xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd<br />
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd&quot;&gt;</p>
<p>	&lt;bean name=&quot;aopProfiler&quot; class=&quot;demo.aop.AopProfiler&quot; /&gt;</p>
<p>	&lt;aop:config&gt;<br />
		&lt;aop:aspect ref=&quot;aopProfiler&quot;&gt;<br />
			&lt;aop:pointcut id=&quot;pointcut&quot; expression=&quot;execution(public * demo.dao.PersonDAOImpl.getById(..))&quot; /&gt;<br />
			&lt;aop:around method=&quot;doProfile&quot; pointcut-ref=&quot;pointcut&quot; /&gt;<br />
		&lt;/aop:aspect&gt;<br />
	&lt;/aop:config&gt;<br />
&lt;/beans&gt;<br />

Lo destacable de esta configuración son los namespaces que agregamos en el elemento para soportar los beans especiales para la configuración de AOP. El bean llamado «aopProfiler» no tiene nada de especial, simplemente es una referencia a la clase antes definida. La magia ocurre en el bean , en donde definimos el aspecto. define el pointcut del aspecto. Este pointcut en particular significa que el aspecto se va a ejecutar cada vez que ejecutemos el método getById de la clase demo.dao.PersonDAOImpl, sin importar qué parametros le pasemos. El elemento describe el comportamiento del aspecto; cuando se detecte una invocación a este método, el framework desviará la llamada al método doProfile de la clase definida en el bean aopProfiler. Cabe notar que parte de la implementación de este aspecto es invocar al método original (invocando el método org.aspectj.lang.ProceedingJoinPoint.proceed()), pero no es mandatorio.

Logging

Otra aplicación de AOP interesante podría ser registrar las invocaciones a cada método de un conjunto determinado de paquetes, clases o métodos de nuestra aplicación. Adaptando el ejemplo anterior no sería muy difícil implementar un aspecto de logging.
Podríamos darle una funcialidad extra, registrando además los parámetros de la invocación; el método org.aspectj.lang.ProceedingJoinPoint.getArgs() nos abre esta posibilidad, retornando un Object[] con los parámetros de invocación.

Seguridad

El control de acceso a nuestros objetos es otra aplicación típica en las que AOP encaja de forma muy natural. En este caso no daremos ejemplos puntuales de implementación, sino que nos referiremos a un producto ya maduro y centrado especialmente en este punto: Spring Security.

Una de las funcionalidades disponibles en Spring Security es la configuración de restricciones de acceso a los métodos de nuestra lógica de negocios. Esta configuración de las restricciones se puede hacer mediante annotations como por ejemplo @Secured de la siguiente forma:

<br />
npublic interface BankService {</p>
<p>	@Secured(&quot;IS_AUTHENTICATED_ANONYMOUSLY&quot;)<br />
	public Account readAccount(Long id);</p>
<p>	@Secured(&quot;IS_AUTHENTICATED_ANONYMOUSLY&quot;)<br />
	public Account[] findAccounts();</p>
<p>	@Secured(&quot;ROLE_TELLER&quot;)<br />
	public Account post(Account account, double amount);<br />
}<br />

Otra forma posible -la que nos interesa destacar- es definiendo pointcuts específicos para este fin, de la forma:

<br />
&lt;global-method-security&gt;<br />
	&lt;protect-pointcut expression=&quot;execution(* com.mycompany.*Service.*(..))&quot; access=&quot;ROLE_USER&quot;/&gt;<br />
&lt;/global-method-security&gt;<br />

Este enfoque es particularmente potente; este ejemplo en particular nos permite definir en 3 líneas una restricción de acceso a todos los métodos de las clases llamadas *Service del paquete com.mycompany.

Por información más detallada, referirse a la documentación y ejemplos de Spring Security.

Conclusiones

Si bien se puede argumentar que el uso de las herramientas de AOP pueden impactar en la performance de una aplicación (aunque la performance no fue considerada en este post), nos abre un abanico de posiblidades en lo que tiene que ver con mejorar la claridad de nuestro código, dado que separamos la lógica de negocios de otros aspectos de nuestra aplicación como ser transaccionabilidad, logging, verificación de permisos de acceso, entre otros.
Gracias a esta separación de responsabilidades nuestra lógica que más simple de verificar, ya que es más fácil escribir POJOs -y sus correspondientes tests- que encapsulen las funciones para la que fueron concebidas.

Referencias

Monitoreo en Linux: nmon

Introducción

NMon (por Nigel’s MONitor) es un sistema de monitoreo para Linux y AIX. Nos permite ver en pantalla los diferentes indicadores de nuestro sistema, o hacerlo de forma no interactiva guardando todos los datos a un CVS para luego procesar y graficar los datos recabados.

No lo probé en AIX, pero en Linux corre sobre SLES9, SLES10, RHEL, Knoppix, Debian, Fedora, Ubuntu y hasta Gentoo con la versión anterior a la actual. Tiene soporte para las distribuciones x86, y para algunas distribuciones x86_64 y POWER.

Es gratis, muy simple de instalar (hay ejecutables para las diferentes distribuciones) y si bien no tiene soporte oficial por parte de IBM, está disponible para bajar desde la wiki de AIX de IBM.

Entre otros, tiene soporte para monitorear los siguientes datos de un sistema:

  • Uso de CPU
  • Uso de memoria
  • Estadísticas del kernel y de la cola de ejecución de procesos
  • I/O, transferencias, y tasas de lectura/escritura de los discos
  • Espacio libre en file systems
  • I/O, transferencias, y tasas de lectura/escritura de las interfaces de red
  • Paginado de memoria
  • Network File System (NFS)

Instalación

No tiene mayores dificultades, debemos bajar un archivo comprimido de aquí, dependiendo de nuestro hardware y versión del sistema operativo. Descomprimimos el archivo, damos permisos de ejecución (chmod +x) al ejecutable que concuerde con nuestra distribución de Linux/AIX y listo.

Uso interactivo

Si usamos NMon de forma interactiva, al ejecutarlo en una terminal veremos una pantalla similar a la siguiente:

<br />
+nmon-12a---------------------Hostname=server-vm----Refresh= 2secs ---09:45.39-+<br />
¦                                                                              ¦<br />
¦  ---------------------<br />
---------       For help type H or ...                 ¦<br />
¦  #    #  #    #   ####   #    #        nmon -?  - hint                       ¦<br />
¦  ##   #  ##  ##  #    #  ##   #        nmon -h  - full                       ¦<br />
¦  # #  #  # ## #  #    #  # #  #                                              ¦<br />
¦  #  # #  #    #  #    #  #  # #       To start the same way every time       ¦<br />
¦  #   ##  #    #  #    #  #   ##        set the NMON ksh variable             ¦<br />
¦  #    #  #    #   ####   #    #                                              ¦<br />
¦  ------------------------------                                              ¦<br />
¦                                                                              ¦<br />
¦  Use these keys to toggle statistics on/off:                                 ¦<br />
¦     c = CPU        l = CPU Long-term   - = Faster screen updates             ¦<br />
¦     m = Memory     j = Filesystems     + = Slower screen updates             ¦<br />
¦     d = Disks      n = Network         V = Virtual Memory<br />
               ¦<br />
¦     r = Resource   N = NFS             v = Verbose hints                     ¦<br />
¦     k = kernel     t = Top-processes   . = only busy disks/procs             ¦<br />
¦     h = more options                   q = Quit                              ¦<br />
¦------------------------------------------------------------------------------¦<br />

En la misma nos muestra las teclas de uso más comunes (con h nos muestra la lista completa):

<br />
¦ HELP ------------------------------------------------------------------------¦<br />
¦     key  --- statistics which toggle on/off ---                              ¦<br />
¦     h = This help information                                                ¦<br />
¦     r = RS6000/pSeries CPU/cache/OS/kernel/hostname details + LPAR           ¦<br />
¦     t = Top Process Stats 1=basic 3=CPU                                      ¦<br />
¦         u = shows command arguments (hit twice to refresh)                   ¦<br />
¦     c = CPU by processor<br />
  l = longer term CPU averages            ¦<br />
¦     m = Memory and Swap  stats       j = JFS Usage Stats                     ¦<br />
¦     n = Network stats                N = NFS                                 ¦<br />
¦     d = Disk I/O Graphs D=Stats      o = Disks %Busy Map                     ¦<br />
¦     k = Kernel stats &amp;amp; loadavg       V = Virtual Memory                      ¦<br />
¦     g = User Defined Disk Groups [start nmon with -g &amp;lt;filename&amp;gt;]             ¦<br />
¦     v = Verbose Simple Checks - OK/Warnings/Danger                           ¦<br />
¦     b = black &amp;amp; white mode                                                   ¦<br />
¦     --- controls ---                                                         ¦<br />
¦     + and - = double or half the screen refresh time                         ¦<br />
¦     q = quit                     space = refresh screen now                  ¦<br />
¦     . = Minimum Mode =display only busy disks and processes                  ¦<br />
¦     0 = reset peak counts to zero (peak = &amp;quot;&amp;gt;&amp;quot;)<br />
                             ¦<br />
¦     Developer Nigel Griffiths                                                ¦<br />
¦------------------------------------------------------------------------------¦<br />

A continuación veremos la salida de las opciones que a mi entender resultan más útiles:

Estadísticas del kernel (tecla k)

<br />
¦ Kernel Stats ----------------------------------------------------------------¦<br />
¦ RunQueue             -1   Load Average    CPU use since boot time            ¦<br />
¦ ContextSwitch       0.0    1 mins  0.71    Uptime Days=  0 Hours= 6 Mins=57  ¦<br />
¦ Forks               0.0    5 mins  0.34    Idle   Days=  0 Hours= 6 Mins=45  ¦<br />
¦ Interrupts        713.0   15 mins  0.16    Average CPU use=  2.83%           ¦<br />
¦------------------------------------------------------------------------------¦<br />

Uso de CPU (tecla c)

En esta gráfica con forma de barras horizontales, las U representan el tiempo de usuario, las s el tiempo de sistema y
las w el wait time. Los > registran los picos de CPU.

<br />
¦ CPU Utilisation -------------------------------------------------------------¦<br />
¦                           +-------------------------------------------------+¦<br />
¦CPU  User%  Sys% Wait% Idle|0          |25         |50          |75       100|¦<br />
¦ 1  53.6  31.4   0.0   14.9|UUUUUUUUUUUUUUUUUUUUUUUUUUsssssssssssssss &amp;gt;      |¦<br />
¦ 2  54.0  19.5   0.0   26.5|UUUUUUUUUUUUUUUUUUUUUUUUUUUsssssssss &amp;gt;           |¦<br />
¦                           +-------------------------------------------------+¦<br />
¦Avg 53.8  25.3   0.0   21.0|UUUUUUUUUUUUUUUUUUUUUUUUUUssssssssssss &amp;gt;         |¦<br />
¦                           +-------------------------------------------------+¦<br />
¦------------------------------------------------------------------------------¦<br />

Uso de memoria (tecla m)

<br />
¦ Memory Stats ----------------------------------------------------------------¦<br />
¦                RAM<br />
High      Low     Swap                                ¦<br />
¦ Total MB      3012.8     -0.0     -0.0   2055.1                              ¦<br />
¦ Free  MB        19.1     -0.0     -0.0   2055.1                              ¦<br />
¦ Free Percent     0.6%   100.0%   100.0%   100.0%                             ¦<br />
¦             MB                  MB                  MB                       ¦<br />
¦                      Cached=  2301.9     Active=  1717.3                     ¦<br />
¦ Buffers=   141.9 Swapcached=     0.0  Inactive =   962.1                     ¦<br />
¦ Dirty  =     3.6 Writeback =     0.0  Mapped   =  1346.4                     ¦<br />
¦ Slab   =    89.7 Commit_AS =   906.5 PageTables=    19.2                     ¦<br />
¦------------------------------------------------------------------------------¦<br />

Estadísticas de red (tecla n)

<br />
¦ Network I/O -----------------------------------------------------------------¦<br />
¦I/F Name Recv=KB/s Trans=KB/s packin packout insize outsize Peak-&amp;gt;<br />
Recv Trans  ¦<br />
¦    lo     8.6     8.6      37.0     37.0   238.6  238.6     1234.6  1234.6   ¦<br />
¦  eth0    44.3  1420.2     613.9   1140.8    73.8 1274.8       44.3  1420.2   ¦<br />
¦vmnet1     0.0     0.0       0.0      0.0     0.0    0.0        0.0     0.0   ¦<br />
¦vmnet8     0.0     0.0       0.0      0.0     0.0    0.0        0.0     0.0   ¦<br />
¦------------------------------------------------------------------------------¦<br />

Estadísticas de disco (teclas D y d)

Con la tecla d nos presenta la información de forma tabular:

<br />
¦ Disk I/O -----(/proc/diskstats)--------all data is Kbytes per second---------¦<br />
¦DiskName Busy    Read    Write       Xfers   Size  Peak%  Peak-RW    InFlight ¦<br />
¦sda        0%      0.0     48.0KB/s    6.5   7.0KB   13%    1883.9KB/s   0   |¦<br />
¦sda1       0%      0.0     48.0KB/s    6.5   7.0KB   12%    1883.9KB/s   0   |¦<br />
¦sdb       39%  14864.6     24.0KB/s  115.9 128.0KB  100%  126938.8KB/s   1   |¦<br />
¦sdb1       0%      0.0<br />
  0.0KB/s    0.0   0.0KB    0%       0.0KB/s   0   |¦<br />
¦sdb2      33%  14652.7     24.0KB/s  101.4 144.0KB  100%  124939.1KB/s   1   |¦<br />
¦sdb3       6%    211.9      0.0KB/s   14.5  14.0KB   13%    1999.6KB/s   0   |¦<br />
¦fd0        0%      0.0      0.0KB/s    0.0   0.0KB    0%       0.0KB/s   0   |¦<br />
¦------------------------------------------------------------------------------¦<br />

Con la tecla D nos presenta la información en forma de gráfica de barras horizontal. De forma similar a la gráfica de uso de CPU, las W representan escrituras en disco, las R lecturas en disco y los > registran los picos de transferencia:

<br />
¦ Disk I/O -----(/proc/diskstats)--------all data is Kbytes per second---------¦<br />
¦DiskName Busy  Read WriteKB|0          |25         |50          |75       100|¦<br />
¦sda        0%    0.0    4.0|      &amp;gt;                                          |¦<br />
¦sda1       0%    0.0    4.0|     &amp;gt;<br />
|¦<br />
¦sdb       43% 1916.5  393.7|WWWWRRRRRRRRRRRRRRRRRRR                          |¦<br />
¦sdb1       0%    0.0    0.0|&amp;gt;                                                |¦<br />
¦sdb2      30% 1688.7  393.7|WWWRRRRRRRRRRRRR                                 |¦<br />
¦sdb3      13%  227.8    0.0|RRRRRR&amp;gt;                                          |¦<br />
¦fd0        0%    0.0    0.0|&amp;gt;                                                |¦<br />
¦------------------------------------------------------------------------------¦<br />

Verbose Simple Checks (tecla d)

<br />
+nmon-12a---------------------Hostname=server-vm----Refresh= 2secs ---23:46.50-+<br />
¦ Verbose Mode ----------------------------------------------------------------¦<br />
¦ Code    Resource            Stats   Now        Warn    Danger                ¦<br />
¦     OK -&amp;gt; CPU               %busy   5.2%       &amp;gt;80%    &amp;gt;90%                  ¦<br />
¦     OK -&amp;gt; Top Disk          %busy   0.0%       &amp;gt;40%    &amp;gt;60%                  ¦<br />
¦------------<br />
------------------------------------------------------------------¦<br />

Capturar datos para análisis posterior

Si queremos capturar datos para posterior análisis, utilizamos la opción -f. La opción -s configura el período de muestreo, y la opción -c la cantidad de muestreos.

Por ejemplo, para obtener muestras cada 30 segundos durante una hora (120 muestras), ejecutamos:

<br />
nmon -f -s 30 -c 120<br />

Esto genera un archivo con nombre hostname_date_time.nmon con formato CSV, que luego puede ser interpretado por el NMon analyser. Por más info, ver la wiki de NMon analyser y la ayuda de NMon.

Referencias

Wiki de NMon
Wiki de NMon analyser
nmon performance: A free tool to analyze AIX and Linux performance
NMon en Wikipedia

Copiar archivos utilizando SCP en Linux

SCP (secure copy) es un comando de Linux que nos permite copiar directorios o archivos entre diferentes hosts que utiliza la autenticación SSH y por lo tanto provee el mismo nivel de seguridad.

Sintaxis

La sintaxis del comando, con las opciones más relevantes es las sigiuente:

scp [-p] [-v] [-r] [-C] [-i identity_file] [[username@]host:]file ... [[username@]host:]file_or_dir

Las descripción de las opciones es la siguiente:

  • -p: preserva las fechas de modificación, acceso y modo del archivo original.
  • -v: verbose mode. Habilita mensajes de debug para diagnosticar problemas de conexión, autenticación o configuración.
  • -r: modo recursivo al copiar directorios (copia también los subdirectorios)
  • -C: habilita la compresión en la conexión SSH
  • -i identity_file: selecciona el archivo desde el cual se lee una clave privada. Esta clave privada se pasa a SSH a la hora de establecer la conexión

Ejemplos de uso

Enviar un archivo a un host remoto

scp archivo.txt usuario@host:/ruta/de/destino/archivoDestino.txt

Envía archivo.txt a host, a la ruta /ruta/de/destino, y lo graba con el nombre archivoDestino.txt. La conexión se establecerá utilizando el nombre de usuario especificado, y el dueño del archivo en el host será el utilizado en la conexión.

scp archivo.txt usuario@host:archivoDestino.txt

Si no se especifica la ruta de destino, se copiará al directorio del usuario especificado (/home/usuario).

scp archivo.txt host:archivoDestino.txt

Si no se especifica un usuario remoto, utilizará el nombre con el que estamos logueados actualmente en el host local.

Copiar un archivo desde un host remoto

scp usuario@host:/ruta/archivoRemoto.txt ./archivo.txt

Copia archivoRemoto.txt del host remoto a mi directorio actual, y lo nombramos archivo.txt.

scp usuario@host:archivoRemoto.txt ./

Copia archivoRemoto.txt ubicado en el home de usuario del host remoto a mi ubicación actual.

Copiar un directorio entero hacia un host remoto

scp -r dirLocal usuario@host:/ruta/de/destino/

Este comando copia el directorio dirLocal a /ruta/de/destino en el host remoto, conectándonos como usuario. El directorio de destino ya debe de existir.

Otra opción es crear un archivo tar o tar comprimido (.tar.gz), copiar ese único archivo y descomprimirlo en el destino.

Copiar un directorio entero desde un host remoto

scp -r usuario@host:/ruta/dirRemoto/ /tmp/

Copia el directorio /ruta/dirRemoto ubicado en el host remoto, y lo copia en el directorio local /tmp

Copiar un archivo entre hosts remotos

Otra de las posiblidades del comando SCP es copiar un archivo (o directorio, similar a los ejemplos antes mostrados) desde un host remoto a otro host remoto.

scp usuario1@host1:/ruta/en/host1/archivoHost1.txt usuario2@host2:/ruta/en/host2/archivoHost2.txt

En este ejemplo, usuario1 es un usuario de host1, mientras que usuario2 es un usuario de host2.

Uso desde Windows

Si necesitamos copiar archivos o directorios desde un ambiente Windows podemos utilizar la excelente aplicación WinSCP, que nos provee una interfaz gráfica para mover, copiar, renombrar, cambiar permisos, etc. Su interfaz es muy intuitiva, y nos permite visualizar el contenido local y remoto con dos paneles al estilo Norton Commander o con otro estilo más parecido al explorador de Windows.

Problemas en Eclipse de proyectos Maven con dependencias a AspectJ

Hace unos días un compañero de trabajo yo nos encontramos con una situación un poco extraña utilizando Maven y AspectJ, digna de comaprtirla. En un proyecto Java en el que utilizamos Maven, algunas de las dependencias en el pom.xml eran las siguientes:

<br />
&lt;dependency&gt;<br />
    &lt;groupId&gt;aspectj&lt;/groupId&gt;<br />
    &lt;artifactId&gt;aspectjrt&lt;/artifactId&gt;<br />
    &lt;version&gt;1.5.3&lt;/version&gt;<br />
&lt;/dependency&gt;<br />
&lt;dependency&gt;<br />
    &lt;groupId&gt;aspectj&lt;/groupId&gt;<br />
    &lt;artifactId&gt;aspectjtools&lt;/artifactId&gt;<br />
    &lt;version&gt;1.5.3&lt;/version&gt;<br />
&lt;/dependency&gt;<br />
&lt;dependency&gt;<br />
    &lt;groupId&gt;aspectj&lt;/groupId&gt;<br />
    &lt;artifactId&gt;aspectjweaver&lt;/artifactId&gt;<br />
    &lt;version&gt;1.5.3&lt;/version&gt;<br />
&lt;/dependency&gt;<br />

Sin embargo, al hacer un mvn eclipse:eclipse en la PC de mi compañero, esas dependencias no se veían reflejadas en el proyecto de Eclipse. La salida del comando de
Maven no mostraba errores, e inclusive bajaba los JARs de AspectJ al repositorio local, y sin embargo, no había rastros de esas dependencias en el Build path del proyecto. En mi PC no había problemas, las dependencias se bajaban y referenciaban de forma correcta.

Probamos diferentes versiones de Maven (2.1.0 y 2.2.0), pero no se solucionó. Probamos diferentes versiones de las dependencias de AspectJ, y tampoco tuvimos suerte. Después de buscar un poco encontramos un par de bugs reportados, en este link, este link y este otro, y comprendimos que el problema venía por el lado del plugin maven-eclipse-plugin de Maven, y no por el lado de nuestro proyecto. Comprobamos que este error se da utlizando las versiones posteriores a la 2.5.1 del plugin (2.6 en adelante), y que las diferencias en nuestros ambientes de
desarrollo se daban porque yo tenía configurado un proxy HTTP, que me retornaba una versión vieja del maven-metadata-central.xml del plugin. En cuanto saqué la configuración del proxy del settings.xml de Maven, Maven actualizó los JARs del plugin en mi PC, y ambos ambientes reflejaron el mismo problema.

El problema se da cuando el soporte para AJDT está activado. Para solucionarlo, debemos agregar la línea <ajdtVersion>none</ajdtVersion> a la configuración de maven-eclipse-plugin en el pom.xml de nuestro proyecto:

<br />
&lt;project ...&gt;<br />
	...<br />
	&lt;build&gt;<br />
		&lt;plugins&gt;<br />
			...<br />
			&lt;plugin&gt;<br />
				&lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;<br />
				&lt;artifactId&gt;maven-eclipse-plugin&lt;/artifactId&gt;<br />
				&lt;configuration&gt;<br />
					...<br />
					&lt;ajdtVersion&gt;none&lt;/ajdtVersion&gt;<br />
					...<br />
				&lt;/configuration&gt;<br />
			&lt;/plugin&gt;<br />
			...<br />
		&lt;/plugins&gt;<br />
	&lt;/build&gt;<br />
	...<br />
&lt;/project&gt;<br />

Referencias

https://fisheye.codehaus.org/browse/MECLIPSE-544
https://fisheye.codehaus.org/browse/MECLIPSE-558
https://bugs.eclipse.org/bugs/show_bug.cgi?id=270554
http://dev.eclipse.org/newslists/news.eclipse.technology.ajdt/msg01933.html

http://maven.apache.org/plugins/maven-eclipse-plugin/examples/ajdt-projects.html

Hotkeys del símbolo de sistema de Windows

El símbolo del sistema de Windows (también conocido como command prompt o cmd.exe) tiene algunas hotkeys interesantes para acelerar un poco su manejo:

  • Flecha arriba, flecha abajo: recorren el historial de comandos previamente ingresados.
  • TAB: parecido a las terminales en Linux (por ejemplo bash), la tecla TAB permite completar el nombre de un directorio o un archivo. El símbolo de sistema propone nombres de directorios/archivos dependiendo de los caracteres previamente ingresados, y de la ruta en donde estemos situados a la hora de escribir el comando.
  • F1: Repite los caracteres del comando anterior, un caracter a la vez.
  • F2: Copia los caracteres hasta la primera ocurrencia de un caracter ingresado en el cuadro de diálogo presentado (no incluye ese caracter).
  • F3: Repite el comando anterior.
  • F4: Elimina los caracteres que están luego del cursor, hasta la primera ocurrencia de un caracter ingresado en el cuadro de diálogo presentado (no incluye ese caracter).
  • F5: Muestra el comando anterior, según el historial de comandos (la misma funcionalidad que la tecla de flecha hacia arriba).
  • F6: Introduce un Ctrl+Z (EOF)
  • F7: A mi entender, este es uno de los más interesantes: despliega el historial de comandos en un cuadro de diálogo. Permite seleccionar uno de los comandos, y lo ejecuta si lo seleccionamos con ENTER, o lo presenta en la consola si lo seleccionamos con flecha izquierda o flecha derecha.
  • F8: Cada vez que presionemos esta tecla muestra un comando del historial -empezando por el  más antiguo-. Si tenemos alguna letra escrita en la consola, esa iteración por los comandos se filtra, mostrando sólo los que empiezan con esos caracteres.
  • F9: Presenta un diálogo para seleccionar un número de comando, donde 0 es el primero (más viejo).

Por defecto la cantidad de comandos guardados en el historial son 50. Esto se puede configurar en las propiedades del símbolo de sistema, aumentando el valor de «Tamaño del búfer».

Crear un nuevo proyecto Java con Maven

El plugin archetype de Maven nos permite crear un proyecto de Maven 2 a partir de un template existente.

Para crear un proyecto Java simple (directorio de código fuente, directorio de código fuente para tests, clase de ejemplo, clase de test de ejemplo y pom.xml) utilizamos el goal archetype:create en el directorio padre del proyecto, de la siguiente manera:

<br />
mvn archetype:create -DgroupId=com.josearrarte -DartifactId=test<br />

Este comando crea el proyecto con un POM como el siguiente:

<br />
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot;<br />
  xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;<br />
  xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd&quot;&gt;</p>
<p>	&lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;<br />
	&lt;groupId&gt;com.josearrarte&lt;/groupId&gt;<br />
	&lt;artifactId&gt;test&lt;/artifactId&gt;<br />
	&lt;packaging&gt;jar&lt;/packaging&gt;<br />
	&lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;<br />
	&lt;name&gt;test&lt;/name&gt;<br />
	&lt;url&gt;http://maven.apache.org&lt;/url&gt;</p>
<p>	&lt;dependencies&gt;<br />
		&lt;dependency&gt;<br />
			&lt;groupId&gt;junit&lt;/groupId&gt;<br />
			&lt;artifactId&gt;junit&lt;/artifactId&gt;<br />
			&lt;version&gt;3.8.1&lt;/version&gt;<br />
			&lt;scope&gt;test&lt;/scope&gt;<br />
		&lt;/dependency&gt;<br />
	&lt;/dependencies&gt;<br />
&lt;/project&gt;<br />

La estructura de directorios generada queda:

<br />
(root)<br />
|   pom.xml<br />
|<br />
---src<br />
    +---main<br />
    |   ---java<br />
    |       ---com<br />
    |           ---josearrarte<br />
    |                   App.java<br />
    |<br />
    ---test<br />
        ---java<br />
            ---com<br />
                ---josearrarte<br />
                        AppTest.java<br />

Otros posibles goals del plugin archetype son los siguientes:

  • archetype:generate muesta un catálogo de plantillas y pide al usuario que seleccione uno. Luego de un conjunto de pasos variables (según la cantidad de parámetros pedidos al usuario), el plugin se baja la plantilla, procesa los parámetros y genera un projecto Maven.
  • archetype:create-from-project crea una nueva plantilla a partir de un proyecto existente.
  • archetype:crawl: escanea el repositorio en búsqueda de nuevos templates y actualiza el catálogo

Más info:

Eliminar elementos de un XML utilizando XSLT

Introducción

XSLT (eXtensible Stylesheet Language Transformations) es un estándar de la W3C basado en XML que permite transformar un XML en un documento de otro tipo: otro XML, HTML, texto, etc. El estándar XSLT está basado en plantillas (templates) que no son más que XMLs que cumple un esquema determinado. Dentro de estos XMLs, se describe cómo transformar los diferentes elementos que componen el documento de origen, utilizando el estándar XPath para asociar los elementos del documento de origen a la salida de la transformación

Una transformación XLST está compuesta por los siguientes elementos:

  • Un documento XML de origen
  • Una plantilla XLST
  • Un motor de procesamiento de plantillas XSLT
  • Un documento resultante de la transformación

El motor toma como entrada una plantilla y un XML de origen y retorna como resultado otro documento (ver diagrama en Wikipedia).

El lenguaje de XSLT no es imperativo, las acciones a realizar se declaran en un conjunto de reglas que definen cómo actuar cuando un nodo coincide con la expresión XPath definida para esa regla. De esta forma el motor, luego de haber procesado el documento de entrada y armado una especie de árbol con esa estructura, parte del nodo raíz del XML y ejecuta las reglas que mejor apliquen para cada elemento, siendo el resultado de esta ejecución el documento de salida.

Eliminar elementos del XML

Si queremos eliminar elementos de un XML existente, podemos utilizar una plantilla XSLT para transformarlo y eliminar el contenido que no necesitemos.

Veamos el siguiente ejemplo: tenemos un XML con un conjunto de empleados, en donde cada elemento tiene un nombre (elemento compuesto), un e-mail y una relación de dependencia con otro(s) empleado(s), que puede ser como subordinado o como jefe. Queremos procesar ese XML y retornar otro XML que
no contenga el apellido o información de dependencia dentro de la empresa. Además, queremos sacar a “Big Boss” de esa lista.

El XML de entrada es el siguiente:

<br />
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br />
&lt;personnel&gt;<br />
    &lt;person id=&quot;Big.Boss&quot;&gt;<br />
        &lt;name&gt;<br />
            &lt;family&gt;Boss&lt;/family&gt;<br />
            &lt;given&gt;Big&lt;/given&gt;<br />
        &lt;/name&gt;<br />
        &lt;email&gt;chief@email.com&lt;/email&gt;<br />
        &lt;link subordinates=&quot;one.worker two.worker three.worker four.worker five.worker&quot;/&gt;<br />
    &lt;/person&gt;<br />
    &lt;person id=&quot;one.worker&quot;&gt;<br />
        &lt;name&gt;<br />
            &lt;family&gt;Worker&lt;/family&gt;<br />
            &lt;given&gt;One&lt;/given&gt;<br />
        &lt;/name&gt;<br />
        &lt;email&gt;one@email.com&lt;/email&gt;<br />
        &lt;link manager=&quot;Big.Boss&quot;/&gt;<br />
    &lt;/person&gt;<br />
    &lt;person id=&quot;two.worker&quot;&gt;<br />
        &lt;name&gt;<br />
            &lt;family&gt;Worker&lt;/family&gt;<br />
            &lt;given&gt;Two&lt;/given&gt;<br />
        &lt;/name&gt;<br />
        &lt;email&gt;two@email.com&lt;/email&gt;<br />
        &lt;link manager=&quot;Big.Boss&quot;/&gt;<br />
    &lt;/person&gt;<br />
    &lt;person id=&quot;three.worker&quot;&gt;<br />
        &lt;name&gt;<br />
            &lt;family&gt;Worker&lt;/family&gt;<br />
            &lt;given&gt;Three&lt;/given&gt;<br />
        &lt;/name&gt;<br />
        &lt;email&gt;three@email.com&lt;/email&gt;<br />
        &lt;link manager=&quot;Big.Boss&quot;/&gt;<br />
    &lt;/person&gt;<br />
    &lt;person id=&quot;four.worker&quot;&gt;<br />
        &lt;name&gt;<br />
            &lt;family&gt;Worker&lt;/family&gt;<br />
            &lt;given&gt;Four&lt;/given&gt;<br />
        &lt;/name&gt;<br />
        &lt;email&gt;four@email.com&lt;/email&gt;<br />
        &lt;link manager=&quot;Big.Boss&quot;/&gt;<br />
    &lt;/person&gt;<br />
    &lt;person id=&quot;five.worker&quot;&gt;<br />
        &lt;name&gt;<br />
            &lt;family&gt;Worker&lt;/family&gt;<br />
            &lt;given&gt;Five&lt;/given&gt;<br />
        &lt;/name&gt;<br />
        &lt;email&gt;five@email.com&lt;/email&gt;<br />
        &lt;link manager=&quot;Big.Boss&quot;/&gt;<br />
    &lt;/person&gt;<br />
&lt;/personnel&gt;<br />

Una solución para el problema sería tener una plantilla XLST como la siguiente:

<br />
&lt;?xml version=&quot;1.0&quot; encoding=&quot;iso-8859-1&quot; ?&gt;<br />
&lt;xsl:stylesheet version=&quot;1.0&quot; xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&gt;</p>
<p>	&lt;xsl:output omit-xml-declaration=&quot;yes&quot; method=&quot;xml&quot; media-type=&quot;xml&quot; indent=&quot;yes&quot;/&gt;<br />
	&lt;xsl:strip-space elements=&quot;*&quot;/&gt;</p>
<p>	&lt;xsl:template match=&quot;node()|@*&quot;&gt;<br />
		&lt;xsl:copy&gt;<br />
			&lt;xsl:apply-templates select=&quot;node()|@*&quot;/&gt;<br />
		&lt;/xsl:copy&gt;<br />
	&lt;/xsl:template&gt;</p>
<p>	&lt;xsl:template match=&quot;/personnel/person/name/family&quot;/&gt;<br />
	&lt;xsl:template match=&quot;/personnel/person/link&quot;/&gt;<br />
	&lt;xsl:template match=&quot;/personnel/person[@id='Big.Boss']&quot;/&gt;<br />
&lt;/xsl:stylesheet&gt;<br />

En el XLST tenemos por un lado los <xsl:template> que aplican para casos bien puntuales (cuando el nodo visitado es coincide con la expresión XPath) y actúan ignorando ese elemento sin escribirlo al documento de salida. Por otro lado está <xsl:template match="node()|@*">, que actúa como regla para el resto de los nodos, copiando su contenido y continuando la transformación en sus hijos.

En <xsl:output> configuramos el tipo de documento de salida, la indentación, etc. Si interesa que el XML resultante quede del menor tamaño posible, podemos eliminar la indentación (indent="no") y ahorrarnos alguna línea y algún tabulador.

La línea que contiene <xsl:strip-space elements="*"/> elimina las líneas en blanco que deja la transformación en donde originalmente estaban ubicados los elementos eliminados.

El resultado de la transformación es el siguiente:

<br />
&lt;personnel&gt;<br />
   &lt;person id=&quot;one.worker&quot;&gt;<br />
      &lt;name&gt;<br />
         &lt;given&gt;One&lt;/given&gt;<br />
      &lt;/name&gt;<br />
      &lt;email&gt;one@email.com&lt;/email&gt;<br />
   &lt;/person&gt;<br />
   &lt;person id=&quot;two.worker&quot;&gt;<br />
      &lt;name&gt;<br />
         &lt;given&gt;Two&lt;/given&gt;<br />
      &lt;/name&gt;<br />
      &lt;email&gt;two@email.com&lt;/email&gt;<br />
   &lt;/person&gt;<br />
   &lt;person id=&quot;three.worker&quot;&gt;<br />
      &lt;name&gt;<br />
         &lt;given&gt;Three&lt;/given&gt;<br />
      &lt;/name&gt;<br />
      &lt;email&gt;three@email.com&lt;/email&gt;<br />
   &lt;/person&gt;<br />
   &lt;person id=&quot;four.worker&quot;&gt;<br />
      &lt;name&gt;<br />
         &lt;given&gt;Four&lt;/given&gt;<br />
      &lt;/name&gt;<br />
      &lt;email&gt;four@email.com&lt;/email&gt;<br />
   &lt;/person&gt;<br />
   &lt;person id=&quot;five.worker&quot;&gt;<br />
      &lt;name&gt;<br />
         &lt;given&gt;Five&lt;/given&gt;<br />
      &lt;/name&gt;<br />
      &lt;email&gt;five@email.com&lt;/email&gt;<br />
   &lt;/person&gt;<br />
&lt;/personnel&gt;<br />

Conclusión

XSLT nos da una infinidad de posibilidades a la hora de transformar un XML a la salida deseada. Este es un ejemplo bastante simple, pero con 16 líneas de XLST y algunas más de código para instanciar un procesador y configurarle la transformación, cumplimos el objetivo con la posibilidad de cambiar o expandir el XML original sin afectar el documento transformado. Además tiene un plus haberlo logrado de forma eficiente y basándonos en estándares.

Referencias

http://en.wikipedia.org/wiki/XSLT
http://www.w3.org/TR/xslt

Monitoreo en linux: top

Mi idea original era hacer un post con un resumen de los comandos de Linux que pueden ser utilizados para diagnosticar algún problema de CPU, memoria o I/O; generalmente este conjunto de comandos está formado por top, iostat, vmstat, netstat, telnet, tail de algún log, cat/grep de algún archivo, y algún otro. Cuando empecé a escribir el post empezó quedar enorme, así que voy a separarlo en pedazos, y hacer algo así como una serie de posts sobre este tema.

El comando top nos provee una vistá dinámica y en tiempo real con la cantidad y estado de los procesos corriendo actualmente, memoria, espacio de swap y los recursos utilizados por cada proceso.

La interfaz es actualizada cada cierto período de tiempo (por defecto, 3segundos). Despliega un resumen del estado del sistema y una lista de los procesos corriendo, de la siguiente manera:

<br />
top - 16:26:10 up  2:53,  1 user,  load average: 0.01, 0.01, 0.00<br />
Tasks:  46 total,   2<br />
running,  44 sleeping,   0 stopped,   0 zombie<br />
Cpu(s):  0.3%us,  0.3%sy,  6.0%ni, 93.0%id,  0.3%wa,  0.0%hi,  0.0%si,  0.0%st<br />
Mem:    252692k total,   248656k used,     4036k free,    19440k buffers<br />
Swap:   506036k total,       44k used,   505992k free,   188384k cached</p>
<p>  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND<br />
 3365 p2p       39  19 42560  21m 4716 S  6.3  8.9   3:32.54 mlnet<br />
 4076 root      20   0  2324 1120  888 R  0.3  0.4   0:00.11 top<br />
    1 root      20   0  1656  496  456 S  0.0  0.2   0:00.38 init<br />
    2 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 kthreadd<br />
    3 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 ksoftirqd/0<br />
    4 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 events/0<br />
    5 root      15  -5     0    0    0 S  0.0  0.0   0:00.03 khelper<br />
  163 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 kblockd/0<br />

Resumen del estado del sistema

En la primer línea tenemos la fecha y hora actual, la cantidad de
usuarios utilizando el sistema y la carga del sistema del último minuto, de los últimos 5 minutos y de los últimos 15 minutos respectivamente. Cómo se calcula el load average es un tema en sí mismo, pero básicamente es el promedio de la cantidad de procesos corriendo o prontos para correr en cierto período de tiempo.

Lo que tenemos que saber que a mayor load average, mayor uso de procesador. Un load average de 0 indica que el procesador ha sido muy poco utilizado en ese período de tiempo, mientras que si es mayor, significa que hay más procesos corriendo y prontos para correr que lo que el(los) core(s) pueden procesar. Un load average igual a la cantidad de cores indica un uso óptimo del CPU.  Más info acá y acá.

En la segunda línea (Tasks) tenemos la cantidad de procesos y una agregación según el estado de cada uno. Los diferentes estados que muestra son los siguientes:

  • Running: procesos corriendo actualmente, o listos para correr en cuanto se les asigne tiempo de CPU.
  • Sleeping: el proceso está dormido esperando que ocurra un evento para volver al estado “running”.
  • Stopped: La ejecución del proceso está parada; no está corriendo, y no va a volver a correr. Los procesos generalmente entran en este estado cuando reciben señales que no están manejando, y la acción por defecto de las mismas es pasar el proceso a stopped. Esto incluye señales como SIGSTOP, SIGTSTP, SIGTTIN, y SIGTTOU. Una señal de tipo SIGCONT saca al proceso de este estado (ver el comando fg). Con Ctrl+Z mandamos el proceso corriendo en la terminal al background, pasando a estado stopped.
  • Zombie: El proceso tampoco está corriendo. Los procesos quedan en este estado cuando su el proceso que los inició murió, ya sea por un error de programación o porque fue matado (ver kill -9).

La tercera línea nos da los
porcentajes de uso de procesador, discriminado por “tipo” de uso. Los diferentes tipos significan lo siguiente:

  • us: tiempo de procesos de usuario
  • sy: tiempo de procesos del sistema (kernel)
  • ni: tiempo de procesos del usuario que tienen un “nice” positivo
  • wa: tiempo en el cual los procesos están esperando por pedidos de I/O pendientes.
  • id: tiempo “idle”, en que no hay procesos requiriendo tiempo de procesador, y tampoco hay pedidos de I/O pendientes.
  • st: “steal time”, sólo aplica cuando nuestro Linux corre en una máquina virtual. Es el tiempo que algún proceso de nuestro sistema estaba esperando en la cola de ejecución, pero el hypervisor eligió no darnos tiempo de procesador, y asignarlo a otro procesador virtual.

Si presionamos la tecla ‘1’, top nos muestra las estadísticas de uso discriminado por cada core/procesador:

<br />
top - 18:57:22 up 12 days,  5:09,  1 user,  load average: 0.03, 0.03, 0.00<br />
nTasks: 174 total,   1 running, 173 sleeping,   0 stopped,   0 zombie<br />
Cpu0  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st<br />
Cpu1  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st<br />
Cpu2  :  0.0%us,  0.3%sy,  0.0%ni, 99.7%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st<br />
Cpu3  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st<br />
Cpu4  :  0.0%us,  0.3%sy,  0.0%ni, 99.7%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st<br />
Cpu5  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st<br />
Cpu6  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st<br />
Cpu7  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st<br />

La línea siguiente (Mem) detalla las estadísticas de uso de memoria. En ella vemos la memoria total, la memoria utilizada, la memoria libre y la memoria utilizada por como buffers.
Mem:    252692k total,   248656k used,     4036k free,    19440k buffers

La última de las líneas del
resumen (Swap) detalla el uso del espacio de swap. Indica cuánto es el espacio de swap total, cuánto está utilizado, cuánto libre y cuánto está siendo utilizado por páginas cacheadas
Swap:   506036k total,       44k used,   505992k free,   188384k cached

Lista de procesos

Luego del resumen del uso de los recursos del sistema top lista los procesos activos, ordenándolos según el uso de procesador.

Las columnas tienen el siguiente significado:

  • PID: Process ID
  • USER: usuario que inició el proceso
  • PR: prioridad del proceso
  • NI: nice value. Un valor negativo significa mayor prioridad (hasta -20), un valor positivo, menor prioridad (hasta 19)
  • VIRT: Cantidad de memoria virtual utilizada por el proceso (incluyendo datos, código, shared libraries y swap)
  • RES: Cantidad de memoria RAM física que el proceso está utilizando
  • SHR: Cantidad de memoria compartida.
    Refleja la memoria que potencialmente podría ser compartida con otros procesos.
  • S: Status del proceso. Los posibles estados son ‘D’ (uninterruptible sleep), ‘R’ (running), ‘S’ (sleeping), ‘T’ (traced o stopped) o ‘Z’ (zombie).
  • %CPU: porcentaje de CPU utilizado desde la última actualización de la pantalla.
  • %MEM: porcentaje de memoria física utilizada por el proceso
  • TIME+: Tiempo total de CPU que el proceso ha utilizado desde que se inició.
  • COMMAND: comando utilizado para iniciar el proceso.

Se pueden agregar, quitar o cambiar el orden de estas columnas con las teclas f y o.

Interacción con top

Podemos utilizar las siguientes teclas para interactuar con top:

  • M – Ordenar por uso de memoria
  • P – Ordenar por uso de CPU
  • T – Ordenar por tiempo de CPU utilizado
  • F – seleccionar campo por el cual ordenar la lista de procesos
  • i  – mostrar u ocultar procesos idle y zombie
  • m, l, t, 1 – muestra u oculta las líneas del resumen (parte de arriba)
  • f, o – agregar/quitar columnas, cambiar el orden
  • s – cambia el tiempo de actualización de la pantalla (por defecto, 3 segundos)
  • z – Colores
  • k – Matar un proceso (luego pregunta el PID)
  • r – “renice” cambia el nice value de un proceso (luego pregunta el PID)
  • q – finalizar
  • h – ayuda

Hay algunas más, que se pueden ver en la ayuda del comando o en las man pages.

Referencias

Audio y video en Java utilizando ffmpeg, Jffmpeg, y JMF

Introducción

Supongamos que queremos implementar un reproductor multimedia en Java. Si a priori no conocemos los codecs de audio o video que debemos soportar, o si simplemente no existe una implementación de ese codec en Java, podemos interactuar con ffmpeg para reproducir multimedia en un montón de formatos diferentes. Para ello podemos utilizar JMF, Jffmpeg del lado del “mundo Java” interactuando con ffmpeg del lado del “mundo nativo”.

ffmpeg es una solución muy completa, open source y multi plataforma para grabar, convertir y reproducir audio y video. El proyecto está licenciado bajo LGPL o GPL (dependiendo de la configuración).

JMF (Java Media Framework) es una API  que permite agregar audio y video a nuestras aplicaciones y applets implementadas sobre tecnología Java. Además de reproducir, JMF nos permite
capturar, transcodificar o hacer streaming en varios formatos.

Jffmpeg es el puente entre ffmpeg y JMF. Si bien JMF soporta algunos formatos, eventualmente nos cruzaremos con el mensaje de error «Unable to handle format:…», especialmente al intentar reproducir los formatos más nuevos. Este plugin de JMF un wrapper Java que utiliza JNI para hacer las llamadas directas al código nativo de ffmpeg.

Instalación en Linux

Vamos a instalar y configurar las diferentes partes de la solución para poder reproducir video en Linux. Quizá el post tienda a compilar todo y configurar “a mano”, es debido a que documenta la necesidad de reproducción de pautas publicitarias en un NLPOS, un flavour de Linux de Novell bastante recortado y orientado a puntos de venta.

1. Instalación de ffmpeg

Como primer punto, compilaremos e instalaremos ffmpeg a partir del código fuente. Tenemos varias opciones: hacer un checkout de SVN, hacer un GIT clone,
o bajarnos el código de la última versión estable. Para cualquier opción, contamos con lo que necesitamos aquí.

Es una buena idea instalar codecs externos para luego poder integrarlos con ffmpeg. Entre estos codecs externos tenemos a LAME para MPEG Audio Layer III,  AMR para 3GPP y xvid para los estándares MPEG-4 Simple Profile and Advanced Simple Profile.

La primer parte de este link nos muestra cómo instalar los diferentes tanto los codecs externos como ffmpeg.

Para la instalación más básica, sin codecs externos, basta con hacer un

./configure

en el directorio en donde está ubicado el código de ffmpeg, luego un

make

y finalmente, con permisos de root un

make install

En distribuciones de Linux más “modernas”  seguramente tengamos la opción de instalar ffmpeg desde repositorios de paquetes, sin la necesidad de compilarlo a mano.

2. Instalación de JMF

JMF no tiene mucha ciencia para instalarlo, simplemente bajamos el instalador de aquí y lo corremos en el directorio que queramos instalarlo. Yo lo ejecuté desde /usr/lib para que JMF quede en /usr/lib/JMF-2.1.1e/ (llamaremos ${JMF_HOME} al directorio de instalación), pero no repercute en el funcionamiento. Debemos recordar que ${JMF_HOME}/lib/jmf.jar deberá estar en el classpath de nuestra aplicación.

3. Instalación de Jffmpeg

Jffmpeg tampoco da muchas dificultades para instalarlo. Podemos bajar el JAR y el .so (o .dll) de aquí, y descomprimirlos en el directorio que nos resulte más cómodo. Lo que debemos tener en cuenta después, es que el JAR deberá estar
en el classpath de nuestra aplicación, y el .so en LD_LIBRARY_PATH, o configurado en el path de las librerías de Linux.

Llamaremos ${JFFMPEG_HOME} al directorio en donde tenemos el JAR y el .so.

4. Classpath, LD_LIBRARY_PATH, etc.

Tanto las librerías nativas como los JARs de JMF y Jffmpeg deberán estar referenciadas por nuestra aplicación para ser tenidas en cuenta.

Para los JARs basta con agregarlos a una variable de entorno que luego se referenciará en el classpath de nuestra aplicación.

Para las librerías nativas podemos agregar un archivo de extensión conf en /etc/ld.so.conf.d/ que contenga una línea para cada directorio que deba ser considerado al buscar las librerías.

La otra opción es agregar los directorios a la variable de entorno LD_LIBRARY_PATH. Esta variable contiene una lista de directorio separados por coma, la cual es utilizada por el sistema operativo para buscar librerías antes de recurrir al conjunto predeterminado de directorios.

Si no queremos definir este conjunto de variables a mano, podemos editar el archivo ~/.bashrc agregando las siguientes líneas (quizá las rutas no sean las que correspondan):

<br />
# cat ~/.bashrc</p>
<p>export JMF_HOME=/usr/lib/JMF-2.1.1e<br />
export JFFMPEG_HOME=/root/jffmpeg<br />
export CLASSPATH=$ JMF_HOME /lib/jmf.jar:$JFFMPEG_HOME/jffmpeg-1.1.0.jar:.:$CLASSPATH<br />
export LD_LIBRARY_PATH=$ JMF_HOME /lib:$JFFMPEG_HOME:${LD_LIBRARY_PATH}<br />
export JAVA_HOME=/usr/java/jdk1.6.0_14<br />

5. Registro de los codecs

Para agregar los codecs de Jffmpeg en JMF utilizaremos la herramienta JMFRegistry que viene con el Java Media Framework. Podemos ejecutarlo por consola tipeando “java JMFRegistry” o desde las preferencias del JMStudio, otra herramienta de JMF que hace de Media Player.

Para cada cambio que listamos a continuación, debemos hacer clickear el botón de commit.

En la pestaña de “Mime types” registramos las siguientes extensiones:

  1. video/vob -> vob
  2. audio/ogg -> ogg

Bajo la pestaña “
Plugins” registramos los siguientes “Demultiplexers”:

  1. net.sourceforge.jffmpeg.demux.vob.VobDemux
  2. net.sourceforge.jffmpeg.demux.ogg.OggDemux

Y bajo la pestaña “Codec” registramos los siguientes codecs:

  1. net.sourceforge.jffmpeg.VideoDecoder
  2. net.sourceforge.jffmpeg.AudioDecoder

6. Parámetros de la aplicación

Como último paso, debemos recordar agregar ya sea la variable $CLASSPATH al classpath de nuestra aplicación, o cada JAR por separado (${JMF_HOME}libjmf.jar,   ${JFFMPEG_HOME}jffmpeg-1.1.0.jar).

Conclusión

Si bien no es “soplar y hacer botellas”, en Java tenemos la posibilidad de agregar contenido multimedia a nuestras aplicaciones o applets utilizando la potencialidad que nos dan los codecs implementados como código nativo al sistema operativo.

En este post vimos un ejemplo en instalación y configuración en Linux; la configuración en Windows no es demasiado diferente.

Referencias

http://jffmpeg.sourceforge.net/download.html

http://downloads.xvid.org/downloads/xvidcore-1.2.2.tar.bz2

http://java.sun.com/javase/technologies/desktop/media/jmf/2.1.1/download.html

http://www.ffmpeg.org/

http://jffmpeg.sourceforge.net/

http://www.hiteshagrawal.com/ffmpeg/installing-ffmpeg-easily-on-linux

http://www.elctech.com/articles/installing-ffmpeg-with-faac-and-x264-encoders-from-source-on-ubuntu

http://www.luniks.net/luniksnet/html/java/jtvd/doc/jmf.html

http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html

Cheat sheets

En http://www.cheat-sheets.org/ tenemos una colección de hojas de referencia sobre un montón de tecnologías, sistemas operativos, bases de datos, entre otros. Están buenas para tener alguna impresa para pegarle un vistazo si no queremos «googlear» algún detalle particular.

Listo algunas de las más interesantes:

.NET

.NET Format String Quick Referencee
Core C# and .NET Quick Reference by Stephen C. Perry [pdf] (digilife.be)
C# and VB.NET Comparison Cheat Sheet by Steven Swafford [pdf] (aspalliance.com)

CVS

CVS Quick Reference Card Andrew Ford [pdf] (refcards.com)

Design patterns

Design Patterns Quick Reference by Jason S. McDonald [pdf] (mcdonaldland.info)

Eclipse

Eclipse Keyboard Shortcuts by Jesper Kamstrup Linnet [pdf, rtf] (eclipse-tools.sourceforge.net)

FTP

List of FTP commands for the Microsoft command-line FTP client (nsftools.com)

Linux

Unix/Linux Command Cheat Sheet by Jacob [pdf] (fosswire.net)
Linux Administrator’s Quick Reference by Jialong He [pdf] (tiger.la.asu.edu)
The One Page Linux Manual by Squadron [pdf] (homepage.powerup.com.au/~squadron/, digilife.be)

MySQL

MySQL Cheat Sheet by Dave Child [png, pdf] (addedbytes.com)
MySQL cheatsheets by Bob Stein, VisiBone [two wall posters 43cmx61cm or 61cmx87cm, jpg] (visibone.com)
MySQL Cheat Sheet (nparikh.org)
MySQL Database Quick Reference by DeepX [pdf] (tiger.la.asu.edu)

OpenSSH

OpenSSH Configuration Quick Reference by Jialong He [pdf] (tiger.la.asu.edu)

Firefox

Keyboard Shortcuts (mozilla.org)

SQL

SQL in one page (sql.su)

SQL Server

SQL Server Cheat Sheet by Dave Child [png, pdf] (addedbytes.com)

Subversion

Subversion Cheat Sheet by Dave Child [pdf] (addedbytes.com)
Subversion Quick Reference Card by Cezary Sobaniec [pdf] (cs.put.poznan.pl)

UNIX

UNIX BASH shell Quick Reference by Arnold Robbins [pdf] (tiger.la.asu.edu)

XML

XML 1.0 Syntax Quick Reference by Mulberry Technologies, Inc. [pdf] (mulberrytech.com)

XPath y XSLT

XSLT 1.0 and XPath 1.0 Quick Reference [pdf] (mulberrytech.com)
XPath by DeepX Ltd [pdf] (refcards.com)

Actualización 24-Nov-2009

Agrego una colección de 25 cheat sheets de diseño web, PHP, WordPress, Photoshop, etc. que me pareció interesante: 34 cheat sheets for web designers and developers