ALogger.java
package com.ada.utilidades.situ.log;
 
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.util.Calendar;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
import com.ada.utilidades.situ.cliente.LogExcepcionClienteWS;
import com.ada.utilidades.situ.entidad.Mannager;
import com.ada.utilidades.situ.exception.ControlException;
import com.ada.utilidades.situ.exception.GeneralException;
import com.ada.utilidades.situ.utils.Resource;
 
/**
 * Clase que encapsula y facilita la utilizacion del Logger
 * 
 * @author Jhon De Avila Mercado
 * @version 1.0
 * @since 2021
 */
public abstract class ALogger {
	private String msgError = "Error del sistema, no se pudo completar la acción solicitada";
 
	private org.apache.log4j.Logger logger;
	protected static ALogger instance;
 
	protected final int debug = 0;
	protected final int info = 1;
	protected final int warn = 2;
	protected final int error = 3;
	protected final int fatal = 4;
 
	private int level = 3;
 
	/**
	 * @param nombre del log especificado en el properties
	 * @deprecated
	 */
	public ALogger(String nombre) {
		logger = org.apache.log4j.Logger.getLogger(nombre);
 
	}
 
	public ALogger() {
		logger = org.apache.log4j.Logger.getLogger("rootLogger");
	}
 
	/**
	 * Se utiliza para escribir mensajes de depuraciñn, este log no debe estar
	 * activado cuando la aplicaciñn se encuentre en producciñn no informa el stack
	 * trace.
	 * 
	 * @param objeto mensaje tipo debug
	 */
	public void debug(final Object objeto) {
		String msg = objeto != null ? objeto.toString() : msgError;
		print(msg, null);
	}
 
	/**
	 * Se utiliza para escribir mensajes de depuraciñn, este log no debe estar
	 * activado cuando la aplicaciñn se encuentre en producciñn.
	 * 
	 * @param objeto    objeto mensaje tipo debug
	 * @param throwable seguimiento de la llamada
	 */
	public void debug(final Object objeto, final Throwable throwable) {
		String msg = objeto != null ? objeto.toString() : msgError;
		print(msg, throwable);
	}
 
	/**
	 * Se utiliza para mensajes similares al modo "verbose" en otras aplicaciones no
	 * informa el stack trace.
	 * 
	 * @param objeto mensaje de tipo info
	 */
	public void info(final Object objeto) {
		String msg = objeto != null ? objeto.toString() : msgError;
		print(msg, null);
	}
 
	/**
	 * Se utiliza para mensajes similares al modo "verbose" en otras aplicaciones.
	 * 
	 * @param objeto    objeto mensaje de tipo info
	 * @param throwable seguimiento de la llamada
	 */
	public void info(final Object objeto, final Throwable throwable) {
		String msg = objeto != null ? objeto.toString() : msgError;
		print(msg, throwable);
	}
 
	/**
	 * Se utiliza para mensajes de alerta sobre eventos que se desea mantener
	 * constancia, pero que no afectan el correcto funcionamiento del programa no
	 * informa el stack trace.
	 * 
	 * @param objeto mensaje de tipo warn
	 */
	public void warn(final Object objeto) {
		String msg = objeto != null ? objeto.toString() : msgError;
		print(msg, null);
	}
 
	/**
	 * Se utiliza para mensajes de alerta sobre eventos que se desea mantener
	 * constancia, pero que no afectan el correcto funcionamiento del programa.
	 * 
	 * @param objeto    mensaje de tipo warn
	 * @param throwable seguimiento de la llamada
	 * 
	 */
	public void warn(final Object objeto, final Throwable throwable) {
		String msg = objeto != null ? objeto.toString() : msgError;
		print(msg, throwable);
	}
 
	/**
	 * Se utiliza en mensajes de error de la aplicaciñn que se desea guardar, estos
	 * eventos afectan al programa pero lo dejan seguir funcionando, como por
	 * ejemplo que algñn parñmetro de configuraciñn no es correcto y se carga el
	 * parñmetro por defecto siempre informa el stack trace.
	 * 
	 * @param objeto mensaje de tipo error
	 */
	public void error(final Object objeto) {
		String msg = objeto != null ? objeto.toString() : msgError;
		print(msg, null);
	}
 
	/**
	 * Se utiliza en mensajes de error de la aplicaciñn que se desea guardar, estos
	 * eventos afectan al programa pero lo dejan seguir funcionando, como por
	 * ejemplo que algñn parñmetro de configuraciñn no es correcto y se carga el
	 * parñmetro por defecto.
	 * 
	 * @param objeto    mensaje de tipo error
	 * @param throwable seguimiento de la llamada
	 */
	public void error(final Object objeto, final Throwable throwable) {
		String msg = objeto != null ? objeto.toString() : msgError;
		print(msg, throwable);
	}
 
	/**
	 * Se utiliza para mensajes crñticos del sistema, generalmente luego de guardar
	 * el mensaje el programa abortarñ siempre informa el stack trace.
	 * 
	 * @param objeto mensaje de tipo fatal
	 */
	public void fatal(final Object objeto) {
		String msg = objeto != null ? objeto.toString() : msgError;
		print(msg, null);
	}
 
	/**
	 * Se utiliza para mensajes crñticos del sistema, generalmente luego de guardar
	 * el mensaje el programa abortarñ.
	 * 
	 * @param objeto    mensaje de tipo fatal
	 * @param throwable seguimiento de la llamada
	 */
	public void fatal(final Object objeto, final Throwable throwable) {
		String msg = objeto != null ? objeto.toString() : msgError;
		print(msg, throwable);
	}
 
	protected void print(final Object objeto, final Throwable throwable) {
		String message = objeto != null ? objeto.toString() : "null";
		print(message, null, 0, throwable);
	}
 
	protected void print(final String pathInfo, final int status, final Throwable throwable) {
		print(null, pathInfo, status, throwable);
	}
 
	@SuppressWarnings("unchecked")
	protected void print(final String message, final String pathInfo, final int status, final Throwable throwable) {
		try {
			final StackTraceElement[] ste = Thread.currentThread().getStackTrace();
			int positionMethodLog = 3;
			String methodLog = null;
 
			methodLog = ALogger.class.getName() + "." + ste[positionMethodLog].getMethodName();
 
			if (methodLog.equals(ALogger.class.getName() + ".debug")) {
				level = debug;
			} else if (methodLog.equals(ALogger.class.getName() + ".info")) {
				level = info;
			} else if (methodLog.equals(ALogger.class.getName() + ".warn")) {
				level = warn;
			} else if (methodLog.equals(ALogger.class.getName() + ".error")) {
				level = error;
			} else if (methodLog.equals(ALogger.class.getName() + ".fatal")) {
				level = fatal;
			}
 
			// No se ejecuta ninguna acción si la acción solicitada es de debug y éste
			// está
			// inactivo
			if (level == debug && logger.isDebugEnabled()) {
				return;
			}
 
			int depth = 1;
			String trace = null;
			String resource = "";
			String solution = "";
			Mannager mannager = null;
			String dispatch = "";
			String cause = "";
 
			if (throwable != null) {
				Class<Throwable> throwableClazz = (Class<Throwable>) throwable.getClass();
				Class<Throwable> causeClazz = null;
				if (throwable.getCause() != null) {
					causeClazz = (Class<Throwable>) throwable.getCause().getClass();
				}
				dispatch = "\n\tDisparador\t::\t" + throwable.getClass();
				Mannager mannagerParam = new Mannager(throwableClazz, causeClazz);
 
				for (Mannager mannagerTemp : Resource.getExceptionsMannagers()) {
					if (mannagerTemp.equals(mannagerParam)) {
						solution = "\n\tSolución\t::\t" + mannagerTemp.getMessage();
						mannager = mannagerTemp;
						break;
					}
				}
			}
 
			if (pathInfo != null) {
				resource = "\n\tOrigen\t\t::\t" + pathInfo;
			}
			cause = "\n\tCausa\t\t::\t";
			if (throwable != null && throwable.getCause() != null && throwable.getCause().getMessage() != null) {
				cause = cause + throwable.getCause().getMessage();
			} else if (status > 100 && status != 200) {
				cause = cause + "HTTP" + status;
			} else {
				cause = "";
			}
 
			String messageFormated = "\n\tMensaje\t\t::\t" + (message != null ? message : msgError);
			if (throwable != null && throwable.getMessage() != null) {
				messageFormated = messageFormated + " --> " + throwable.getMessage();
			}
			int length = 0;
			if (level >= warn) {
				length = ste.length - 1 - depth;
			} else {
				length = 4;
			}
 
			boolean lock = false;
 
			for (int i = length; length > 0 && i > 0; i--) {
				StackTraceElement element = ste[i];
				String tracePoint = element.getClassName() + "{" + element.getMethodName() + "} --> "
						+ element.getFileName() + " --> línea: " + element.getLineNumber();
 
				if (!lock) {
					String methodLocker = element.getClassName() + "." + element.getMethodName();
					lock = Resource.getLockersByException().contains(methodLocker);
				}
 
				if ((!tracePoint.startsWith("com.ada.utilidades.Logger") && tracePoint.startsWith("com.ada"))
						|| tracePoint.startsWith("com.ada.utilidades.Logger{executeRegainer}")) {
					if (trace == null) {
						trace = resource;
						trace = trace + dispatch;
						trace = trace + cause;
						trace = trace + solution;
						trace = trace + messageFormated;
						trace = trace + "\n\tTraza del evento::";
						trace = trace + "\t";
					}
					if (!trace.endsWith("\t")) {
						trace = trace + "\t\t\t\t";
					}
 
					trace = trace + tracePoint;
					trace = trace + "\n";
				}
			}
 
			if (trace != null) {
				trace = trace.substring(0, trace.lastIndexOf("\n"));
			}
 
			String idMensaje = null;
			if (level >= warn) {
				idMensaje = Math.abs(messageFormated.hashCode()) + "" + (Calendar.getInstance().getTimeInMillis());
				String idMensajeString = "\n\tID evento\t::\t" + idMensaje;
				trace = idMensajeString + trace;
			}
 
			switch (level) {
			case debug:
				logger.debug(trace);
				break;
			case info:
				logger.info(trace);
				break;
			case warn:
				logger.warn(trace);
				break;
			case error:
				logger.error(trace);
				break;
			case fatal:
				logger.fatal(trace);
				break;
			}
 
			if (level >= warn) {
				InetAddress inetAddress = InetAddress.getLocalHost();
				String ip = inetAddress.getHostAddress();
				ip = ip.substring(ip.lastIndexOf(".") + 1);
 
				String resume = " :: Causa: ";
//				String resume = " :: ID evento:" + ip + "-" + idMensaje + " :: Mensaje:";
 
				try {
					LogExcepcionClienteWS.save(null);
				} catch (GeneralException e) {
					logger.fatal(e);
				}
 
				if (mannager != null || lock) {
					if (lock || (!lock && mannager.isLocker())) {
						try {
							resume = "Acción no procesada" + resume;
							addMessage(idMensaje, level, resume, resume + message);
						} catch (Exception e) {
						}
 
						if (mannager != null) {
							executeRegainer(mannager);
						}
 
						throw new ControlException(idMensaje, throwable);
					}
				} else if (throwable != null && !(throwable instanceof ControlException)) {
					resume = "Advertencia de posible fallo" + resume;
					try {
						addMessage(idMensaje, level, resume, resume + message);
					} catch (Exception e) {
					}
				}
			}
		} catch (ControlException e) {
			throw e;
		} catch (Exception e) {
			logger.error(e);
		}
	}
 
	/**
	 * Ejecuta el método de recuración definido para el manejador de la excepción,
	 * sólo se ejecuta si el método está definido en el formato correcto o
	 * <code>package.ClassName{method}</code> y no está en ejecución
	 * 
	 * @param mannager Manejador de la excepción a controlar
	 */
	private void executeRegainer(Mannager mannager) {
		boolean excecuted = false;
		if (mannager != null && mannager.getRegainer() != null && !mannager.isExecutingRegainer()) {
			try {
				for (String regainerTemp : mannager.getRegainer()) {
					Pattern pattern = Pattern.compile(
							"^[a-z]{1}[[a-z]+[\\.]*]+\\.[a-zA-Z]{1}[a-zA-Z0-9\\_]+[\\{[a-zA-Z]{1}[a-zA-Z0-9\\_]+\\}]+");
					Matcher matcher = pattern.matcher(regainerTemp);
					if (matcher.matches()) {
						final String regainer = regainerTemp;
						String className = regainer.substring(0, regainer.indexOf("{"));
						Class<?> clazz = Class.forName(className);
 
						String methodsNames = regainer.substring(regainer.indexOf("{") + 1, regainer.lastIndexOf("}"))
								.replace("}{", "/");
						String[] methods = methodsNames.split("/");
 
						Object object = null;
						mannager.setExecutingRegainer(true);
						info("Iniciando tarea de recuperación para el subsanar " + mannager.getThrowable().getName()
								+ " --> " + mannager.getRegainer());
						for (String method : methods) {
							Method exec = clazz.getDeclaredMethod(method);
							object = exec.invoke(object);
							if (object != null) {
								clazz = object.getClass();
							}
						}
						excecuted = true;
					} else {
						warn(mannager.getThrowable().getName() + " --> " + mannager.getRegainer()
								+ ". Formato no válido. Formato esperado: package.ClassName{method}");
					}
				}
			} catch (Exception e) {
				error(e);
			} finally {
				if (excecuted) {
					info("Finalizada tarea de recuperación para subsanar " + mannager.getThrowable().getName() + " --> "
							+ mannager.getRegainer());
				}
				mannager.setExecutingRegainer(false);
			}
		}
	}
 
	/***
	 * Método abastracto para ser implementado en la clase desendiente, el cual
	 * tiene el propósito de notificar visualmente al usuario acerca los eventos que
	 * están siendo reportados. En la implementación de este método, se usará
	 * cualquier tecnología de mensajería con la cual esté familiarizado el
	 * front-end del aplicativo, permitiendo así la portabilidad a cualquier
	 * framework
	 */
	public abstract void addMessage(final String idMessage, final int severity, final String resume,
			final String detail);
 
}

<< regresar