All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.uqbar.common.transaction.Context Maven / Gradle / Ivy

package com.uqbar.common.transaction;

import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Encapsula el contexto correspondiente a un proceso que debe ejecutarse. Este contexto no se pasa por
 * parámetro, en cambio, se obtiene a partir de getCurrentContext de esta clase.
 * 
 * Para la mayoría de los usos, el contexto se considera válido una vez que se le ha asignado un owner. Un
 * contexto sin owner podría considerarse un NullObject, que no debe ser utilizado.
 * 
 * @author npasserini
 */
public class Context implements ContextConstants {
	private static final Log LOG = LogFactory.getLog(Context.class);

	private static ThreadLocal threadLocalContext = new ThreadLocal();

	private Map parameters;

	private static final Object DUMMY_OWNER = new Object() {
		public String toString() {
			return "DummyContextOwner";
		}
	};

	/*
	 * Static methods. Context creation, invalidation & retrieval.
	 */

	/**
	 * Inicializa en Contexto y le asocia un dueño, el cual podra terminar el Contexto; Si el Contexto ya fue
	 * inicializado solo lo usa; Si el Contexto fue creado con dueño Dummy se le asocia al primero que lo
	 * tome.
	 */
	public static Context beginContext(Object owner) {
		AssertUtils.assertArgumentNotNull("Context OWNER cannot be NULL!", owner);

		// TODO: synchronize
		Context current = threadLocalContext.get();
		if (current == null) {
			LOG.debug("Begining Context with owner: " + owner);
			current = new Context(owner);
			threadLocalContext.set(current);
		}
		else {
			if (current.isContextOwner(DUMMY_OWNER) && DUMMY_OWNER != owner) {
				current.setContextOwner(owner);
				LOG.debug("Asigning context to owner: " + owner);
			}
		}
		return current;
	}

	/**
	 * Termina el Contexto y libera todos los recurso asociados.
	 */
	public static void endContext(Object owner) {
		Context current = threadLocalContext.get();
		AssertUtils.assertNotNull("No initialized Context found to end!", current);

		if (!current.isContextOwner(DUMMY_OWNER)) {
			AssertUtils.assertTrue("Cannot end Context, the given object '" + owner + "' isn't the expected owner: "
				+ current.getContextOwner(), current.isContextOwner(owner));
		}
		LOG.debug("Ending Context with owner: " + owner);
		current.parameters.clear();
		threadLocalContext.set(null);
	}

	/**
	 * Obtiene el Contexto actual y si no existe uno crea uno.
	 */
	public static Context getCurrentContext() {
		Context current = threadLocalContext.get();
		if (current == null) {
			current = beginContext(DUMMY_OWNER);
		}
		return current;
	}


	/**
	 * Invalida el contexto actual, si existe un contexto padre se asigna ese.
	 */
	public static void unsecureInvalidateCurrentContext() {
		Context context = getCurrentContext();
		threadLocalContext.set(context.getParentContext());
	}

	/*
	 * Parameter management
	 */

	/**
	 * Devuelve el parámetro 'parameterName'
	 */
	@SuppressWarnings("unchecked")
	public  T getParameter(String parameterName) {
		return (T) this.parameters.get(parameterName);
	}

	/**
	 * Agrega un nuevo parámetro a este contexto
	 */
	public void setParameter(String parameterName, Object parameterValue) {
		this.parameters.put(parameterName, parameterValue);
	}

	/**
	 * Elimina un parámetro de este contexto
	 */
	public void removeParameter(String parameterName) {
		this.parameters.remove(parameterName);
	}

	/**
	 * Determina si existe el parámetro 'parameterName' en este contexto.
	 */
	public boolean containsParameter(String parameterName) {
		return this.parameters.containsKey(parameterName);
	}


	/*
	 * Parent management
	 */

	/**
	 * Devuelve el owner del contexto.
	 */
	public Object getContextOwner() {
		return this.getParameter(CONTEXT_OWNER);
	}

	/**
	 * Permite al contexto modificar su owner. S�lo deber�a ser utilizado dentro del framework y para tareas
	 * espec�ficas de manejo de contextos.
	 */
	protected void setContextOwner(Object owner) {
		this.setParameter(CONTEXT_OWNER, owner);
	}

	/**
	 * Determina si el objeto es el dueño del contexto y por lo tanto es responsable de las tareas de
	 * administración.
	 */
	public boolean isContextOwner(Object obj) {
		return this.getParameter(CONTEXT_OWNER) == obj;
	}

	/**
	 * Determina si este contexto tiene un contexto padre.
	 */
	public boolean isChildContext() {
		return this.containsParameter(CONTEXT_PARENT);
	}

	/**
	 * Devuelve el contexto padre de este contexto.
	 */
	public Context getParentContext() {
		return (Context) this.getParameter(CONTEXT_PARENT);
	}

	/*
	 * Constructors (always protected)
	 */

	/**
	 * Constructor protegido.
	 */
	protected Context(Object owner) {
		this.parameters = new HashMap<>();
		this.setParameter(CONTEXT_OWNER, owner);
	}

	/**
	 * Constructor protegido.
	 */
	protected Context(Object owner, Context parentContext) {
		this(owner);
		this.setParameter(CONTEXT_PARENT, parentContext);
	}

	public Log getLog() {
		// LOG Manejar por contexto.
		return Context.LOG;
	}

	/*
	 * Stack available parameters
	 */

	public void pushParameter(String parameterName, Object parameterValue, Object owner) {
		if (this.containsParameter(parameterName)) {
			Stack stack = this.getParameterStack(parameterName);
			Object oldValue = this.getParameter(parameterName);
			Object oldOwner = this.getParameter(parameterName + ".owner");
			stack.push(new ParameterStackElement(oldValue, oldOwner));
		}
		this.setParameter(parameterName, parameterValue);
		this.setParameter(parameterName + ".owner", owner);
	}

	public void popParameter(String parameterName, Object owner) {
		if (getParameter(parameterName + ".owner") == owner) {
			Stack stack = this.getParameterStack(parameterName);
			if (stack.isEmpty()) {
				this.removeParameter(parameterName);
				this.removeParameter(parameterName + ".owner");
			}
			else {
				ParameterStackElement element = (ParameterStackElement) stack.pop();
				this.setParameter(parameterName, element.getValue());
				this.setParameter(parameterName + ".owner", element.getOwner());
			}

		}
	}

	private Stack getParameterStack(String parameterName) {
		if (this.containsParameter(parameterName + ".stack")) {
			return this.getParameter(parameterName + ".stack");
		}
		else {
			Stack stack = new Stack();
			this.setParameter(parameterName + ".stack", stack);
			return stack;
		}
	}

	/**
	 * 
	 * @author npasserini
	 */
	private class ParameterStackElement {
		private Object value, owner;

		private ParameterStackElement(Object value, Object owner) {
			this.value = value;
			this.owner = owner;
		}

		private Object getValue() {
			return this.value;
		}

		private Object getOwner() {
			return this.owner;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy