RepositoryGestioneStateful.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.core.transazioni;

import java.sql.Connection;
import java.util.ArrayList;

import org.openspcoop2.core.commons.dao.DAOFactory;
import org.openspcoop2.core.commons.dao.DAOFactoryProperties;
import org.openspcoop2.core.id.IDSoggetto;
import org.openspcoop2.core.transazioni.dao.ITransazioneService;
import org.openspcoop2.generic_project.utils.ServiceManagerProperties;
import org.openspcoop2.pdd.config.DBTransazioniManager;
import org.openspcoop2.pdd.config.OpenSPCoop2Properties;
import org.openspcoop2.pdd.config.Resource;
import org.openspcoop2.pdd.logger.OpenSPCoop2Logger;
import org.openspcoop2.protocol.sdk.diagnostica.MsgDiagnostico;
import org.openspcoop2.protocol.sdk.dump.Messaggio;
import org.openspcoop2.protocol.sdk.tracciamento.Traccia;
import org.openspcoop2.utils.Utilities;
import org.slf4j.Logger;

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

	private static final String ID_MODULO = "RepositoryGestioneStateful";
	
	private static Boolean gestioneStatefulAbilitata = null;
	
	private static String tipoDatabase = null; //tipoDatabase
	private static DAOFactory daoFactory = null;
    private static ServiceManagerProperties daoFactoryServiceManagerPropertiesTransazioni = null;
    private static Logger log = null;
    private static Logger daoFactoryLoggerTransazioni = null;
	
	private static OpenSPCoop2Properties openspcoopProperties = null;
	private static boolean debug;
	
	private static GestoreTransazioniStateful gestoreTransazioniStateful = null;
	private static synchronized void init() throws TransactionStatefulNotSupportedException{
		if(gestioneStatefulAbilitata==null){
			try{
				openspcoopProperties = OpenSPCoop2Properties.getInstance();
				gestioneStatefulAbilitata = openspcoopProperties.isTransazioniStatefulEnabled();
			
				tipoDatabase = openspcoopProperties.getDatabaseType();
				//System.out.println("DS["+this.datasource+"] TIPODB["+this.tipoDatabase+"]");
	
				if(tipoDatabase==null){
					throw new Exception("Tipo Database non definito");
				}
	
				openspcoopProperties = OpenSPCoop2Properties.getInstance();
	
				debug = openspcoopProperties.isTransazioniStatefulDebug();
				
				DAOFactoryProperties daoFactoryProperties = null;
				log = OpenSPCoop2Logger.getLoggerOpenSPCoopTransazioniStateful(debug);
				daoFactoryLoggerTransazioni = OpenSPCoop2Logger.getLoggerOpenSPCoopTransazioniStatefulSql(debug);
				daoFactory = DAOFactory.getInstance(daoFactoryLoggerTransazioni);
				daoFactoryProperties = DAOFactoryProperties.getInstance(daoFactoryLoggerTransazioni);
				daoFactoryServiceManagerPropertiesTransazioni = daoFactoryProperties.getServiceManagerProperties(org.openspcoop2.core.transazioni.utils.ProjectInfo.getInstance());
				daoFactoryServiceManagerPropertiesTransazioni.setShowSql(debug);	
				daoFactoryServiceManagerPropertiesTransazioni.setDatabaseType(DBTransazioniManager.getInstance().getTipoDatabase());

			}catch(Exception e){
				throw new TransactionStatefulNotSupportedException("Inizializzazione risorse database non riuscita: "+e.getMessage(),e);
			}
			try{
				gestoreTransazioniStateful = new GestoreTransazioniStateful(log, daoFactoryLoggerTransazioni,
						tipoDatabase,
						debug);
			}catch(Exception e){
				throw new TransactionStatefulNotSupportedException("Inizializzazione GestoreTransazioniStateful non riuscita: "+e.getMessage(),e);
			}
		}
	}
	private static void checkGestioneAbilitata() throws TransactionStatefulNotSupportedException{
		if(gestioneStatefulAbilitata==null){
			init();
		}
		if(gestioneStatefulAbilitata==false){
			throw new TransactionStatefulNotSupportedException("Non abilitata la gestione delle transazioni stateful");
		}
	}
	
	
	// TODO: Gestione realizzata su database!!!!
	// Questa implementazione puo' causare OUT OF MEMORY
	private static ArrayList<StatefulObject> repository = 
		new ArrayList<StatefulObject>();
			
	private static void invokeGestoreTransazioniStateful(StatefulObject s,TransactionDB transactionDB)throws TransactionStatefulNotSupportedException {
		Resource dbResource = null;
		DBTransazioniManager dbManager = DBTransazioniManager.getInstance();
		IDSoggetto idDominio = openspcoopProperties.getIdentitaPortaDefault(s.getProtocollo(), null);
		Connection con = null;
		try{
			dbResource = dbManager.getResource(idDominio, ID_MODULO, null);
			con = (Connection) dbResource.getResource();	
			
			boolean autoCommit = false;
			con.setAutoCommit(autoCommit);
			
			org.openspcoop2.core.transazioni.dao.jdbc.JDBCServiceManager jdbcServiceManager =
					(org.openspcoop2.core.transazioni.dao.jdbc.JDBCServiceManager) daoFactory.getServiceManager(org.openspcoop2.core.transazioni.utils.ProjectInfo.getInstance(), 
							con, autoCommit,
							daoFactoryServiceManagerPropertiesTransazioni, daoFactoryLoggerTransazioni);
			jdbcServiceManager.getJdbcProperties().setShowSql(debug);
			ITransazioneService transazioneService = jdbcServiceManager.getTransazioneService();
			
			gestoreTransazioniStateful.gestioneStatefulObject(transazioneService, con, s, transactionDB);
			con.commit();
		}catch(Exception e){
			try{
				if(con!=null)
					con.rollback();
			}catch(Exception eRollback){
				// close
			}
			throw new TransactionStatefulNotSupportedException("Errore durante la gestione della transazione stateful",e);
		}finally{
			try{
				if(con!=null)
					con.setAutoCommit(true);
			}catch(Exception eRollback){
				// ignore
			}
			try {
				dbManager.releaseResource(idDominio, ID_MODULO, dbResource);
			} catch (Exception e) {
				// close
			}
		}
	}
	
	private static TransactionDB invokeGestoreTransazioniStateful_readTransactionDB(String protocollo, String idTransazione)throws TransactionStatefulNotSupportedException {
		Resource dbResource = null;
		DBTransazioniManager dbManager = DBTransazioniManager.getInstance();
		IDSoggetto idDominio = openspcoopProperties.getIdentitaPortaDefault(protocollo, null);
		Connection con = null;
		try{
			dbResource = dbManager.getResource(idDominio, ID_MODULO+".read", null);
			con = (Connection) dbResource.getResource();
			
			org.openspcoop2.core.transazioni.dao.jdbc.JDBCServiceManager jdbcServiceManager =
					(org.openspcoop2.core.transazioni.dao.jdbc.JDBCServiceManager) daoFactory.getServiceManager(org.openspcoop2.core.transazioni.utils.ProjectInfo.getInstance(), con,
							daoFactoryServiceManagerPropertiesTransazioni, daoFactoryLoggerTransazioni);
			jdbcServiceManager.getJdbcProperties().setShowSql(debug);
			ITransazioneService transazioneService = jdbcServiceManager.getTransazioneService();
			
			return gestoreTransazioniStateful.readTransazione(transazioneService, idTransazione);
		}catch(Exception e){
			throw new TransactionStatefulNotSupportedException("Errore durante la gestione della transazione stateful",e);
		}finally{
			try {
				dbManager.releaseResource(idDominio, ID_MODULO, dbResource);
			} catch (Exception e) {
				// close
			}
		}
	}
	
	
	public static void addMessaggio(String idTransazione, Messaggio messaggio) throws TransactionStatefulNotSupportedException {
		
		checkGestioneAbilitata();
		
		StatefulObject s = new StatefulObject(messaggio.getProtocollo());
		s.setIdTransazione(idTransazione);
		s.setObject(messaggio);
		s.setType(StatefulObjectType.MESSAGGIO);
		
		// OUT OF MEMORY PROBLEM 
		//repository.add(s);
		invokeGestoreTransazioniStateful(s,null);

	}
	
	public static void addMsgDiagnostico(String idTransazione, MsgDiagnostico msgDiag) throws TransactionStatefulNotSupportedException {
		
		checkGestioneAbilitata();
		
		StatefulObject s = new StatefulObject(msgDiag.getProtocollo());
		s.setIdTransazione(idTransazione);
		s.setObject(msgDiag);
		s.setType(StatefulObjectType.MSGDIAGNOSTICO);
		
		// OUT OF MEMORY PROBLEM 
		//repository.add(s);
		invokeGestoreTransazioniStateful(s,null);

	}
	
	public static void addTraccia(String idTransazione, Traccia traccia) throws TransactionStatefulNotSupportedException {

		checkGestioneAbilitata();
		
		StatefulObject s = new StatefulObject(traccia.getProtocollo());
		s.setIdTransazione(idTransazione);
		s.setObject(traccia);
		s.setType(StatefulObjectType.TRACCIA);
		// OUT OF MEMORY PROBLEM 
		//repository.add(s);
		invokeGestoreTransazioniStateful(s,null);

	}
	
	public static void addOutRequestStatefulObject(String protocollo,String idTransazione, OutRequestStatefulObject object) throws TransactionStatefulNotSupportedException {
		
		checkGestioneAbilitata();
		
		StatefulObject s = new StatefulObject(protocollo);
		s.setIdTransazione(idTransazione);
		s.setObject(object);
		s.setType(StatefulObjectType.OUT_REQUEST_STATEFUL_OBJECT);
			
		TransactionDB tr = invokeGestoreTransazioniStateful_readTransactionDB(protocollo,idTransazione);
		// Se la transazione e' null, attendo 1 secondo e attendo se deve essere terminata la sua scrittura
		if(tr==null){
			Utilities.sleep(500);
			tr = invokeGestoreTransazioniStateful_readTransactionDB(protocollo,idTransazione);
		}
		if(tr==null){
			Utilities.sleep(500);
			tr = invokeGestoreTransazioniStateful_readTransactionDB(protocollo,idTransazione);
		}
		if(tr!=null){
			invokeGestoreTransazioniStateful(s,tr);
		}else{
			// OUT OF MEMORY PROBLEM 
			repository.add(s);
		}
	}
	
	public static void addInResponseStatefulObject(String protocollo,String idTransazione, InResponseStatefulObject object) throws TransactionStatefulNotSupportedException {
		
		checkGestioneAbilitata();
		
		StatefulObject s = new StatefulObject(protocollo);
		s.setIdTransazione(idTransazione);
		s.setObject(object);
		s.setType(StatefulObjectType.IN_RESPONSE_STATEFUL_OBJECT);
		
		TransactionDB tr = invokeGestoreTransazioniStateful_readTransactionDB(protocollo,idTransazione);
		// Se la transazione e' null, attendo 1 secondo e attendo se deve essere terminata la sua scrittura
		if(tr==null){
			Utilities.sleep(500);
			tr = invokeGestoreTransazioniStateful_readTransactionDB(protocollo,idTransazione);
		}
		if(tr==null){
			Utilities.sleep(500);
			tr = invokeGestoreTransazioniStateful_readTransactionDB(protocollo,idTransazione);
		}
		if(tr!=null){
			invokeGestoreTransazioniStateful(s,tr);
		}else{
			// OUT OF MEMORY PROBLEM 
			repository.add(s);
		}
	}
	
	public static void addObject(StatefulObject s) throws TransactionStatefulNotSupportedException {

		checkGestioneAbilitata();
		
		repository.add(s);
	}
	
	// NOTA: se si realizza questa versione su database mantenere il comportamento a LISTA
	// Si inserisce in fondo, si preleva in cima, tramite la order by
	
	public static int size(){
		return repository.size();
	}
	
	public static StatefulObject getObject(){
		return repository.get(0); // oggetto in testa alla coda
	}
	
	public static StatefulObject removeObject(){
		return repository.remove(0); // oggetto in testa alla coda
	}
}