BasicProducer.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.protocol.basic;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Properties;

import javax.sql.DataSource;

import org.openspcoop2.core.commons.CoreException;
import org.openspcoop2.core.commons.IMonitoraggioRisorsa;
import org.openspcoop2.core.config.OpenspcoopAppender;
import org.openspcoop2.protocol.sdk.IProtocolFactory;
import org.openspcoop2.protocol.sdk.ProtocolException;
import org.openspcoop2.protocol.sdk.config.IProtocolConfiguration;
import org.openspcoop2.protocol.sdk.diagnostica.MsgDiagnosticoException;
import org.openspcoop2.utils.TipiDatabase;
import org.openspcoop2.utils.Utilities;
import org.openspcoop2.utils.resources.GestoreJNDI;


/**
 * Contiene l'implementazione di un appender personalizzato,
 * per la registrazione su database.
 *
 * @author Poli Andrea (apoli@link.it)
 * @author $Author$
 * @version $Rev$, $Date$
 */
public class BasicProducer extends BasicComponentFactory implements IMonitoraggioRisorsa {

	/** Properties */
	protected Properties appenderProperties;
		
	/** DataSource dove attingere connessioni */
	protected DataSource ds = null;
	protected String datasource = null;
   
	/** Connessione diretta via JDBC */
	protected String connectionViaJDBC_url = null;
	protected String connectionViaJDBC_driverJDBC = null;
	protected String connectionViaJDBC_username = null;
	protected String connectionViaJDBC_password = null;

    /** SingleConnection */
	protected boolean singleConnection = false;
	protected HashMap<BasicProducerType, Connection> singleConnection_connection_map = new HashMap<>(); 
	protected HashMap<BasicProducerType, String> singleConnection_source_map = new HashMap<>(); 
	
	/** TipoDatabase */
	protected String tipoDatabase = null; 

	/** OpenSPCoop Connection */
	protected boolean openspcoopConnection = false;
    
	/** Emit debug info */
	protected boolean debug = false;

	/** forceIndex */
	protected boolean forceIndex = false;
	public void setForceIndex(boolean forceIndex) {
		this.forceIndex = forceIndex;
	}
	
	/** IProtocolConfiguration */
	protected IProtocolConfiguration protocolConfiguration;
	
	/** ISAlive */
	protected boolean isAlive = true;
	
	private BasicProducerType producerType;
	
	public BasicProducer(IProtocolFactory<?> factory, BasicProducerType producerType) throws ProtocolException{
		super(factory);
		this.producerType = producerType;
	}
	
	

	protected synchronized void initConnection(DataSource dsA,String dataSourceS)throws Exception{
		Connection singleConnection_connection = this.singleConnection_connection_map.get(this.producerType);
    	if(singleConnection_connection==null){
    		try{
    			String singleConnection_source = dataSourceS;
    			singleConnection_connection = dsA.getConnection();
    			this.singleConnection_connection_map.put(this.producerType, singleConnection_connection);
    			this.singleConnection_source_map.put(this.producerType, singleConnection_source);
    		}catch(Exception e){
    			 throw new Exception("Inizializzazione single connection (via datasource) non riuscita",e);
    		}
    	}
    }
	protected synchronized void initConnection(String jdbcUrl,String jdbcDriver,String username, String password)throws Exception{
		Connection singleConnection_connection = this.singleConnection_connection_map.get(this.producerType);
    	if(singleConnection_connection==null){
    		try{
    			String singleConnection_source = "url:"+jdbcUrl+" driver:"+jdbcDriver+" username:"+username+" password:"+password;
    			if(username==null){
    				singleConnection_connection = DriverManager.getConnection(jdbcUrl);
    			}
    			else{
    				singleConnection_connection = DriverManager.getConnection(jdbcUrl,username,password);
    			}
    			this.singleConnection_connection_map.put(this.producerType, singleConnection_connection);
    			this.singleConnection_source_map.put(this.producerType, singleConnection_source);
    		}catch(Exception e){
    			 throw new Exception("Inizializzazione single connection (via jdbc connection) non riuscita",e);
    		}
    	}
    }
	protected Connection getConnectionViaJDBC() throws SQLException{
    	if(this.connectionViaJDBC_username==null){
			return DriverManager.getConnection(this.connectionViaJDBC_url);
		}
		else{
			return DriverManager.getConnection(this.connectionViaJDBC_url,
					this.connectionViaJDBC_username,this.connectionViaJDBC_password);
		}
    }
	
	protected BasicConnectionResult getConnection(Connection conOpenSPCoopPdD,String methodName) throws Exception{
		Connection con = null;
		BasicConnectionResult cr = new BasicConnectionResult();
		cr.setReleaseConnection(false);
		if(this.debug){
			this.log.info("@@ ["+methodName+"] SINGLE CONNECTION["+this.singleConnection+"] OPEN["+this.openspcoopConnection+"]");
		}
		if(this.singleConnection==false){
			if(this.openspcoopConnection && conOpenSPCoopPdD!=null){
				//System.out.println("["+methodName+"]@GET_CONNECTION@ USE CONNECTION OPENSPCOOP");
				if(this.debug){
					this.log.info("@@ ["+methodName+"] GET_CONNECTION, USE CONNECTION OPENSPCOOP");
				}
				con = conOpenSPCoopPdD;
			}else{
				if(this.ds!=null){
					try{
						con = this.ds.getConnection();
//						if(con == null)
//							throw new Exception("Connessione non fornita");
						cr.setReleaseConnection(true);
						//System.out.println("["+methodName+"]@GET_CONNECTION@ USE CONNECTION FROM DATASOURCE");
						if(this.debug){
							this.log.info("@@ ["+methodName+"] GET_CONNECTION, USE CONNECTION FROM DATASOURCE");
						}
					}catch(Exception e){
						throw new Exception("Errore durante il recupero di una connessione dal datasource ["+this.datasource+"]: "+e.getMessage());
					}
				}
				else{
					try{
						con = this.getConnectionViaJDBC();
						if(con == null)
							throw new Exception("Connessione non fornita");
						cr.setReleaseConnection(true);
						//System.out.println("["+methodName+"]@GET_CONNECTION@ USE CONNECTION VIA JDBC");
						if(this.debug){
							this.log.info("@@ ["+methodName+"] GET_CONNECTION, USE CONNECTION VIA JDBC");
						}
					}catch(Exception e){
						throw new Exception("Errore durante il recupero di una connessione via jdbc url["+this.connectionViaJDBC_url+"] driver["+
								this.connectionViaJDBC_driverJDBC+"] username["+this.connectionViaJDBC_username+"] password["+this.connectionViaJDBC_password
								+"]: "+e.getMessage());
					}
				}
			}
		}else{
			con = this.singleConnection_connection_map.get(this.producerType);
			if(con == null){
				throw new Exception("Connessione (singleConnection enabled) non fornita dalla sorgente ["+this.singleConnection_source_map.get(this.producerType)+"]");
			}
			//System.out.println("["+methodName+"]@GET_CONNECTION@ SINGLE CONNECTION");
			if(this.debug){
				this.log.info("@@ ["+methodName+"] GET_CONNECTION, SINGLE CONNECTION");
			}
		}
		cr.setConnection(con);
		return cr;
	}
	protected void releaseConnection(BasicConnectionResult connectionResult,String methodName) throws SQLException{
		if(this.debug){
			this.log.info("@@ ["+methodName+"] RELEASE_CONNECTION ["+connectionResult.isReleaseConnection()+"]?");
		}
		if(connectionResult.isReleaseConnection()){
			//System.out.println("["+methodName+"]@RELEASE_CONNECTION@");
			if(this.debug){
				this.log.info("@@ ["+methodName+"] RELEASE_CONNECTION effettuato");
			}
			connectionResult.getConnection().close();
		}
	}
	

	
    

    
    /**
	 * Inizializza l'engine di un appender per la registrazione
	 * 
	 * @param appenderProperties Proprieta' dell'appender
	 * @throws MsgDiagnosticoException
	 */
	public void initializeAppender(OpenspcoopAppender appenderProperties, boolean tipoDatabaseRequired) throws ProtocolException{
		
		try{
		
			// Lettura modalita' di gestione
			this.appenderProperties = new Properties();
			if(appenderProperties.sizePropertyList()>0){
				
				for(int i=0; i<appenderProperties.sizePropertyList(); i++){
					this.appenderProperties.put(appenderProperties.getProperty(i).getNome(),
							appenderProperties.getProperty(i).getValore());
				}
				
				this.datasource = this.appenderProperties.getProperty("datasource");
				if(this.datasource==null){
					this.connectionViaJDBC_url = this.appenderProperties.getProperty("connectionUrl");
					if(this.connectionViaJDBC_url==null){
						String tmp = this.appenderProperties.getProperty("checkProperties");
						if(tmp == null || Boolean.valueOf(tmp.trim())) {
							throw new Exception("Proprietà 'datasource' e 'connectionUrl' non definite (almeno una delle due è obbligatoria)");
						}
						else {
							this.isAlive = false;
						}
					}
				}
				
				this.tipoDatabase=this.appenderProperties.getProperty("tipoDatabase");
				// non obbligatorio in msg diagnostico per retrocompatibilità
				if(this.tipoDatabase==null && tipoDatabaseRequired){
					throw new Exception("Proprieta' 'tipoDatabase' non definita");
				}
				if(this.tipoDatabase!=null){
					if(!TipiDatabase.isAMember(this.tipoDatabase)){
						throw new Exception("Proprieta' 'tipoDatabase' presenta un tipo ["+this.tipoDatabase+"] non supportato");
					}
				}
				
				String singleConnectionString = this.appenderProperties.getProperty("singleConnection");
				if(singleConnectionString!=null){
					singleConnectionString = singleConnectionString.trim();
					if("true".equals(singleConnectionString)){
						this.singleConnection = true;
					}
				}
				
				String openspcoopConnectionString = this.appenderProperties.getProperty("usePdDConnection");
				if(openspcoopConnectionString!=null){
					openspcoopConnectionString = openspcoopConnectionString.trim();
					if("true".equals(openspcoopConnectionString)){
						this.openspcoopConnection = true;
					}
				}
				
			}else{
				throw new Exception("Proprietà 'datasource' e 'connectionUrl' non definite (almeno una delle due è obbligatoria)");
			}
			
			// Datasource
			if(this.datasource!=null){
				
				java.util.Properties ctx= new java.util.Properties();
				ctx = Utilities.readProperties("context-", this.appenderProperties);
			
				GestoreJNDI jndi = new GestoreJNDI(ctx);
				if(this.singleConnection){
					if(this.singleConnection_connection_map.get(this.producerType)==null){
						DataSource ds = (DataSource) jndi.lookup(this.datasource);
						initConnection(ds,this.datasource);
					}
				}else{
					this.ds = (DataSource) jndi.lookup(this.datasource);
				}
				
			}
			
			
			// connectionViaJDBC
			if(this.connectionViaJDBC_url!=null){
				
				this.connectionViaJDBC_driverJDBC = this.appenderProperties.getProperty("connectionDriver");
				if(this.connectionViaJDBC_driverJDBC==null){
					throw new Exception("Proprietà 'connectionDriver' non definita (obbligatoria nella modalita' 'connection via jdbc')");
				}
				
				this.connectionViaJDBC_username = this.appenderProperties.getProperty("connectionUsername");
				if(this.connectionViaJDBC_username!=null){
					this.connectionViaJDBC_password = this.appenderProperties.getProperty("connectionPassword");
					if(this.connectionViaJDBC_password==null){
						throw new Exception("Proprietà 'connectionPassword' non definita (obbligatoria nella modalita' 'connection via jdbc' se viene definita la proprieta' 'connectionUsername')");
					}
				}
				
				Class.forName(this.connectionViaJDBC_driverJDBC);
				
				if(this.singleConnection){
					if(this.singleConnection_connection_map.get(this.producerType)==null){
						initConnection(this.connectionViaJDBC_url,this.connectionViaJDBC_driverJDBC,this.connectionViaJDBC_username,this.connectionViaJDBC_password);
					}
				}
			}
			
			// debug info
			String debug = this.appenderProperties.getProperty("debug");
			if(debug!=null){
				debug = debug.trim();
				if("true".equals(debug)){
					this.debug = true;
				}
			}
			
			
			// Protocol Configuration
			this.protocolConfiguration = this.protocolFactory.createProtocolConfiguration();
			
		}catch(Exception e){
			throw new ProtocolException("Errore durante l'inizializzazione dell'appender: "+e.getMessage(),e);
		}
	}

	protected String getSQLStringValue(String value){
		if(value!=null && ("".equals(value)==false)){
			return value;
		}
		else{
			return null;
		}
	}
	
	
	
	public String getTipoDatabase() {
		return this.tipoDatabase;
	}

	public void setTipoDatabase(String tipoDatabase) {
		this.tipoDatabase = tipoDatabase;
	}
	

	/**
	 * Metodo che verica la connessione ad una risorsa.
	 * Se la connessione non e' presente, viene lanciata una eccezione che contiene il motivo della mancata connessione
	 * 
	 * @throws DriverException eccezione che contiene il motivo della mancata connessione
	 */
	@Override
	public void isAlive() throws CoreException{
		if(this.isAlive==false) {
			return;
		}
		// Verifico la connessione
		Connection con = null;
		Statement stmtTest = null;
		BasicConnectionResult cr = null;
		try {
			// Connessione al DB
			cr = this.getConnection(null,"isAlive");
			con = cr.getConnection();
			
			// test:
			stmtTest = con.createStatement();
			stmtTest.execute("SELECT * from db_info");
		} catch (Exception e) {
			throw new CoreException("Connessione al database '"+this.producerType+"' non disponibile: "+e.getMessage(),e);

		}finally{
			try{
				if(stmtTest!=null)
					stmtTest.close();
			}catch(Exception e){
				// close
			}
			try{
				this.releaseConnection(cr, "isAlive");
			}catch(Exception e){
				// close
			}
		}
	}

}