ConnettoreStresstest.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.connettori;

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

import org.openspcoop2.core.config.ResponseCachingConfigurazione;
import org.openspcoop2.core.constants.Costanti;
import org.openspcoop2.core.constants.CostantiConnettori;
import org.openspcoop2.core.constants.CostantiLabel;
import org.openspcoop2.core.id.IDSoggetto;
import org.openspcoop2.core.registry.constants.CostantiRegistroServizi;
import org.openspcoop2.message.OpenSPCoop2MessageFactory;
import org.openspcoop2.message.OpenSPCoop2MessageParseResult;
import org.openspcoop2.message.constants.MessageRole;
import org.openspcoop2.pdd.config.DBManager;
import org.openspcoop2.pdd.config.OpenSPCoop2Properties;
import org.openspcoop2.pdd.config.Resource;
import org.openspcoop2.pdd.mdb.ConsegnaContenutiApplicativi;
import org.openspcoop2.protocol.engine.ProtocolFactoryManager;
import org.openspcoop2.protocol.engine.builder.Imbustamento;
import org.openspcoop2.protocol.engine.driver.ProfiloDiCollaborazione;
import org.openspcoop2.protocol.engine.driver.RepositoryBuste;
import org.openspcoop2.protocol.sdk.Busta;
import org.openspcoop2.protocol.sdk.IProtocolFactory;
import org.openspcoop2.protocol.sdk.Integrazione;
import org.openspcoop2.protocol.sdk.config.ITraduttore;
import org.openspcoop2.protocol.sdk.constants.RuoloMessaggio;
import org.openspcoop2.protocol.sdk.state.StatefulMessage;
import org.openspcoop2.utils.Utilities;
import org.openspcoop2.utils.date.DateManager;
import org.openspcoop2.utils.random.RandomUtilities;





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

    @Override
	public String getProtocollo() {
    	return "HTTP";
    }
	
	public static final String ENDPOINT_TYPE = "stresstest";
	
	public static final String LOCATION = "openspcoop2://stresstest";
	

	/* ********  F I E L D S  P R I V A T I  ******** */

	private static final String HEADER_APPLICATIVO = "<thdr:headerApplicativo xmlns:thdr=\"http://example.org/test\" tipo=\"TEST\" soapenv:actor=\"http://example.org/test/actor\">\n"+
													 "<identificativoDominio>ITALIA</identificativoDominio>\n"+
													 "<thdr:identificatore>RISP@SERIAL@</thdr:identificatore>\n"+
													 "</thdr:headerApplicativo>";
	
	private static final String SOAP_ENVELOPE_RISPOSTA = 
		"<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " +
		"	xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><soapenv:Header>@HDR@</soapenv:Header>";
	private static final String SOAP_ENVELOPE_RISPOSTA_END = 
		"<soapenv:Body><prova>test</prova></soapenv:Body></soapenv:Envelope>";


    private Resource resource = null;
    private DBManager dbManager = null;
   
    public ConnettoreStresstest(){
    	super();
    	this.dbManager = DBManager.getInstance();
    }
    
	
	/* ********  METODI  ******** */

    @Override
	protected boolean initializePreSend(ResponseCachingConfigurazione responseCachingConfig, ConnettoreMsg request) {
		
    	if(this.initialize(request, false, responseCachingConfig)==false){
			return false;
		}
		
		return true;
		
	}
	
	@Override
	protected boolean send(ConnettoreMsg request) {	
		
		// - Header Applicativo nella risposta
		boolean headerApplicativoRisposta = false;
		if(this.properties.get(CostantiConnettori.CONNETTORE_STRESS_TEST_HEADER_APPLICATIVO)!=null){
			if("true".equalsIgnoreCase(this.properties.get(CostantiConnettori.CONNETTORE_STRESS_TEST_HEADER_APPLICATIVO).trim()))
				headerApplicativoRisposta = true;
		}
			
		this.codice = 200;
				
		try{
			
			// SIMULAZIONE WRITE_TO
			
			org.apache.commons.io.output.NullOutputStream nullOutputStream = org.apache.commons.io.output.NullOutputStream.INSTANCE;
			this.requestMsg.writeTo(nullOutputStream,true);
			nullOutputStream.flush();
			nullOutputStream.close();
				
			//this.response = request.getRequestMessage();
			//java.io.FileOutputStream fout = new java.io.FileOutputStream("/dev/null");
			//request.getRequestMessage().writeTo(fout,true);
			//fout.flush();
			//fout.close();
			
			this.dataRichiestaInoltrata = DateManager.getDate();
			
			
			
			
			/* ------------  PostOutRequestHandler ------------- */
			this.postOutRequest();
			
			
			
			
			
			
			
			// SLEEP
			// Connettore custom, impostare nei parametri i tempi di sleep
			if(request.getConnectorProperties()!=null){
//				java.util.Enumeration<String> enValues = request.getConnectorProperties().keys();
//				while (enValues.hasMoreElements()) {
//					String key = (String) enValues.nextElement();
//					System.out.println("KEY["+key+"]=["+request.getConnectorProperties().get(key)+"]");
//				}
				
				Object max = request.getConnectorProperties().get(CostantiConnettori.CONNETTORE_STRESS_TEST_SLEEP_MAX);
				Object min = request.getConnectorProperties().get(CostantiConnettori.CONNETTORE_STRESS_TEST_SLEEP_MIN);
				if(max!=null){
					int maxSleep = Integer.parseInt((String)max);
					int minSleep = 0;
					if(min!=null){
						minSleep = Integer.parseInt((String)min);
					}
					int sleep = minSleep + RandomUtilities.getRandom().nextInt(maxSleep-minSleep);
					if(sleep>1000){
						int count = sleep/1000;
						int resto = sleep%1000;
						this.logger.info("sleep "+sleep+"ms ...",false);
						for (int i = 0; i < count; i++) {
							Utilities.sleep(1000);
						}
						Utilities.sleep(resto);
						this.logger.info("sleep "+sleep+"ms terminated", false);
					}else{
						this.logger.info("sleep "+sleep+"ms ...", false);
						Utilities.sleep(sleep);
						this.logger.info("sleep "+sleep+"ms terminated", false);
					}
				}
				else{
					Object sleepConstant = request.getConnectorProperties().get(CostantiConnettori.CONNETTORE_STRESS_TEST_SLEEP);
					if(sleepConstant!=null){
						int millisecond = Integer.parseInt((String)sleepConstant);
						if(millisecond>1000){
							int count = millisecond/1000;
							int resto = millisecond%1000;
							this.logger.info("sleep "+millisecond+"ms ...", false);
							for (int i = 0; i < count; i++) {
								Utilities.sleep(1000);
							}
							Utilities.sleep(resto);
							this.logger.info("sleep "+millisecond+"ms terminated", false);
						}else{
							this.logger.info("sleep "+millisecond+"ms ...", false);
							Utilities.sleep(millisecond);
							this.logger.info("sleep "+millisecond+"ms terminated", false);
						}
					}
				}
			}
			
			
			
			
			
			
			/* ------------  PreInResponseHandler ------------- */
			this.preInResponse();
			
			
			
			// Lettura risposta parametri NotifierInputStream per la risposta
			org.openspcoop2.utils.io.notifier.NotifierInputStreamParams notifierInputStreamParams = null;
			if(this.preInResponseContext!=null){
				notifierInputStreamParams = this.preInResponseContext.getNotifierInputStreamParams();
			}
			
			
    		if(org.openspcoop2.protocol.sdk.constants.ProfiloDiCollaborazione.ONEWAY.equals(request.getBusta().getProfiloDiCollaborazione())){
    			// se non devo generare un riscontro, non e' prevista una risposta
    			if ( ! (request.getBusta().isConfermaRicezione() &&
    					this.openspcoopProperties.isGestioneRiscontri(CostantiRegistroServizi.IMPLEMENTAZIONE_STANDARD))){
    				return true; // non devo generare alcuna risposta
    			}
    		}
			String protocolHeader = this.buildProtocolHeader(request);
			if(headerApplicativoRisposta){
				String hdrApplicativo = HEADER_APPLICATIVO.replace("@SERIAL@", DateManager.getTimeMillis()+"");
				protocolHeader = hdrApplicativo + "\n" + protocolHeader;
			}
			String messaggio = SOAP_ENVELOPE_RISPOSTA.replace("@HDR@", protocolHeader) + SOAP_ENVELOPE_RISPOSTA_END;
			byte [] messaggioArray = messaggio.getBytes();
			
			ByteArrayInputStream bin = new ByteArrayInputStream(messaggioArray);
			OpenSPCoop2MessageFactory messageFactory = org.openspcoop2.pdd.core.Utilities.getOpenspcoop2MessageFactory(this.logger.getLogger(),this.requestMsg, this.requestInfo, MessageRole.RESPONSE);
			OpenSPCoop2MessageParseResult pr = messageFactory.createMessage(this.requestMsg.getMessageType(),MessageRole.RESPONSE,
					this.requestMsg.getContentType(),
					bin,notifierInputStreamParams,
					this.openspcoopProperties.getAttachmentsProcessingMode());
			// Non funziona con gli attachments: this.responseMsg = OpenSPCoop2MessageFactory.getMessageFactory().createMessage(request.getRequestMessage().getVersioneSoap(),(bout.toByteArray()),notifierInputStreamParams);
			if(pr.getParseException()!=null){
				this.getPddContext().addObject(org.openspcoop2.core.constants.Costanti.CONTENUTO_RISPOSTA_NON_RICONOSCIUTO_PARSE_EXCEPTION, pr.getParseException());
			}
			this.responseMsg = pr.getMessage_throwParseException();
						
			// content length
			if(this.responseMsg!=null){
				this.contentLength = messaggioArray.length;
			}
			
		}catch(Exception e){
			this.eccezioneProcessamento = e;
			this.logger.error("Riscontrato errore durante l'echo del msg soap",e);
			this.errore = "Riscontrato errore durante l'echo del msg soap:" +this.readExceptionMessageFromException(e);
			return false;
		}finally{
			// release database
			this.dbManager.releaseResource(this.openspcoopProperties.getIdentitaPortaDefault(this.getProtocolFactory().getProtocol(), this.requestInfo),"ConnettoreStresstest", this.resource);
		}
		
		return true;
	}
    
    /**
     * Ritorna l'informazione su dove il connettore sta spedendo il messaggio
     * 
     * @return location di inoltro del messaggio
     */
    @Override
	public String getLocation() throws ConnettoreException {
    	return ConnettoreUtils.buildLocationWithURLBasedParameter(this.logger!=null ? this.logger.getLogger() : null, this.requestMsg, ConnettoreStresstest.ENDPOINT_TYPE, this.propertiesUrlBased, LOCATION,
				this.getProtocolFactory(), this.idModulo);
    }
 
    
    
    private String buildProtocolHeader(ConnettoreMsg request) throws Exception{
		Busta bustaRichiesta = request.getBusta();
    	if( CostantiLabel.SPCOOP_PROTOCOL_NAME.equals(bustaRichiesta.getProtocollo())){
    		return buildSPCoopProtocolHeader(request);
    	}
    	else{
    		return "";
    	}
    }
    

    
    private String buildSPCoopProtocolHeader(ConnettoreMsg request) throws Exception{	
    	
		Busta bustaRichiesta = request.getBusta();
		
		StatefulMessage state = new StatefulMessage(null, this.logger.getLogger());
    	
		Object id = this.getPddContext().getObject(Costanti.ID_TRANSAZIONE);
		String idTransazione = null;
		if(id!=null){
			idTransazione = (String) id;
		}
    			
		StringBuilder protocolHeader = new StringBuilder();
		
    	if(bustaRichiesta!=null && (bustaRichiesta.sizeListaEccezioni()==0) && !ConsegnaContenutiApplicativi.ID_MODULO.equals(request.getIdModulo())){
			// Creo busta di risposta solo se la busta di richiesta non conteneva una busta SPCoop Errore e se il profilo lo richiede.
    		    		
			String idRiscontro = null;	
			
			IProtocolFactory<?> protocolFactory = ProtocolFactoryManager.getInstance().getProtocolFactoryByName(bustaRichiesta.getProtocollo());
			ITraduttore traduttore = protocolFactory.createTraduttore();
			
			protocolHeader.append("<eGov_IT:Intestazione SOAP_ENV:actor=\"http://www.cnipa.it/eGov_it/portadominio\" SOAP_ENV:mustUnderstand=\"1\" " +
					"xmlns:SOAP_ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:eGov_IT=\"http://www.cnipa.it/schemas/2003/eGovIT/Busta1_0/\"><eGov_IT:IntestazioneMessaggio>");
			
			// mittente
			protocolHeader.append("<eGov_IT:Mittente><eGov_IT:IdentificativoParte tipo=\""+traduttore.toProtocolOrganizationType(bustaRichiesta.getTipoDestinatario())+"\">"+bustaRichiesta.getDestinatario()+"</eGov_IT:IdentificativoParte></eGov_IT:Mittente>");
		
			// destinatario
			protocolHeader.append("<eGov_IT:Destinatario><eGov_IT:IdentificativoParte tipo=\""+traduttore.toProtocolOrganizationType(bustaRichiesta.getTipoMittente())+"\">"+bustaRichiesta.getMittente()+"</eGov_IT:IdentificativoParte></eGov_IT:Destinatario>");
		
			// ProfiloCollaborazione
			if(bustaRichiesta.getProfiloDiCollaborazione()!=null){

				
				if(org.openspcoop2.protocol.sdk.constants.ProfiloDiCollaborazione.ONEWAY.equals(bustaRichiesta.getProfiloDiCollaborazione()) &&
						bustaRichiesta.isConfermaRicezione() &&
						this.openspcoopProperties.isGestioneRiscontri(CostantiRegistroServizi.IMPLEMENTAZIONE_STANDARD)){
					
						protocolHeader.append("<eGov_IT:ProfiloCollaborazione>"+traduttore.toString(bustaRichiesta.getProfiloDiCollaborazione())+"</eGov_IT:ProfiloCollaborazione>");
						// Attendono riscontro
						idRiscontro = bustaRichiesta.getID();
				} else if(org.openspcoop2.protocol.sdk.constants.ProfiloDiCollaborazione.ASINCRONO_ASIMMETRICO.equals(bustaRichiesta.getProfiloDiCollaborazione()) &&
						bustaRichiesta.getRiferimentoMessaggio()==null){
					
						// devo generare ricevuta
						protocolHeader.append("<eGov_IT:ProfiloCollaborazione tipo=\""+traduttore.toProtocolServiceType(bustaRichiesta.getTipoServizio())+"\" servizioCorrelato=\""+
								(bustaRichiesta.getServizio()+"Correlato")+"\" >"+traduttore.toString(bustaRichiesta.getProfiloDiCollaborazione())+"</eGov_IT:ProfiloCollaborazione>");
				} else if(org.openspcoop2.protocol.sdk.constants.ProfiloDiCollaborazione.ASINCRONO_SIMMETRICO.equals(bustaRichiesta.getProfiloDiCollaborazione()) &&
						bustaRichiesta.getRiferimentoMessaggio()==null){
				
					// salvo messaggio sul database asincrono/repositoryEGov
					// get database
					try{
						this.resource = this.dbManager.getResource(this.openspcoopProperties.getIdentitaPortaDefault(this.getProtocolFactory().getProtocol(), this.requestInfo),"ConnettoreStresstest",idTransazione);
					}catch(Exception e){
						throw new Exception("Risorsa non ottenibile",e);
					}
					if(this.resource==null)
						throw new Exception("Risorsa is null");
					if(this.resource.getResource() == null)
						throw new Exception("Connessione is null");
					Connection connectionDB = (Connection) this.resource.getResource();
					//POOL,TRANSACTIONISOLATION:connectionDB.setTransactionIsolation(DBManager.getTransactionIsolationLevel());
					
					state.setConnectionDB(connectionDB);
					
					// repository
					RepositoryBuste repositoryBuste = new RepositoryBuste(state, true,this.getProtocolFactory());
					repositoryBuste.registraBustaIntoInBox(bustaRichiesta, new ArrayList<>() ,
							OpenSPCoop2Properties.getInstance().getRepositoryIntervalloScadenzaMessaggi());
					Integrazione infoIntegrazione = new Integrazione();
					infoIntegrazione.setIdModuloInAttesa(null);
					repositoryBuste.aggiornaInfoIntegrazioneIntoInBox(bustaRichiesta.getID(),infoIntegrazione);
				
					// asincrono
					ProfiloDiCollaborazione profiloCollaborazione = new ProfiloDiCollaborazione(state,this.getProtocolFactory());
					profiloCollaborazione.asincronoSimmetrico_registraRichiestaRicevuta(bustaRichiesta.getID(),bustaRichiesta.getCollaborazione(),
							bustaRichiesta.getTipoServizioCorrelato(),bustaRichiesta.getServizioCorrelato(),bustaRichiesta.getVersioneServizioCorrelato(),true,
							this.openspcoopProperties.getRepositoryIntervalloScadenzaMessaggi());
				
					// commit
					try{
						connectionDB.setAutoCommit(false);
						state.executePreparedStatement(); 
			
						connectionDB.commit();
						connectionDB.setAutoCommit(true);
					}catch (Exception e) {	
						this.logger.error("Riscontrato errore durante la gestione transazione del DB per la richiesta: "+e.getMessage(),e);
						// Rollback quanto effettuato (se l'errore e' avvenuto sul commit, o prima nell'execute delle PreparedStatement)
						try{
							connectionDB.rollback();
						}catch(Exception er){
							// ignore
						}
						// Ripristino connessione
						try{
							connectionDB.setAutoCommit(true);
						}catch(Exception er){
							// ignore
						}
						state.closePreparedStatement(); // Chiude le PreparedStatement aperte(e non eseguite) per il save del Msg
					}
					protocolHeader.append("<eGov_IT:ProfiloCollaborazione>"+traduttore.toString(bustaRichiesta.getProfiloDiCollaborazione())+"</eGov_IT:ProfiloCollaborazione>");
				}
				else{
					protocolHeader.append("<eGov_IT:ProfiloCollaborazione>"+traduttore.toString(bustaRichiesta.getProfiloDiCollaborazione())+"</eGov_IT:ProfiloCollaborazione>");
				}
			}
			
			// servizio
			if(bustaRichiesta.getTipoServizio()!=null && bustaRichiesta.getServizio()!=null)
				protocolHeader.append("<eGov_IT:Servizio tipo=\""+traduttore.toProtocolServiceType(bustaRichiesta.getTipoServizio())+"\">"+bustaRichiesta.getServizio()+"</eGov_IT:Servizio>");
			
			// azione
			if(bustaRichiesta.getAzione()!=null)
				protocolHeader.append("<eGov_IT:Azione>"+bustaRichiesta.getAzione()+"</eGov_IT:Azione>");
			
			// Messaggio
			protocolHeader.append("<eGov_IT:Messaggio>");
			
			// Identificativo egov
			String dominio = null;
			if(request.getConnectorProperties()!=null)
				dominio = request.getConnectorProperties().get("identificativo-porta");
			if(dominio==null)
				dominio=bustaRichiesta.getDestinatario()+"SPCoopIT";
			String idBustaRisposta = null;
			Imbustamento imbustatore = new Imbustamento(this.logger.getLogger(), this.getProtocolFactory(),state);
			try{
				idBustaRisposta = 
					imbustatore.buildID(new IDSoggetto(bustaRichiesta.getTipoDestinatario(), bustaRichiesta.getDestinatario(), dominio), 
							null, 
							this.openspcoopProperties.getGestioneSerializableDB_AttesaAttiva(),
							this.openspcoopProperties.getGestioneSerializableDB_CheckInterval(),
							RuoloMessaggio.RISPOSTA);
			}catch(Exception e){
				// rilancio
				throw e;
			}
			protocolHeader.append("<eGov_IT:Identificatore>"+idBustaRisposta+"</eGov_IT:Identificatore>");
		
			// OraRegistrazione
			String oraS = traduttore.getDate_protocolFormat(bustaRichiesta.getOraRegistrazione());
			protocolHeader.append("<eGov_IT:OraRegistrazione tempo=\""+traduttore.toString(bustaRichiesta.getTipoOraRegistrazione())+"\">"+
					oraS+"</eGov_IT:OraRegistrazione>");
			
			// RiferimentoMessaggio
			protocolHeader.append("<eGov_IT:RiferimentoMessaggio>"+bustaRichiesta.getID()+"</eGov_IT:RiferimentoMessaggio>");
			
			protocolHeader.append("</eGov_IT:Messaggio>");
		
			protocolHeader.append("</eGov_IT:IntestazioneMessaggio>");
			
			if(idRiscontro!=null){
				
				protocolHeader.append("<eGov_IT:ListaRiscontri><eGov_IT:Riscontro>" +
						"<eGov_IT:Identificatore>"+idRiscontro+"</eGov_IT:Identificatore>" +
						"<eGov_IT:OraRegistrazione tempo=\""+traduttore.toString(bustaRichiesta.getTipoOraRegistrazione())+"\">"+oraS+"</eGov_IT:OraRegistrazione>" +
								"</eGov_IT:Riscontro> </eGov_IT:ListaRiscontri>");
			}
			
			protocolHeader.append("</eGov_IT:Intestazione>");
			
    	}
    	
    	return protocolHeader.toString();
    }
    
}