Compatibilidad
AspectJ es una extensión compatible de Java para facilitar el uso de aspectos por parte de los programadores de Java. Por compatible se entiende:
Compatibilidad base
Todos los programas válidos de Java deben ser programas válidos de AspectJ.
Compatibilidad de plataforma
Todos los programas válidos de AspectJ deben correr sobre la máquina virtual estándar de Java.
Compatibilidad de programación
La programación en AspectJ debe ser una extensión natural de la programación en Java.
Esta última meta fue una de las guías más importante a la hora de tomar decisiones sobre el lenguaje. Es estáticamente tipado y usa el sistema de tipos estático de Java.
Instalación
Prerrequisitos:
Tener instalado Java JDK y JRE. En este caso se enseñará a instalar AspectJ en Intellij para un sistema operativo Windows
Semántica
En sí, AspectJ funciona extiendiendo a Java como Base para soportar el manejo de aspectos y clases, agregando a la semántica de Java cuatro entidades principales.
Los puntos de enlace (Join Points)
Son puntos bien definidos en la ejecución de un programa, entre ellos podemos citar llamadas a métodos y accesos a atributos.
Los cortes (Point Cuts)
Agrupan puntos de enlace y permiten exponer el contexto en ejecución de dichos puntos. Existen cortes primitivos y también definidos por el usuario.
Los avisos (Advices)
Son acciones que se ejecutan en cada punto de enlace incluido en un corte. Los avisos tienen acceso a los valores expuestos por el corte. Las tres entidades anteriores son dinámicas porque permiten definir comportamiento adicional que actuará en tiempo de ejecución.
Las introducciones y declaraciones (Inter-Type Declarations)
Permiten cambiar la estructura de clases de un programa agregando o extendiendo interfaces y clases con nuevos atributos, constructores o métodos. Esta última entidad es estática porque afecta la signatura estática del programa.
Semantica De Declaración
[ privileged ] aspect Id [ extends Type ] [ implements TypeList ] [ Per Clause ] { Body }
Un Aspecto puede ser declarado como cualquier clase de Java, con su id, con la palabra reservada "aspect", con sus respectivos modifiers para modificar el acceso y comportamiento de la clase, e introduciendo nuevos elementos a la semántica de cómo funcionan y van a interactuar con respecto a las demás clases de nuestro proyecto. De estas nos enfocaremos en 3 en especial debido a su particularidad con los Aspectos:
Un modifier especial que, como su nombre nos lo indica, le dará privilegios al aspecto, esto significa que nos permitirá poder acceder a métodos y atributos privados de clases y aspectos externos.
Un aspecto puede extender una clase, u otro aspecto abstracto y puede implementar tantos interfaces como se le indiquen.
La siguientes son unas reglas a tener en cuenta:
- De un aspecto a pesar de extender una clase no se puede crear una instancia del mismo con el método new.
- Una clase no puede extender un aspecto.
- Un aspecto no puede extender un aspecto que no sea abstracto.
Los Aspectos originalmente se generan como singleton. Sin embargo, pueden haber varias formas de crear diversas instancias del mismo acceso, según su objeto asociado, su posición de ejecución, entre otras. Las Per Clause son quienes se encargan de modificar los Aspectos para poder tener más control sobre la cantidad y comportamiento de los Aspectos
Sin embargo, no se recomienda mezclar varios de estos métodos debido a que pueden llegar a inteferir con flujos ajenos de los distintos Aspectos.
Compiladores diseñados para AspectJ
Los dos principales compiladores para AspectJ son:
- ajc ajc parte de las herramientas soportadas por el proyecto Eclipse
- abc que es un compilador, que optimiza y es extensible, producido en aspectbench.org.
Objetivos
La intención de AspectJ es ser un LOA práctico, que provea un conjunto sólido y maduro de características orientadas a aspectos, compatible con Java para aprovechar su popularidad.
Lenguaje
Aspect
Es la unidad central de Aspectj, se puede colocar en un archivo .aj.Contiene el código que expresa las reglas de los crosscutting.Un aspecto es una unidad de modularización en AOP como las clases son en OOP.
PointCut
Una palabra del lenguaje que selecciona los puntos interesantes (join points) y colecta el contexto de este punto. Selecciona puntos interesantes de la ejecución. Pueden ser llamadas, ejecuciones, instanciar objetos, constructores, manejo de excepciones.
Tipos de point cuts
PointCut Pattern
Advice
Código que se ejecutará cuando se llegue al pointcut este se puede definir de diferentes maneras. Existen tres tipos de advice:
- before()
- after()
- around()
Before
Se ejecuta antes de cada join point.
After
Se ejecuta después de cada join point. Puede de tres tipos:
- Defecto: el cual retorna sin importar el resultado.
- Returning: Me realiza la acción únicamente si finalizó correctamente y/o me retornó el valor (Este Advice también puede servir con JointPoints que sean voids). Este returning me permite también utilizar los valores retornados por los JoinPoints para utilizarlos en los advices.
- Throwing: Me realiza la acción únicamente si la acción del PointCut finalizó lanzando una acción o un resultado como una excepción.
Around
Se ejecuta en lugar de el join point. Debe ser declarado con un tipo de retorno.
El código del join point se puede ejecutar usando la palabra
proceed();
Atributos de los advice
thisJoinPoint
: Representa el join point en el cual el advice se está ejecutando.
thisJoinPointStaticPart
: equivalente a thisJoinPoint.getStaticPart()
pero
consume menos recursos.
thisEnclosingJoinPointStaticPart
: la parte estatica de la dinamica que encierra el
join point.
Particularidades
Sintaxis de las notaciones
Aspect
PointCut
Advice before
Advice after
Advice around
Tutorial
A partir de una aplicación de un banco se desea implementar un Log de transacciones y un sistema de login mediante programación orientada a aspectos. Para esto se tienen las siguientes clases en las cuales se implementa la funcionalidad sencilla de un banco.
Adicionalmente se tiene la siguiente clase la cual representa a los usuarios de este banco.
Aspectos
Se implementarán dos aspectos uno llamado Login
y otro llamado
Log
.
Ahora debemos identificar los join points de nuestra aplicación para poder implementar los pointcuts en los aspectos.
Identificacion de los puntos de corte de los aspectos
Esta es la funcionalidad que queremos guardar en el log de transacciones.
Esta es la funcionalidad que queremos aplicarle un login. Aunque hay join point que son comunes por buena practica los viviremos en dos aspectos.
En el primer punto de corte queremos capturar los metodos que comiensen con make y my.
Queremos capturar las distintos tipos de transacciones. Posteriormente agregamos los advices que queremos en los dos aspectos con su funcionalidad correspondiente.
Queremos que escribir el los se realice depues de que la transacción se haya realizado, por esta razón elegimos after.
Queremos que el login sea antes de la transacción se haya realizado, por esta razón elegimos before. Este es un ejemplo muy sencillo de lo que nos permite aspectj.
Finalmente este código nos agrega la funcionalidad de un login antes de las transacciones y un registro de sus actividades en un archivo.
Todo el codigo presentado esta en el Siguiente Github
Main Vamos a hacer distintos puntos de corte para:
- Funciones de la clase Repository, Service y RestController
- Spring Beans
- Lance una excepción en cualquiera de los metodos propuestos
- Entre a una función
- Salga de una función
- Entre a una función con parametros invalidos
Todo el código presentado está en el siguiente link: Github.
Main Vamos a hacer distintos puntos de corte para las funciones donde hay crosscutting:
- MakeAppointment
- Update Level
- Se deba verificar si la mascota es elegible para pedir una cita
- Entre a una función
- Salga de una función
Ejemplos
Hello World
Ejemplo más sencillo de AspectJ.
Clase TestAsp
La clase en la cual tenemos unos cuantos metodos y un main.
Aspect Aspect
Nuestro aspecto con algunos puntos de corte para ver su funcion.
Comodines
Calls y Execution
Calls vs Execution
La diferencia entre calls y execution es que calls se refiere al acto de llamar a una función, mientras que execution se refiere al acto de ejecutar el código de una función.
En otras palabras, calls es el evento de pasar el control a una función, mientras que execution es el proceso de ejecutar las instrucciones de una función.
Por ejemplo, la siguiente línea de código:
int x = add(1, 2);
contiene una llamada a la función add(). Cuando se ejecuta esta línea de código, el control se pasa a la función add(). La función add() entonces ejecuta sus instrucciones, que en este caso son:
int sum = x + y;
return sum;
El proceso de ejecutar las instrucciones de la función add() se conoce como ejecución.
Context Passing
Aspect Behaviours
Main Seguridad
Diferentes usuario realizan transacciones
Clase Seguridad
Define si un usuario tiene acceso
Aspecto Seguridad
Aspecto en que se define si un usuario tiene permisos
Main productos
Uso de diferentes metodos de productos
Clase productos
Clase de productos donde se definen sus metodos
Aspecto productos
Aspecto define el tiempo de ejecucion en cualquier metodo
Main pedido
Uso de diferentes metodos para poder realizar un pedido
Clase Pedido
Clase de pedido donde se definen sus metodos
Clase inventario
Clase de inventario donde se definen sus metodos
Clase inventario helper
Clase de InventarioHelper donde se definen sus metodos, ayuda en la actualizacion de los aspectos de inventario
Aspecto Actualizacion del stock
Aspecto que se encarga de la logica de la actualizacion del stock
Aspecto Registro Actividad
Aspecto que se encarga de registrar los productos agrgados y eliminados
Aspecto Verifica Stock
Aspecto se encarga de revisar si existe suficiente stock del producto
Clase Calculadora
A continuación se presenta la clase calculadora con los métodos básicos.
Aspecto LogCal
Aspecto que realiza los logs respectivos.
Clase Main
Clase Main de la calculadora.
Ventajas y Desventajas
Ventajas
- Facilita/mejora la modularidad de los desarrollos de software.
- El código es organizado y comprimido
- Es reutilizable
- Añade constructores a Java que permiten la implementación modular de crosscutting concerns
- Permite modelar referencias transversales, extiende las capacidades de POO\
Desventajas
- Puede introducir nuevos errores y fallas de seguridad si no se implementa adecuadamente
- El paradigma puede emplearse mal quitando y/o delegando responsabilidades a ciertas clases
- Los Aspectos pueden ser mal utilizados. Un programador puede implementar una falsa funcionalidad en cualquier estado del desarrollo y afectar a un amplio rango del sistema.
Contribudores
2016-1
- Sergio Alejandro Diaz Pinilla
- Pedro Luis Monroy Garces
- Jefferson Javier Hernández Panqueba
2016-2
- Juan Rodriguez Duran
- Johann Triana Olaya
- Jonatan Parra Toro
2017-1
- Juan Sebastián Martínez Beltrán
- Andrés Felipe Sánchez Lemus
2019-2
- Juan Sebastián Becerra Barcenas
- Juan Sebastián Peña Quintero
- Brayan David Vega Triana
2020-1
- Andres Esteban Romero Romero
- Oscar Andres Mancera Garzón
- Yerson Andres Valderrama Ceron
2020-2
- Sergio Esteban González Cárdenas
- Elsa Johanna Arias Muñoz
- Nicolás Alejandro Contreras
- Hubert Alejandro Tovar Strubinger
2021-1
- Verbo Sebastián Camacho Silva
- Miguel Alejandro Peña Hurtado
- Diego Fernando Pastás
2022-1
- Ángel Mateo González
- Rubén Darío Guarnizo
- Lorraine Rojas Parra
- Alejandra Superlano Esquibel
2022-2
- Kevin Leonardo Alvarez Mora
- Jose Francisco Lugo Nomesque
- Andres Yohany Velasquez Martinez
- Valentina Viafara Esteban
2023-1
- Angel Guillermo Peñarredonda Silva
- Manuel David Maya Rosero
- Nicol Estefania Guerrero Gutierrez
2023-2
- Juan Pablo Garzon Parra
- Brayan Sebastián Yepes Garcia
- Diego Sebastián Rubiano Ballén
- Joe Zafir Mendez Leon
Bibliografía
- Libro: Mariano Lorente López, Fernando Asteasuain, Bernardo Ezequiel Contreras. (2005). Programemos en AspectJ.
- https://sistemasacademico.uniandes.edu.co/~miso4204/dokuwiki/lib/exe/fetch.php?media=temas:aspectj.pdf
- http://ldc.usb.ve/~yudith/docencia/ci-4822/presentacionPOA.pdf
- https://es.wikipedia.org/wiki/AspectJ
- https://eclipse.org/aspectj/
- Constantinides, C. (2015). V Aspect-Oriented Programming with AspectJ. En Principles of Programming Languages (págs. 309-407). Montreal: Concordia University.
- eclipse. (Abril de 2020). The AspectJ Language. Obtenido de The AspectJ Programming Guide: https://www.eclipse.org/aspectj/doc/released/progguide/language-joinPoints.html
- Fernández Egido, A. (Junio de 2009). CORE. Obtenido de CONFLICTOS ENTRE ASPECTOS EN LA PROGRAMACIÓN ORIENTADA A ASPECTOS : https://core.ac.uk/download/pdf/29400487.pdf
- IBM. (1 de Enero de 2002). IBM. Obtenido de Improve modularity with aspect-oriented programming: https://www.ibm.com/developerworks/library/j-aspectj/index.html
- Laiseca Manso, X. (2007 de Julio de 27). MORElab. Obtenido de Cursillo 2007: http://e-ghost.deusto.es/docs/2007/cursillos/aop/curso_aop.pdf
- Lorente Lopez, M., Asteasuain, F., & Contreras, E. B. (2005). Programemos en AspectJ. programemos.
- Colyer, A., Clement, A., Harley, G., & Webster, M. (2004). Eclipse AspectJ: Aspect-Oriented Programming with AspectJ and the Eclipse AspectJ Development Tools. Addison Wesley Professional .
- Eclipse Foundation. (Año). AspectJ Documentation. Recuperado de https://eclipse.dev/aspectj/sample-code.html#declares-exceptionSpelunking
- Laddad, R. (2009). Aspectj in action: enterprise AOP with spring applications. Simon and Schuster.
Sistema de inventario con log
En este tutorial vamos a ver el paso a paso de cómo subir a la nube un servidor para el control de inventarios. Es una API Rest y se utiliza el entorno de trabajo Spring. Vamos a ver la estructura del proyecto, las clases y cómo subirlo a un nodo de AWS con Putty. También veremos cómo hacer peticiones al servidor mediante Postman.
Para acceder y descargar el proyecto, ir al siguiente enlace https://github.com/esgonzalezca/SpringLenguajes
Estructura del proyecto
Entramos a src/main/java/com/spring/aop/api/
Advice
Dentro de este directorio está la clase que contiene los pointcuts para la petición GET (myPointCutGet) y para la petición POST (myPointCutPost). Ambos son de tipo execution.
Después están las dos funciones que se usarán para hacer los logs:applicationLoggerPost para las peticiones POST, donde se crea un ObjectMapper, se obtiene el nombre del método, el nombre de la clase y los argumentos para registrar la información en el log. Luego con pjp.proceed() se ejecuta el JoinPoint. Esta función tiene la anotación
@Around porque reemplaza el código que está en el joinpoint
La segunda función applicationLoggerGet cumple prácticamente la misma función de applicationLoggerPost pero como tiene la anotación @AfterReturning recibe el retorno del pointcut (myPointCutGet) en la variable redVal y luego hace el registro en el log.
Model
En la clase Product se describen los atributos de los productos que estarán en nuestro repositorio, los constructores, getters y setters.
Service
En la clase ProductService se inicia la base de datos y se hacen las operaciones de consulta y adición de registros.
Controller
En la clase ProductController es donde se expone la información con REST, hay una petición POST (save) para guardar un producto o una lista de productos.
La petición GET (findProducts) para obtener todos los productos en el sistema.
En esta clase usamos la clase ProductService para acceder a la base de datos.
Repository
La clase ProductRepository hereda de JpaRepository, hay que declarar la tabla con Producto y el tipo de dato de la llave primaria (Integer).
Y por último, fuera de los directorios vistos arriba, está la clase SpringAopApplication, donde está el método main para correr el servidor.
Creación del .jar
Usaremos el IDE Netbeans.
En la parte superior de la pantalla haremos clic en el icono del Martillo con la escoba. Así se creará un archivo .jar con un nombre genérico (el cual se puede cambiar más adelante) en la carpeta “Target” de nuestro directorio del proyecto en local.
Creación del Dockerfile
Ahora crearemos un archivo llamado “Dockerfile” que no tendrá extensión y tendrá este contenido:
Nótese que aquí “myService.jar” es como se debe llamar el archivo ejecutable de Java. Este archivo debe estar en la misma carpeta del Dockerfile ya que será transportado a la carpeta /opt/app de nuestro entorno virtual (nodo de AWS). Recuerde que este archivo .jar fue generado al principio dentro de la carpeta target de nuestro proyecto en local.
Creación del nodo EC2
Nota: Para esta sección se usó una máquina t2.micro de AWS (se puede acceder a una de estas máquinas con la capa gratuita de AWS).
Vamos a la página de AWS https://aws.amazon.com/ , creamos una cuenta y accedemos a la consola.
Vamos a la sección EC2
Vamos a la sección instances y oprimimos Launch instance.
img src="https://i.imgur.com/LI3czvB.png" alt="">
Seleccionamos Amazon Linux 2 64 bits(X86) y luego en “Select”.
Seleccionamos la t2.micro.
Luego hacemos click en “Review and Launch”.
Hacemos click en Launch. A continuación nos pedirá ingresar un nuevo valor de llave. Ingresamos los datos como sale a continuación.
Acceder al nodo usando Putty
Ya con la llave del nodo, accedemos a él mediante Putty. Descargar en: https://www.putty.org
Interfaz inicial de Putty
En el cuadro de Host Name ingresamos la IP del nodo del nodo que creamos unos pasos arriba. Para el caso de la exposición hecha en clase:
Luego vamos a la categoría SSH - Auth.
En el campo Private key file for authentication ponemos la ruta de la llave del nodo de AWS. Luego regresamos a la categoría Session y oprimimos open.
Accedemos con el usuario ec2-user (es el usuario por defecto).
Desde esta ventana de comandos instalamos docker para hacer el contenedor para correr nuestra API.
Iniciamos docker.
Luego vamos a la carpeta donde está el Dockerfile.
Construimos el contenedor.
Corremos el contenedor.
Ya está corriendo el servidor, debajo comenzarán a aparecer los logs.
Peticiones al servidor con Postman
Enlace para descargar Postman: https://www.postman.com/downloads/
Agregamos una nueva petición de tipo GET para obtener la lista de productos de nustro inventario. En la dirección escribimos la ip del nodo seguida por “:” el puerto “/” findProducts. Damos click a Send para enviar la petición al servidor.
Log del servidor.
Ahora agregamos otra petición de tipo POST para agregar productos al inventario. Ingresamos la misma ruta cambiando lo que va depués del “/” por save. En la pestaña Body seleccionamos raw y JSON para escribir el cuerpo de la petición (los artículos que vamos a agregar). Enviamos la petición son Send
Log del servidor
Luego hacemos otro GET para obtener la lista de productos actualizada.
Log del servidor