GestoreControlloTraffico.java

  1. /*
  2.  * GovWay - A customizable API Gateway
  3.  * https://govway.org
  4.  *
  5.  * Copyright (c) 2005-2025 Link.it srl (https://link.it).
  6.  *
  7.  * This program is free software: you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License version 3, as published by
  9.  * the Free Software Foundation.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  *
  19.  */

  20. package org.openspcoop2.pdd.core.controllo_traffico;

  21. import java.util.Date;
  22. import java.util.concurrent.atomic.AtomicLong;

  23. import org.openspcoop2.core.commons.CoreException;
  24. import org.openspcoop2.core.config.driver.DriverConfigurazioneException;
  25. import org.openspcoop2.core.controllo_traffico.constants.TipoErrore;
  26. import org.openspcoop2.message.constants.ServiceBinding;
  27. import org.openspcoop2.pdd.core.PdDContext;
  28. import org.openspcoop2.pdd.core.handlers.HandlerException;
  29. import org.openspcoop2.pdd.logger.MsgDiagnosticiProperties;
  30. import org.openspcoop2.pdd.logger.MsgDiagnostico;
  31. import org.openspcoop2.protocol.sdk.ProtocolException;
  32. import org.openspcoop2.utils.UtilsException;
  33. import org.openspcoop2.utils.date.DateManager;
  34. import org.slf4j.Logger;

  35. /**    
  36.  * GestoreControlloTraffico
  37.  *
  38.  * @author Poli Andrea (poli@link.it)
  39.  * @author $Author$
  40.  * @version $Rev$, $Date$
  41.  */
  42. public class GestoreControlloTraffico {
  43.    
  44.     private static GestoreControlloTraffico staticInstance = null;
  45.     public static synchronized void initialize(boolean erroreGenerico){
  46.         if(staticInstance==null){
  47.             staticInstance = new GestoreControlloTraffico(erroreGenerico);
  48.         }
  49.     }
  50.     public static GestoreControlloTraffico getInstance() throws CoreException{
  51.         if(staticInstance==null){
  52.             // spotbugs warning 'SING_SINGLETON_GETTER_NOT_SYNCHRONIZED': l'istanza viene creata allo startup
  53.             synchronized (GestoreControlloTraffico.class) {
  54.                 throw new CoreException("GestorePolicyAttive non inizializzato");
  55.             }
  56.         }
  57.         return staticInstance;
  58.     }
  59.    
  60.    
  61.     private GestoreControlloTraffico(boolean erroreGenerico){
  62.         this.erroreGenerico = erroreGenerico;
  63.     }
  64.    
  65.     /**
  66.      * Threads attivi complessivi sulla Porta
  67.      **/
  68.     private AtomicLong activeThreads = new AtomicLong(0l);
  69.     private boolean erroreGenerico;
  70.     private Long maxThreads = null;
  71.     private Integer threshold = null;
  72.    
  73.     public StatoTraffico getStatoControlloTraffico() {
  74.         long currentActiveThreads = this.activeThreads.get();
  75.        
  76.         StatoTraffico stato = new StatoTraffico();
  77.         stato.setActiveThreads(currentActiveThreads);
  78.         stato.setPddCongestionata(this.isPddCongestionata(currentActiveThreads));
  79.         return stato;
  80.     }
  81.    
  82.    
  83.     public void addThread(ServiceBinding serviceBinding,
  84.             Long maxThreadsObj, Integer thresholdObj, Boolean warningOnly,
  85.             PdDContext pddContext, MsgDiagnostico msgDiag, TipoErrore tipoErrore,
  86.             boolean includiDescrizioneErrore,Logger log) throws ProtocolException, HandlerException, CoreException, UtilsException, DriverConfigurazioneException  {
  87.        
  88.         boolean emettiDiagnosticoMaxThreadRaggiunto = false;
  89.        
  90.         boolean emettiEventoMaxThreadsViolated = false;
  91.         String descriptionEventoMaxThreadsViolated = null;
  92.         Date dataEventoMaxThreadsViolated = null;
  93.        
  94.         boolean emettiEventoPddCongestionata = false;
  95.         String descriptionEventoPddCongestionata = null;
  96.         Date dataEventoPddCongestionata = null;
  97.        
  98.         try{
  99.             long maxThreadsPrimitive = maxThreadsObj.longValue();
  100.             int thresholdPrimitive = (thresholdObj!=null ? thresholdObj.intValue() : 0);
  101.            
  102.             long activeThreadsSyncBeforeIncrement = -1;
  103.             boolean errorSync = false;
  104.             boolean pddCongestionataSync = false;
  105.            
  106.             /**
  107.              * Gestione della concorrenza lock-free, la gestione dei thread massimi
  108.              * consentiti viene fatta usando una variabile atomica, in questo caso
  109.              * l'unica situazione negativa si verifica nel caso n thread contemporaneamente
  110.              * prendano
  111.              */
  112.            
  113.             /**String idTransazione = null;
  114.             if(pddContext!=null) {
  115.                 idTransazione = (String) pddContext.getObject(org.openspcoop2.core.constants.Costanti.ID_TRANSAZIONE);
  116.             }
  117.             System.out.println("["+idTransazione+"] PRIMA: "+this.activeThreads.get());*/
  118.            
  119.             // utilizzo una variabile atomica per gestire la concorrenza
  120.             long currentActiveThreads = this.activeThreads.incrementAndGet();
  121.            
  122.             /**System.out.println("["+idTransazione+"] DOPO: "+currentActiveThreads);*/
  123.            
  124.             // nel caso l'incremento abbia superato il massimo di thread consentiti devo decrementare il contatore
  125.             if (currentActiveThreads > maxThreadsPrimitive) {
  126.                 errorSync = true;
  127.                
  128.                 // nel caso warningOnly posso continuare indisturbato
  129.                 if (!warningOnly.booleanValue())
  130.                     this.activeThreads.decrementAndGet();
  131.             }
  132.            
  133.             // nel caso il thread sia stato correttamente aggiunto controllo la congestione
  134.             if((!errorSync || warningOnly.booleanValue()) && thresholdObj!=null){
  135.                 boolean prePddCongestionata = this.isPddCongestionata(maxThreadsPrimitive, thresholdPrimitive, currentActiveThreads - 1);
  136.                 boolean curPddCongestionata = this.isPddCongestionata(maxThreadsPrimitive, thresholdPrimitive, currentActiveThreads);
  137.            
  138.                 // se l'aggiunta del thread corrente ha congestionato il sistema mando il segnale
  139.                 if (!prePddCongestionata && curPddCongestionata) {
  140.                     emettiEventoPddCongestionata = true;
  141.                     dataEventoPddCongestionata = DateManager.getDate();
  142.                 }
  143.             }
  144.            
  145.            
  146.             HandlerException he = null;
  147.             if(errorSync) {
  148.                 emettiDiagnosticoMaxThreadRaggiunto = true;
  149.                 msgDiag.addKeyword(GeneratoreMessaggiErrore.TEMPLATE_ACTIVE_THREADS, activeThreadsSyncBeforeIncrement+"");
  150.                 if(pddContext!=null) {
  151.                     pddContext.addObject(GeneratoreMessaggiErrore.PDD_CONTEXT_ACTIVE_THREADS, activeThreadsSyncBeforeIncrement);
  152.                 }
  153.                 msgDiag.addKeyword(GeneratoreMessaggiErrore.TEMPLATE_MAX_THREADS_THRESHOLD, maxThreadsPrimitive+"");
  154.                
  155.                 emettiEventoMaxThreadsViolated = true;
  156.                 descriptionEventoMaxThreadsViolated = "Superato il numero di richieste complessive ("+maxThreadsPrimitive+") gestibili dalla PdD";
  157.                 dataEventoMaxThreadsViolated = DateManager.getDate();
  158.                
  159.                 if(pddContext!=null) {
  160.                     GeneratoreMessaggiErrore.addPddContextInfoControlloTrafficoMaxThreadsViolated(pddContext,warningOnly);
  161.                 }
  162.                
  163.                 String msgDiagnostico = null;
  164.                 if(warningOnly.booleanValue()) {
  165.                     msgDiag.getMessaggio_replaceKeywords(GeneratoreMessaggiErrore.MSG_DIAGNOSTICO_INTERCEPTOR_CONTROLLO_TRAFFICO_MAXREQUESTS_VIOLATED_WARNING_ONLY);
  166.                 }
  167.                 else {
  168.                     msgDiag.getMessaggio_replaceKeywords(GeneratoreMessaggiErrore.MSG_DIAGNOSTICO_INTERCEPTOR_CONTROLLO_TRAFFICO_MAXREQUESTS_VIOLATED);
  169.                 }
  170.                 he = GeneratoreMessaggiErrore.getMaxThreadsViolated(
  171.                         msgDiagnostico,
  172.                         this.erroreGenerico, pddContext
  173.                         );
  174.                 he.setEmettiDiagnostico(false);
  175.                 GeneratoreMessaggiErrore.configureHandlerExceptionByTipoErrore(serviceBinding, he, tipoErrore, includiDescrizioneErrore,log);
  176.                 if(!warningOnly.booleanValue()) {
  177.                     throw he;
  178.                 }
  179.             }
  180.            
  181.             long activeThreadsSyncAfterIncrement = activeThreadsSyncBeforeIncrement+1;
  182.             msgDiag.addKeyword(GeneratoreMessaggiErrore.TEMPLATE_ACTIVE_THREADS, activeThreadsSyncAfterIncrement+""); // per policy applicabilità
  183.            
  184.             if(thresholdObj!=null){
  185.                 // Aggiungo l'informazione se la pdd risulta congestionata nel pddContext.
  186.                 if(pddContext!=null) {
  187.                     pddContext.addObject(CostantiControlloTraffico.PDD_CONTEXT_PDD_CONGESTIONATA, pddCongestionataSync);
  188.                 }
  189.                
  190.                 if(emettiEventoPddCongestionata) {
  191.                     descriptionEventoPddCongestionata = this.buildDescription(maxThreadsPrimitive, thresholdPrimitive, msgDiag);
  192.                 }
  193.                
  194.                 // Il timer dovra' vedere se esiste un evento di controllo del traffico.
  195.                 // Se non esiste utilizzera' il metodo 'isControlloTrafficoAttivo' per vedere che il controllo del traffico e' rientrato.
  196.             }
  197.        
  198.             if(he!=null) {
  199.                 // caso di warning only
  200.                 throw he;
  201.             }
  202.         }
  203.         finally{
  204.            
  205.             if(emettiEventoMaxThreadsViolated){
  206.                 CategoriaEventoControlloTraffico evento = null;
  207.                 if(warningOnly.booleanValue()) {
  208.                     evento = CategoriaEventoControlloTraffico.LIMITE_GLOBALE_RICHIESTE_SIMULTANEE_WARNING_ONLY;
  209.                 }
  210.                 else {
  211.                     evento = CategoriaEventoControlloTraffico.LIMITE_GLOBALE_RICHIESTE_SIMULTANEE;
  212.                 }
  213.                 NotificatoreEventi.getInstance().log(evento, dataEventoMaxThreadsViolated, descriptionEventoMaxThreadsViolated);
  214.             }
  215.            
  216.             // fuori dal synchronized
  217.             if(emettiDiagnosticoMaxThreadRaggiunto){
  218.                 if(warningOnly.booleanValue()) {
  219.                     msgDiag.logPersonalizzato(GeneratoreMessaggiErrore.MSG_DIAGNOSTICO_INTERCEPTOR_CONTROLLO_TRAFFICO_MAXREQUESTS_VIOLATED_WARNING_ONLY);
  220.                 }
  221.                 else {
  222.                     msgDiag.logPersonalizzato(GeneratoreMessaggiErrore.MSG_DIAGNOSTICO_INTERCEPTOR_CONTROLLO_TRAFFICO_MAXREQUESTS_VIOLATED);
  223.                 }
  224.             }
  225.            
  226.             // fuori dal synchronized (per evitare deadlock)
  227.             if(emettiEventoPddCongestionata){
  228.                 NotificatoreEventi.getInstance().log(CategoriaEventoControlloTraffico.CONGESTIONE_PORTA_DOMINIO, dataEventoPddCongestionata, descriptionEventoPddCongestionata);
  229.             }
  230.            
  231.         }
  232.     }
  233.        
  234.     public void removeThread() {        
  235.         this.activeThreads.decrementAndGet();
  236.     }
  237.    
  238.     public long sizeActiveThreads(){
  239.             return this.activeThreads.get();
  240.     }
  241.    
  242.     public Boolean isPortaDominioCongestionata(Long maxThreadsObj, Integer thresholdObj) {
  243.         return this.isPddCongestionata(maxThreadsObj, thresholdObj, this.activeThreads.get());
  244.     }
  245.    
  246.    
  247.    
  248.    
  249.     // Utilities
  250.    
  251.     /**
  252.      * Restituisce l'ultimo valore calcolato di PddCongestionata
  253.      * @param activeThreads: numero di thread attualmente attivi
  254.      * @return
  255.      */
  256.     private boolean isPddCongestionata(long activeThreads) {
  257.         return this.isPddCongestionata(this.maxThreads, this.threshold, activeThreads);
  258.     }
  259.    
  260.     /**
  261.      * Restituisce se la Pdd risulta congestionata
  262.      * @param maxThreads: numero massimo di thread attivi
  263.      * @param threshold: valore percentuale sul numero di thread massimo oltre il quale
  264.      * la pdd risulta congestionata (null se non attivo)
  265.      * @param activeThreads: numero di thread attivi
  266.      * @return true se il controllo della congestione della pdd é abilitato e risulta
  267.      * congestionata
  268.      */
  269.     private boolean isPddCongestionata(Long maxThreads, Integer threshold, long activeThreads){
  270.         // mi salvo i valori di maxThreads e threshold in caso volessi restituire l'ultimo valore calcolato
  271.         this.maxThreads = maxThreads;
  272.         this.threshold = threshold;
  273.         if (threshold == null || maxThreads == null)
  274.             return false;
  275.         double dActiveT = maxThreads;
  276.         double dThreshold = threshold;
  277.         double t = dActiveT / 100d;
  278.         double tt = t * dThreshold;
  279.         int numeroThreadSoglia = (int)tt;
  280.         return activeThreads > numeroThreadSoglia;  // non ci vuole >=, nella govwayConsole si dice chiaramente 'Il controllo del traffico verrà attivato oltre le <numeroThreadSoglia> richieste '
  281.     }
  282.    
  283.     private String buildDescription(long maxThreads, int threshold, MsgDiagnostico msgDiag){
  284.         StringBuilder bf = new StringBuilder();
  285.        
  286.         msgDiag.addKeyword(GeneratoreMessaggiErrore.TEMPLATE_MAX_THREADS_THRESHOLD, maxThreads+"");
  287.         msgDiag.addKeyword(GeneratoreMessaggiErrore.TEMPLATE_CONTROLLO_TRAFFICO_THRESHOLD, threshold+"");
  288.         bf.append(msgDiag.getMessaggio_replaceKeywords(MsgDiagnosticiProperties.MSG_DIAG_ALL, GeneratoreMessaggiErrore.MSG_DIAGNOSTICO_INTERCEPTOR_CONTROLLO_TRAFFICO_PDD_CONGESTIONATA));
  289.        
  290.         return bf.toString();
  291.     }
  292.    
  293.    
  294. }