/** * Analytica - beta version - Systems Monitoring Tool * * Copyright (C) 2013, KleeGroup, direction.technique@kleegroup.com (http://www.kleegroup.com) * KleeGroup, Centre d'affaire la Boursidi�re - BP 159 - 92357 Le Plessis Robinson Cedex - France * * This program is free software; you can redistribute it and/or modify it under the terms * of the GNU General Public License as published by the Free Software Foundation; * either version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with this program; * if not, see <http://www.gnu.org/licenses> * * Linking this library statically or dynamically with other modules is making a combined work based on this library. * Thus, the terms and conditions of the GNU General Public License cover the whole combination. * * As a special exception, the copyright holders of this library give you permission to link this library * with independent modules to produce an executable, regardless of the license terms of these independent modules, * and to copy and distribute the resulting executable under terms of your choice, provided that you also meet, * for each linked independent module, the terms and conditions of the license of that module. * An independent module is a module which is not derived from or based on this library. * If you modify this library, you may extend this exception to your version of the library, * but you are not obliged to do so. * If you do not wish to do so, delete this exception statement from your version. */ package io.analytica.api; import java.util.Stack; /** * Datas collector agent. * Collect and build Process. * Building process are bind to current thread. * * @author pchretien, npiedeloup * @version $Id: AgentManagerImpl.java,v 1.7 2012/03/29 08:48:19 npiedeloup Exp $ */ public final class KProcessCollector { private final KProcessConnector processConnector; private final String appName; private final String location; /** * Constructor. * Should be created only once. * @param processConnector Collector output connector */ public KProcessCollector(final String appName, final String location, final KProcessConnector processConnector) { KProcessUtil.checkNotNull(appName, "appName is required"); KProcessUtil.checkNotNull(location, "location is required"); KProcessUtil.checkNotNull(processConnector, "processConnector is required"); //----------------------------------------------------------------- this.processConnector = processConnector; this.appName = appName; this.location = location; } /** * Processus bind� sur le thread courant. Le processus , recoit les notifications des sondes plac�es dans le code de * l'application pendant le traitement d'une requ�te (thread). */ private static final ThreadLocal<Stack<KProcessBuilder>> THREAD_LOCAL_PROCESS = new ThreadLocal<>(); /** * Retourne le premier �l�ment de la pile (sans le retirer). * @return Premier �l�ment de la pile */ private static KProcessBuilder peek() { return getStack().peek(); } /** * Retire le premier �l�ment de la pile. * @return Premier �l�ment de la pile */ private static KProcessBuilder pop() { return getStack().pop(); } private static Stack<KProcessBuilder> getStack() { final Stack<KProcessBuilder> stack = THREAD_LOCAL_PROCESS.get(); if (stack == null) { throw new IllegalArgumentException("Pile non initialis�e : startProcess()"); } return stack; } private static void push(final KProcessBuilder processBuilder) { Stack<KProcessBuilder> stack = THREAD_LOCAL_PROCESS.get(); if (stack == null) { stack = new Stack<>(); THREAD_LOCAL_PROCESS.set(stack); } //--------------------------------------------------------------------- if (stack.size() >= 100) { throw new IllegalStateException("La pile des KProcess atteind une profondeur de 100, il est probable qu'une fermeture de KProcess ait �t� oubli�e.\nStack:" + stack); } //--------------------------------------------------------------------- stack.push(processBuilder); } /** * Enregistre dans le thread courant le d�marrage d'un process. * Doit respecter les r�gles sur le nom d'un process. * @param type Type de process */ public KProcessCollector startProcess(final String type, final String category) { final KProcessBuilder processBuilder = new KProcessBuilder(appName, type) .withLocation(location) .withCategory(category); push(processBuilder); return this; } /** * Incr�mentation d'une mesure du process courant (set si pas pr�sente). * @param measureType Nom de la mesure * @param value Valeur */ public KProcessCollector incMeasure(final String measureType, final double value) { peek().incMeasure(measureType, value); return this; } /** * Annule et remplace une mesure du process courant. * @param measureType Nom de la mesure * @param value Valeur */ public KProcessCollector setMeasure(final String measureType, final double value) { peek().setMeasure(measureType, value); return this; } /** * Ajoute une m�ta-donn�e du process courant (set si pas pr�sente). * TODO V0+ : voir si mutlivalu�e int�ressante. * @param metaDataName Nom de la m�ta donn�e * @param value Valeur */ public KProcessCollector addMetaData(final String metaDataName, final String value) { peek().addMetaData(metaDataName, value); return this; } /** * Termine le process courant. * Le processus courant devient alors le processus parent le cas �ch�ant. */ public KProcessCollector stopProcess() { final KProcess process = doStopProcess(); if (process != null) { processConnector.add(process); } return this; } /** * Termine le process courant. * Le processus courant devient alors le processus parent le cas �ch�ant. * @return Processus uniquement dans le cas ou c'est le processus parent. */ private static KProcess doStopProcess() { final KProcess process = pop().build(); if (getStack().isEmpty()) { //On est au processus racine on le collecte THREAD_LOCAL_PROCESS.remove(); //Et on le retire du ThreadLocal return process; } peek().addSubProcess(process); //On n'est pas dans le cas de la racine : conform�ment au contrat on renvoie null return null; } /** * Ajout d'un process d�j� assembl� par une sonde. * Cet ajout peut-�tre multi-thread�. * @param process Process � ajouter */ public void add(final KProcess process) { if (THREAD_LOCAL_PROCESS.get() != null) { throw new IllegalStateException("A process is already have started. You can't add a new full process tree at this time."); } if (process == null) { throw new NullPointerException("process is required"); } //--------------------------------------------------------------------- processConnector.add(process); } }