TimerEventiThread.java

/*
 * GovWay - A customizable API Gateway 
 * https://govway.org
 * 
 * Copyright (c) 2005-2024 Link.it srl (https://link.it).
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3, as published by
 * the Free Software Foundation.
 *
 * 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/>.
 *
 */

package org.openspcoop2.pdd.timers;


import java.io.File;
import java.io.FileInputStream;
import java.sql.Connection;
import java.util.Date;
import java.util.List;

import org.openspcoop2.core.controllo_traffico.driver.PolicyGroupByActiveThreadsType;
import org.openspcoop2.pdd.config.DBTransazioniManager;
import org.openspcoop2.pdd.config.OpenSPCoop2Properties;
import org.openspcoop2.pdd.config.Resource;
import org.openspcoop2.pdd.core.controllo_traffico.NotificatoreEventi;
import org.openspcoop2.pdd.core.controllo_traffico.policy.driver.GestorePolicyAttive;
import org.openspcoop2.pdd.core.handlers.HandlerException;
import org.openspcoop2.utils.UtilsException;
import org.openspcoop2.utils.date.DateManager;
import org.openspcoop2.utils.threads.BaseThread;
import org.slf4j.Logger;


/**     
 * TimerEventiThread
 *
 * @author Poli Andrea (poli@link.it)
 * @author $Author$
 * @version $Rev$, $Date$
 */
public class TimerEventiThread extends BaseThread{

	private static TimerState STATE = TimerState.OFF; // abilitato in OpenSPCoop2Startup al momento dell'avvio
	
	public static TimerState getSTATE() {
		return STATE;
	}
	public static void setSTATE(TimerState sTATE) {
		STATE = sTATE;
	}

	public static final String ID_MODULO = "TimerEventi";
		
	/** Logger utilizzato per debug. */
	private Logger log = null;
	
	/** Indicazione se deve essere effettuato il log delle query */
	private boolean debug = false;	
	
	
	private OpenSPCoop2Properties properties;
	
	/** NotificatoreEventi */
	private NotificatoreEventi notificatoreEventi = null;
	
	/** LastInterval */
	private Date lastInterval;
	
	/** ConnectionTimeout */
	private int checkConnectionTimeoutEveryXTimes = 1;
	private int offsetConnectionTimeoutEveryXTimes = 0;
	private Date lastIntervalConnectionTimeout;
	
	/** RequestReadTimeout */
	private int checkRequestReadTimeoutEveryXTimes = 1;
	private int offsetRequestReadTimeoutEveryXTimes = 0;
	private Date lastIntervalRequestReadTimeout;
	
	private int checkReadTimeoutEveryXTimes = 1;
	private int offsetReadTimeoutEveryXTimes = 0;
	private Date lastIntervalReadTimeout;
	
	/** Immagine */
	@SuppressWarnings("unused")
	private boolean forceCheckPrimoAvvio = false;
	
	private static boolean inizializzazioneAttiva = false;
	public static boolean isInizializzazioneAttiva() {
		return inizializzazioneAttiva;
	}
	public static void setInizializzazioneAttiva(boolean inizializzazioneAttiva) {
		TimerEventiThread.inizializzazioneAttiva = inizializzazioneAttiva;
	}
	
	/** Costruttore */
	@SuppressWarnings("deprecation")
	public TimerEventiThread(Logger log) throws Exception{
	
		this.log = log;
	
		this.properties = OpenSPCoop2Properties.getInstance();
		this.setTimeout(this.properties.getEventiTimerIntervalSeconds());
		
		this.checkConnectionTimeoutEveryXTimes = this.properties.getEventiTimerIntervalConnectionTimeoutEveryXTimes();
		this.checkRequestReadTimeoutEveryXTimes = this.properties.getEventiTimerIntervalRequestReadTimeoutEveryXTimes();
		this.checkReadTimeoutEveryXTimes = this.properties.getEventiTimerIntervalReadTimeoutEveryXTimes();
		
		// Eventi per Controllo Traffico
		if(this.properties.isControlloTrafficoEnabled()){
			this.notificatoreEventi = NotificatoreEventi.getInstance();
			
			// Il meccanismo di ripristino dell'immagine degli eventi non sembra funzionare
			// Lascio comunque il codice se in futuro si desidera approfindire la questione
			if(inizializzazioneAttiva) {
				List<PolicyGroupByActiveThreadsType> tipiGestorePolicyRateLimiting = null;
				try{
					tipiGestorePolicyRateLimiting = GestorePolicyAttive.getTipiGestoriAttivi();
				}catch(Throwable e){
					this.log.error("Errore durante l'inizializzazione dell'immagine degli eventi per il Controllo del Traffico: "+e.getMessage(),e);
				}
				if(tipiGestorePolicyRateLimiting!=null && !tipiGestorePolicyRateLimiting.isEmpty()) {
					for (PolicyGroupByActiveThreadsType type : tipiGestorePolicyRateLimiting) {
						File fDati = null;
						try{
							File fRepository = this.properties.getControlloTrafficoGestorePolicyFileSystemRecoveryRepository();
							if(fRepository!=null){
								if(fRepository.exists()==false){
									throw new Exception("Directory ["+fRepository.getAbsolutePath()+"] not exists");
								}
								if(fRepository.isDirectory()==false){
									throw new Exception("File ["+fRepository.getAbsolutePath()+"] is not directory");
								}
								if(fRepository.canRead()==false){
									throw new Exception("File ["+fRepository.getAbsolutePath()+"] cannot read");
								}
								if(fRepository.canWrite()==false){
									throw new Exception("File ["+fRepository.getAbsolutePath()+"] cannot write");
								}
								fDati = new File(fRepository, GestorePolicyAttive.getControlloTrafficoEventiImage(type));
								if(fDati.exists() && fDati.canRead() && fDati.length()>0){
									FileInputStream fin = new FileInputStream(fDati);
									this.notificatoreEventi.initialize(fin);
									if(!fDati.delete()) {
										// ignore
									}
									this.forceCheckPrimoAvvio = true;
								}
							}
						}catch(Exception e){
							String img = null;
							if(fDati!=null){
								img = fDati.getAbsolutePath();
							}
							throw new HandlerException("Inizializzazione dell'immagine degli eventi ["+img+"] per il Controllo del Traffico non riuscita: "+e.getMessage(),e);
						}
					}
				}
			}
		}
		
		this.lastInterval = DateManager.getDate();
		this.lastIntervalConnectionTimeout = DateManager.getDate();
		this.lastIntervalRequestReadTimeout = DateManager.getDate();
		this.lastIntervalReadTimeout = DateManager.getDate();
		
		this.debug = this.properties.isEventiDebug();

	}
	
	
	@Override
	public void process(){
	
		if(TimerState.ENABLED.equals(STATE)) {
		
			DBTransazioniManager dbManager = null;
	    	Resource r = null;
	    	try{
	    		dbManager = DBTransazioniManager.getInstance();
				r = dbManager.getResource(this.properties.getIdentitaPortaDefaultWithoutProtocol(), ID_MODULO, null);
				if(r==null){
					throw new UtilsException("Risorsa al database non disponibile");
				}
				Connection con = (Connection) r.getResource();
				if(con == null)
					throw new UtilsException("Connessione non disponibile");	
				
				if(this.properties.isControlloTrafficoEnabled()){
					
					try{
						this.lastInterval = this.notificatoreEventi.process(this.log, this.getTimeout(), this.lastInterval, con, this.debug);
					}catch(Exception e){
						this.log.error("Errore durante la generazione degli eventi per il controllo del traffico: "+e.getMessage(),e);
					}
					
					// Comprensione offset per analisi connection timeout events
					try{
						boolean analyzeConnectionTimeout = isAnalyzeConnectionTimeout();
						if(analyzeConnectionTimeout) {
							this.lastIntervalConnectionTimeout = this.notificatoreEventi.processConnectionTimeout(this.log, (this.getTimeout()*this.checkConnectionTimeoutEveryXTimes), this.lastIntervalConnectionTimeout, con, this.debug);
						}
						else {
							this.notificatoreEventi.emitProcessConnectionTimeoutSkip(this.log, this.debug, this.offsetConnectionTimeoutEveryXTimes, this.checkConnectionTimeoutEveryXTimes);
						}
					}catch(Exception e){
						this.log.error("Errore durante la generazione degli eventi di connection timeout: "+e.getMessage(),e);
					}
					
					// Comprensione offset per analisi request read timeout events
					try {
						boolean analyzeRequestReadTimeout = isAnalyzeRequestReadTimeout();
						if(analyzeRequestReadTimeout) {
							this.lastIntervalRequestReadTimeout = this.notificatoreEventi.processRequestReadTimeout(this.log, (this.getTimeout()*this.checkRequestReadTimeoutEveryXTimes), this.lastIntervalRequestReadTimeout, con, this.debug);
						}
						else {
							this.notificatoreEventi.emitProcessRequestReadTimeoutSkip(this.log, this.debug, this.offsetRequestReadTimeoutEveryXTimes, this.checkRequestReadTimeoutEveryXTimes);
						}
					}catch(Exception e){
						this.log.error("Errore durante la generazione degli eventi di request read timeout: "+e.getMessage(),e);
					}
					
					// Comprensione offset per analisi read timeout events
					try {
						boolean analyzeReadTimeout = isAnalyzeReadTimeout();
						if(analyzeReadTimeout) {
							this.lastIntervalReadTimeout = this.notificatoreEventi.processReadTimeout(this.log, (this.getTimeout()*this.checkReadTimeoutEveryXTimes), this.lastIntervalReadTimeout, con, this.debug);
						}
						else {
							this.notificatoreEventi.emitProcessReadTimeoutSkip(this.log, this.debug, this.offsetReadTimeoutEveryXTimes, this.checkReadTimeoutEveryXTimes);
						}
					}catch(Exception e){
						this.log.error("Errore durante la generazione degli eventi di request read timeout: "+e.getMessage(),e);
					}
					
				}
								
				// Aggiungere in futuro altre gestione degli eventi
				
			}catch(Exception e){
				this.log.error("Errore durante la generazione degli eventi: "+e.getMessage(),e);
			}finally{
				try{
					if(r!=null)
						dbManager.releaseResource(this.properties.getIdentitaPortaDefaultWithoutProtocol(), ID_MODULO, r);
				}catch(Exception eClose){
					// ignore
				}
			}
	    	
		}
		else {
			this.log.info("Timer "+ID_MODULO+" disabilitato");
		}
				
	}
	
	@Override
	public void close(){
		this.log.info("Thread per la generazione degli eventi terminato");
	}
			
	private boolean isAnalyzeConnectionTimeout() {
		this.offsetConnectionTimeoutEveryXTimes++;
		boolean esito = false;
		if(this.offsetConnectionTimeoutEveryXTimes==this.checkConnectionTimeoutEveryXTimes) {
			/**System.out.println("CONNECTION TIMEOUT CHECK '"+this.offsetConnectionTimeoutEveryXTimes+"'=='"+this.checkConnectionTimeoutEveryXTimes+"' TRUE");*/
			esito = true;
			this.offsetConnectionTimeoutEveryXTimes = 0;
		}
		/**else {
			System.out.println("CONNECTION TIMEOUT CHECK '"+this.offsetConnectionTimeoutEveryXTimes+"'<>'"+this.checkConnectionTimeoutEveryXTimes+"' FALSE");
		}*/
		return esito;
	}
	private boolean isAnalyzeRequestReadTimeout() {
		this.offsetRequestReadTimeoutEveryXTimes++;
		boolean esito = false;
		if(this.offsetRequestReadTimeoutEveryXTimes==this.checkRequestReadTimeoutEveryXTimes) {
			/**System.out.println("REQUEST READ TIMEOUT CHECK '"+this.offsetRequestReadTimeoutEveryXTimes+"'=='"+this.checkRequestReadTimeoutEveryXTimes+"' TRUE");*/
			esito = true;
			this.offsetRequestReadTimeoutEveryXTimes = 0;
		}
		/**else {
			System.out.println("REQUEST READ TIMEOUT CHECK '"+this.offsetRequestReadTimeoutEveryXTimes+"'<>'"+this.checkRequestReadTimeoutEveryXTimes+"' FALSE");
		}*/
		return esito;
	}
	private boolean isAnalyzeReadTimeout() {
		this.offsetReadTimeoutEveryXTimes++;
		boolean esito = false;
		if(this.offsetReadTimeoutEveryXTimes==this.checkReadTimeoutEveryXTimes) {
			/**System.out.println("READ TIMEOUT CHECK '"+this.offsetReadTimeoutEveryXTimes+"'=='"+this.checkReadTimeoutEveryXTimes+"' TRUE");*/
			esito = true;
			this.offsetReadTimeoutEveryXTimes = 0;
		}
		else {
			/**System.out.println("READ TIMEOUT CHECK '"+this.offsetReadTimeoutEveryXTimes+"'<>'"+this.checkReadTimeoutEveryXTimes+"' FALSE");*/
		}
		return esito;
	}
}