Logo Studenta

aop

Esta es una vista previa del archivo. Inicie sesión para ver el archivo original

LEEME.TXT
NOTA SOBRE EL CÓDIGO DE EJEMPLO:
Para ejecutar la aplicación de ejemplo debes instalar AspectWerkz. Tienes información sobre cómo hacerlo en la página del proyecto, aunque básicamente se reduce a 
1. descomprimir el paquete en alguna carpeta de tu sistema
2. crear una variable de entorno ASPECTWERKZ_HOME que apunte a la carpeta que has utilizado
3. añadir la ruta ASPECTWERKZ_HOME/bin al PATH de tu sistema.
¡A disfrutar!
articulo_aop.html
 La Programación Orientada a Aspectos
("Aspect Oriented Programming", o AOP) es, quizá, uno de los
campos de investigación en
el ámbito de la Ingeniería de Software que más interés despierta
en la actualidad, tanto en círculos académicos como
empresariales. La razón de ello es que propone una nueva
visión de los sistemas informáticos que promete
simplificar considerablemente el desarrollo y mantenimiento de
aplicaciones, aumentando por tanto la productividad del desarrollador.
La AOP lleva la separación de responsabilidades más
allá que la programación orientada a objetos, aumentando
el nivel de encapsulación y por tanto, permitiendo
diseños más limpios, fáciles de entender y
mantener.
A la vez, la AOP permite adoptar esa visión de forma muy poco
traumática para los equipos de desarrollo, pues los conceptos
introducidos son relativamente sencillos y las herramientas requeridas
se pueden construir sobre las plataformas orientadas a objetos
tradicionales. 
Como veremos, las ventajas de la Programación
Orientada a Aspectos son muchas y muy valiosas, y el esfuerzo
requerido para adoptarla es razonablemente pequeño.
 
 
		INTRODUCCIÓN
 La programación orientada a
objetos (OOP) utiliza un modelo
lógico del mundo real para construír una solución
a un problema concreto. Cuando diseñamos una aplicación
orientada a objetos, empezamos por distinguir las distintas entidades
(personajes) que componen el espacio del problema, y así
obtenemos las clases que formarán el modelo
de datos. Luego identificamos los procesos
que involucran a las entidades para alterar el estado del sistema y los
plasmamos en el modelo de lógica de negocio. Y
empezamos a construír nuestra aplicación escribiendo el
código de cada una de nuestras clases intentando mantener en la
medida de lo posible una separación adecuada de las
responsabilidades (una clase para cada cosa).
 Este método de trabajo lleva muchos
años demostrando su eficacia en proyectos muy diferentes, pero
también tiene sus limitaciones, derivadas del hecho de que
estamos trabajando con modelos de la realidad, que
nunca serán tan ricos como la realidad misma. En concreto, una
de las limitaciones que se presentan es que existen determinados Aspectos
de nuestra solución que se resistirán a ser encapsulados
en clases estándar, normalmente porque afectan a un gran
número de procesos y/o actores. Son asuntos que conceptualmente
son ortogonales (independientes) a los demás, pero que al
modelizarse en términos de objetos terminan plasmándose
en forma de código repetido en distintos puntos del sistema, y
dependencias entre módulos que no están relacionadas con
el problema real que pretendíamos resolver.
 Consideremos como ejemplo la seguridad.
Supongamos que debemos desarrollar una aplicación de
gestión para una escuela, y que ésta debe tener un modelo
de seguridad complejo en el que, además de distinguir entre "usuario
autorizado" y "usuario no autorizado", cada usuario del
sistema debe tener una política de acceso en función de
sus características individuales, con reglas del tipo "un
profesor puede acceder a los datos de un alumno, pero sólo si
está matriculado en alguno de los cursos que imparte el
profesor. Además, si no es el tutor del alumno, entonces
sólo podrá consultar los datos, no modificarlos".
Una regla así requiere muchas comprobaciones en tiempo de
ejecución antes de permitir que un profesor modifique la ficha
del alumno, lo que puede (aunque hay formas de evitarlo)
provocar que el código relacionado con la seguridad termine
desperdigado entre las clases de lógica de negocio, la clase
Curso y la clase Alumno. Téngase en cuenta el énfasis en
la palabra "puede": existen patrones de diseño
orientado a objetos que permiten aislar este tipo de conceptos, como el
patrón comando, que encapsula los procesos de negocio
en clases individuales y permite ejercer un control muy fino sobre las
condiciones de invocación de cada proceso. Pero como veremos la AOP
nos proporciona formas más sencillas de resolverlos. 
 Conceptualmente, la AOP nos
proporciona nuevos elementos para representar conceptos que escapaban a
las técnicas de análisis orientadas a objetos.
Estructuralmente, los entornos de ejecución basados en Aspectos
añaden a nuestros ejecutables puntos de captura ("hooks")
a los que se puede asociar código arbitrario de forma
dinámica o estática. En definitiva, la AOP
nos da las herramientas necesarias para modelizar el "cuando se
acceda a un método de la clase Alumno, si la llamada viene de un
objeto de la clase Profesor, antes de ejecutarlo hay que comprobar si
el alumno pertenece a algún curso de éste y lanzar una
excepción si no es así" sin tener que introducir en
las clases Profesor ni Alumno código relativo a unas
funcionalidades que no les corresponden.
 La programación orientada a Aspectos
surgió a partir del trabajo de investigación sobre
lenguajes de programación orientados a objetos desarrollado
entre 1972 y 1980 por el equipo de Gregor Kiczales en
el Xerox Palo Alto Research Center
 
		CONCEPTOS 
 Lo que la AOP introduce de nuevo respecto a la
 OOP tradicional es que conceptos que hasta ahora
hemos estado representando por medio de clases, pasan
a tener una representación propia de primer nivel: el Aspecto.
 
 Utilizamos los Aspectos para
representar características globales de una aplicación
que por serlo influyen y reciben influencia de distintos componentes de
la misma, y que por tanto escapan a la ordenación tradicional de
capas (presentación, negocio, persistencia, servicios). Un
ejemplo muy habitual es el de los sistemas de trazas. Si necesitamos
que nuestra aplicación proporcione información en tiempo
de ejecución sobre las tareas que se van desarrollando,
normalmente utilizamos frameworks como Log4J o
java.util.logging, desperdigando por todo nuestro código
llamadas a éstos sistemas de trazas para ir registrando los
eventos. Pues bien, en términos de AOP, la
generación de trazas es un Aspecto de nuestra
aplicación, encapsulado en su propio -y único-
módulo de código fuente y por tanto desacoplado respecto
a las demás clases del sistema. Elementos ortogonales en el
sistema real pasan a ser también ortogonales en el modelo de
software.
 Una de las críticas más
recurrentes que se escuchan sobre AOP es que en
realidad no permite hacer nada nuevo que no se pueda hacer ya y que se
exagera su importancia. Es importante destacar que la novedad -y la
ventaja- de AOP no está en el qué,
sino en el cómo, pues permite diseños
mucho más limpios y fáciles de representar y comunicar
que por tanto dan lugar a aplicaciones mejor construídas y
más fáciles de implementar y mantener. Por ejemplo, hasta
ahora la persistencia se ha implementado como un conjunto de clases de
utilidad, gestores de esquema y una serie de técnicas repartidas
por el código a la hora de instanciar objetos o modificar sus
atributos (independientemente de si usamos JDBC directo, CMP, JDO o
frameworks a medida). La consecuencia de esto es que cuando un
fragmento de código invoca un método sobre un bean que
representa una entidad del modelo de datos, al menos uno de los dos (y
muchas veces ambos) deben ser conscientes del hecho de que el bean es
persistente, ya sea porque hay que comenzar una transacción JDO,
o enviar una consulta SQL a la base de datos o cualquier otro medio que
hayamos elegido. Como veremos más adelante, la AOP
nos proporciona herramientas para que la persistencia sea realmente un
elemento ortogonal a los demás de nuestra aplicacion, lo que se
ha venido a llamar "persistencia
transparente".
 Ciertamente hay muy pocas cosas que se puedan hacer con AOP que
no hayamos estado haciendo ya con la OOP tradicional. Debemos esperar
un cambio en la forma de resolver los problemas, no en ámbito de
éstos.
 A continuación se presentan los conceptos fundamentales
introducidos por la AOP. Son las herramientas que podemos utilizar para
representar esos Aspectos de nuestro sistema que antes se adaptaban a
duras penas a la representación por medio de clases: 
 		Punto de unión (join point):
Representa un "momento" en la ejecución de un programa, por
ejemplo, una llamada a un método, o un constructor, o el acceso
a un miembro de una clase en particular.
		Intersección (pointcut):
Declaración de un conjunto de puntos de unión, por
ejemplo, "llamadas a los métodos que empiecen por set".
		Guía/Consejo/Orientación (advice): Comportamiento
que queremos invocar cuando se alcance un determinado punto de
intersección.
		Aspecto (aspect): Módulo que define
uno o varios puntos de intersección y las acciones
(guías) que deben ejecutarse cuando la ejecución alcance
cualquiera de ellos.
		Introducción (introduction):
Comportamiento que añadimos a un objeto en tiempo de
ejecución para que implemente una interfaz adicional aparte de
la suya original.
 La programación orientada a Aspectos
complementa la programación orientada a objetos, introduciendo
nuevos conceptos que representan comportamientos que queremos asociar a
determinados momentos de la ejecución de un programa, pero que
no encajan en el modelado estático para el que tan buenos
resultados proporcionan las clases tradicionales. 
 
		APLICACIONES
 A estas alturas probablemente el lector ya tendrá en la
cabeza algunas posibles aplicaciones de estos nuevos conceptos. Algunos
de los más inmediatos son: 
 		 Trazas (logging): si podemos asociar un
determinado código a la invocación de un método,
podemos incluír en ese código las trazas sobre la llamada
al método, los parámetros, el tiempo que tarda en
ejecutarse, etc, de forma que el propio método sólo
contenga el código para completar la tarea que le corresponde.
		Seguridad: como ya comentamos antes, al
interceptarse las llamadas a métodos, acceso a miembros y
demás, podemos aplicar políticas de seguridad tan
arbitrarias como necesitemos sin mezclar ese código con el
existente.
		Persistencia: podemos interceptar las
llamadas a constructores y mutadores ("setters" ) de una clase y
aprovecharlas para lanzar consultas sql sincronizando los miembros con
la información de la base de datos.
		Funcionalidad arbitraria: incluso con el
sistema completamente desarrollado y en ejecución, podemos
agregar nuevas funcionalidades para tratar casos especiales o de
aparición tardía, sin modificar el código
existente.
		Monitorización y administración:
funcionalidades análogas a JMX se pueden implementar en
términos de Aspectos.
		Cacheado de información: podemos
aprovechar la intercepción de la llamada a un método para
decidir si efectivamente lo ejecutamos o si devolvemos un resultado
almacenado previamente.
 
 
		DIFERENTES ENFOQUES
 La AOP es una metodología emergente,
alrededor de la cual aún existe una intensa labor investigadora
en ámbitos académicos y empresariales. Esto ha derivado
en la existencia de muchos y muy variados enfoques a la hora de aplicar
las nuevas ideas. En mi opinión, y restringiéndome a los
frameworks Java, los que quizá tengan más posibilidades
de establecerse en un futuro cercano son los siguientes (en la
sección referencias se pueden
encontrar más información sobre ellos):
 		AspectJ: Actualmente en la versión
1.1. Desarrollado inicialmente en Xerox PARC y hospedado actualmente en
la fundación eclipse, AspectJ propone una extensión del
lenguaje Java, con nuevas palabras reservadas y construcciones
específicas para definir Aspectos, puntos de corte,
guías, etc.En su sitio web podemos descargar toda una plataforma
de desarrollo compuesta por un entorno de edición de
código (independiente o integrado en eclipse IDE), un compilador
y abundante documentación y ejemplos.
		Nanning:Actualmente en la versión
0.9. Framework basado en proxies dinámicos: clases que se
generan dinámicamente en tiempo de ejecución y se
interponen entre el autor de una llamada y el código de destino.
Los Aspectos se implementan mediante clases Java, y pueden
añadirse al sistema programáticamente o declararse en un
fichero xml de configuración. 
		AspectWerkz: Actualmente en la
versión 0.10. Al igual que en Nanning, los Aspectos se definen
como clases Java y pueden ser añadidos al sistema mediante un
fichero de configuración xml, pero además, podemos
declarar los Aspectos y guías en forma de atributos definidos en
el código fuente. En la actualidad se utilizan etiquetas
xDoclet, aunque se prevé adoptar el modelo de metadatos
introducido con el JDK 1.5 (JSR 175). AspectWerkz soporta el enlazado
de los Aspectos tanto en tiempo de ejecución (mediante proxies
dinámicos) como de forma estática, para lo que
proporciona un post-procesador que incorpora a las clases compiladas el
bytecode correspondiente a la funcionalidad definidda en las
guías en los puntos de corte seleccionados.
		JBossAOP: Actualmente en la versión
1.0Beta. La próxima versión 4.0 del servidor de
aplicaciones JBoss contiene un entorno AOP gracias al cual se pueden
proporcionar servicios como gestión de transacciones y
persistencia a POJO's ("Plain Old Java Objects") de forma
trasparente. Al generar los descriptores de despliegue para nuestra
aplicación deberemos incorporar uno más en el que se
definan qué servicios AOP va a requerir y JBoss los
incorporará en tiempo de ejecución mediante proxies
dinámicos.También podemos usar JBossAOP de forma
independiente del servidor.
 Cuál de los enfoques mencionados
gozará de mayor aceptación es algo que tendremos que ver
con el tiempo. Lo que está claro es que las grandes firmas del
Software están empezando a hacer una apuesta firme por la
Programación Orientada a Aspectos, y que eventos como la Aspect
Oriented Software Development Conference han trascendido los
entornos meramente académicos para convertirse en encuentros
empresariales donde, quizá, se esté definiendo el futuro
de las técnicas en Ingeniería de Software. 
 
		UN CASO PRÁCTICO
 Para ilustrar los conceptos introducidos, vamos
a desarrollar un pequeño ejemplo consistente en una
aplicación de gestión para un centro de enseñanza.
Supongamos que queremos representar Profesores, Cursos y Alumnos, y las
relaciones establecidas entre ellos. Cada alumno tiene un tutor y
está matriculado en una serie de cursos. Cada profesor imparte
una serie de cursos y además es tutor de una serie de alumnos, y
por último cada curso tiene un profesor y una serie de alumnos
matriculados. El modelo de datos estaría formado por las
siguientes clases: 
 		Entidad.java
		
 public abstract class Entidad
{
	/*
	 * La clase Entidad define las características comunes a todas las
	 * entidades. En particular, el hecho de que cada entidad debe tener un
	 * identificador único que permita realizar búsquedas, por ejemplo.
	 */
	protected Integer ID;
	/**
	 * Si nos pasan un id en el constructor, lo utilizamos para esta entidad.
	 * 
	 * @param id
	 */
	public Entidad(Integer id)
	{
		ID = id;
	}
	/**
	 * El constructor sin parámetros generará un nuevo ID. Cada entidad tendrá
	 * un ID generado aleatoriamente entre 0 y 1.000.000
	 */
	public Entidad()
	{
		ID = new Integer(10000000 * Math.random());
	}
	// .. //
}
 
		Alumno.java
		
 public class Alumno extends Entidad
{
	protected String	nombre;
	protected String	apellidos;
	protected List		cursos;
	protected Profesor	tutor;
	
	/**
	 * @param id
	 */
	public Alumno(Integer id)
	{
		super(id);
	}
	
	public Alumno()
	{
		//creamos el id...
		super();
		cursos = new ArrayList();
	}
	/**
	 * Añade un curso a la lista del alumno.
	 * 
	 * @param c
	 */
	public void addCurso(Curso c)
	{
		cursos.add(c);
	}
	//...getters
y setters //
}
 
		Profesor.java
		
 public class Profesor extends Entidad
{
	protected String nombre;
	protected String apellidos;
	protected List cursos;
	protected List alumnosTutelados;
	/**
	 * @param id
	 */
	public Profesor(Integer id)
	{
		super(id);
	}
	public Profesor()
	{
		super();
		alumnosTutelados = new ArrayList();
		cursos=new ArrayList();
	}
	/**
	 * 
	 * @param c
	 */
	public void addCurso(Curso c)
	{
		cursos.add(c);
	}
	/**
	 * 
	 * @param a
	 */
	public void addAlumnoTutelado(Alumno a)
	{
		alumnosTutelados.add(a);
	}
//... getters y setters	//	
}
 
		Curso.java
		
 public class Curso extends Entidad
{
	protected String nombre;
	protected Profesor profesor;
	protected List alumnos;
	
	/**
	 * @param id
	 */
	public Curso(Integer id)
	{
		super(id);
	}
	
	public Curso()
	{
		super();
		alumnos=new ArrayList();
	}
	
	/**
	 * 
	 * @param a
	 */
	public void addAlumno(Alumno a)
	{
		alumnos.add(a);
	}
	//...getters y setters //
}
 
		Main.java
		
 public class Main
{
	public static void main(String[] args)
	{
		//Creamos las entidades:
		System.out.println("Creando curso, profesor y alumno:");
		Curso c = new Curso();
		c.setNombre("Aspect Oriented Programming");
		Profesor p = new Profesor();
		p.setNombre("Nacho");
		p.setApellidos("Brito");
		Alumno a = new Alumno();
		a.setNombre("Manolito");
		a.setApellidos("Gafotas");
		
		//establecemos las relaciones:
		System.out.println("Estableciendo relaciones:");
		//El profesor p imparte el curso c, al que está matriculado el alumno
		// a, que además tiene a p como tutor.
		c.setProfesor(p);
		c.addAlumno(a);
		a.setTutor(p);
		a.addCurso(c);
		p.addAlumnoTutelado(a);
		p.addCurso(c);
	}
}		
 
 Hasta aquí todo es bastante
sencillo pero poco interesante. Parece el típico proyecto de
ejemplo en el que las partes complejas de las clases se omiten por
simplicidad. Pero... ¿y si afirmase que podemos hacer
persistentes estas entidades sin tocar una linea del código
existente? 
 Para este ejemplo vamos a utilizar AspectWerkz,
quizá el framework más flexible de entre los existentes.
Como vimos en el apartado 4, AspectWerkz nos permite definir nuestros
Aspectos como clases tradicionales, añadiendo la
metainformación sobre puntos de corte bien en un fichero xml
externo o bien en forma de atributos insertados en el código
fuente. Vamos a utilizar esta última manera por dos razones: la
primera es que el manejo del fichero xml es trivial y está muy
bien documentado en el sitio web de AspectWerkz (ver referencias), y la segunda porque tal como se
comenta en la documentación, próximamente la
declaración de puntos de corte se hará aprovechando las
nuevas características sobre metadatos que aporta la nueva JVM
1.5, con lo cual tendremos Aspectos autocontenidos (definidos en un
solo fichero de código fuente) y perfectamente integrados con la
plataforma estándar de Java.
 Veamos como definir la persistencia
en nuestra aplicación como un Aspecto. AspectWerkz
trata los Aspectos como clases java normales, con la única
restricción de que deben heredar de org.codehaus.aspectwerkz.aspect.Aspect.
Las guías que defina un Aspecto serán métodos de
la clase, y los puntos de corte podrán ser anónimos, en
cuyo caso simplemente se anotarán como atributos en el metadata
de la clase, o bien ser miembros de tipo JoinPoint. Así, nuestro
Aspecto para la persistencia queda como sigue:
 		PersistenceAspect.java
		
 public class PersistenceAspect extends Aspect {
 /**
 * Intercepta los accesos de escritura a los campos y almacena el valor
 * asignado en la base de datos.
 * 
 * @After set(* org.tres.escuela.modelo.*.*)
 */
 public void setterAdvice(JoinPoint joinPoint) throws Throwable {
 FieldSignature declaracion = (FieldSignature) joinPoint.getSignature();
 String sql = null;
 String nombreCampo = declaracion.getField().getName();
 System.out.println("Modificando el campo " + nombreCampo);
 DBHelper dbHelper = DBHelper.getInstance();
 //obtenemos información sobre la invocación:
 String tabla = joinPoint.getTargetClass().getName();
 Entidad sujeto = (Entidad) joinPoint.getTargetInstance();
 Field campo = declaracion.getField();
 Object resultado = campo.get(sujeto);
 if (nombreCampo.equals("ID"))
 {
 if (dbHelper.existeEntidad(sujeto))
 dbHelper.poblar(sujeto);
 else
 dbHelper.insertar(sujeto);
 }
 else
 dbHelper.actualizarCampo(campo, sujeto);
 }
 /*
 * (non-Javadoc)
 * 
 * @see java.lang.Object#finalize()
 */
 protected void finalize() throws Throwable {
 DBHelper.getInstance().close();
 super.finalize();
 }
 
 Lo primero que tenemos que destacar es la
nomenclatura de la guía "setterAdvice". En AspectWerkz, como en
la mayoría de frameworks AOP existentes en la actualidad, se
distinguen distintos tipos de guía en función de
cuándo queremos ejecutarlas para un punto de corte:
 		Before Advices: son guías que se ejecutarán
antes que el punto de corte al que están asociadas.
		After Advices: guías que se ejecutarán
después del punto de corte.
		Around Advices: guías que toman el control antes del
punto de ejecución y lo pierden después, teniendo la
posibilidad de modificar el flujo de ejecución en vez de ceder
el control al código original.
 Si vamos a definir un Around Advice,  el
método deberá devolver un Object en lugar de ser void,
como consecuencia de que una guía de este tipo puede incluso
suplantar la ejecución del punto de unión haciendo que el
objeto devuelto sea uno diferente
 
 Estas guías podrán aplicarse tanto
a constructores como métodos y campos de una clase cualquiera.
Es importante prestar atención a la etiqueta " @After
set(* org.tres.escuela.modelo.*.*)" que se encuentra en el
comentario javaDoc del método setterAdvice. En la actualidad
AspectWerkz utiliza etiquetas XDoclet para la generación de
metainformación sobre los Aspectos, aunque como hemos visto esto
cambiará con el JDK 1.5. Con esta etiqueta estamos declarando
que el método setterAdvice es una guía para el punto de
corte representado por "set(* org.tres.escuela.modelo.*.*)", que
comprende todos los accesos de escritura ("set") sobre campos de
cualquier tipo (primer asterisco) de cualquier clase del paquete
org.tres.escuela.modelo, sin ninguna restricción de nombre
(penúltimo y último asteriscos, respectivamente). En la
práctica totalidad de los frameworks AOP se contempla el empleo
de expresiones regulares para declarar puntos de corte. Para una
información más detallada sobre el funcionamiento de este
framework, consultar las referencias
anotadas al final del artículo.
 Como vemos, el método guía recibe
un único parámetro, de tipo JoinPoint, que nos
proporciona acceso al contexto de ejecución del punto de
unión que se está ejecutando en el momento de invocar
nuestro Aspecto. Podemos obtener información sobre la instancia
sobre la que se modificaba el campo, su clase, el valor del campo
modificado, etc. En este caso utilizamos esta información para
generar una consulta SQL que mantendrá sincronizado nuestro
objeto con la base de datos. En caso de que estemos modificando el
campo ID, se asume que lo que se quiere es modificar la identidad del
objeto, que pasará a representar una entidad distinta.
 Para ejecutar nuestra aplicación debemos
primero declarar el Aspecto en un archivo "aspectwerkz.xml" y colocarlo
en el classpath:
 
 <!DOCTYPE aspectwerkz PUBLIC "-//AspectWerkz//DTD 0.10//EN" "http://aspectwerkz.codehaus.org/dtd/aspectwerkz_0_10.dtd">
<aspectwerkz>
 <system id="escuela">
 <package name="org.tres.escuela">
 <aspect class="aop.PersistenceAspect"/>
	
 </package>
 </system>
</aspectwerkz> 
 En este archivo estamos declarando un
único
Aspecto, definido en la clase org.tres.escuela.aop.PersistenceAspect.
Para introducir los ganchos ("hooks"), y a la espera de
JDK1.5, deberemos ejecutar el postprocesador:
 H:\AOP>java org.codehaus.aspectwerkz.definition.AspectC -verbose ./src ./bin
AspectC::INFO - compiling attributes...
AspectC::INFO - aspect [org.tres.escuela.aop.PersistenceAspect]
AspectC::INFO - deployment model [perJVM]
AspectC::INFO - after advice [setterAdvice::set(* org.tres.escuela.modelo.*.*)]
AspectC::INFO - compiled classes written to ./bin
AspectC::INFO - compilation successful	
 Y, finalmente, ejecutamos nuestra
aplicación sustituyendo el comando java por el script
"aspectwerkz", que invoca a la máquina virtual sustituyendo el
ClassLoader estándar por uno específico que se
encargará de monitorizar la ejecución del código e
invocar a cada Aspecto cuando se alcance el punto de
intersección definido: 
 
 H:\AOP>aspectwerkz -cp bin org.tres.escuela.Main
 NOTA: En la versión 0.10
de AspectWerkz existe un fallo en los scripts proporcionados
(aspectwerkz y setEnv); al definir el CLASSPATH se olvidan de incluir
la librería bcel.jar. Hay que modificar el script para
incluírla en el CLASSPATH o el ejemplo no funcionará. 
 
		CONCLUSIONES
 Vamos a seguir oyendo hablar sobre la AOP. La
prueba de ello es el interés que han mostrado en la idea
empresas com IBM, que lo manifestó
abiertamente en la última Aspect Oriented Software
Development Conference (AOSD), Bea, que
recientemente ha comenzado su patrocinio del proyecto AspectWerkz, o JBoss,
que basa la próxima versión 4.0 de su servidor de
aplicaciones en aplicar Aspectos sobre los componentes del
desarrollador que les proporcionen los servicios definidos por la
especificación J2EE. 
 Puede sin embargo que la adopción de la
AOP sea desigual, al menos la adopción directa. Parece que donde
primero veremos aparecer implementaciones estables basadas en Aspectos
es en los servidores de aplicaciones, que de esta forma podrán
proveer de distintos servicios a los componentes desplegados en su
interior de una forma mucho menos intrusiva que hasta ahora. Pronto
veremos contenedores que no necesitarán que implementemos
interfaces extrañas para proporcionarnos servicios de
persistencia, gestión de transacciones o seguridad.
 
		REFERENCIAS 
		Aspect Oriented Software Development
		Aspect Oriented Software
Development Conference
		Seguimiento
de la AOSD en TheServerside
		AspectWerkz
		Artículo
de Graham O'Regan sobre AspectWerkz, traducido al castellano por Juan
Antonio Palos
		Cambios
en la version 0.10 de AspectWerkz, despues de que Bea comenzara su
patrocinio del proyecto.
		AspectJ
		Artículo
de Nicholas Lesiecki sobre AspectJ
		Documentación
sobre AspectJ en el sitio de Xerox PARC
		Introducción
teórica a la AOP, por los miembros del equipo original de Xerox
PARC
		JBossAOP
		Artículo
de Bill Burke y Adrian Brock sobre AOP y JBoss 
		Artículo
de Yasser EL-Manzalawy sobre AOP en developer.com
		Artículo
de Russ Milles sobre Lazy Loading con AspectJ
ejecutar.bat
java org.codehaus.aspectwerkz.definition.AspectC -verbose ./src ./bin
aspectwerkz -cp bin org.tres.escuela.Main
src/aspectwerkz.xml
 
 
 
 
 
 
src/org/tres/escuela/Main.java
src/org/tres/escuela/Main.java
package org.tres.escuela;
import org.tres.escuela.modelo.Alumno;
import org.tres.escuela.modelo.Curso;
import org.tres.escuela.modelo.Profesor;
/**
 * @author Nacho
 */
public class Main
{
    public static void main(String[] args)
    {
        //Creamos las entidades:
        System.out.println("Creando curso, profesor y alumno:");
        Curso c = new Curso();
        c.setNombre("Aspect Oriented Programming");
        //System.out.println(c);
        Profesor p = new Profesor();
        p.setNombre("Nacho");
        p.setApellidos("Brito");
        //System.out.println(p);
        Alumno a = new Alumno();
        a.setNombre("Manolito");
        a.setApellidos("Gafotas");
        //System.out.println(a);
         
        //establecemos las relaciones:
        System.out.println("Estableciendo relaciones:");
        //El profesor p imparte el curso c, al que está matriculado el alumno
        // a, que además tiene a p como tutor.
        c.setProfesor(p);
        c.addAlumno(a);
        a.setTutor(p);
        a.addCurso(c);
        p.addAlumnoTutelado(a);
        p.addCurso(c);
        //System.out.println(c);
        //System.out.println(p);
        //System.out.println(a);
    }
}
src/org/tres/escuela/aop/PersistenceAspect.java
src/org/tres/escuela/aop/PersistenceAspect.java
package org.tres.escuela.aop;
import java.lang.reflect.Field;
import org.codehaus.aspectwerkz.aspect.Aspect;
import org.codehaus.aspectwerkz.joinpoint.FieldSignature;
import org.codehaus.aspectwerkz.joinpoint.JoinPoint;
import org.tres.escuela.modelo.Entidad;
import org.tres.escuela.persistencia.DBHelper;
/**
 * @Aspect perJVM
 * @author Nacho. La persistencia se trata como un aspecto de la aplicación, de
 *         forma que en esta clase se implementan los distintos "advices" que
 *         defienen el comportamiento "persistente"
 */
public class PersistenceAspect extends Aspect
{
    /**
     * Intercepta los accesos de escritura a los campos y almacena el valor
     * asignado en la base de datos.
     * 
     * @param invocation
     * @return El resultado de invocar al siguiente consejo o el método final. 
     * @throws Throwable
     * @After set(* org.tres.escuela.modelo.*.*)
     */
    public void setterAdvice(JoinPoint joinPoint) throws Throwable
    {
        FieldSignature declaracion = (FieldSignature) joinPoint.getSignature();
        String sql = null;
        String nombreCampo = declaracion.getField().getName();
        System.out.println("Modificando el campo " + nombreCampo);
        DBHelper dbHelper = DBHelper.getInstance();
        //obtenemos información sobre la invocación:
        String tabla = joinPoint.getTargetClass().getName();
        Entidad sujeto = (Entidad) joinPoint.getTargetInstance();
        Field campo = declaracion.getField();
        Object resultado = campo.get(sujeto);
        if (nombreCampo.equals("ID"))
        {
            if (dbHelper.existeEntidad(sujeto))
                dbHelper.poblar(sujeto);
            else
                dbHelper.insertar(sujeto);
        }
        else
            dbHelper.actualizarCampo(campo, sujeto);
    }
    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#finalize()
     */
    protected void finalize() throws Throwable
    {
        DBHelper.getInstance().close();
        super.finalize();
    }
}
src/org/tres/escuela/modelo/Alumno.java
src/org/tres/escuela/modelo/Alumno.java
package org.tres.escuela.modelo;
import java.util.ArrayList;
import java.util.List;
/**
 * @author Nacho
 */
public class Alumno extends Entidad
{
    protected String        nombre;
    protected String        apellidos;
    protected List      cursos;
    protected Profesor  tutor;
    
    /**
     * @param id
     */
    public Alumno(Integer id)
    {
        super(id);
    }
    
    public Alumno()
    {
        //creamos el id...
        super();
        cursos = new ArrayList();
    }
    /**
     * Añade un curso a la lista del alumno.
     * 
     * @param c
     */
    public void addCurso(Curso c)
    {
        cursos.add(c);
    }
    /**
     * @return Returns the apellidos.
     */
    public String getApellidos()
    {
        return apellidos;
    }
    /**
     * @param apellidos
     *            The apellidos to set.
     */
    public void setApellidos(String apellidos)
    {
        this.apellidos = apellidos;
    }
    /**
     * @return Returns the nombre.
     */
    public String getNombre()
    {
        return nombre;
    }
    /**
* @param nombre
     *            The nombre to set.
     */
    public void setNombre(String nombre)
    {
        this.nombre = nombre;
    }
    /**
     * @return Returns the tutor.
     */
    public Profesor getTutor()
    {
        return tutor;
    }
    /**
     * @param tutor
     *            The tutor to set.
     */
    public void setTutor(Profesor tutor)
    {
        this.tutor = tutor;
    }
    /**
     * @return Returns the cursos.
     */
    public List getCursos()
    {
        return cursos;
    }
}
src/org/tres/escuela/modelo/Curso.java
src/org/tres/escuela/modelo/Curso.java
package org.tres.escuela.modelo;
import java.util.ArrayList;
import java.util.List;
/**
 * @author Nacho
 */
public class Curso extends Entidad
{
    protected String nombre;
    protected Profesor profesor;
    protected List alumnos;
    
    /**
     * @param id
     */
    public Curso(Integer id)
    {
        super(id);
    }
    
    public Curso()
    {
        super();
        System.out.println("Instanciando curso");
        alumnos=new ArrayList();
    }
    
    /**
     * 
     * @param a
     */
    public void addAlumno(Alumno a)
    {
        alumnos.add(a);
    }
    /**
     * @return Returns the nombre.
     */
    public String getNombre()
    {
        return nombre;
    }
    /**
     * @param nombre The nombre to set.
     */
    public void setNombre(String nombre)
    {
        this.nombre = nombre;
    }
    /**
     * @return Returns the profesor.
     */
    public Profesor getProfesor()
    {
        return profesor;
    }
    /**
     * @param profesor The profesor to set.
     */
    public void setProfesor(Profesor profesor)
    {
        this.profesor = profesor;
    }
    /**
     * @return Returns the alumnos.
     */
    public List getAlumnos()
    {
        return alumnos;
    }
}
src/org/tres/escuela/modelo/Entidad.java
src/org/tres/escuela/modelo/Entidad.java
package org.tres.escuela.modelo;
import java.lang.reflect.Field;
/**
 * @author Nacho
 */
public abstract class Entidad
{
    /*
     * La clase entidad define las características comunes a todas las
     * entidades. En particular, el hecho de que cada entidad debe tener un
     * identificador único que permita realizar búsquedas, por ejemplo.
     */
    protected Integer   ID;
    /**
     * Si nos pasan un id en el constructor, lo utilizamos para esta entidad.
     * 
     * @param id
     */
    public Entidad(Integer id)
    {
        ID = id;
    }
    /**
     * El constructor sin parámetros generará un nuevo ID. Cada entidad tendrá
     * un ID generado aleatoriamente entre 0 y 1.000.000
     */
    public Entidad()
    {
        ID = new Integer((int) (10000000 * Math.random()));
        System.out.println("ID generado: " + ID);
    }
    /**
     * @return Returns the iD.
     */
    public Integer getID()
    {
        return ID;
    }
    /**
     * muy útil para depuración ;-)
     */
    public String toString()
    {
        StringBuffer sb = new StringBuffer("\n" + getClass().getName() + ":\n");
        Field[] campos = getClass().getDeclaredFields();
        try
        {
            Class list = Class.forName("java.util.List");
            for (int i = 0; i < campos.length; i++)
            {
                if (!list.isAssignableFrom(campos[i].getType()))
                {
                    try
                    {
                        sb = sb.append(campos[i].getName() + ": " + campos[i].get(this) + "\n");
                    }
                    catch (Exception e1)
                    {
                        sb = sb.append(campos[i].getName() + ": <inaccesible>\n");
                    }
                }
                else
                    sb = sb.append(campos[i].getName() + ": <lista>\n");
            }
        }
        catch (ClassNotFoundException e)
        {
            e.printStackTrace();
        }
        return sb.toString();
    }
}
src/org/tres/escuela/modelo/Profesor.java
src/org/tres/escuela/modelo/Profesor.java
package org.tres.escuela.modelo;
import java.util.ArrayList;
import java.util.List;
/**
 * @author Nacho
 */
public class Profesor extends Entidad
{
    protected String nombre;
    protected String apellidos;
    protected List cursos;
    protected List alumnosTutelados;
    /**
     * @param id
     */
    public Profesor(Integer id)
    {
        super(id);
    }
    public Profesor()
    {
        super();
        alumnosTutelados = new ArrayList();
        cursos=new ArrayList();
    }
    /**
     * 
     * @param c
     */
    public void addCurso(Curso c)
    {
        cursos.add(c);
    }
    /**
     * 
     * @param a
     */
    public void addAlumnoTutelado(Alumno a)
    {
        alumnosTutelados.add(a);
    }
    /**
     * @return Returns the apellidos.
     */
    public String getApellidos()
    {
        return apellidos;
    }
    /**
     * @param apellidos The apellidos to set.
     */
    public void setApellidos(String apellidos)
    {
        this.apellidos = apellidos;
    }
    /**
     * @return Returns the nombre.
     */
    public String getNombre()
    {
        return nombre;
    }
    /**
     * @param nombre The nombre to set.
     */
    public void setNombre(String nombre)
    {
        this.nombre = nombre;
    }
    /**
     * @return Returns the alumnosTutelados.
     */
    public List getAlumnosTutelados()
    {
        return alumnosTutelados;
    }
    /**
     * @return Returns the cursos.
     */
    public List getCursos()
    {
        return cursos;
    }
}
src/org/tres/escuela/persistencia/DBHelper.java
src/org/tres/escuela/persistencia/DBHelper.java
package org.tres.escuela.persistencia;
import java.lang.reflect.Field;
import java.sql.Connection;
import org.tres.escuela.modelo.Entidad;
public class DBHelper
{
    private static DBHelper instance = null;
    private Connection cn = null;
    /**
     * SINGLETON
     * 
     * @return
     */
    public static DBHelper getInstance()
    {
        if (instance == null)
            instance = new DBHelper();
        return instance;
    }
    /**
     * 
     *  
     */
    private DBHelper()
    {
        System.out.println("DBHelper: Instanciando DBHelper");
    }
    /**
     * @param sql
     */
    public void execute(String sql) throws Exception
    {
        System.out.println("DBHelper: Ejecutando " + sql);
    }
    /**
     * @param e
     */
    public void insertar(Entidad e)
    {
        System.out.println("DBHelper: Insertando " + e.getClass().getName());
    }
    /**
     * @param e
     */
    public void poblar(Entidad e)
    {
        System.out.println("DBHelper: Poblando " + e.getClass().getName());
    }
    /**
     * @param class1
     */
    public void comprobarQueExisteTabla(Class class1)
    {
        System.out.println("DBHelper: Comprobando si existe la tabla " + class1.getName());
    }
    /**
     *  
     */
    public void close()
    {
        System.out.println("DBHelper: Cerrando conexión.");
    }
    /**
     * Comprueba si existe la entidad proporcionada
     * 
     * @param resultado
     * @return
     */
    public boolean existeEntidad(Entidad resultado)
    {
        System.out.println("DBHelper:Comprobando si existe el " + resultado.getClass().getName()
                + " con ID " + resultado.getID());
        return false;
    }
    /**
     * @param campo
     * @param sujeto
     */
    public void actualizarCampo(Field campo, Entidad sujeto)
    {
        System.out.println("DBHelper: Actualizando " + campo.getName() + " en el "
                + sujeto.getClass().getName() + " con ID " + sujeto.getID());
}
}

Continuar navegando