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 org.openspcoop2.core.commons.CoreException;
  23. import org.openspcoop2.core.constants.Costanti;
  24. import org.openspcoop2.core.controllo_traffico.constants.TipoErrore;
  25. import org.openspcoop2.message.constants.ServiceBinding;
  26. import org.openspcoop2.pdd.core.PdDContext;
  27. import org.openspcoop2.pdd.core.handlers.HandlerException;
  28. import org.openspcoop2.pdd.logger.MsgDiagnosticiProperties;
  29. import org.openspcoop2.pdd.logger.MsgDiagnostico;
  30. import org.openspcoop2.utils.SemaphoreLock;
  31. import org.openspcoop2.utils.date.DateManager;
  32. import org.slf4j.Logger;

  33. /**    
  34.  * GestoreControlloTraffico
  35.  *
  36.  * @author Poli Andrea (poli@link.it)
  37.  * @author $Author$
  38.  * @version $Rev$, $Date$
  39.  */
  40. public class GestoreControlloTraffico {
  41.    
  42.     private static GestoreControlloTraffico staticInstance = null;
  43.     public static synchronized void initialize(boolean erroreGenerico){
  44.         if(staticInstance==null){
  45.             staticInstance = new GestoreControlloTraffico(erroreGenerico);
  46.         }
  47.     }
  48.     public static GestoreControlloTraffico getInstance() throws CoreException{
  49.         if(staticInstance==null){
  50.             // spotbugs warning 'SING_SINGLETON_GETTER_NOT_SYNCHRONIZED': l'istanza viene creata allo startup
  51.             synchronized (GestoreControlloTraffico.class) {
  52.                 throw new CoreException("GestorePolicyAttive non inizializzato");
  53.             }
  54.         }
  55.         return staticInstance;
  56.     }
  57.    
  58.    
  59.     private GestoreControlloTraffico(boolean erroreGenerico){
  60.         this.erroreGenerico = erroreGenerico;
  61.     }
  62.    
  63.     /**
  64.      * Threads attivi complessivi sulla Porta
  65.      **/
  66.     //private final Boolean semaphore = true; // Serve perche' senno cambiando i valori usando auto-box un-box, si perde il riferimento.
  67.     private final org.openspcoop2.utils.Semaphore lock = new org.openspcoop2.utils.Semaphore("GestoreControlloTraffico");
  68.     private long activeThreads = 0l;
  69.     private boolean pddCongestionata = false;
  70.     private boolean erroreGenerico;
  71.     public StatoTraffico getStatoControlloTraffico(String idTransazione, boolean sync) {
  72.         if(sync) {
  73.             long syncActiveThreads = 0l;
  74.             boolean syncPddCongestionata = false;
  75.             //synchronized (this.semaphore) {
  76.             SemaphoreLock lock = this.lock.acquireThrowRuntime("getStatoControlloTraffico", idTransazione);
  77.             try {
  78.                 syncActiveThreads = this.activeThreads;
  79.                 syncPddCongestionata = this.pddCongestionata;
  80.             }finally {
  81.                 this.lock.release(lock, "getStatoControlloTraffico", idTransazione);
  82.             }
  83.             StatoTraffico stato = new StatoTraffico();
  84.             stato.setActiveThreads(syncActiveThreads);
  85.             stato.setPddCongestionata(syncPddCongestionata);
  86.             return stato;
  87.         }
  88.         else {
  89.             //Risolve problema di deadlock che scaturiva utilizzando solamente 1 connessione e facendo un test in cui più thread invocavano con più messaggi, senza avere alcuna informazione in cache
  90.             // Si perde un pochino in precisione, ma risolve il problema del deadlock
  91.             StatoTraffico stato = new StatoTraffico();
  92.             stato.setActiveThreads(this.activeThreads);
  93.             stato.setPddCongestionata(this.pddCongestionata);
  94.             return stato;
  95.         }
  96.     }
  97.     public void addThread(ServiceBinding serviceBinding, Long maxThreadsObj, Integer thresholdObj, Boolean warningOnly, PdDContext pddContext, MsgDiagnostico msgDiag,
  98.             TipoErrore tipoErrore, boolean includiDescrizioneErrore,Logger log) throws Exception{
  99.        
  100.         boolean emettiDiagnosticoMaxThreadRaggiunto = false;
  101.        
  102.         boolean emettiEventoMaxThreadsViolated = false;
  103.         String descriptionEventoMaxThreadsViolated = null;
  104.         Date dataEventoMaxThreadsViolated = null;
  105.        
  106.         boolean emettiEventoPddCongestionata = false;
  107.         String descriptionEventoPddCongestionata = null;
  108.         Date dataEventoPddCongestionata = null;
  109.        
  110.         try{
  111.             long maxThreadsPrimitive = maxThreadsObj.longValue();
  112.             int thresholdPrimitive = (thresholdObj!=null ? thresholdObj.intValue() : 0);
  113.             String idTransazione = (pddContext!=null && pddContext.containsKey(Costanti.ID_TRANSAZIONE)) ? PdDContext.getValue(Costanti.ID_TRANSAZIONE, pddContext) : null;
  114.            
  115.             long activeThreadsSyncBeforeIncrement = -1;
  116.             boolean errorSync = false;
  117.             boolean pddCongestionataSync = false;
  118.            
  119.             //synchronized (this.semaphore) {
  120.             SemaphoreLock lock = this.lock.acquire("addThread", idTransazione);
  121.             try {
  122.                 activeThreadsSyncBeforeIncrement = this.activeThreads;
  123.                 //System.out.println("@@@addThread CONTROLLO ["+this.activeThreads+"]<["+maxThreads+"] ("+(!(this.activeThreads<maxThreads))+")");
  124.                 if(!(this.activeThreads<maxThreadsPrimitive)){
  125.                     errorSync = true;
  126.                 }
  127.                 if(!errorSync || warningOnly) {
  128.                    
  129.                     this.activeThreads++;
  130.                    
  131.                     if(thresholdObj!=null){
  132.                         pddCongestionataSync = this._isPddCongestionata(maxThreadsPrimitive, thresholdPrimitive);
  133.                        
  134.                         //System.out.println("ACTIVE THREADS TOTALI: "+this.activeThreads);
  135.                         //System.out.println("PDD CONGESTIONATA: "+pddCongestionata);
  136.                        
  137.                         // verifica rispetto a variabile interna
  138.                         if(this.pddCongestionata){
  139.                             if(pddCongestionataSync==false){
  140.                                 //System.out.println("@@ NON PIU' RICHIESTO");
  141.                                 this.pddCongestionata = false;
  142.                             }
  143.                         }
  144.                         else{
  145.                             if(pddCongestionataSync){
  146.                                 //System.out.println("@@ C.T. RICHIESTO ATTIVO");
  147.                                 this.pddCongestionata = true;
  148.                                
  149.                                 // Emetto un evento di congestione in corso
  150.                                 emettiEventoPddCongestionata = true;
  151.                                 dataEventoPddCongestionata = DateManager.getDate();
  152.                             }
  153.                         }
  154.                     }
  155.                 }
  156.                 //System.out.println("@@@addThread (dopo): "+this.activeThreads);
  157.             }finally {
  158.                 this.lock.release(lock, "addThread", idTransazione);
  159.             }
  160.            
  161.             HandlerException he = null;
  162.             if(errorSync) {
  163.                 emettiDiagnosticoMaxThreadRaggiunto = true;
  164.                 msgDiag.addKeyword(GeneratoreMessaggiErrore.TEMPLATE_ACTIVE_THREADS, activeThreadsSyncBeforeIncrement+"");
  165.                 if(pddContext!=null) {
  166.                     pddContext.addObject(GeneratoreMessaggiErrore.PDD_CONTEXT_ACTIVE_THREADS, activeThreadsSyncBeforeIncrement);
  167.                 }
  168.                 msgDiag.addKeyword(GeneratoreMessaggiErrore.TEMPLATE_MAX_THREADS_THRESHOLD, maxThreadsPrimitive+"");
  169.                
  170.                 //System.out.println("@@@addThread ERR");
  171.                 emettiEventoMaxThreadsViolated = true;
  172.                 descriptionEventoMaxThreadsViolated = "Superato il numero di richieste complessive ("+maxThreadsPrimitive+") gestibili dalla PdD";
  173.                 dataEventoMaxThreadsViolated = DateManager.getDate();
  174.                
  175.                 if(pddContext!=null) {
  176.                     GeneratoreMessaggiErrore.addPddContextInfoControlloTrafficoMaxThreadsViolated(pddContext,warningOnly);
  177.                 }
  178.                
  179.                 String msgDiagnostico = null;
  180.                 if(warningOnly) {
  181.                     msgDiag.getMessaggio_replaceKeywords(GeneratoreMessaggiErrore.MSG_DIAGNOSTICO_INTERCEPTOR_CONTROLLO_TRAFFICO_MAXREQUESTS_VIOLATED_WARNING_ONLY);
  182.                 }
  183.                 else {
  184.                     msgDiag.getMessaggio_replaceKeywords(GeneratoreMessaggiErrore.MSG_DIAGNOSTICO_INTERCEPTOR_CONTROLLO_TRAFFICO_MAXREQUESTS_VIOLATED);
  185.                 }
  186.                 he = GeneratoreMessaggiErrore.getMaxThreadsViolated(
  187.                         msgDiagnostico,
  188.                         this.erroreGenerico, pddContext
  189.                         );
  190.                 he.setEmettiDiagnostico(false);
  191.                 GeneratoreMessaggiErrore.configureHandlerExceptionByTipoErrore(serviceBinding, he, tipoErrore, includiDescrizioneErrore,log);
  192.                 if(warningOnly == false) {
  193.                     throw he;
  194.                 }
  195.             }
  196.            
  197.             long activeThreadsSyncAfterIncrement = activeThreadsSyncBeforeIncrement+1;
  198.             msgDiag.addKeyword(GeneratoreMessaggiErrore.TEMPLATE_ACTIVE_THREADS, activeThreadsSyncAfterIncrement+""); // per policy applicabilità
  199.            
  200.             if(thresholdObj!=null){
  201.                 // Aggiungo l'informazione se la pdd risulta congestionata nel pddContext.
  202.                 if(pddContext!=null) {
  203.                     pddContext.addObject(CostantiControlloTraffico.PDD_CONTEXT_PDD_CONGESTIONATA, pddCongestionataSync);
  204.                 }
  205.                
  206.                 if(emettiEventoPddCongestionata) {
  207.                     descriptionEventoPddCongestionata = this._buildDescription(maxThreadsPrimitive, thresholdPrimitive, msgDiag);
  208.                 }
  209.                
  210.                 // Il timer dovra' vedere se esiste un evento di controllo del traffico.
  211.                 // Se non esiste utilizzera' il metodo 'isControlloTrafficoAttivo' per vedere che il controllo del traffico e' rientrato.
  212.             }
  213.        
  214.             if(he!=null) {
  215.                 // caso di warning only
  216.                 throw he;
  217.             }
  218.         }
  219.         finally{
  220.        
  221.             // *** ATTIVITA DA FARE FUORI DAL SYNCHRONIZED **
  222.                        
  223.             // fuori dal synchronized (per evitare deadlock)
  224.             if(emettiEventoMaxThreadsViolated){
  225.                 CategoriaEventoControlloTraffico evento = null;
  226.                 if(warningOnly) {
  227.                     evento = CategoriaEventoControlloTraffico.LIMITE_GLOBALE_RICHIESTE_SIMULTANEE_WARNING_ONLY;
  228.                 }
  229.                 else {
  230.                     evento = CategoriaEventoControlloTraffico.LIMITE_GLOBALE_RICHIESTE_SIMULTANEE;
  231.                 }
  232.                 NotificatoreEventi.getInstance().log(evento, dataEventoMaxThreadsViolated, descriptionEventoMaxThreadsViolated);
  233.             }
  234.            
  235.             // fuori dal synchronized
  236.             if(emettiDiagnosticoMaxThreadRaggiunto){
  237.                 if(warningOnly) {
  238.                     msgDiag.logPersonalizzato(GeneratoreMessaggiErrore.MSG_DIAGNOSTICO_INTERCEPTOR_CONTROLLO_TRAFFICO_MAXREQUESTS_VIOLATED_WARNING_ONLY);
  239.                 }
  240.                 else {
  241.                     msgDiag.logPersonalizzato(GeneratoreMessaggiErrore.MSG_DIAGNOSTICO_INTERCEPTOR_CONTROLLO_TRAFFICO_MAXREQUESTS_VIOLATED);
  242.                 }
  243.             }
  244.            
  245.             // fuori dal synchronized (per evitare deadlock)
  246.             if(emettiEventoPddCongestionata){
  247.                 NotificatoreEventi.getInstance().log(CategoriaEventoControlloTraffico.CONGESTIONE_PORTA_DOMINIO, dataEventoPddCongestionata, descriptionEventoPddCongestionata);
  248.             }
  249.            
  250.         }
  251.     }
  252.        
  253.     public void removeThread(Long maxThreadsObj, Integer thresholdObj, String idTransazione) throws Exception{
  254.         //synchronized (this.semaphore) {
  255.         if(maxThreadsObj==null) {
  256.             throw new Exception("MaxThreads param is null");
  257.         }
  258.         long maxThreadsPrimitive = maxThreadsObj.longValue();
  259.         int thresholdPrimitive = (thresholdObj!=null ? thresholdObj.intValue() : 0);
  260.         SemaphoreLock lock = this.lock.acquire("removeThread", idTransazione);
  261.         try {
  262.             this.activeThreads--;
  263.            
  264.             if(thresholdObj!=null && this.pddCongestionata){
  265. //              System.out.println("AGGORNO CONGESTIONE");
  266. //              boolean old = this.pddCongestionata;
  267.                 this.pddCongestionata = this._isPddCongestionata(maxThreadsPrimitive, thresholdPrimitive);
  268. //              if(old!=this.pddCongestionata){
  269. //                  System.out.println("OLD["+old+"] NEW["+this.pddCongestionata+"]");
  270. //              }
  271.             }
  272.            
  273.             //System.out.println("@@@removeThread (dopo): "+this.activeThreads);
  274.         }finally {
  275.             this.lock.release(lock, "removeThread", idTransazione);
  276.         }
  277.     }
  278.    
  279.     public long sizeActiveThreads(){
  280.         //synchronized (this.semaphore) {
  281.         SemaphoreLock lock = this.lock.acquireThrowRuntime("sizeActiveThreads");
  282.         try {
  283.             //System.out.println("@@@SIZE: "+this.activeThreads);
  284.             return this.activeThreads;
  285.         }finally {
  286.             this.lock.release(lock, "sizeActiveThreads");
  287.         }
  288.     }
  289.    
  290.     public Boolean isPortaDominioCongestionata(Long maxThreadsObj, Integer thresholdObj) {
  291.         //synchronized (this.semaphore) {
  292.         long maxThreadsPrimitive = maxThreadsObj.longValue();
  293.         int thresholdPrimitive = (thresholdObj!=null ? thresholdObj.intValue() : 0);
  294.         SemaphoreLock lock = this.lock.acquireThrowRuntime("isPortaDominioCongestionata");
  295.         try {
  296.             if(thresholdObj!=null){
  297.                 this.pddCongestionata = this._isPddCongestionata(maxThreadsPrimitive, thresholdPrimitive); // refresh per evitare che l'ultimo thread abbia lasciato attivo il controllo
  298.             }
  299.             else{
  300.                 this.pddCongestionata = false; // controllo non attivo
  301.             }
  302.             return this.pddCongestionata;
  303.         }finally {
  304.             this.lock.release(lock, "isPortaDominioCongestionata");
  305.         }
  306.     }
  307.    
  308.    
  309.    
  310.    
  311.     // Utilities
  312.    
  313.     private boolean _isPddCongestionata(long maxThreads, int threshold){
  314.         double dActiveT = maxThreads;
  315.         double dThreshold = threshold;
  316.         double t = dActiveT / 100d;
  317.         double tt = t * dThreshold;
  318.         int numeroThreadSoglia = (int)tt;
  319.         return this.activeThreads > numeroThreadSoglia;  // non ci vuole >=, nella govwayConsole si dice chiaramente 'Il controllo del traffico verrà attivato oltre le <numeroThreadSoglia> richieste '
  320.     }
  321.     private String _buildDescription(long maxThreads, int threshold, MsgDiagnostico msgDiag){
  322.         StringBuilder bf = new StringBuilder();
  323.        
  324.         msgDiag.addKeyword(GeneratoreMessaggiErrore.TEMPLATE_MAX_THREADS_THRESHOLD, maxThreads+"");
  325.         msgDiag.addKeyword(GeneratoreMessaggiErrore.TEMPLATE_CONTROLLO_TRAFFICO_THRESHOLD, threshold+"");
  326.         bf.append(msgDiag.getMessaggio_replaceKeywords(MsgDiagnosticiProperties.MSG_DIAG_ALL, GeneratoreMessaggiErrore.MSG_DIAGNOSTICO_INTERCEPTOR_CONTROLLO_TRAFFICO_PDD_CONGESTIONATA));
  327.        
  328.         return bf.toString();
  329.     }
  330.    
  331.    
  332. }