Patrón Proxy Protegido

Es el momento de revisar el siguiente tipo de Proxy, el cual llamamos Patrón Proxy Protegido, ya que, por medio de un Proxy, podemos determinar si un cliente puede o no realizar una acción sobre un objeto.

Para este patrón podemos hacer uso de clases utilitarias dentro de JAVA, en específico las del paquete java.lang.reflect.

Este paquete nos brinda clases que nos van a permitir crear clases proxy en tiempo de ejecución, es decir, no vamos a tener que codificarlas.

Estos proxy dinámicos funcionan por medio de llamados a métodos de la clase que le especifiquemos. ¿Por qué se le dicen Proxy Dinámicos? La razón es simple, son clases que se crean en tiempo de ejecución.

Otros patrones como Estrategia y Decorador, cambian el comportamiento de los objetos dinámicamente.

Estos proxy son creados en tiempo de ejecución, es decir, el código no existe en alguna clase que fue creada por nosotros. JAVA determina cómo debe crearse el proxy y cómo debe invocar los métodos que necesitamos por medio de Reflection.

Según el libro Head First Design Patterns, este es el diagrama de este patrón.

Diagrama de clases del patrón proxy protegido

En el diagrama de clases anterior tenemos dos objetos nuevos. El primero es la interfaz InvocationHandler, la cual es definida por JAVA dentro del paquete java.lang.reflect.

El segundo objeto es la implementación de esta interfaz, InvocationHandlerA. Esta es la clase que vamos a utilizar para indicarle al Proxy dinámico qué método de la clase RealSubject debe invocar. En esta clase es donde decidimos cómo y qué métodos pueden ser invocados.

La clase Proxy, es la que JAVA va a generar en tiempo de ejecución.

Veamos un diagrama de secuencia que aclare el flujo de los llamados.

Diagrama de secuencia de mensajes del patrón proxy protegido

La imagen anterior nos describe los llamados a los métodos de cada clase de la siguiente manera.

  1. El cliente realiza una solicitud. La clase Proxy recibe la solicitud, recuerden que para el cliente es transparente y no tiene conocimiento de que está utilizando un Proxy en lugar del objeto real.
  2. Proxy utiliza la implementación de InvocationHandler que le fue asignada en tiempo de ejecución y delega la invocación del método. En este caso el Proxy le envía el nombre del método y los parámetros del método.
  3. La implementación de InvocationHandler, determina si el método que se esta tratando de acceder está permitido, es decir, esta clase contiene la lógica que determina si es posible o no acceder al método.
  4. Si se determina que es posible acceder al método, entonces, por medio de reflection, se llama al método y se envían los parámetros a RealSubject.
  5. RealSubject ejecuta el método deseado y devuelve el resultado.

Para nuestra aplicación de ejemplo vamos a suponer que tenemos un sistema que cuenta con Usuarios. Dichos usuarios pueden tener únicamente uno de los dos Roles del sistema, Administrador y Cliente.

Sólo el Rol Administrador puede deshabilitar a un usuario, si el rol del usuario es Cliente, no debe permitirse la acción.

Este es el diagrama de clases de nuestra aplicación.

Diagrama de clases del ejemplo implementando el patrón
  • AllowActivate y DenyActivate son las clases que heredan de la interfaz InvocationHandler. Las cuales van a determinar si la acción que quiere realizar el usuario está permitida o no según su Rol.
  • Proxy es una clase que se crea dinámicamente y se le asigna el InvocationHandler según corresponda.

En el código mostrado a continuación, creamos el Handler específico para cada usuario según su Rol.

/**
 * Method used to create the proxy instance
 * @param _entity The entity to use to generate the proxy
 * @param _role The current user Role
 * @return The proxy to use
 */
public static IActivatable getProxy(IActivatable _entity, RoleEnum _role) {
		
	// check specific enum value
	switch (_role) {
	case ADMIN:
		// when it is admin role then select the Allow handler
		return (IActivatable)Proxy.newProxyInstance(_entity.getClass().getClassLoader(), 
					_entity.getClass().getInterfaces(), new AllowActivateHandler(_entity));
	case CLIENT:
		// when it is client role, then select the Deny handler
		return (IActivatable)Proxy.newProxyInstance(_entity.getClass().getClassLoader(), 
					_entity.getClass().getInterfaces(), new DenyActivateHandler(_entity));
	}
		
	return null;
}

El resultado de ejecutar nuestra aplicación de ejemplo es el siguiente.

Resultado de ejecutar el código de ejemplo

Como podemos observar, si el usuario tiene el Rol Administrador, puede cambiar el estado del usuario Paul.

Por el contrario, si el usuario tiene el Rol Cliente, el proxy y el Handler se encargan de lanzar una excepción que nos indica que ese Rol no tiene permisos para modificar el estado del usuario.

El código de ejemplo del patrón proxy protegido lo pueden descargar aquí.

En el próximo post vamos a discutir el Patrón llamado Modelo – Vista – Controlador.

Recordá suscribirte aquí para recibir las últimas actualizaciones todas las semanas.

Referencias:
Libro Head First Design Patterns. Versión digital.

Leave a Reply

Your email address will not be published. Required fields are marked *