AbstractFSRecovery.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.monitor.engine.fs_recovery;

import java.io.File;
import java.sql.Connection;

import org.openspcoop2.utils.UtilsException;
import org.openspcoop2.utils.UtilsMultiException;
import org.openspcoop2.utils.resources.FileSystemUtilities;
import org.slf4j.Logger;

/**
 * AbstractFSRecovery
 *
 * @author Poli Andrea (apoli@link.it)
 * @author $Author$
 * @version $Rev$, $Date$
 */
public abstract class AbstractFSRecovery {

	protected Logger log;
	protected boolean debug;
	protected File directory;
	protected File directoryDLQ;
	protected int tentativi;
	protected long msAttesaProcessingFile;
	
	protected AbstractFSRecovery( 
			Logger log,
			boolean debug,
			File directory, File directoryDLQ,
			int tentativi,
			long msAttesaProcessingFile) {
		this.log = log;
		this.debug = debug;
		this.directory = directory;
		this.directoryDLQ = directoryDLQ;
		this.tentativi = tentativi;
		this.msAttesaProcessingFile = msAttesaProcessingFile;
	}
	
	public abstract void insertObject(File file, Connection connection) throws UtilsException, UtilsMultiException;
	
	protected void logDebug(String msg) {
		if(this.log!=null) {
			this.log.debug(msg);
		}
	}
	protected void logInfo(String msg) {
		if(this.log!=null) {
			this.log.info(msg);
		}
	}
	protected void logWarn(String msg) {
		if(this.log!=null) {
			this.log.warn(msg);
		}
	}
	protected void logWarn(String msg, Exception e) {
		if(this.log!=null) {
			this.log.warn(msg, e);
		}
	}
	protected void logError(String msg, Exception e) {
		if(this.log!=null) {
			this.log.error(msg, e);
		}
	}
	
	public void process(Connection connection){

		// process file presenti nella directory.
		// Per ogni file fare il marshall dell'oggetto 'it.link.pdd.core.plugins.eventi.utils.serializer.JaxbDeserializer'
		try {
			// NOTA: prima di processare un file verificare che la sua data di ultima modifica sia piu' vecchia almeno di X minuti (mettere X minuti in una costante)
			// 		 in modo da evitare di processare i file che sono creati nello stesso momento in cui gira la procedura
			File[] filesToProcess = this.directory.listFiles(new LastModifiedFileFilter(this.msAttesaProcessingFile));
			
			if(filesToProcess!=null && filesToProcess.length > 0) {
				this.logInfo("Processamento di ["+filesToProcess.length+"] file");
				
				int countProcessatiCorrettamente = 0;
				int countProcessatiConErrore = 0;

				for(File file: filesToProcess) {
					if(process(connection, file)) {
						countProcessatiCorrettamente++;
					}
					else {
						countProcessatiConErrore++;
					}
				}
				this.logInfo("Processamento di ["+filesToProcess.length+"] file completato. ["+countProcessatiCorrettamente+"] file processati correttamente, ["+countProcessatiConErrore+"] con errore");
			} else {
				this.logInfo("Nessun file da processare");
			}
			
		}catch(Exception e) {
			this.logError("Errore durante Il Recovery: "+e.getMessage(), e);
		}
	}
	private boolean process(Connection connection, File file) throws UtilsException{
		try {
			if(this.debug)
				this.logInfo("Inserimento del file ["+file.getName()+"] ...");

			// Implementare il salvataggio nella classe concreta
			// Se il salvataggio su database va a buon fine si puo eliminare il file.
			this.insertObject(file, connection);
			FileSystemUtilities.deleteFile(file);
			if(this.debug)
				this.logInfo("Inserimento del file ["+file.getName()+"] completato con successo");
			return true;
		} catch(Exception e) {
			error(file, e);
			return false;
		}
	}
	private void error(File file, Exception e) throws UtilsException {
		if(this.debug)
			this.logWarn("Errore durante l'inserimento del file ["+file.getName()+"] rinomino il file:"+e.getMessage(), e);
		
		int tentativiPerFile = FSRecoveryFileUtils.getTentativiFromFilename(file.getName());
		if(tentativiPerFile < this.tentativi) {
			// Se avviene un errore sul marshal o se avviene un errore durante l'inserimento effettuare un rename del file file.renameTo(file2)
			// aggiungendo un suffisso sul numero del tentativo: es. 
			// File originale: Evento_2015-04-27_09\:37\:34.323_1.xml
			// Dopo primo tentativo: Evento_2015-04-27_09\:37\:34.323_1.xml_1.error
			// Dopo secondo tentativo: Evento_2015-04-27_09\:37\:34.323_1.xml_2.error
			// ...
			// In modo da riconoscere gli originali *.xml da quelli che sono andati in errore almeno una volta *.error

			File newFile = new File(this.directory, FSRecoveryFileUtils.getNewFileNameFromFilename(file.getName()));
			if(!file.renameTo(newFile)) {
				// ignore
			}
			if(this.debug)
				this.logWarn("File ["+file.getName()+"] rinominato in ["+newFile.getName()+"]");
		} else {
			// Se per un file si raggiunge il massimo numero di tentativi, effettuare il rename del file file.renameTo(file2)
			// Spostandolo nella directory DLQ.

			// NOTA: in DLQ estrapolare la data (solo anno mese e giorno) dal nome del file e usarla come nome della directory all'interno di DLQ. Inserire 
			String newFileName = FSRecoveryFileUtils.renameToDLQ(this.directoryDLQ, file, e, this.log);
			if(this.debug)
				this.logWarn("File ["+file.getName()+"] rinominato in ["+newFileName+"]");
		}
	}
	
}