Documente Academic
Documente Profesional
Documente Cultură
Motivaciones
Antes de profundizar en la temtica propia de la orientacin a aspectos y sus aplicaciones en el mundo real, sera conveniente describir las motivaciones principales que han ocasionado la escritura de este captulo de la memoria. La primera de ellas ha sido la intencin de introducir al lector en algunas de las tcnicas de desarrollo avanzadas utilizadas en la actualidad por los equipos de desarrollo de software ms vanguardistas. La segunda est relacionada con el desarrollo de nuevas herramientas de programacin y, por ende, con la herramienta desarrollada como ejemplo de este proyecto: R-Eclipse. Si el lector desconoce muchos de los trminos definidos en esta seccin no se preocupe, a lo largo del captulo comprender la terminologa aqu utilizada. En los ltimos aos han surgido muchos lenguajes similares a Java que se ejecutan sobre la propia mquina virtual de este ltimo (JVM), lo cual es un indicador bastante fiable del futuro del desarrollo de aplicaciones sobre la plataforma Java.1Sin embargo, Eclipse y su solucin JDT, no ofrecen soporte para la integracin de estos nuevos lenguajes en su modelo Java subyacente. Por ejemplo, no existe un modo de incluir jerarquas de tipos,jerarquas de llamadas, etc.
R Eclipse no ha utilizado el enfoque descrito en esta seccin por dos motivos principalmente; el primero de ellos es que R no es un lenguaje similar a Java ni corre bajo su mquina virtual. El segundo de ellos consiste en que el framework base de desarrollo, DLTK, no utiliza la arquitectura descrita en estas lneas.
Algunos de los problemas que se encuentran los ingenieros de software cuando intentan construir herramientas para algunos de los lenguajes descritos anteriormente son: Necesidad de acoplarse al modelo ofrecido por JDT. No se puede. Necesidad de acoplarse al motor de indexacin de cdigo fuente. No se puede. Necesidad de acoplarse al parser de JDT. No se puede. Una aproximacin utilizada por muchos entornos de desarrollo de lenguajes actuales como pueden ser Scala o Groovy es la utilizacin del servicio de tejido de JDT. Las caractersticas principales son: Utiliza AspectJ aadiendo puntos de unin al modelo JDT Se encapsula en puntos de extensin de Eclipse, hacindolo extensible a terceras partes. Utiliza un proyecto de Eclipse conocido como Equinox Aspects que soporta el proceso de tejido en tiempo de carga en un entorno OSGI. El siguiente grfico ilustra como funciona el proceso anterior:
A lo largo de las siguentes secciones se introducir la terminologa AOP as como la definicin de sus elementos ms relevantes.
fenmeno es conocido como scattering , puesto que el cdigo relacionado con un mismo asunto se encuentra repartido a lo largo de todo el sistema. Sumemos, adems, que los mdulos que contienen cdigo relativo a muchos asuntos diferentes tienden a ser, en general, menos reutilizables. El fenmeno en el que diferentes asuntos son entremezclados en el cdigo se conoce como tangling . La problemtica introducida en los prrafos anteriores, tangling y scattering , afecta al diseo y desarrollo de software de muchas y diferentes maneras. Veamos alguna de las principales: Trazabilidad reducida. La implementacin de diferentes conceptos en un mismo lugar dificulta el proceso de establecimiento de una relacin entre los requisitos y su implementacin y viceversa. As por ejemplo, para completar la trazabilidad del requerimiento de autenticacin podramos llegar a examinar todos los mdulos del sistema. Baja producitividad. Varios conceptos no relacionados que han sido implementados en un mismo lugar ocasiona que la atencin se disperse a lo largo de todos ellos. La falta de un objetivo concreto provoca que los desarrolladores se vean obligados a manejar diferentes conceptos no relacionados con el objetivo principal. En muchas ocasiones,la construccin de un mdulo implicar la participacin de diversos desarrolladores, con diferentes perfiles, o que el desarrollador tenga conocimiento en todos los mbitos que se estn incluyendo en el nuevo mdulo. Escasa reutilizacin del cdigo. Los conceptos implementados en un mdulo podran ser requeridos por otros mdulos con funcionalidades similares Baja calidad. El code tangling provoca que el cdigo sea ms difcil de leer, de ubicar los potenciales problemas y de hacer revisiones del mismo. Por ejemplo, la revisin de cdigo de un mdulo en el que se implementan diversos conceptos requerir la presencia de expertos en cada uno de ellos. A menudo muchos de estos expertos no estarn disponibles de manera simultnea, y el resto no prestar demasiada atencin en los temas que se encuentren fuera de su rea de conocimiento. Dificultad para llevar a cabo evoluciones. La falta de recursos o una visin incompleta derivan en un diseo que maneja nicamente los conceptos actuales. Cuando aparezcan nuevos requerimientos,a menudo, nos veremos obligados a reimplementar. Dado que la implementacin no se encuentra modularizada,la inclusin de un nuevo requerimiento podra obligar a realizar cambios en todos los mdulos. Los problemas descritos en los puntos anteriores han servido como impulso en la bsqueda de nuevos y mejores enfoques en la arquitectura, diseo e implementacin. AOP ofrece una solucin a todos los problemas anteriores.
Hype Cycle
Hype Cycle es una representacin grfica del grado de madurez, adopcin y aplicacin en el mundo real de una tecnologa determinada. Es importante comprender bien el grfico anterior, y la posicin de la tecnologa que se est considerando; en este caso, AOP, puesto que se dispondr de una visin mucho ms ajustada de los riesgos y beneficios a los que nos estamos exponiendo.
La interpretacin de la curva Hype Cicle implica cinco fases diferentes las cuales analizaremos a continuacin, relacionndolas, evidentemente con AOP.
Activacin de la tecnologa
Este es el momento en el que la tecnologa aparece con la intencin/promesa de solucionar un conjunto determinado de problemas. Podra ser el anuncio de un nuevo producto o la liberacin de una nueva versin de un producto ya existente. En el caso de AOP, este proceso de activacin se produjo en 2002 con el lanzamiento de AspectJ 1.0, seguido de una liberacin mucho ms importante (AspectJ 1.1) en el ao 2003. Mucha gente se dio cuenta del potencial de AspectJ, especialmente su utilizacin en aplicaciones empresariales.
Desilusin
Esta es la fase de ciclo Hype en la que la tecnologa comienza a perder toda la atencin que se le haba prestado hasta el momento. Mientras que los equipos que la adoptaron desde sus inicios continuan utilizndola con el objetivo de obtener una ventaja competitiva, muchos otros comienzan a observarla con cierto escepticismo. Nuevas tecnologas aparecen en escena aportando soluciones diferentes al mismo problema. Resulta
interesante destacar que muchos de estos nuevos competidores estn en la fase de "expectativas irreales". AOP atraves esta fase durante 2006 aproximadamente. Enterprise Java Beans ofreca una seria competencia, permitiendo implementar funcionalidades transversales como seguridad o transaccionalidad de una manera modular. Pero EJB no era el nico competidor, y tampoco el ms importante. La aparicin de lenguajes dinmicos como Groovy o Ruby y sus frameworks asociados, Grails y Rails, supuso una dura competencia para AOP. El modelo de metaprogramacin del que disponen estas tecnologas facilitaba una nueva solucin para realizar la modularizacin de funciones transversales.
Viendo la luz
Numerosos factores intervienen en el desarrollo de esta fase: maduracin de la tecnologa, cambios en la misma para acercarse a la realidad, bsqueda de un contexto de uso en el que realmente se cause impacto o la "desilusin" con otras alternativas, que en su momento fueron competidores, son algunas de ellas. En el caso de AOP, el comienzo de esta fase se produjo cuando algunos de los lderes del proyecto abandonaron IBM para fichar por SpringSource:Adrian Colyer,Andy Clement, Andrew Eisinberg, . . ., conviertiendo a AspectJ en un proyecto ms del portfolio de Spring. Analicemos los factores enumerados anteriormente: Acercamiento a la realidad:La introduccin de anotaciones en Java 5, los cambios en la sintxis o la supresin del proceso de weaving si se utiliza conjuntamente con Spring fueron algunos de los cambios realizados. La mejora en las herramientas de desarrollo fue otra de las respuestas a las necesidades reales de los usuarios. Contexto de utilizacin: la influencia de Spring: En sus inicios AspectJ careca de un contexto de utilizacin definido (C naci en el mbito de los sistemas operativos, C++ en el contexto de interfaz de usuario, etc). Ha sido Spring la que le ha proporcionado a AspectJ un contexto de uso bien definido: la aplicaciones empresariales. Desilusin con los competidores: Anteriormente indicamos que EJB permita modularizar los conceptos transversales de un sistema. Los desarrolladores se dieron cuenta de que la solucin ofrecida era demasiado pesada en la mayora de las ocasiones. La versin 3 de EJB introdujo interceptores, un concepto similar a los advices de AspectJ, aunque carecan de un modelo de unin. Los lenguajes dinmicos ofrecen una gran alternativa a AspectJ aunque son relativamente nuevos. Tendremos que esperar el paso del tiempo y el uso en grandes aplicaciones empresariales para determinar la evolucin de los mismos, y ver cmo contina evolucionando AspectJ.
Plena productividad
Es la ltima fase definida en el ciclo Hype. En esta situacin la tecnologa est ampliamente difundida y se utiliza en las solucin de problemas para los que ofrece una gran respuesta. Ser en esta fase cuando se produzca una aceptacin mavisa de la tecnologa. En la actualidad,Java o C , se encuentran en esta fase. AOP y AspectJ debern alcanzar este nivel con el paso del tiempo.
Aplicaciones empresariales
Gestin de transacciones, seguridad, auditora, monitorizacin, gestin de la concurrencia, manejo de errores y un largo ectera son funcionalidades transversales en la mayora de aplicaciones empresariales.
Aquellas aplicaciones que usen Spring como base de su arquitectura ya estarn utilizando algunos de los aspectos que vienen facilitados por el framework. Gracias a las anotaciones, concretamente @Aspect, la construccin de aspectos se ha convertido en una tarea habitual.
Frameworks
Gestin de transacciones y seguridad son habitualmente implementadas mediante aspectos. Asimismo, otras utilizaciones de los aspectos podra ser la inyeccin de dependencias en objetos de dominio. Para obtener un amplio abanico de posibilidades de uso de los aspectos, el lector podra visitar los proyectos de Spring Roo o Apache Magma.
Herramientas de monitorizacin
El uso de aspectos facilita tambin la construccin de herramientas de monitorizacin. Muchas herramientas utilizan AspectJ como tecnologa subyacente: Glassbox,Perf4J,Contract4J,JXInsight o MaintainJ son algunos de los ejemplos.
Introduccin a AOP
AOP se construye sobre metodologas existentes como OOP o programacin funcional, mejorndolas con las construcciones necesarias que permiten modularizar correctamente los conceptos transversales. Por ejemplo, si se trabaja con OOP, el ncleo de nuestro sistema ser implementado mediante la utilizacin de clases. Los aspectos sern los encargados de representar las funcionalidades transversales y determinar cmo todos los diferentes mdulos debern ser tejidos para construir el sistema final.
Metodologa AOP
Desarrollar un sistema utilizando AOP es similar a un desarrollo basado en otras metodologas: determinar los requerimientos, implementarlos y construir el sistema final mediante la combinacin de los mismos. La comunidad AOP define tres pasos: 1. Descomposicin en aspectos En este paso se indentificarn los diferentes concerns , tanto los transversales como los que componen el ncleo. Por ejemplo, en una capa de negocio encargada de calcular el IVA total de los productos los aspectos pertenecientes al ncleo sera el clculo del IVA en s, mientras que elementos como la transaccionalidad, registro de actividad,seguridad en hilos, manejo de cachs, . . . seran conceptos de un espectro mucho ms amplio, que sern necesitados en otros muchos mdulos del sistema, y por tanto, se categorizan como conceptos transversales 2. Implementacin de "concerns" En este punto tendr que realizarse la implementacin de los diferentes requerimientos de manera independiente . Siguiendo con el ejemplo anterior, un grupo
2
sera el encargado de realizar la implementacin del mdulo de lgica de negocio encargado de calcular el IVA, otro grupo llevara a cabo la gestin del logging, un tercer grupo sera el encargado de asegurarse que las operaciones fuesen thread safe , y as sucesivamente. 3. Recomposicin de aspectos . En este paso se deben definir las reglas de composicin mediante la creacin de mdulos o aspectos . Este proceso, conocido como weaving , utiliza esta informacin para construir el sistema final. La principal aportacin de AOP es la independencia de los "concerns" en el momento de su implementacin. El modo en que se realiza la implementacin permite una completa trazabilidad entre los requerimientos y su implementacin, por lo que el sistema final ser ms fcil de comprender, implementar o adaptar ante futuros cambios
Implementacin de AOP
La implementacin del lenguaje debe llevar a cabo dos acciones:combinar los aspectos individuales mediante las reglas de tejido,para, posteriormente, convertir la informacin resultante en cdigo ejecutable. El primero de los dos pasos anteriores es conocido como weaving, y el procesador encargado de realizar dicha tarea es el weaver. Proceso de weaving . Tal y como argumentaba la introduccin de este punto, el proceso de weaving es el encargado de componer el sistema final mediante la composicin de los diferentes concerns siguiendo las pautas establecidas en las reglas de tejido . Estas reglas son definidas en aspectos
independientes del ncleo del sistema por lo que con unas nuevas reglas de "tejido" podramos construir un sistema final completamente diferente. Procesador (Weaver) El procesador encargado de llevar a cabo el proceso de weaving descrito en el punto anterior es comunmente conocido como weaver Una posible implementacin sera utilizar una transformacin cdigo a cdigo (un compilador). De ese modo, el compilador de aop "tejera" los aspectos junto al resto de clases generando un nuevo cdigo ya "tejido". Una vez finalizado este proceso, el cdigo generado anteriormente servira como entrada para el compilador de lenguaje base el cual sera el encargado de generar el ejecutable. Utilizando el enfoque anterior, una aproximacin basada en C++ convertira todos los archivos individuales (aspectos y clases) en cdigo C++ tejido(weaving). El siguiente diagrama ilustra la aproximacin descrita en el prrafo anterior:
XP (siglas en ingls de Programacin Extrema) siguiendo la prctica del principio YAGNI (siglas en ingls de No lo vas a necesitar ) . De este modo, podemos seguir el principio anterior, dando vida nicamente a las funcionalidades requeridas e implementando futuros requerimientos sin la necesidad de grandes modificaciones en el sistema. Sencillez en las mejoras . AOP permite aadir una nueva funcionalidad sin ms que desarrollar un nuevo aspecto (el cual no afecta al ncleo del sistema). Gracias a ello, el tiempo de respuesta ante nuevos requerimientos disminuye notablemente. Incremento en la reutilizacin del cdigo .Puesto que AOP implementa cada aspecto en un mdulo independiente, cada uno de ellos es independiente del resto. En general, cada uno de ellos no suelen tener conocimiento del resto de elementos que conforman el sistema final. Realmente, el nico elemento consciente del acoplamiento entre los diferentes mdulos son las reglas de tejido , de manera que, si cambiamos stas, podemos componer un sistema final completamente diferente. Reduccin de costes y accesos al mercado ms rpidos .Las caractersticas descritas en los puntos anteriores generan sistemas ms rpidos, tanto en su desarrollo como en su implantacin . Eliminando la necesidad de modificar mltiples mdulos para la implementacin de un nuevo concepto transversal, AOP provoca que dicha implementacin sea ms barata. Asimismo, permitiendo que los desarrolladores estn centrados en su especialidad logramos que el coste del desarrollo disminuya.
10
encapsulan todo el comportamiento, mientras que AOP elimina estos niveles de control de las mismas. AOP reemplazar a OOP . Falso. Los conceptos principales seguirn siendo implementados en OOP ( o puede que en un lenguaje procedimantal como puede ser C). AOP aade un nuevo conjunto de conceptos adicionales a la metodologa orientada a objetos. Efectivamente, AOP cambiar el modo en el que se utilizan las metodologas actuales para la implementacin de conceptos transversales.
Introduccin a AspectJ
El compilador de AspectJ es el encargado de utilizar los mdulos que contienen las definiciones de las reglas de tejido para aadir nuevo comportamiento a los mdulos que implementan las funcionalidades principales. El proceso anterior no realiza ninguna modificacin sobre el cdigo fuente del ncleo dado que el proceso de tejido se realiza sobre el bytecode generado por el compilador.
11
Joint Point
Como ya se defini anteriormente, un join point es un punto de ejecucin en un sistema. As por ejemplo, el acceso al campo de una clase, la ejecucin de una funcin o una sentencia for son ejemplos de join points. AspectJ solamente expone un subconjunto de todos los posibles joint points, limitando de este modo, el acceso a las construcciones ms estables.
Pointcuts
Es un artefacto que nos permite seleccionar joint points y recuperar su contexto.Veamos algunas de las caractersticas principales:
Utilizacin de signaturas
En Java, todos los elementos que componente un programa tienen una signatura. La utilizacin de patrones para dichas signaturas permiten a los pointcuts especificar las reglas que permiten seleccionar los joint point deseados.
12
Conceptos bsicos
A continuacin se analizarn los elementos bsicos que se deben conocer para definir un pointcut.
Operadores
AspectJ proporciona el operador unario de negacin (!) y dos operadores binarios: && y ||, gracias a los cuales se permite construir reglas de matching complejas mediante la combinacin de pointcuts ms sencillos. Tanto la semntica como la precedencia es la misma que en el lenguaje Java. As por ejemplo,en el caso del operador binario &&, se seleccionarn aquellos joint points que concuerden con los dos pointcuts que actan como operandos.
Cualquier tipo cuyo nombre termine en Por ejemplo, HighlightingAstVisitor o AstVisitor SemanticAstVisitor concuerdan con el patrn El tipo Date en cualquier subpaquete java.util.Date o java.sql.Date son directo del paquete java ejemplos de tipos concordantes Cualquier tipo en el paquete javax y en Cualquier tipo en el paquete sus subpaquetes (tanto directos como javax.security as como cualquiera indirectos) de sus subpaquetes indirectos como javax.security.auth.login
java.*.Date javax..*
13
la Descripcin
Todos los tipos en el paquete javax TableModel, TreeModel y sus (subpaquetes directos e indirectos) subtipos como DefaultTreeModel o cuyo nombre termine en Model, y todos DefaultTableModel. los subtipos de estos.
El tipo User anotado con la anotacin @Secured class User{. . .} Secured Cualquier tipo anotado con la anotacin @Entity class Section {. . .},@Entity Entity class Report {. . .} El tipo Manager y cualquiera de sus clases derivadas que estn anotados con una anotacin cuyo nombre comienze por Transactional @TransactionalDefault class Manager{},@TransactionalOracle class OracleManager extends Manager{}
El tipo Map cuyo primer argumento En este caso nicamente concordar el genrico est fijado a Integer y el tipo Map<Integer,String> segundo a String Cualquier tipo genrico cuyo nico Collection<User>,List<User>, . . . argumento genrico sea de tipo User El tipo Collection con un parmetro de Collection<User>, tipo User o derivado Collection<DomainUser>, . . . El tipo Collection, cuyo parmetro ser Collection<Serializable>, uno de los tipos base de User Collection<BaseUser>, asumiendo que, User extiende o implementa, directa o indirectamente, Serializable y BaseUser
Cualquier tipo que se encuentre anotado class NonTransactionalManager{} por por la anotacin Transactional Cualquier tipo que se encuentre anotado @Serializable @Encrypted por las dos anotaciones UserCredentials{} class
14
Patrn de signatura
la Descripcin
(@Serializable || Cualquier tipo que est anotado por @Serializable class User {} @Encrypted) * alguna de las dos anotaciones
public void Cualquier mtodo pblico de la clase class User{ public void setName(String User.set*(*) User cuyo nombre comienze por set, name){} } cuyo tipo de retorno sea void, y que espere un nico argumento public User.*() void Cualquier mtodo pblico de la clase class User { public void updateInfo() User cuyo tipo de retorno sea void y que {}} no espere argumentos Cualquier mtodo pblico de la clase class User{ public User que no espera argumentos y getUserInfo(){}} retorna cualquier tipo UserInfo
public * User.*()
public * User.*(..) Cualquier mtodo pblico de la clase User que retorna cualquier tipo, y espera cualquier nmero y tipo de argumentos (incluido cero) * *.*(..) o * * (..)
class User{ public UserInfo getUserInfo(){},public Date updatesBetween(Date first,Date last) {}}
Cualquier mtodo independiente de su Cualquier mtodo del sistema tipo, del tipo de retorno, de su nombre y de los argumentos que espere
!public * User.*(..) Cualquier mtodo que no sea pblico class User {protected getUserInfo(){}} (privado,protegido o paquete) * * (..) throws Cualquier mtodo que declare que clas AntlRBasedParser { RecognitionException puede lanzar una excepcin de tipo void parser(String file) RecognitionException RecognitionException} * User+.*(..) User UserService.*(..) public throws
Cualquier mtodo en la clase User y sus class UserDetails extends User {} subclases Cualquier mtodo del tipo UserService cuyo tipo de retorno sea User. Si alguna de las subclases sobreescribe el tipo de retorno con un subtipo de User (mediante el tipo de retorno covariante introducido en Java 5) tambin ser seleccionado. class UserService{public User retrieveUser(String name){}} class DetailUserService extends UserService{public DetailedUser retrieveUser(String name){}}
La signatura en el caso de los constructores difiere de la signatura de mtodos en los siguientes aspectos: Los constructores no tienen tipo de retorno por lo que no se permite utilizar el valor de retorno en la especificacin de un pointcut de este tipo. Dado que los nombres de los constructores no pueden ser libres (tienen que utilizar el mismo nombre de la clase), la parte de la signatura destinada al nombre ser sustituida con la palabra new. Por ltimo, puesto que los constructores no pueden ser estticos, no se podr utilizar la palabra reservada static
15
private String Campo privado (tanto campo de una class User { private String username;} User.username instancia como esttico) de la clase User * User.* Cualquier campo de la clase User class User{private String independiente de sus cualificadores, username;protected int credits;private tipo y nombre. UserDetails details;} Cualquier campo de la El ejemplo de la fila anterior o class clase User y todas sus SpecificUser extends User {private subclases, independientemente de sus String address;} cualificadores, tipo y nombre.
* User+.*
Implementacin de pointcuts
AspectJ ofrece dos mecanimos diferentes que permiten a los pointcuts realizar la seleccin de los joint points Kinded pointcuts. En este caso, los pointcuts seleccionan categoras de joint points (de ah su nombre). As, por ejemplo, se ofrece la posibilidad de realizar matching sobre la ejecucin de un mtodo Non-kinded pointcuts. Se seleccionan los joint point en base a la informacin de la que disponen, como los tipos en tiempo de ejecucin o su contexto. En esta situacin se seleccionan joint points de cualquier clase, siempre y cuando sastisfagan la condicin descrita De nuevo, al igual que en el apartado anterior, veremos las diferentes opciones disponibles, tanto para los kinded como para los non-kinded pointcuts.
Por ejemplo, si deseamos seleccionar todas las llamadas a los mtodos pblicos commit() de la clase TransactionManager, escribiramos un pointcut similar al siguiente: call(public void TransactionManager.commit(. .))
16
Non-kinded pointcuts
Este tipo de pointctus permiten la seleccin de joint points basados en criterios adicionales a las signaturas vistas anteriormente. Por ejemplo, podremos seleccionar todos los joint point donde el objeto this es de un determinado tipo. Dicho joint point incluira las llamadas a mtodos, ejecuciones, manejadores de excepciones, etc. De nuevo, a travs de ejemplos, veremos los diferentes tipos de non-kinded pointcuts ofrecios por AspectJ Non-kinded pointcuts basados en control de flujo
cflow(execution(@Secured * * Todos los joint points en el flujo de la ejecucin de cualquier (..))) mtodo anotado con la anotacin Secured cflow(transacted()) Cualquier joint point en el flujo de ejecucin de los joint points seleccionados por el pointcut transacted()
Non-kinded pointcuts basados en la estructura lxica Dentro de este tipo de pointcuts tenemos dos categoras: within(TypeSingnature): selecciona cualquier joint point que aparece en el cuerpo de las clases y aspectos que concuerden con el tipo especificado. withincode(ConstructorSignature),withincode(MethodSignature): selecciona cualquier joint point que aparezca dentre de un mtodo o un constructor, incluendo la definicin de cualquier clase local que puediera aparecer en los mismos.
withincode(* Selecciona todos los joint points que parecen dentro de cualquier TransactionManager.retrieve*(..)) mtodo de la clase TransactionManager cuyo nombre comience por retrieve Non-kinded pointcuts de ejecucin Este tipo de pointcuts nos permiten seleccionar joint points en base al tipo de los objetos en tiempo de ejecucin. De este modo, disponemos de: this(). Acepta dos formas diferentes: this(ObjectIdentifier) o this(Type). Seleccionar aquellos joint points cuyo objeto this sea del tipo (o el objeto) indicado.
17
target(). Similar al concepto anterior, aunque en este caso, se utilizar el target del joint point en lugar del this
target(User)
Non-kinded pointcuts sobre argumentos Este tipo de pointcuts nos permiten seleccionar joint points en base al tipo de los argumentos en tiempo de ejecucin. Veamos los distintos tipos de argumentos, en funcin del tipo del joint point : En el caso de los joint points manejadores de excepciones el argumento ser la excepcin manejada. En los mtodos y constructores, los argumentos sern los argumentos del mtodo y constructor Los accesos de modificacin de un campo, el argumento ser el nuevo valor que va a tomar dicho campo.
Crosscutting dinmico
A lo largo de las secciones anteriores hemos analizado el modelo de joint point de AspectJ y la manera de defininir las reglas que nos permitan seleccionar aquellos joint points que sean de nuestro inters. Durante este captulo analizaremos el modo en el que podemos alterar el comportamiento de nuestro sistema en los joint points que hayamos seleccionado mediante la definicin de nuestros pointcuts.
Descripcin general
Las reglas de tejido estn compuestas de dos partes:
3
El trmino crosscuting representa la naturaleza transversal de las funcionalidades que estamos aadiendo. Se ha optado por no realizar la traduccin del trmino y utilizar la terminologa orginal
18
advice: qu deseamos hacer pointcuts: donde aplicamos el advice anterior AspectJ soporta el crosscutting dinmico mediante los advices, construcciones similares a los mtodos que nos permiten definir las acciones que a ejecutar en los joint points seleccionados por un pointcut.
Categoras de advices
Dependiendo de las funcionalidades que estemos implementando necesitaremos ejecutar nuestra lgica en un determinado lugar del flujo de ejcucin orginal; as por ejemplo, si estamos construyendo la seguridad de un sistema, nuestro cdigo tendr que verificar dicha seguridad antes de la ejecucin del joint point. Si estuvieramos construyendo un sistema de cachs, nuestra nueva funcionalidad tendra que ejecutarse alrededor de joint point original, intentando recuperar el valor de la cach, y en caso de que no exista, ejecutar el cdigo real y aadirlo a la misma para futuras invocaciones. AspectJ ofrece tres categorias de advices que satisfacen los escenarios anteriores (y alguno ms): Before Advice se ejecutan anteriormente a la ejecucin del joint point After Advice: se ejecutan posteriormente a la ejecucin del joint point. Existen tres variantes diferentes After finally se ejecuta tras la ejecucin del join point independientemente del resultado de dicha ejecucin After returning se ejecuta tras la ejecucin del joint point siempre y cundo sta ltima haya finalizado correctamente, es decir, sin lanzar ninguna excepcin. After throwing se ejecuta tras la ejecucin fallida de un joint point, es decir, despus de que dicho joint point dispare una excepcin. Around Advice rodean la ejecucin del joint point.
pointcut secureOperation(User user): call( * User.*(..)) && target(user) En el pointcut anterior estamos capturando todas las llamadas a cualquier mtodo de la clase User, y, adicionalmente estamos recogiendo el objeto que actua como target de la llamada. A continuacin veremos un around advice para ilustrar la sintaxis: Object around(User user):secureOperation(user){ System.out.println("Securing operation on user " + user.toString());
19
Object retValue = proceed(user); System.out.println("Finished secured operation on user " + user.toString()); return retValue; } En la definicin anterior podemos ver la estructura de la declaracin de un advice descrita anteriormente 1. La parte que precede a los dos puntos indica el momento de ejecucin del advice (after,before,around). En este caso, se ejecutar alrededor del joint point seleccionado. 2. La parte que sigue a los dos puntos representa el pointcut, es decir, la definicin de los criterios que determinan cuando se ejecutar el advice 3. La ltima parte representa el cuerpo del advice, es decir, el cdigo que se ejecutar cuando alguno de los joint point definidos por el pointcut sea alcanzado.
Advices y mtodos
Al igual que los mtodos de una clase, los advices se utilizan para definir comportamiento. La sintaxis de stos ltimos es similar a la de los mtodos aunque existen algunas diferencias dado que los advices son aplicados de manera automtica, sin la necesidad de realizar explicitamente la invocacin del mismo.
Similitudes
Analizemos las similitudes de ambos en tres categoras diferentes: declaracin, cuerpo y comportamiento. La declaracin de un advice es similar a la signatura de un mtodo tradicional: Opcionalmente puede asigarse un nombre al advice mediante el uso de la anotacin @AdviceName Recibe argumentos a travs del contexto del joint point, que posteriormente podrn ser utilizados en el cuerpo para implementar la lgica necesaria. Puede declarar el lanzamiento de una excepcin. En cuerpo de los advices tambin es muy parecido al de los mtodos: El cdigo del cuerpo del advice sigue las mismas reglas de acceso a miembros de otros tipos y/ o aspectos. Se puede referenciar a la propia instancia del aspecto mediante el uso de this, Los advices de tipo around pueden retornar un valor. Los advices deben declarar las excepciones que sean checked que la implementacin podra disparar. En el caso de los mtodos, los advices : No pueden declarar el disparo de una excepcin que no est declarada en TODOS los joint points sobre los que actua Pueden omitir algunas de las excepciones de tipo checked que han sido declaradas por alguno de los joint point sobre los que actua. Pueden declarar el disparo de excepciones ms especficas (de tipo checked) que las definidas por los joint point sobre los que est actuando. Pueden lanzar cualquier tipo de excepcin de tipo runtime.
20
Diferencias
En comparacin con los mtodos, los advices: La declaracin de un nombre es opcional. No pueden ser invocados directamente. No presentan especificadores de acceso (relacionado con la caracterstica de que no pueden ser invocados directamente) No presentan un tipo de retorno en los advices de tipo before y after Tienen acceso a unas cuantas variables en el thisJointPoint,thisJointPointStaticPart,thisEnclosingJointPointStaticPart propio aspecto:
Se puede utilizar la palabra reservada proceed en los advices de tipo around para ejecutar el joint point sobre el cual se est realizando el advice.
Before advice
Este tipo de advices se ejecutan antes de la ejecucin del joint point sobre el que actan. En el siguiente ejemplo: before():execution(@Secured * * (..)){ // asegurarse de que el usuario puede realizar la operacin } el advice realiza una comprobacin de seguridad antes de que se produzca la ejecucin de cualquier mtodo anotado con Secured. En caso de que el advice dispare una excepcin, el joint point no se ejecutar. Este tipo de aspectos son comunmente utilizados en aspectos tales como seguridad o trazabilidad.
After advice
Se ejecutan despus de la ejecucin del joint point sobre el que actuan. Dentro de esta categora, AspectJ ofrece tres tipos de advices: Ejecucin del advice independientemente del resultado de la ejecucin del joint point. Ejecucin del advice nica y exclusivamente si el joint point ha finalizado correctamente. Ejecucin del advice despus que el joint point haya disparado una excepcin. Veamos en detalle cada uno de los tres tipos anteriores: Advice After Este tipo de advices se ejecutan independientemente del resultado de la ejecucin del joint point sobre el que actan. Habitualmente se conoce a este tipo de advices como after finally puesto que su semntica es similar a la de un bloque finally. El siguiente advice: after(): call(@Logging * ServiceManager.*(..)){ // registrar el resultado de la operacin
21
} registra el resultado de todas las operaciones de la clase ServiceManager que estn marcadas con la anotacin Loggin, independientemente si retornan correctamente o terminan su ejecucin de forma inesperada mediante el disparo de una excepcin. Advice After Returning En muchas ocasiones,ser necesario ejecutar el cdigo de nuestro advice nica y exclusivamente cuando la ejecucin del joint point haya terminado de forma correcta. Continuando con el ejemplo anterior: after () returning: call(@Logging * ServiceManager.*(..)){ // registrar el resultado de la operacin } se seguir registrando el resultado de las operaciones, siempre y cuando, la ejecucin haya terminado correctamente, sin el disparo de ninguna excepcin. AspectJ ofrece una pequea variante para este tipo de advices:
after() returning (ReturnType returnObject) gracias a la cual se permite recuperar el objeto retornado por la ejecucin del joint point dentro del advice. Veamos un pequeo ejemplo ilustrativo:
after() returning (java.sql.Connection connection): call(java.sql.Connection DriverManager.getConnection(..)){ System.out.println("Se ha recuperado la conexin " + connection); } Es importante tener claro que no se puede retornar un objeto nuevo (si que lo podemos modificar, pero no retornar uno nuevo). Advice After Exception Este tipo de advices son similares a los descritos en el apartado anterior. En este caso, el advice se ejecutar nica y exclusivamente cuando el joint point dispare una excepcin. Presentan la siguiente estructura: after() throwing:execution (* ServiceManager+.*(..)) El advice del ejemplo anterior se ejecutar siempre y cuando algn mtodo de la clase ServiceManager (o alguna de sus subclases), dispare una excepcin. En el supuesto de que la ejecucin del joint point termine correctamente, este tipo de advices no sern ejecutados. Al igual que los advices del apartado anterior, AspectJ ofrece una modo de recuperar la excepcin que ha sido disparada por el joint point de modo que est disponible en el cuerpo del advice. Siguiendo una sintxis similar a la anterior, tendramos: after() throwing (ExceptionType exceptionObject): Un after throwing advice nunca podr tragarse la excepcin;por lo que seguir subiendo por la pila de llamadas hasta llegar al objeto que realiz la invocacin del joint point.
Around advice
Este clase de advices engloban al joint point, pudiendo ejecutar la lgica del mismo un nmero indefinido de veces. Incluso pueden omitir la ejecucin del propio joint point. Algunos de los usos principales de este tipo de advices son los siguientes:
22
Ejecucin de lgica adicional antes y despus de la ejecucin de un joint point, como por ejemplo, acciones de profiling. Omitir la ejecucin original, y realizar otra en su lugar, como por ejemplo, operaciones con cachs. Envolver la operacin con una gestin de excepciones, con el objetivo de aplicar una poltica de gestin de excepciones. Un ejemplo de este uso sera la gestin de transacciones. Este advice ofrece una potencia superior a todos los advices vistos hasta el momento, puesto que podran sustituir a los anteriores. De todos modos, se considera una buena prctica utilizar el advice ms sencillo que cumpla las necesidades de la tarea que necesitamos llevar a cabo. Ejecucin del joint point Si desde el around advice deseamos llevar a cabo la ejecucin del joint point, tendremos que hacer uso de la palabra reservada proceed() dentro del cuerpo del advice. Debemos recordar, que, puesto que la invocacin de proceed() ejecuta el joint point, tendremos que pasarle el mismo nmero de argumentos que han sido recolectados por el advice. Asimismo, puesto que la invocacin de proceed() supone la ejecucin del joint point, el valor de retorno ser el retornado por ste ltimo. Veamos un pequeo ejemplo de utilizacin de advices de este tipo: void around(User user,int credits) throws InsufficientCreditsException: call(* User.pay*(int)) && target(user) & & args(credits){ try { proceed(user,credits); }catch(InsufficientCreditsException ex){ if(!processException()){ throw ex; } } Analicemos en detalle la construccin anterior: 1. El pointcut selecciona cualquier llamada a los mtodos de la clase User cuyo nombre comienze por pay y disparen una excepcin de tipo InsufficientCreditsException 2. La segunda parte del pointcut recolecta el contexto del joint point: el usuario sobre el que se est realizando la llamada y el nmero de crditos que se estn pasando como argumento del mtodo que se est ejecutando. 3. En el cuerpo del advice, se engloba la ejecucin del mtodo con un bloque de gestin de excepciones, para realizar una proteccin adicional en caso de que se produzca una excepcin. En el caso de que la proteccin adicional no sea correcta, la excepcin ser disparada de nuevo. Retornando valores Todos los around advices deben declarar un valor de retorno (puediendo ser void). Habitualmente el tipo de retorno de stos se corresponde con el tipo de retorno de los joint points sobre los que est actuando. En algunas ocasiones, todos los joint points sobre los que actua el advice no presentan el mismo tipo de retorno, como puede ocurrir cuando estamos aadiendo soporte transaccional a diferentes operaciones. En estas situaciones el tipo de retorno que debe declarar el advice ser Object. AspectJ acomodar el valor de retorno de acuerdo a las siguientes reglas: Si se est retornando un tipo primitivo, AspectJ realizar el boxing/unboxing correspondiente. Esta caracterstica es similar a la incluida a partir de Java 5, pero AspectJ no precisa de dicha versin de Java para realizar la operacin.
23
En el caso en el que el tipo de retorno no sea primitivo, AspectJ realizar los casts oportunos antes de retornar el valor.
args(obj1,obj2,...)
Aspectos
Los aspectos representan la nidad bsica de modularizacin en el mundo de la orientacin a aspectos en general, y en AspectJ, en particular. Los siguientes subapartados nos mostrarn una definicin ms formal que la vista hasta este momento.4 Analizaremos en detalle los aspectos, realizaremos una comparativa con las clases y veremos como nos pueden ayudar a modularizar y construir componentes reutilizables.
Seguiremos analizando los nuevos conceptos, al igual que en las secciones anteriores, desde elpunto de vista de la sintaxis tradicional, dejando un poco de lado la sintaxis @AspectJ
24
[access specification][abstract] aspect <AspectName> [extends class or aspect] [implements interface-list] [ [<association-speficier>(Pointcut)] | [pertypewithin(TypePattern) ] ]{ // aspect body } La palabra reservada aspect permite realizar la declaracin de un nuevo aspecto. Cada uno de estos aspectos presenta las siguientes caractersticas: Presenta un nombre para podere referirse a l desde otras partes del cdigo. Puede presentar especificadores de acceso (public,proteced o private) Puede ser abstract Puede aplicar el mecanismo de herencia, derivando de otros aspectos o de clases tradicionales. Asimismo puede implementar interfaces. Puede especificar el modelo de instanciacin Su cuerpo puede estar compuesto por definiciones de pointcuts, miembros o tipos anidados.
Resumen
Nos hemos introducido en el mundo AOP, hemos analizado su evolucin a lo largo a lo largo del Hype Cycle, visto sus usos en el mundo real y hemos realizado un estudio de sus principales componentes y el modo en el que se utilizan cada uno de ellos.
25
Evidentemente, esto pretende ser un primer acercamiento al mundo de AOP, y concretamente a AspectJ, a travs del cual el lector pueda comprender los beneficios de esta tecnologa y le permita utilizarlo para escribir sus propios programas. Soy consciente de que se han quedado muchas cosas en el tintero, que daran cabida para un libro completo, por lo que a continuacin se enumeran algunas de ellas para las mentes inquietas que deseen profundizar en otros aspectos que no tienen cabida en este documento: Tcnicas como static crosscutting tales como: Introduccin de nuevos miembros en una clase Complemento de anotaciones Modificacin de jerarquas de tipos Respuesta a errores y warnings en tiempo de compilacin Debilitado de excepciones Asociacin y predencia de aspectos Sintxis @AspectJ Anlisis detallado de los procesos de weaving Integracin con Spring ... Para una anlisis exhaustivo de estos y otros muchos aspectos, el usuario puede acudir a la seccin bibliografa El objetivo de este introduccin no era dar una visin terica y aburrida de AspectJ sino dar una visin pragmtica del mismo. De este modo, la siguiente seccin ilustrar la mayora de conceptos vistos anteriormente mediante una serie de ejemplos reales.
Ejemplos reales
Hasta este momento hemos visto las posibilidades que nos ofrece AOP en general, y AspectJ en particular, mediante la exploracin de sus elementos, sintxis y ejemplos sencillos. Los siguientes subapartados ofrecern un conjunto de ejemplos reales de aplicacin de la tecnologa as como algunos patrones habituales. La estructura de los ejemplos ser la siguiente: se plantear un problema, se dar una solucin general, y despus se propondr una alternativa basada en AOP y AspectJ. Pongmonos manos a la obra.
Patrn wormhole
Este patrn consiste, bsicamente, en habilitar un contexto de informacin desde un llamante a un llamado sin la necesidad de pasar dicha informacin como un conjunto de argumentos a lo largo de todas las invocaciones del los diferentes mtodos del flujo de ejecucin. Imaginemos por un momento que estamos implementando un sistema de seguridad en el que cada uno de los mtodos tiene que comprobar quien les ha invocado para determinar si se les permite ejecutar la operacin. Creando un canal de comunicacin directa entre dos niveles cualesquiera en la pila de llamadas, nos evitar tener que ir moviendo la informacin necesaria por cada una de las capas. De este modo, evitaremos la necesidad de modificar la cadena de llamadas cuando necesitemos aadir algn parmetro adicional al contexto de informacin.
5
De nuevo, se ha optado por mantener la nomenclartura original del patrn, sin realizar una traduccin al castellano, puesto que considero que el resultado de dicha traduccin no resultara demasiado intuitiva para el lector.
26
Solucin tradicional
Sin la utilizacin de una tecnologa como AOP disponemos de dos alternativas de solucin. La primera de ellas movera toda la informacin necesaria a lo largo del contexto de llamadas aadiendo los parmetros que fueran necesarios, mientras que la segunda, hara uso de un almacenamiento espefco de los hilos. La solucin que pasa a travs de parmetros el contexto de informacin necesario produce una contaminacin del API, puesto que cada uno de los mtodos que intervienen en el flujo que transcurre desde el llamante hasta el llamado necesitar de parmetros adicionales que permitan mover dicha informacin a lo largo de la pila de llamadas. La segunda solucin propuesta, el uso de un almacenamiento especfico, pasara porque el llamante crease una variable ThreadLocal en la que se almacenase toda la informacin necesaria. Aunque esta segunda solucin evita la contaminacin del API, se necesita modicar tanto el llamante como el llamado, adems de requerir un conocimiento de cmo se almacena el contexto de informacin.
Descripcin general
La siguiente figura ilustra la idea bsica de este patrn arquitectnico:
La idea general consiste en indentificar dos pointcuts: uno en el llamado y otro en el llamante. El primero de ellos ser el encargado de recolectar toda la informacin que ser transmitida a lo largo del "aguejero de gusano". El segundo pointcut tendr que especificar aquellos joint point del llamado en los que debe actuar el wormhole. En la imagen anterior cada una de las cajas trasnversales representa un nivel en la pila de llamadas. Habitualemente, para comunicar el llamante y el llamado tendramos que ir pasando toda la informacin de nivel en nivel, hasta que alcanzsemos el nivel deseado. El patrn descrito en esta seccin establece un canal de comunicacin directo a lo largo de todos los niveles de llamadas, evitando el paso de informacin nivel a nivel.
Plantilla
A continuacin se propone una plantilla de solucin que puede ser utilizada como base para la implementacin de este patrn en nuestros sistemas
27
public aspect WormholeAspect { pointcut callerSpace(caller context) : <caller pointcut> ; pointcut calleeSpace(callee context) : <callee pointcut> ; pointcut wormhole(<caller context>, <callee context>) : cflow(callerSpace(<caller context>)) && calleeSpace(<callee context<); // advices para el wormhole around(<caller context>, <callee context>) : wormhole(<caller context>, <callee context>) { // ... advice body } } En la plantilla anterior, los dos primeros pointcuts recolectan los contextos en el llamante y en el llamado respectivamente. El tercero de ellos construye el wormhole entre los dos espacios, capturando todos los joint point determinados por el pointcut calleeSpace que se encuentren en el flujo de ejecucin de aquellos joint points capturados por el pointcut callerSpace. Puede que con un ejemplo nos queden las cosas un poquito ms claras. Escribamos un pequeo aspecto que genere un canal de comunicacin entre un sistema iniciador de transacciones y las ejecuciones de una query: public aspect SqlTransactionAspect { pointcut transactionSystemUsage(TransactionSystem ts) : execution(* TransactionSystem.*(..)) && this(ts) pointcut queryExecutions(SqlQuery query, String[ ] params) : this(query) && args(params) && execution(public * SqlQuery.exec*(String [ ])); pointcut wormhole(TransactionSystem ts, SqlQuery query, String[ ] params) : cflow(transactionSystemUsage(ts)) && queryExecutions(query, params); before(TransactionSystem ts, SqlQuery query, String[ ] params) returning : wormhole(ts, query, params) { // realizar las operaciones deseadas } El pointcut transactionSystemUsage captura todos los joint point de ejecucin en de la clase TransactionSystem. Adems recolecta el objeto en si en el contexto de ejecucin. El pointcut queryExecutions() captura todas las llamadas a los mtodos exec de la clase SqlQuery y recolecta la propia query y los argumentos El pointcut wormhole genera un canal de comunicacin directo entre el el sistema de transacciones y la ejecucin de la query, capturando todos los joint points que se produzcan bajo el flujo de ejecucin de transactionSystemUsage. Adems, se captura el contexto de los dos pointcuts constituyentes. El advice que actua sobre el pointcut wormhole dispone ahora de toda la informacin: la query y sus parmetros as como el sistema de trasancciones
28
Hilos seguros
La amplia difusin de los procesadores con mltiples ncleos, el uso de lenguajes especialidados como Erlang o Haskell, y la popularidad de numeros libros al respecto, han logrado que los sistemas de software alcancen niveles de concurrencia insospechados hasta hace poco tiempo. Si embargo, para muchos desarrolladores, incluso gente experimentada,la concurrencia supone un autntico misterio. Implementar un sistema que presente un control de concurrencia es una tarea complicada, dado que, en muchas ocasiones, los conceptos se difuminan a lo largo de diferentes mdulos. Estas circunstancias pueden ocasionar, la construccin de sistemas no demasiado ricos, con erros aparentes, cadas del sistema inesperadas, integridad comprometid, deadlocks, . . . Por norma general, la implementacin de un sistema de concurrencia basado en los patrones arquitectnicos y de diseo apropiados suele ocasionar sistemas mucho ms fiables que los descritos en el prrafo anterior. Muchos de los patrones de concurrencia presentan numerosos conceptos trasnversales, por lo que AOP puede ayudarnos a simplificar su diseo y posterior implementacin. En este ejemplo, analizaremos el patrn read-write lock. La implentacin clsica de este patrn supone la adicin de cdigo en todos aquellos mtodos que necesiten modificar el estado de un objeto. Los siguientes subapartados nos mostarn como podemos realizar una implementacin modular de este patrn basado en AspectJ.
Implementacin tradicional.
Este patrn utiliza un par de bloqueos (locks): el bloqueo de lectura, y el bloqueo de escritura. Mltiples hilos lectores podrn adquirir el bloqueo de lectura siempre y cuando el bloqueo de escritura no haya sido adquirido. El otro bloqueo, el de escritura, nicamente podr ser adquirido siempre y cuando ninguno de los hilos restantes haya tomado posesin del bloqueo de escritura. La siguiente clase ilustra, mediante una pequea clase de ejemplo, la solucin anterior.
// package definition . . . import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @author migue * */ public abstract class User { protected String username; protected String login; protected int credits; public User(int credits) { this.credits = credits; } private ReadWriteLock lock = new ReentrantReadWriteLock(); public void increaseCredit(int credit) { // adquirmos el bloqueo de lectura this.lock.writeLock().lock(); try {
29
// realizamos la operacin, en este caso, // aumentar el crdito del usuario this.credits += credit; } finally { // liberamos el recurso adquirido this.lock.writeLock().unlock(); } } public void decreaseCredit(int credit) { // adquirmos el bloqueo de lectura this.lock.writeLock().lock(); try { // realizamos la operacin, en este caso, // disminuir el crdito del usuario this.credits -= credit; } finally { // liberamos el recurso adquirido this.lock.writeLock().unlock(); } } public boolean hasCredit() { // adquirimos el bloqueo de lectura this.lock.readLock().lock(); boolean hasCredit; try { hasCredit = this.credits > 0 ? true : false; } finally { this.lock.readLock().unlock(); } return hasCredit; } } Resulta evidente que la manera anterior de realizar los bloqueos resulta intrusiva, puesto que para cada uno de los mtodos para los que en los que se desee gestionar la gestin de la concurrencia, tendremos que aadir los fragmentos de cdigo vistos en el ejemplo. Cualquier mtodo en el que nos olvidemos de aadir el cdigo de gesti de la concurrencia puede ocasionarnos un incorrecto funcionamiento de nuestro sistema. Adems, debemos asegurarnos que si un mtodo adquire el bloqueo de lectura, sea este el que libere, y no el de lectura, y viceversa.
30
public abstract pointcut readOperation(); public abstract pointcut writeOperation(); private ReadWriteLock lock = new ReentrantReadWriteLock(); Object around(): readOperation(){ this.lock.readLock().lock(); try{ return proceed(); }finally{ this.lock.readLock.unlock(); } } Object around(): writeOperation(){ this.lock.writeLock().lock(); try{ return proceed(); }finally{ this.lock.writeLock.unlock(); } } }
Analicemos con un poquito ms de detalle la definicin del aspecto anterior: 1. En primer lugar, mediante la asociacin de aspectos6, asociamos una instancia de nuestro aspecto con cada uno de los objetos que concuerden con los criterios establecidos en los pointcuts readOperations y writeOperations. Ntese que una nueva instancia de nuestro aspecto ser creada cada vez que se prduzca un matching. El uso de la asociacin nos permite introducir, en las clases que requieren sincronismo, el objeto de lock, sin necesidad de conocer el tipo de las mismas. 2. El pointut abstracto obligar que los aspectos hijos lo tengan que definir, capturando con l todas las llamadas a los mtodos que necesitan sincronismo y no modifican el estado del objeto. 3. De modo similar al anterior, el pointcut writeOperations, capturar todas las llamadas a los mtodos que necesiten realizar una modificacin en el objeto. 4. Puesto que cada matching que se produzca generar una nueva instancia del aspecto para cada objeto this diferente, cada elemento de sinronizacin estar asociado con el objeto sobre el que se est realizando el advice. 5. El around advice readOperation adquiere y libera el bloqueo de lectura. 6. Del mismo modo, writeOperation, adquiere y lbera el bloque de escritura. Ahora que tenemos preprada nuestros aspecto base, realizemos una implementacin concreta. Implementacin de subaspectos La habilitacin de este patrn requiere la implementacin de un aspeto concreto que ponga en juego las clases sobre las que deseamos establecer un control de la concurrencia. Dado que los aspectos concretos tendrn que marcar qu metodos son de lectura y escritura, el uso de anotaciones que nos simplifiquen la seleccin suele ser una buena idea. Por tanto, defininiremos la siguiente anotacin para marcar los mtodos de lectura:
31
@Target(ElementType.METHOD) public @interface ReadOnly{ } Del mismo modo definiremos una anotacin para marcar los mtodos de escritura: @Target(ElementType.METHOD) public @interface ReadWrite{ } Adems, necesitamos definir una anotacin que nos indique cuando estamos utilizando el patrn. @Target(ElementType.TYPE) @Inherited public @interface ReadWriteLockManaged Ahora estamos listos para definir el aspecto,basado en las anotaciones anteriores, que nos aplique el patrn read-write lock. public aspect AnnotationDrivenReadWriteAspect extends ReadWriteLockAspect { public pointcut readWriteLockManaged(): execution(* (@ReadWriteLockManaged *).*(..) ); public pointcut readOperation() : execution(@ReadOnly * *(..)) && readWriteLockManaged(); public pointcut writeOperation() : execution(@ReadWrite * *(..)) && readWriteLockManaged(); }
Analicemos en detalle la construccin del aspecto anterior: 1. El pointcut readWriteLockManaged captura todas las llamadas a los mtodos de aquellas clases que se encuentren marcadas con la anotacin AnnotationDrivenReadWriteAspect 2. El pointcut readOperation complementa al anterior, seleccionando nicamente, de todos los mtodos capturados por readWriteLockManager, aquellos que se encuentren anotados con ReadOnly 3. De un modo similar al anterior, el pointcut writeOperation, captura nicamente aquellos mtodos descritos con la anotacin ReadWrite. Ahora llega la parte ms divertida de esta seccin. Apliquemos nuestra nueva construccin sobre el ejemplo analizado en implementacin tradicional: // package definition . . . import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @author migue *
32
*/ @ReadWriteLockManaged public abstract class User { protected String username; protected String login; protected int credits; public User(int credits) { this.credits = credits; } @ReadWrite public void increaseCredit(int credit) { this.credits += credit; } @ReadWrite public void decreaseCredit(int credit) { this.credits -= credit; } @ReadOnly public boolean hasCredit() { return this.credits > 0 ? true : false; } } Comparemos este listado con la implementacin tradicional realizada anteriormente . No resulta mucho ms comprensible? Evidentemente, aunque esta es una buena solucin, existe un acoplamiento entre la anotacin @ReadWriteLockManaged, que una clase indique su participacin en el patrn puede no ser deseable, si dicha clase se utiliza en mltiples sistemas. El problema anterior podra solucionarse mediante la inclusin de un aspecto que introdujese la anotacin en los tipos indicados.7 Veamos un aspecto que introducira la anotacin indicada en las clases que la requieran, de este modo evitaremos el acoplamiento entre la clase y la anotacin que aplica el patrn.
public aspect InventoryReadWriteLockParticipation { declare @type: User: @ReadWriteLockManaged; } El aspecto anterior anotara la clase User con la anotacin ReadWriteLockManaged. De este modo, la anotacin de cualquier clase no requerira ms que la modificacin de este aspecto, para que detectase aquellas clases susceptibles de estar bajo la gestin de concurrencia.
Bibliografa
Al igual que en el resto de captulos, se incluye una referencia bibliogrfica especfica que permitir al lector profundizar en la temtica introducida: AspectJ Programming Guide [http://www.eclipse.org/aspectj/docs.php] AspectJ in Action
7
Aunque no hemos visto la introduccin de tipos, se ha decidido incluir un pequeo aspecto de ejemplo.
33
AspectJ in Action Second Edition: Enterprise AOP with Spring Applications Spring AOP reference [http://static.springsource.org/spring/docs/2.0.8/reference/aop.html] Eclipse AspectJ. Aspect-Oriented Programming with AspectJ and the Eclipse Aspect - Addison Wesley - 2004 John Wiley And Sons Mastering Aspectj Aspect-Oriented Programming in Java AspectJ.Cookbook - OReilly - 2004 Mastering AspectJ - Wiley
34