OpenSPCoopState.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.state;

import java.sql.Connection;
import java.util.List;

import org.openspcoop2.core.id.IDSoggetto;
import org.openspcoop2.pdd.config.DBConsegneMessageBoxManager;
import org.openspcoop2.pdd.config.DBConsegnePreseInCaricoManager;
import org.openspcoop2.pdd.config.DBManager;
import org.openspcoop2.pdd.config.Resource;
import org.openspcoop2.pdd.logger.OpenSPCoop2Logger;
import org.openspcoop2.pdd.mdb.GenericMessage;
import org.openspcoop2.protocol.sdk.state.IState;
import org.openspcoop2.protocol.sdk.state.StateMessage;
import org.openspcoop2.protocol.sdk.state.StatelessMessage;
import org.openspcoop2.utils.UtilsException;
import org.slf4j.Logger;

/**
 * Oggetto che rappresenta lo stato di una richiesta/risposta all'interno della PdD
 *
 * @author Poli Andrea (apoli@link.it)
 * @author Fabio Tronci (tronci@link.it)
 * @author $Author$
 * @version $Rev$, $Date$
 */
public abstract class OpenSPCoopState implements IOpenSPCoopState {
	
	/* ---------- Logger ---------*/
	protected Logger logger = null;
	
	/* ---------- Connessione al database ---------------- */
	protected OpenSPCoopStateDBManager dbManager = null;
	/** DBManager */
	protected DBManager dbManager_runtime= null;
	/** DBManager */
	protected DBConsegnePreseInCaricoManager dbManager_consegnePreseInCarico = null;
	/** DBManager */
	protected DBConsegneMessageBoxManager dbManager_consegneMessageBox = null;
	/** Resource */
	protected Resource resourceDB = null;
	/** Connessione al database */
	protected Connection connectionDB = null;
	/** Connessione inizializzata */
	protected boolean connessioneInizializzata = false;
	
	/* ----------- Altre informazioni ------------*/
	/** Identita PdD */
	protected IDSoggetto identitaPdD = null;
	/** Identita Modulo */
	protected String idModulo = null;
	/** GenericMessage LIB */
	protected GenericMessage messageLib;
	/** Identificativo della sessione */
	protected String IDMessaggioSessione;
	
	/* ---------- Stato ------------ */
	protected StateMessage richiestaStato = null;
	protected StateMessage rispostaStato = null;
	
	/* ---------- Indicazione se lavorare come stateful (utilizzare la connessione) o come stateless (operazioni NOP) -------------- */
	protected boolean useConnection;
	
	
	
	
	
	
	/* ----------- Convertitori ------------*/
	public static OpenSPCoopStateless toStateless(OpenSPCoopStateful stateful,boolean useConnection){
		OpenSPCoopStateless stateless = new OpenSPCoopStateless();
		stateless.connectionDB = stateful.connectionDB;
		stateless.dbManager = stateful.dbManager;
		stateless.dbManager_runtime = stateful.dbManager_runtime;
		stateless.dbManager_consegnePreseInCarico = stateful.dbManager_consegnePreseInCarico;
		stateless.dbManager_consegneMessageBox = stateful.dbManager_consegneMessageBox;
		stateless.IDMessaggioSessione = stateful.IDMessaggioSessione;
		stateless.identitaPdD = stateful.identitaPdD;
		stateless.idModulo = stateful.idModulo;
		stateless.logger = stateful.logger;
		stateless.messageLib = stateful.messageLib;
		stateless.resourceDB = stateful.resourceDB;
		stateless.richiestaStato = stateful.richiestaStato;
		stateless.rispostaStato = stateful.rispostaStato;
		stateless.useConnection = useConnection;
		stateless.connessioneInizializzata = stateful.connessioneInizializzata;
		
		StatelessMessage tempRichiesta = new StatelessMessage(stateful.getConnectionDB(),stateful.logger);
		if(stateful.getStatoRichiesta()!=null) {
			tempRichiesta.setPreparedStatement(((StateMessage) stateful.getStatoRichiesta()).getPreparedStatement());
		}
		stateless.setStatoRichiesta(new StatelessMessage(tempRichiesta));
		
		StatelessMessage tempRisposta = new StatelessMessage(stateful.getConnectionDB(),stateful.logger);
		if(stateful.getStatoRisposta()!=null) {
			tempRisposta.setPreparedStatement(((StateMessage) stateful.getStatoRisposta()).getPreparedStatement());
		}
		stateless.setStatoRisposta(new StatelessMessage(tempRisposta));
		
		return stateless;
	}
	
	
	


	

	/* ----------- Init resource ------------*/

	public abstract void updateStatoRichiesta() throws UtilsException ;
	public abstract void updateStatoRisposta() throws UtilsException ;
		
	@Override
	public void initResource(IDSoggetto identitaPdD,String idModulo,String idTransazione)throws OpenSPCoopStateException{
		initResource(identitaPdD,idModulo,idTransazione, OpenSPCoopStateDBManager.runtime);
	}
	@Override
	public void initResource(IDSoggetto identitaPdD,String idModulo,String idTransazione, OpenSPCoopStateDBManager dbManager)throws OpenSPCoopStateException{
		
		this.dbManager = dbManager; // per update
		
		// Check parametri
		if(identitaPdD==null){
			throw new OpenSPCoopStateException("IdentitaPdD non presente");
		}
		this.identitaPdD = identitaPdD;
		if(idModulo==null){
			throw new OpenSPCoopStateException("IDModulo non presente");
		}
		this.idModulo = idModulo;
		
		// Logger
		this.logger = OpenSPCoop2Logger.getLoggerOpenSPCoopCore();
		
		if(this.useConnection){
			
			// Get Connessione
			if(dbManager!=null) {
				switch (dbManager) {
				case runtime:
					this.dbManager_runtime = DBManager.getInstance();
					break;
				case smistatoreMessaggiPresiInCarico:
					this.dbManager_consegnePreseInCarico = DBConsegnePreseInCaricoManager.getInstanceSmistatore();
					break;
				case consegnePreseInCarico:
					this.dbManager_consegnePreseInCarico = DBConsegnePreseInCaricoManager.getInstanceRuntime();
					break;
				case messageBox:
					this.dbManager_consegneMessageBox = DBConsegneMessageBoxManager.getInstanceRuntime();
					break;
				}
			}
			else {
				this.dbManager_runtime = DBManager.getInstance();
			}
			try{
				if(this.dbManager_runtime!=null) {
					this.resourceDB = this.dbManager_runtime.getResource(identitaPdD,this.idModulo,idTransazione);
				}
				else if(this.dbManager_consegnePreseInCarico!=null) {
					this.resourceDB = this.dbManager_consegnePreseInCarico.getResource(identitaPdD,this.idModulo,idTransazione);
				}
				else {
					this.resourceDB = this.dbManager_consegneMessageBox.getResource(identitaPdD,this.idModulo,idTransazione);
				}
			}catch(Exception e){
				throw new OpenSPCoopStateException("Riscontrato errore durante la richiesta di una connessione al DB",e);
			}
			if(this.resourceDB==null){
				throw new OpenSPCoopStateException("Riscontrato errore durante la richiesta di una connessione al DB (Risorsa is null).");
			}
			if(this.resourceDB.getResource() == null){
					throw new OpenSPCoopStateException("Riscontrato errore durante la richiesta di una connessione al DB (Connessione is null)."); 
			}
			this.connectionDB = (Connection) this.resourceDB.getResource();
			
			// Stato
			try{
				this.updateStatoRichiesta();
				this.updateStatoRisposta();
			}catch(Exception e){
				this.logger.error("Update stato richiesta/risposta non riuscito",e);
				if(this.dbManager_runtime!=null) {
					this.dbManager_runtime.releaseResource(this.identitaPdD,this.idModulo,this.resourceDB);
				}
				else if(this.dbManager_consegnePreseInCarico!=null) {
					this.dbManager_consegnePreseInCarico.releaseResource(this.identitaPdD,this.idModulo,this.resourceDB);
				}
				else {
					this.dbManager_consegneMessageBox.releaseResource(this.identitaPdD,this.idModulo,this.resourceDB);
				}
				throw new OpenSPCoopStateException("Update stato richiesta/risposta non riuscito",e);
			}
			
			this.connessioneInizializzata = true;
		}
	} 
	
	@Override
	public void updateResource(String idTransazione) throws OpenSPCoopStateException{
		if( this.useConnection ){
			try{
				if(this.dbManager!=null) {
					switch (this.dbManager) {
					case runtime:
						if(this.dbManager_runtime==null) {
							this.dbManager_runtime = DBManager.getInstance();
						}
						break;
					case smistatoreMessaggiPresiInCarico:
						if(this.dbManager_consegnePreseInCarico==null) {
							this.dbManager_consegnePreseInCarico = DBConsegnePreseInCaricoManager.getInstanceSmistatore();
						}
						break;
					case consegnePreseInCarico:
						if(this.dbManager_consegnePreseInCarico==null) {
							this.dbManager_consegnePreseInCarico = DBConsegnePreseInCaricoManager.getInstanceRuntime();
						}
						break;
					case messageBox:
						if(this.dbManager_consegneMessageBox==null) {
							this.dbManager_consegneMessageBox = DBConsegneMessageBoxManager.getInstanceRuntime();
						}
						break;
					}
				}
				else {
					if(this.dbManager_runtime==null) {
						this.dbManager_runtime = DBManager.getInstance();
					}
				}
				
				if(this.dbManager_runtime!=null) {
					this.resourceDB = this.dbManager_runtime.getResource(this.identitaPdD,this.idModulo,idTransazione);
				}
				else if(this.dbManager_consegnePreseInCarico!=null) {
					this.resourceDB = this.dbManager_consegnePreseInCarico.getResource(this.identitaPdD,this.idModulo,idTransazione);
				}
				else {
					this.resourceDB = this.dbManager_consegneMessageBox.getResource(this.identitaPdD,this.idModulo,idTransazione);
				}
			}catch(Exception e){
				throw new OpenSPCoopStateException("Riscontrato errore durante la richiesta di una connessione al DB",e);
			}
			if(this.resourceDB==null){
				throw new OpenSPCoopStateException("Riscontrato errore durante la richiesta di una connessione al DB (Risorsa is null).");
			}
			if(this.resourceDB.getResource() == null){
				throw new OpenSPCoopStateException("Riscontrato errore durante la richiesta di una connessione al DB (Connessione is null)."); 
			}
			this.connectionDB = (Connection) this.resourceDB.getResource();
			
			this.richiestaStato.updateConnection(this.connectionDB);
			this.rispostaStato.updateConnection(this.connectionDB);
			
			this.connessioneInizializzata = true;
		}
	}
	
	@Override
	public void releaseResource() {
		if(this.useConnection && this.connessioneInizializzata){
			try{
				if(this.richiestaStato!=null && this.richiestaStato.getPreparedStatement()!=null){
					if(this.richiestaStato.getPreparedStatement().size()>0){
						List<String> l = this.richiestaStato.getPreparedStatement().keys();
						if(l!=null && !l.isEmpty()) {
							for (String key : l) {
								this.logger.error("PREPARED STATEMENT NON CHIUSA (RICHIESTA): "+key);
							}
						}
						this.richiestaStato.closePreparedStatement();
					}
				}
			}catch (Exception e) {	
				this.logger.error("Chiusure prepared statement della richiesta non riuscita",e);
			}
			try{
				if(this.rispostaStato!=null && this.rispostaStato.getPreparedStatement()!=null){
					if(this.rispostaStato.getPreparedStatement().size()>0){
						List<String> l = this.rispostaStato.getPreparedStatement().keys();
						if(l!=null && !l.isEmpty()) {
							for (String key : l) {
								this.logger.error("PREPARED STATEMENT NON CHIUSA (RISPOSTA): "+key);
							}
						}
						this.rispostaStato.closePreparedStatement();
					}
				}
			}catch (Exception e) {	
				this.logger.error("Chiusure prepared statement della risposta non riuscita",e);
			}
			try{
				if(this.resourceDB!=null){
					if(this.dbManager_runtime!=null) {
						this.dbManager_runtime.releaseResource(this.identitaPdD,this.idModulo,this.resourceDB);
					}
					else if(this.dbManager_consegnePreseInCarico!=null) {
						this.dbManager_consegnePreseInCarico.releaseResource(this.identitaPdD,this.idModulo,this.resourceDB);
					}
					else {
						this.dbManager_consegneMessageBox.releaseResource(this.identitaPdD,this.idModulo,this.resourceDB);
					}
				}
				if(this.richiestaStato!=null) {
					this.richiestaStato.updateConnection(null);
				}
				if(this.rispostaStato!=null) {
					this.rispostaStato.updateConnection(null);
				}
			}catch (Exception e) {	
				this.logger.error("Rilasciate risorse con errore: "+e.getMessage(),e);
				OpenSPCoop2Logger.getLoggerOpenSPCoopConsole().error("Rilasciate risorse con errore: "+e.getMessage());
			}
			this.connessioneInizializzata = false;
		}
	}
	
	@Override
	public boolean resourceReleased(){
		return !this.connessioneInizializzata;
	}
	
	public void forceFinallyReleaseResource() {
		if(this.connessioneInizializzata){
			this.useConnection = true; // force
			//System.out.println("Force close ...");
			this.releaseResource();
		}
	}
	
	
	
	
	
	
	/* ----------- Commit / Close ------------*/
	
	@Override
	public void commit() throws OpenSPCoopStateException{
		if(this.useConnection){
			if(   (this.richiestaStato!=null && this.richiestaStato.getPreparedStatement()!=null && this.richiestaStato.getPreparedStatement().size()>0)  ||
				  (this.rispostaStato!=null && this.rispostaStato.getPreparedStatement()!=null && this.rispostaStato.getPreparedStatement().size()>0)
			){
				try{
					this.connectionDB.setAutoCommit(false);
					
//					System.out.println("PREPARED STATEMENT (RICHIESTA)");
//					Enumeration<String> en = this.richiestaStato.getPreparedStatement().keys();
//					while(en.hasMoreElements()){
//						String key = en.nextElement();
//						System.out.println("PREPARED STATEMENT (RICHIESTA): "+key);
//					}			
					if(this.richiestaStato!=null) {
						this.richiestaStato.executePreparedStatement();
					}
					
//					System.out.println("PREPARED STATEMENT (RISPOSTA)");
//					en = this.rispostaStato.getPreparedStatement().keys();
//					while(en.hasMoreElements()){
//						String key = en.nextElement();
//						System.out.println("PREPARED STATEMENT (RISPOSTA): "+key);
//					}	
					if(this.rispostaStato!=null) {
						this.rispostaStato.executePreparedStatement();
					}
					
					this.connectionDB.commit();
					this.connectionDB.setAutoCommit(true);
					
				}catch (Exception e) {
					// Chiudo eventuali prepared statement non chiuse
					try{
						if(this.richiestaStato!=null) {
							this.richiestaStato.closePreparedStatement();
						}
					}catch(Exception eClose){}
					try{
						if(this.rispostaStato!=null) {
							this.rispostaStato.closePreparedStatement();
						}
					}catch(Exception eClose){}
					//  Rollback quanto effettuato (se l'errore e' avvenuto sul commit, o prima nell'execute delle PreparedStatement)
					try{
						this.connectionDB.rollback();
					}catch(Exception er){}
					// Ripristino connessione
					try{
						this.connectionDB.setAutoCommit(true);
					}catch(Exception er){}
					// Rilancio l'eccezione: sara' catturata dal catch seguente, che chiudera' le preparedStatement, 
					// chiude la connessione al DB ed effettua il Rollback dell'MDB(a meno del profilo sincrono).
					throw new OpenSPCoopStateException(e.getMessage(),e);
				}
			}
		}
	}
	
	
	
	
	
	
	
	
	/* ----------- GET / SET ------------*/
	@Override
	public GenericMessage getMessageLib() {
		return this.messageLib;
	}

	public void setMessageLib(GenericMessage messageLib) {
		this.messageLib = messageLib;
	}

	@Override
	public String getIDMessaggioSessione() {
		return this.IDMessaggioSessione;
	}

	public void setIDMessaggioSessione(String idSessione) {
		this.IDMessaggioSessione = idSessione;
	}
	
	@Override
	public IState getStatoRichiesta(){
		return this.richiestaStato;
	}
	@Override
	public void setStatoRichiesta(IState statoRichiesta){
		this.richiestaStato = (StateMessage) statoRichiesta;
	}
	@Override
	public IState getStatoRisposta(){
		return this.rispostaStato;
	}
	@Override
	public void setStatoRisposta(IState statoRisposta){
		this.rispostaStato = (StateMessage) statoRisposta;
	}
	public Connection getConnectionDB() {
		return this.connectionDB;
	}
	public void setConnectionDB(Connection connectionDB) {
		this.connectionDB = connectionDB;
	}
	
	public boolean isUseConnection() {
		return this.useConnection;
	}

	public void setUseConnection(boolean useConnection) {
		this.useConnection = useConnection;
	}

}