Buscar este blog

Cargando...

jueves, 16 de mayo de 2013

Ejemplo: Implementacion del Patron Singleton en C++

Buenas! Si, después de casi dos años de inactividad, volví para mostrar la implementación de un patrón Singleton en C++.

Como sabemos, una clase que implementa este patrón, tiene una característica muy importante: no puede crearse mas que una instancia (objeto) de esa clase. Pero claro, esta caracteristica es relevante o toma importancia en algunos casos. Personalmente, donde mas utilizo este patron es cuando creo "fabricas", es decir, utilizo el patron Factory para con alguna finalidad. El patron Factory lo dejo para otro momento, y es igual de interesante y util que el Singleton pero ahora no viene al caso.

Entonces, lo importante que debemos tener en cuenta, es que sin importar cuantos objetos queramos crear, solo estaremos creando una y solo una instancia de esta clase. Si por ejemplo creamos 5 variables de una clase llamada MiClase e instanciamos dichas variables, todas las variables corresponderán a la misma instancia. Es decir, sera indistinto utilizar una u otra de estas variables para acceder a los métodos y atributos del objeto.

Pero este patron tiene dos puntos que hay que tener en cuenta:

Punto 1. No puede inicializarse "manualmente".
Es decir, no podemos hacer la asignación con new:
MiClase ObjetoA = new MiClase();

Es imposible! Y por que? Porque el constructor debe ser privado. De esta forma nos aseguramos que no se pueda andar creando instancias libre y salvajemente por ahí. Bueno, si no se pueden crear instancias... cómo hacemos para exista esa famosa única instancia?

Punto 2. Alguien debe crear la instancia única.
Y si, nada es magia en esto de la programación. Quien puede crear la instancia? Bueno, pues la misma clase! Es decir, que de alguna manera, la clase debe crear una instancia de si misma y asegurarse que sea solo una. Esto lo haremos con un método que le llamaremos, por convención nomás: getInstance().

Es decir, que para obtener la unica instancia de una clase que implementa el patron Singleton, haremos algo asi:
MiClase ObjetoA = MiClase()::getInstance();

Súper fácil! Y ahora si, ObjetoA apunta directamente a la instancia única de la clase MiClase. Ahora veamos que se esconde detrás de todo esto, en términos de C++. Como toda clase de C++ tendremos los archivos .h y .cpp:

MiClase.h
En este archivo lo importante a tener en cuenta es:
  • El constructor MiClase() es privado. No podrá usarse la palabra clave new.
  • Tenemos un atributo estático llamado unica_instancia que es un puntero a la clase que lo contiene y que tambien es privado. No podra accederse desde fuera de un objeto.
  • El método getInstance() es también estático! Claro, sino no podría accederse hasta tener un objeto de la clase, y justamente este el método que crea el primer (y único) objeto, con lo cual debe ser estático si o si.
class MiClase
{
private:
 MiClase(void);
 static MiClase* unica_instancia;
 
public:
 ~MiClase(void);
 
 static MiClase *getInstance()
 {
  if(unica_instancia == NULL)
   unica_instancia = new MiClase();
   
  return unica_instancia;  
 } 
};


MiClase.cpp
Acá lo importante es inicializar la variable estática unica_instancia. La inicializamos en NULL de forma que nos aseguremos que no se crea ningún objeto hasta que se llame por primera vez a getInstance().
Atención! El caso particular de C++ requiere que las variables estáticas sean definidas en el archivo .CPP y no en el .H. Caso contrario se obtiene un error de compilación.
#include "MiClase.h"

MiClase* MiClase::unica_instancia = NULL;

MiClase::MiClase(void)
{
}
MiClase::~MiClase(void)
{
}

Por ultimo, cabe explicar brevemente lo que hace el método getInstance(). Básicamente, crea una instancia de la clase solo en el caso de que no exista una (por eso el if). Luego devuelve la instancia creada o, sino creó porque ya existia, devuelve la existente. Asi es seguro que no tendremos mas de una instancia.
Saludos!

viernes, 8 de julio de 2011

Error: Clase No Registrada.

Tenía un proyecto en .NET que en una máquina compilaba y corría sin problemas. Pero al querer pasar el proyecto a otra máquina, luego de compilar, me aparecía la siguiente excepción:

Clase no registrada (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG))

La solución es simple: además de agregar las referencias al proyecto, debemos hacer click derecho (desde un adminsitrador de archivos) en los archivos DLLs que hemos referenciado, y luego click en "Registrar".

Con eso se soluciona el problema.

S2

viernes, 22 de abril de 2011

Programación Orientada a Aspectos. Implementando un Aspecto. (Parte 3)

En la parte 2 planteamos una situación utópica: que una clase realizara algo sin indicarle que lo hiciera. Bueno, sí, eso es utópico. Pero, podemos pensar en otra "entidad" que se encargue de realizar esa tarea (en nuestro caso es registrar un movimiento) detectando el momento preciso en el que debe realizarla. Es decir, tener "algo" que sepa cuando registrar un movimiento, pero que ese "algo" no tenga nada que ver con la clase Cuenta. Ese algo, es lo que llamamos aspecto. Un aspecto, entonces, es algo que entrecruza una o más clases. Dicho de otra forma, un aspecto es un concepto que ofrece funcionalidad transversal a los objetos del negocio.

Imaginémoslo como algo que vigila un programa a medida que este se ejecuta; y a partir de ciertas acciones que se producen en el programa, este algo realiza acciones propias de él. Llamemos a este algo "aspecto". Podemos decirle a un aspecto, que cuando se termine de ejecutar cualquier método que comience con la palabra "hacer" realice un registro de movimiento. La clase Cuenta de nuestro ejemplo, no se enteraría jamás de la existencia de este aspecto, pero este aspecto está atento a las ejecuciones hacerAlgo...() de esa clase.

Vamos a definir rápidamente este aspecto para poder visualizar mejor lo que estamos tratando de decir. Para poder escribir un aspecto y compilar el programa con este aspecto, es necesario tener instalado el plugin de AspectJ en el editor de Java que estemos usando, o poder compilar configurando el editor. Bueno, pasemos a definir el aspecto de una vez. Agregamos un nuevo archivo con extensión .aj (por "AspectJ") al proyecto:

public aspect RegistroDeMovimientos {

after():execution (public * hacer*(..)) {
Date hora = new Date();
SimpleDateFormat formatoDeFecha = new SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss");
System.out.println("Movimiento realizado a las " + formatoDeFecha.format(hora)) ;
}
}


Observemos este código. Lo primero que vemos, es la declaración del aspecto bajo el nombre de RegistroDeMovimientos. Por ende, al igual que las clases de Java, el archivo del aspecto debe llamarse RegistroDeMovimientos.aj. Si seguimos vemos la linea que dice:

after():execution (public * hacer*(..)) {


Esta línea es clave para definir unos conceptos que explicaré más adelante. Pero por el momento, analizaremos de manera simple qué significa. Si tuviera que decirlo en lenguaje informal, la describiría asi: "Después de la ejecución de cualquier método público, sin importar el tipo que retorne, que comience con hacer, y sin importar la cantidad y tipo de parámetros que requiera, hacer lo siguiente:". Eso significaría mas o menos. Ahora examinemos lo que significa cada parte:

  • after(): Esto indica que el cuerpo se ejecutará después de algo. Ahora veamos ese algo.
  • execution ( ): esto significa que se toma como referencia una ejecución de lo que sigue:
  • public * hacer*(..): public nos indica que se buscará un método público cualquiera. El asterisco que sigue, indica que ademas no importa el tipo que retorna el método. hacer* significa que el nombre del método debe comenzar con la palabra "hacer" y no importa cómo termine (para eso está el asterisco luego de "hacer"). Y finalmente, los dos puntos entre paréntesis significa que no importa ni el tipo ni la cantidad de parámetros del método.

Entonces, revisemos la descripción informal del método: "Después dela ejecución de cualquier método que sea público, que retorne cualquier tipo de dato, que comience con "hacer" y sin importar el tipo y cantidad de parámetros", se debe ejecutar lo que se indica en el cuerpo. El cuerpo es muy simple: no es mas que aquello que hacía el método RegistrarMovimiento() que hicimos antes. Esto es un aspecto. Simple, ¿no? El aspecto, se encargará de ejecutar ese cuerpo de código cada vez que ocurra esa descripción informal.

Con esto, hemos solucionado el problema del apartado anterior. ¿Por qué? Porque hemos logrado aislar el comportamiento de registrar un movimiento, de forma tal que la clase Cuenta no conoce de su existencia. Por lo tanto, no hemos tenido que repetir ningún código dentro de la clase, y además, al aislar ese comportamiento en un sólo aspecto, este se hace más fácilmente mantenible, ya que si queremos modificar la forma en que se registran los movimientos sólo debemos modificar el cuerpo de ejecución del aspecto, y no preocuparnos por las clases del negocio.

Por supuesto, para compilar aspectos, no podemos usar el compilador de java, para eso usamos el compilador AspectJ que lo que hace es armar un código complementando el código base con el código de aspectos. Una vez que esta herramienta genera el código final, ahí si se puede correr sobre la máquina virtual de java.

miércoles, 20 de abril de 2011

Programación Orientada a Aspectos. ¿Por qué usar POA? (Parte 2)

En la parte 1, di una introducción a lo que es la programación orientada a aspectos de una forma bastante teórica. En esta segunda parte, voy a mostrar un ejemplo práctico muy simplificado para poder asentar un poco más el concepto. Para el ejemplo utilicé el lenguaje Java, y la extensión del lenguaje Java que implementa aspectos AspectJ. Ya he contado como compilar con AspectJ en NetBeans.

Bueno, ¿en qué consiste la POA? Voy a poner un ejemplo muy fácil que ilustra el potencial que nos ofrece la POA Supongamos una aplicación de transacciones bancarias. (Este es el típico ejemplo que se menciona en todos lados, y lo voy a poner en mi versión porque es muy ilustrativo).

Vamos a tener una clase cuyo nombre es Cuenta y es una versión muy simplificada de una cuenta de un banco. Esta clase, tiene un atributo llamado saldo de tipo Double que indica el saldo en la cuenta. Y vamos a tener tres métodos: Uno que llamado hacerDeposito() con un único parámetro de tipo Double que indica la cantidad a depositar en la cuenta. Otro llamado hacerExtraccion() que cuenta con un solo parámetro que indica la cantidad de dinero que se quiere extraer de la cuenta. El método restante se llama hacerTransferencia() y tiene dos parámetros: uno indica la cantidad de dinero y el otro es la cuenta a la que se quiere hacer la transferencia. Además tendremos una típica -y muy simplificada- clase que representa un cliente del supuesto "banco" llamada Cliente. Para seguir simplificando (cosa que se me está haciendo mala costumbre ya) un cliente sólo puede tener una cuenta. Ilustremos con UML:



A continuación, les muestro un ejemplo en java bien simple. Lo que haré en el método Main() será crear dos clientes (Pepe y Juan) y crear una cuenta para cada uno. Después, le asignaré a Pepe una cuenta y a Juan la otra. Finalmente, haré una extracción de la cuenta de Pepe; y -felizmente para Juan- terminaré con una transferencia de dinero de la cuenta de Pepe a la de Juan. Aunque lo que realiza el método Main(), por el momento no nos interesa. Veamos el código de ambas clases (sin los getter y los setters porque son muy triviales).

Veamos la definición de los métodos hacer...() de la clase Cuenta:

public void hacerDeposito(Double cantidad) {
if(cantidad <= 0) {
System.out.println("No hay dinero suficiente para hacer el depósito");
}
else {
Date hora = new Date();
SimpleDateFormat formatoDeFecha = new SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss");
//Realizamos el depósito
this.saldo += cantidad;
//Registramos el movmiento
System.out.println("Movimiento realizado a las " + formatoDeFecha.format(hora)) ;
}
}

public void hacerTransferencia(Double cantidad, Cuenta cuentaDestino)
{
if(this.saldo < cantidad) {
System.out.println("No hay fondos suficientes para la transferencia.");
}
else {
Date hora = new Date();
SimpleDateFormat formatoDeFecha = new SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss");
cuentaDestino.hacerDeposito(cantidad);
this.saldo -= cantidad;
//Registramos el movmiento
System.out.println("Movimiento realizado a las " + formatoDeFecha.format(hora)) ;
}
}

public void hacerExtraccion(Double cantidad) {

if(this.saldo < cantidad) {
System.out.println("No hay fondos suficientes para la extracción.");
}
else {
Date hora = new Date();
SimpleDateFormat formatoDeFecha = new SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss");
//Extraemos la cantidad del saldode la cuenta.
this.saldo -= cantidad;
//Registramos el movmiento
System.out.println("Movimiento realizado a las " + formatoDeFecha.format(hora)) ;
}
}
Examinemos un poco el código: en todos métodos comenzamos con una verificación de la cantidad que se quiere extraer, depositar o transferir. Esta verificación es necesaria, ya que ciertamente sería un error, por ejemplo, depositar una cantidad negativa de dinero de una cuenta; también sería un error permitir una extracción de más cantidad de dinero de la que se dispone. Estas situaciones deben evitarse si o si.

Por otra parte, vemos que una vez que se comprueban las cantidades y que esta todo bien, se procede a realizar el deposito o la extracción o la transferencia (según sea el caso). Pero para esto, he supuesto (a modo de regla de negocio) que el banco necesita tener un registro (logging) de cada movimiento realizado en cada cuenta. Por eso es que creé una variable llamada hora y la mostré en pantalla. Lo más común no es mostrarlo en pantalla sino almacenarlo en un archivo de logs, pero lo hice así por practicidad.

Lo interesante, curioso, y que tenemos que tener en cuenta de estos métodos, es que los tres repiten el proceso de registrar un movimiento. Y no solo eso, sino que además se hace en los tres métodos de la misma forma! Lo cual es una muy mala práctica. Nunca debería repetirse código, eso lo sabemos bien. Entonces, he aquí un problema. ¿Cómo lo solucionamos?...

Algún iluminado podría indicar hacer lo siguiente: Creamos un cuarto método dentro de la clase al que podríamos llamar registrarMovimiento(). Este método se encargaría sólo de la parte del registro del movimiento; y cada uno de los anteriores tres métodos lo llama cuando ha concluido un movimiento. Genial. Veamos cómo quedaría registrarMovimiento():

private void registrarMovimiento()
{
Date hora = new Date();
SimpleDateFormat formatoDeFecha = new SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss");
System.out.println("Movimiento realizado a las " + formatoDeFecha.format(hora)) ;
}

Y ahora, el código de los otros tres métodos se modifica para llamar a registrarMovimiento() quedando así (sólo mostramos dos, pero el tercero seguiría la misma lógica que éstos):

public void hacerTransferencia(Double cantidad, Cuenta cuentaDestino)
{
if(this.saldo < cantidad) {
System.out.println("No hay fondos suficientes para la transferencia.");
}
else {
cuentaDestino.hacerDeposito(cantidad);
this.saldo -= cantidad;
//Registramos el movmiento
registrarMovimiento();
}
}

public void hacerExtraccion(Double cantidad) {

if(this.saldo < cantidad) {
System.out.println("No hay fondos suficientes para la extracción.");
}
else {
//Extraemos la cantidad del saldode la cuenta.
this.saldo -= cantidad;
//Registramos el movmiento
registrarMovimiento();
}
}
Pero lo malo de esta solución, es que si se efectuara otro movimiento que no fuera "dentro" de la clase Cuenta sino "dentro" de otra clase, esta clase tendría que tener su propio método registrarMovimiento(), y nuevamente estaríamos repitiendo código, pero entre clases. Ante este nuevo problema, podemos proponer otra solución: creamos una clase que se encargue específicamente de registrar movimientos; y cualquier método de cualquier clase puede instanciarla y llamar al método que registra movimientos. Podríamos, por ejemplo, crear una clase llamada RegistroDeMovimientos con un método público llamado registrarMovimiento(). Parece que esta es la mejor solución. Sin embargo no es así. Sigue habiendo "algo malo". ¿Qué es?...

Está claro: aunque tengamos una clase aparte que registre los movimientos, cada clase debe instanciar y llamar al método de esa clase. Es decir, seguimos repitiendo código. Cada método que deba registrar un movimiento, debe repetir el mismo código que los otros métodos que también deban registrar un movimiento. ¡Que feo! ¡Y no solo eso! Además, el hecho de registrar un movimiento -ya sea dentro del mismo método o llamando a RegistroDeMovimientos.registrarMovimiento()- significa introducir código que no pertenece exclusivamente al movimiento. El movimiento sólo debería realizar el movimiento y nada más. El registro debería hacerse aparte, no debería ser responsabilidad de un depósito, o una extracción o una transferencia. Esta forma de registrar un movimiento, ensucia el código que se refiere a los métodos de la clase Cuenta. Es decir, lo ideal sería que estos métodos se vieran así:

public void hacerDeposito(Double cantidad) {
if(cantidad <= 0) {
System.out.println("No hay dinero suficiente para hacer el depósito");
}
else {
this.saldo += cantidad;
}
}

public void hacerTransferencia(Double cantidad, Cuenta cuentaDestino)
{
if(this.saldo < cantidad) {
System.out.println("No hay fondos suficientes para la transferencia.");
}
else {
cuentaDestino.hacerDeposito(cantidad);
this.saldo -= cantidad;
}
}

public void hacerExtraccion(Double cantidad) {

if(this.saldo < cantidad) {
System.out.println("No hay fondos suficientes para la extracción.");
}
else {
this.saldo -= cantidad;
}
}
Como dije, sería ideal que a pesar de no llamar a registrarMevimiento(), el movimiento se registrara igual. Eso sería ideal, ¿no? No ensuciaríamos código y tampoco lo repetiríamos. La clase sería tremendamente cohesiva. Parece utópico ¿verdad? Bueno, para nuestra felicidad, esto es realizable y es acá donde entran en juego los "aspectos".

En la tercer parte, voy a mostrar cómo implementar un aspecto que solucione el problema planteado.

viernes, 15 de abril de 2011

Programación Orientada a Aspectos. ¿Qué es? (Parte 1)

Para explicar la programación orientada a aspectos, quizás lo ideal sería comenzar con una breve descripción de la historia de la ingeniería de software, como lo hacen la mayoría de los artículos o PDFs que podemos encontrar en la web, pero como justamente la mayoría lo hace así, yo no. Quien quiera verlo así, busque en la web el tema y ahí van a tener mucho para leer (y no está demás). Pero yo prefiero comenzar yendo al grano.

La programación orientada a objetos trata la manera de modularizar "conceptos comunes" de software. Sin embargo, existen otros conceptos o asuntos que se extienden a lo largo de estos "conceptos comunes" y que no pueden ser modularizados con el diseño orientado a objetos. En un intento más de subsanar lo que la orientación a objetos no puede, aparece una nueva solución: la Programación Orientada a Aspectos (y su consecuente Diseño Orientado a Aspectos).

La programación orientada a aspectos se ha planteado como un nuevo paradigma de programación (con lo que no estoy de acuerdo), el cual consiste en separar los conceptos que entrecruzan varias clases y se extienden a lo largo de éstas, pero que no pertenecen a esas clase en sí mismas. Incluso, los conceptos pueden aparecer no sólo en varias clases, sino de una sola. Ahora la pregunta: ¿de qué tipo de conceptos hablamos? Pensemos como ejemplo, en una aplicación que requiere del registro (logging) de las acciones que realiza. Bien, estos registros "alguien" tiene que llevarlos a cabo, y es normal cargar a muchas clases con la responsabilidad de hacerlo cuando, seguramente, no sea la función principal de esas clases hacer dicha tarea. Como vemos, se trata de una misma funcionalidad (registrar acciones) que se encuentra entrecruzada en varias clases, pero que a la vez no es parte de ninguna.

Otro ejemplo, simple de entender, es el manejo de errores. Los errores hay que tratarlos sí o si en una aplicación. Pero, desde un punto de vista "purista" de objetos, no tenemos clases que traten los errores por sí solos. Siempre las clases que definen la funcionalidad de la aplicación van a tener que lidiar con los errores, y esa no es su función principal. En cierta forma, esto hace a dichas clases menos cohesivas. Un tercer ejemplo puede ser el manejo de la sincronización. Nuevamente, los objetos del negocio deben tratar la sincronización además de su función principal.

En todo los ejemplos estamos viendo que hay ciertos asuntos que no pertenecen al negocio pero que sin embargo, deben ser tratados. Y lo negativo de esto, es que según el paradigma de objetos, son los objetos del negocio quienes deben tratar estos asuntos y, como si fura poco que hagan tareas que no les corresponden, estas tareas se esparcen a lo largo de toda la aplicación, llevando a dispersar código y enredarlo por la misma (a esto último se llama Code Tangling y Code Scattering).

Entonces, para darle más sentido a la POA, veamos en qué se afecta el desarrollo de aplicaciones cuando surgen estos asuntos:
  • Baja cohesión: las clases realizan tareas que no le corresponden específicamente a ellas.
  • Baja reusabilidad: Cuando una clase trata un asunto que no le corresponde, esta clase probablemente sea difícil de re usar en otro sistema.
  • Peor calidad de código: El código se complica, y cuesta más entenderlo y mantenerlo.
  • Evolución dificultosa: Se vuelve más costoso que el sistema evoluciones al tener código disperso y enredado por toda la aplicación.

Estos asuntos son denominados "conceptos transversales". La POA viene para tratar de separar y encapsularlos en una aplicación y aislarlos para independizar a los objetos del negocio de éstos conceptos. Este aislamiento se encapsula en "aspectos".

Por lo tanto, la POA permite la separación de conceptos transversales a través de mecanismos que permiten abstraer y encapsular estos conceptos en un sistema. Un aspecto es la unidad que encapsula uno o más conceptos transversales, y que con la programación orientada a objetos no es posible diferenciarlo de forma clara.

La definición actual de aspecto dice: "Un aspecto es una unidad modular que se disemina por la estructura de otras unidades funcionales. Los aspectos existen tanto en la etapa de diseño como en la de implementación. Un aspecto de diseño es una unidad modular del diseño que se entremezcla en la estructura de otras partes del diseño. Un aspecto de programa o de código es una unidad modular del programa que aparece en otras unidades modulares del programa.

La principal ventaja de la POA es que permite tratar la funcionalidad pura por un lado, y los aspectos por otro, de forma separada. Luego ambos se combinan con un tipo de programa llamado 'Weaver') para dar por resultado el sistema final.

Hay mucho más por hablar de POA aún. En la próxima parte (parte 2), voy a mostrar un ejemplo muy claro, para asentar toda esta teoría en algo más palpable, así que a no abandonar si esta pequeña introducción a resultado medio difícil de entender, en el ejemplo de la Parte 2 quedará muy claro de que se trata.

martes, 12 de abril de 2011

Instalar AspectJ en NetBeans 6.9.1

English version

Hola. Finalmene, después de horas de intentos, logré copilar AspectJ en NetBeans 6.9.1.
Ahora les muestro la forma de hacerlo. Pero quiero aclarar que no voy a instalar un plug-in de netbeans, sino que voy a mostrar la forma de compilar aspectos en netbeans con AspectJ. Veamos los pasos:

1) Descargar la última versión estable de AspectJ en este sitio.
2) Descomprimir el archivo ".jar" en algún directorio donde pongan librerías. No debería ser en el directorio de librerías del proyecto, ya que quizás quieras usar esta librería en otros proyectos.
3) Crear un proyecto en netbeans, basta con un simple "Java Project".

Ahora, los próximos pasos deben seguirlos en cada nuevo proyecto que hagan:

4) Ir a las propiedades del proyecto, y en el panel de "librerias", seleccionar "Add Jar/Folder". Ahora, seleccionar los siguientes archivos del archivo descomprimido:
  • aspectjrt.jar
  • aspectjtools.jar
  • org.aspectj.matcher.jar

5)Una vez que se agregaron estos archivos, hay que editar el archivo build.xml creado en el directorio del proyecto.
6) Entre los tags <project> y </project> pegar el siguiente código:


<taskdef classpath="/home/ignacio/NetBeansProjects/lib/aspectj/aspectjtools.jar"
resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties"/>

<target name="aspectj">
<echo level="info">--- aspectj (start) ---</echo>
<iajc destDir="${build.classes.dir}">
<inpath>
<pathelement location="/home/ignacio/NetBeansProjects/lib/aspectj/aspectjrt.jar"/>
<pathelement location="${build.classes.dir}" />
</inpath>
<sourceroots>
<pathelement location="${src.dir}"/>
</sourceroots>
<classpath>
<pathelement location="${javac.classpath}"/>
<pathelement location="${j2ee.platform.classpath}"/>
</classpath>
</iajc>
<echo level="info">--- build.xml by Ignacio Rigoni email: {name}.{lastname}@gmail.com ---</echo>
</target>

<target name="-post-compile" depends="aspectj"></target>


De forma tal que el archivo build.xml les quede así:


<?xml version="1.0" encoding="UTF-8"?>

<project name="pruebaAspectJ_nb6.9.1" default="default" basedir=".">
<description>Builds, tests, and runs the project pruebaAspectJ_nb6.9.1.</description>
<import file="nbproject/build-impl.xml"/>

<taskdef classpath="/home/ignacio/NetBeansProjects/lib/aspectj/aspectjtools.jar"
resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties"/>

<target name="aspectj">
<echo level="info">--- aspectj (start) ---</echo>
<iajc destDir="${build.classes.dir}">
<inpath>
<pathelement location="/home/ignacio/NetBeansProjects/lib/aspectj/aspectjrt.jar"/>
<pathelement location="${build.classes.dir}" />
</inpath>
<sourceroots>
<pathelement location="${src.dir}"/>
</sourceroots>
<classpath>
<pathelement location="${javac.classpath}"/>
<pathelement location="${j2ee.platform.classpath}"/>
</classpath>
</iajc>
<echo level="info">--- build.xml by Ignacio Rigoni email: {name}.{lastname}@gmail.com ---</echo>
</target>

<target name="-post-compile" depends="aspectj"></target>

</project>


7) Ahora, modificar las lineas 7 y 14. En la línea 7 hay que especificar la ruta completa del archivo "aspectjtools.jar". Esto se hace donde descomprimiste aspectj. En la línea 14 hay que hacer lo mismo, pero apuntando al archivo "aspectjrt.jar".

8) Eso es todo!

Consideraciones

1) Bajar el archivo aspect{version}.jar, no el archivo aspectj{version}-src.jar.
2) Tener cuidado con las rutas de los archivos, siempre causan problemas!
3) No estoy seguro, pero es posible que las otras lineas que agregaron en build.xml tengan errores. A mi me funcionaron bien, pero puede que esto dependa del proyecto creado, así que si esto les causa problemas, hay que chequear los directorios a los que apunta el resto del archivo, y otras causas posibles de errores.

Espero que esto te ayude. Vuelvan a comentar si anduvo y/o si tienen sugerencias que crean que puede mejorar esto.

lunes, 11 de abril de 2011

Install AspectJ in NetBeans 6.9.1

Versión en español

Hi. First, sorry my English, it's not my native languaje.
Second, after hours trying, I managed to compile with AspectJ in NetBeans 6.9.1
Now I'll show the way to make it possible. But I want to clarify that I wont install a NetBeans's plugin, but it is the way to make it possible to compile aspects in netbeans with AspectJ. Now, let's go on the steps:

1) Download the AspectJ Latest Stable Release, on this page.
2) Unzip de ".jar" file in the directory you like to put your libraries. It should not be in the proyect's lib directory, because you may want to use it in other projects too. You will unzip about 4 ".jar" files.
3) Create a project in netbeans, just a simple "Java Project".

Now listen, you have to follow the next steps in every new project you make:

4) Go to the project's propierties and in the libraries panel, select the "Add Jar/Folder". Now, select this files from the unzipped file:
  • aspectjrt.jar
  • aspectjtools.jar
  • org.aspectj.matcher.jar

5) Once this files were added, you must edit the build.xml file created inside you project directory.
6) Between the tags <project> and </project> paste this code:


<taskdef classpath="/home/ignacio/NetBeansProjects/lib/aspectj/aspectjtools.jar"
resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties"/>

<target name="aspectj">
<echo level="info">--- aspectj (start) ---</echo>
<iajc destDir="${build.classes.dir}">
<inpath>
<pathelement location="/home/ignacio/NetBeansProjects/lib/aspectj/aspectjrt.jar"/>
<pathelement location="${build.classes.dir}" />
</inpath>
<sourceroots>
<pathelement location="${src.dir}"/>
</sourceroots>
<classpath>
<pathelement location="${javac.classpath}"/>
<pathelement location="${j2ee.platform.classpath}"/>
</classpath>
</iajc>
<echo level="info">--- build.xml by Ignacio Rigoni email: {name}.{lastname}@gmail.com ---</echo>
</target>

<target name="-post-compile" depends="aspectj"></target>


So the complete build.xml file can be like this:


<?xml version="1.0" encoding="UTF-8"?>

<project name="pruebaAspectJ_nb6.9.1" default="default" basedir=".">
<description>Builds, tests, and runs the project pruebaAspectJ_nb6.9.1.</description>
<import file="nbproject/build-impl.xml"/>

<taskdef classpath="/home/ignacio/NetBeansProjects/lib/aspectj/aspectjtools.jar"
resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties"/>

<target name="aspectj">
<echo level="info">--- aspectj (start) ---</echo>
<iajc destDir="${build.classes.dir}">
<inpath>
<pathelement location="/home/ignacio/NetBeansProjects/lib/aspectj/aspectjrt.jar"/>
<pathelement location="${build.classes.dir}" />
</inpath>
<sourceroots>
<pathelement location="${src.dir}"/>
</sourceroots>
<classpath>
<pathelement location="${javac.classpath}"/>
<pathelement location="${j2ee.platform.classpath}"/>
</classpath>
</iajc>
<echo level="info">--- build.xml by Ignacio Rigoni email: {name}.{lastname}@gmail.com ---</echo>
</target>

<target name="-post-compile" depends="aspectj"></target>

</project>


7) Now, modify the lines 7 and 14. In line 7 you must specify the "aspectjtools.jar" with the full path. This is where you unzipped aspectj. In line 14 you must do the same, but pointing to the "aspectjrt.jar" file.

8) That's all.

Considerations

1) Use the aspect{version}.jar file, no the aspectj{version}-src.jar file.
2) Be careful with the paths, it always cause problems!
3) I'm not shure, but may be possible that the other lines you added in build.xml could have errors. It worked fine for me, but may be it depends on the project, so if that causes a problem, you should check the dirs, and other possible error sources.

I wish this helps you! Please, come back and comment or suggest if you think this could be improved in any way.

sábado, 9 de abril de 2011

Colorear código fuente en Bolgger con "Syntax HighLighter"

Esto si que me costo encontrarlo, y mas aun hacerlo funcionar. ¿Por que? Porque en la mayoria de las web esta mal explicado, como en esta.

Luego encontré cómo se configura blogger para que realmente funcione esto: es muy facil. Lo pasos son los siguientes:

1º) Modificamos la plantilla de Blogger.
Para esto vamos a Diseño -> Edición de HTML. Ahi buscamos la etiqueta </head>. Y justo una linea encima de esta agregamos el siguiente código:


<!--SYNTAX HIGHLIGHTER BEGINS-->
<link href='http://alexgorbatchev.com/pub/sh/current/styles/shCore.css' rel='stylesheet' type='text/css'/>
<link href='http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css' rel='stylesheet' type='text/css'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCpp.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCSharp.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCss.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPhp.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPython.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushRuby.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushSql.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushVb.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPerl.js' type='text/javascript'></script>
<script language='javascript'>
SyntaxHighlighter.config.bloggerMode = true;
SyntaxHighlighter.config.clipboardSwf = 'http://alexgorbatchev.com/pub/sh/current/scripts/clipboard.swf';
SyntaxHighlighter.all();
</script>
<!--SYNTAX HIGHLIGHTER ENDS-->


2º) Verificar si todo anduvo bien haciendo click en "Ver Blog".

3º) Agregar el código fuente que quieras.
Para esto, cuando estamos editando una entrada, tenemos que hacer click en la pestaña que dice "Edicion de HTML" y ahi agregar las siguientes líneas:


<pre class="brush:java">
Aca va tu codigo en java
</pre>


Donde dice java, ponen el lenguaje que esten usando. Para ver una lista de lenguajes disponibles y como se nombran, vean este link.

Por ultimo, me gustaria recalcar algo. Conviene formatear el codigo fuente, al final de la edición del post, ya que si se hace cambiando el tipo de edición (de "Edicion de HTML" a "Redactar") se pierde el formato de saltos de lineas y espaciados del codigo fuente. Por lo tanto, recomiendo escribir el post completo, y al final poner todo el código fuente que se quiera.

Saludos!

jueves, 7 de abril de 2011

Instalar AspectJ en NetBeans

UPDATE 1: Para compilar AspectJ en NB 6.9.1, leer esta entrada.

Bueno, este es un punto que me tenía un poco molesto porque no encontraba una buena página que describiera cómo hacerlo. Resultó mucho más fácil de lo que imaginé. La instalación no es precisamente difícil, pero creo que nunca está demás mostrar como hace, sobre todo porque lamentablemente el plugin de AspectJ para NetBeans dejó de desarrollarse oficialmente. Ramón Ramos hizo una nueva versión compatible con está versión del IDE, y es ésta versión del plugin la que instalaremos. Bien, vamos:


1º) Instalar el IDE NetBeans 6.1. Probé de instalarlo en Netbeans 6.9.1 pero no me reconocía algunas partes del plugin, y no las instalaba por un problema de versiones. Como no soy muy ducho con esos temas, opté por directamente instalarlo en la versión 6.1. Ahora, si alguien puede instalarlo en una versión más reciente, que comente y lo agregamos a este pequeño tutorial.

2º) Descargar los plugins de AspectJ. Desde la misma página de NetBeans, vamos a la sección de plugins y buscamos en el catálogo todos los plugins que coincidan con "aspectj". Descargamos el más nuevo.

3º) Agregar los plugins a NetBeans. Descomprimimos el archivo descargado del paso anterior en una carpeta temporal. Luego vamos a NetBeans, y al menú "Herramientas | Complementos". Allí seleccionamos la pestaña "Descargados" y agregamos todos los archivos que salieron de la extracción del archivo comprimido. Luego los instalamos y listo.


En este punto ya tenemos instalado el plugin de AspectJ, es decir, ya podemos agregar aspectos a nuestros proyectos. Ahora queda un últimp paso, que es configurar el proyecto que al que queremos añadir aspectos. Esto es muy simple:


1º) Añadir la librería "AspectJ-Runtime". Para esto vamos a las propiedades del proyecto, y en Librerías seleccionamos la pestaña "Compilación". Le damos click a "Añadir librería" y seleccionamos la que se llama AspectJ-Runtime.


Listo, con esto ya podemos empezar a hacer uso de los aspectos en Java bajo NetBeans. Simple, ¿no? A mi me costó al no encontrar una buena página que describiera los pasos. Al final recién di con la que mencioné al principio.

S2!

viernes, 7 de enero de 2011

¿Convolución? ¡Pero si es muy fácil! (Parte 3/3)

Buenas. Hoy voy a terminar con la última parte que había comentado sobre el tema de convolución. Básicamente voy a presentar un pequeño código que hice en C, y que muestra dos formas de realizar la convolución. En la primera de ellas, llamada (Input Side Algorithm) y denominada como input_side_conv() en el código, se puede observar que se obtiene la convolución de una forma muy simple: se recorren todos los puntos de la señal x[n] y h[n], y en base a esto se calcula el y[n] correspondiente.

La segunda función, llamada output_side_conv(), obtiene la convolución con el Output Side Algorithm, la cual varía de la anterior en un punto muy importante. Antes de ver cual es la diferencia importante, veamos el código, ya que es muy simple de entender:


#include <stdio.h>
#include <stdlib.h>

#define PUNTOS_X (6)
#define PUNTOS_H (4)
#define PUNTOS_Y ((PUNTOS_X) + (PUNTOS_H) - 1)

/* Los metodos tienen la misma interfaz:
x, h ---> son las señales de entrada
y ---> es la señal de salida */
void input_side_conv(int *x, int *h, int *y)
{
int i,j;
for(i=0;i<PUNTOS_X; i++)
for(j=0;j<PUNTOS_H;j++)
y[i+j]=y[i+j]+x[i]*h[j];
}

void output_side_conv(int *x, int *h, int *y)
{
int i,j;

for(i=0;i<PUNTOS_Y; i++) {
y[i]=0;
for(j=0;j<PUNTOS_H;j++) {
if(i-j<0 || i-j>=PUNTOS_X) continue;
y[i] = y[i]+h[j]*x[i-j];
}
}
}

int main()
{
int x[PUNTOS_X] = {0,-1,-1,2,1,1};
int h[PUNTOS_H] = {1,0,-1,1};
int y1[PUNTOS_Y] = {0,0,0,0,0,0,0,0,0};
int y2[PUNTOS_Y] = {0,0,0,0,0,0,0,0,0};

int i;

//calculamos la convolucion por el primer metodo
input_side_conv(x, h, y1);
//calculamos la convolucion por el otro metodo
output_side_conv(x, h, y2);

//mostramos las dos respuestas
printf("Input Side Output Side\n");
for(i=0;i<PUNTOS_Y;i++)
printf("[%2d] [%d]\n", y1[i], y2[i]);

return 0;
}


Vemos que he definido 3 constantes simbólicas con #define. Las mismas son PUNTOS_X, PUNTOS_H y PUNTOS_Y. Cada uno denota la cantidad de puntos que tiene cada señal involucrada. En el caso de PUNTOS_Y se puede obtener con la operación que puse, según la fórmula que expliqué en la primera parte de esta serie de artículos.

Luego siguen las definiciones de las funciones que calculan la convolución. Ambas dan el mismo resultado, pero cada una lo calcula de forma distinta.

Finalmente, tenemos un main() que lo unico que hace es fijar valores para x[n] y h[n] y luego realiza la convolución de las mismas en dos señales de salida, y1[n] e y2[n] y muestra en forma "de tabla" el resultado de ambas para simplificar la comparación y ver que dan el mismo resultado.

La diferencia importante de la que hablé recién, es la siguiente: si observamos con detalle cómo se calcula cada convolución, podemos notar que la segunda forma, output_side_conv() tiene una ventaja importante, y ésta es que permite calcular un valor específico de y[n] sin que sea necesario conocer todos los puntos de x[n], sino solo los necesarios. En cambio, en la otra función necestiamos conocer todos los puntos de x[n] de antemano, ya que los recorremos uno a uno, y en base a esto vamos calculando cada valor de y[n]. ¿Por qué esto es tan importante? Porque generalmente, no contamos con todos los puntos de x[n] ya que muchas veces se necesita obtener la convolución a medida que se va obteniendo la señal x[n], es decir, obtener y[n] en tiempo real.

Acá les dejo el código en C para que no tengan que copiarlo a mano: bajar código en C .

Bueno, con esto doy por finalizados los artículos de convolución, espero que les haya resultado interesante, divertido.. o al menos práctico!