TransactionManager.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.transaction;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.openspcoop2.core.commons.dao.DAOFactory;
import org.openspcoop2.core.transazioni.DumpAllegato;
import org.openspcoop2.core.transazioni.DumpContenuto;
import org.openspcoop2.core.transazioni.DumpHeaderTrasporto;
import org.openspcoop2.core.transazioni.DumpMessaggio;
import org.openspcoop2.core.transazioni.IdDumpMessaggio;
import org.openspcoop2.core.transazioni.Transazione;
import org.openspcoop2.core.transazioni.constants.TipoMessaggio;
import org.openspcoop2.core.transazioni.dao.IDumpMessaggioService;
import org.openspcoop2.core.transazioni.dao.IDumpMessaggioServiceSearch;
import org.openspcoop2.core.transazioni.dao.ITransazioneServiceSearch;
import org.openspcoop2.generic_project.exception.NotFoundException;
import org.openspcoop2.generic_project.expression.IExpression;
import org.openspcoop2.generic_project.expression.IPaginatedExpression;
import org.openspcoop2.monitor.sdk.constants.ContentResourceNames;
import org.openspcoop2.monitor.sdk.constants.MessageType;
import org.openspcoop2.monitor.sdk.constants.TransactionExceptionCode;
import org.openspcoop2.monitor.sdk.exceptions.TransactionException;
import org.openspcoop2.monitor.sdk.transaction.AbstractContentResource;
import org.openspcoop2.monitor.sdk.transaction.Attachment;
import org.openspcoop2.monitor.sdk.transaction.AttachmentResource;
import org.openspcoop2.monitor.sdk.transaction.ContentResource;
import org.openspcoop2.monitor.sdk.transaction.SOAPEnvelopeResource;
import org.openspcoop2.monitor.sdk.transaction.Transaction;
import org.openspcoop2.monitor.sdk.transaction.TransportHeaderResource;
import org.openspcoop2.protocol.sdk.constants.RuoloMessaggio;
import org.openspcoop2.protocol.sdk.diagnostica.DriverMsgDiagnosticiNotFoundException;
import org.openspcoop2.protocol.sdk.diagnostica.FiltroRicercaDiagnosticiConPaginazione;
import org.openspcoop2.protocol.sdk.diagnostica.IDiagnosticDriver;
import org.openspcoop2.protocol.sdk.diagnostica.MsgDiagnostico;
import org.openspcoop2.protocol.sdk.tracciamento.DriverTracciamentoNotFoundException;
import org.openspcoop2.protocol.sdk.tracciamento.ITracciaDriver;
import org.openspcoop2.protocol.sdk.tracciamento.Traccia;
import org.openspcoop2.utils.date.DateManager;
import org.slf4j.Logger;

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

	public static Transaction getTransaction(DAOFactory daoFactory, Logger log, String id, boolean debug)
			throws TransactionException {
		
		Transaction transactionInfo = null;

		ITracciaDriver driverTracciamento = null;
		IDiagnosticDriver driverDiagnostici = null;
		try {
			org.openspcoop2.core.transazioni.dao.IServiceManager transazioniSM = 
					(org.openspcoop2.core.transazioni.dao.IServiceManager) daoFactory.getServiceManager(org.openspcoop2.core.transazioni.utils.ProjectInfo.getInstance());
			ITransazioneServiceSearch transazioniSearchDAO = transazioniSM.getTransazioneServiceSearch();

			driverTracciamento = (ITracciaDriver) 
					daoFactory.getServiceManager(org.openspcoop2.core.tracciamento.utils.ProjectInfo.getInstance());
			
			driverDiagnostici = (IDiagnosticDriver) 
					daoFactory.getServiceManager(org.openspcoop2.core.diagnostica.utils.ProjectInfo.getInstance());
			
			// prelevo la transazione
			IExpression exprFindTraccia = transazioniSearchDAO.newExpression();
			exprFindTraccia.equals(Transazione.model().ID_TRANSAZIONE, id);
			Transazione transazione = null;
			try{
				transazione = transazioniSearchDAO.find(exprFindTraccia);
				transactionInfo = new Transaction(log,daoFactory,transazione);
			}catch(NotFoundException notFound){
				log.info("Transazione con id ["+id+"] non trovata: "+notFound.getMessage(),notFound);
				throw new TransactionException(TransactionExceptionCode.NOT_FOUND,"Transazione con id ["+id+"] non trovata: "+notFound.getMessage(),notFound);
			}
						
			// tracce / diagnostici
			Map<String, String> propertiesRicerca = new HashMap<>();
			
			propertiesRicerca.put("id_transazione", id);
			Traccia tracciaRichiesta = null;
			try{
				tracciaRichiesta = driverTracciamento.getTraccia(RuoloMessaggio.RICHIESTA, propertiesRicerca);
				transactionInfo.setRequestTrace(tracciaRichiesta);
			}catch(DriverTracciamentoNotFoundException notFound){
				if(debug)
					log.debug("Traccia di richiesta non trovata per la transazione con id ["+id+"]: "+notFound.getMessage(),notFound);
			}
			Traccia tracciaRisposta = null;
			try{
				tracciaRisposta = driverTracciamento.getTraccia(RuoloMessaggio.RISPOSTA, propertiesRicerca);
				transactionInfo.setResponseTrace(tracciaRisposta);
			}catch(DriverTracciamentoNotFoundException notFound){
				if(debug)
					log.debug("Traccia di risposta non trovata per la transazione con id ["+id+"]: "+notFound.getMessage(),notFound);
			}
			
			FiltroRicercaDiagnosticiConPaginazione filtro = new FiltroRicercaDiagnosticiConPaginazione();
			filtro.setProperties(propertiesRicerca);
			List<MsgDiagnostico> listDiagnostici = null;
			try{
				listDiagnostici = driverDiagnostici.getMessaggiDiagnostici(filtro);
				transactionInfo.setMsgdiagnosticiList(listDiagnostici);
			}catch(DriverMsgDiagnosticiNotFoundException notFound){
				if(debug)
					log.debug("Diagnostici non presenti per la transazione con id ["+id+"]: "+notFound.getMessage(),notFound);
			}
			
			// risorse di contenuto
			IDumpMessaggioServiceSearch dumpMessaggioSearchDAO = transazioniSM.getDumpMessaggioServiceSearch();
			TransactionManager.retrieveContentResources(
						dumpMessaggioSearchDAO, transactionInfo);

		} catch (Exception e) {
			log.error(
					"TransactionManager.getTransaction(" + id
							+ ") ha generato un errore: " + e.getMessage(), e);
			throw new TransactionException(TransactionExceptionCode.GENERIC_ERROR,e.getMessage(),e);
		}finally{
			try{
				driverTracciamento.close();
			}catch(Exception eClose){
				// close
			}
			try{
				driverDiagnostici.close();
			}catch(Exception eClose){
				// close
			}
		}

		return transactionInfo;
	}

	
	public static void updateContentResources(Transaction transaction)
			throws TransactionException {

		// !AGGIORNA L'IMMAGINE PRESENTE SUL DATABASE!
		// delle risorse NOME VALORE
		
		try {
			List<ContentResource> resList = transaction.getContentResourcesByType(ContentResource.class);
			if (resList.size() != 0) {
				
				org.openspcoop2.core.transazioni.dao.IServiceManager transazioniSM = 
						(org.openspcoop2.core.transazioni.dao.IServiceManager) transaction.getDAOFactory().getServiceManager(org.openspcoop2.core.transazioni.utils.ProjectInfo.getInstance());
				IDumpMessaggioService dumpMessaggioDAO = transazioniSM.getDumpMessaggioService();
				IDumpMessaggioServiceSearch dumpMessaggioSearchDAO = transazioniSM.getDumpMessaggioServiceSearch();

				IPaginatedExpression expr = dumpMessaggioSearchDAO.newPaginatedExpression();
				expr.
					limit(1000).
					equals(DumpMessaggio.model().ID_TRANSAZIONE,transaction.getIdTransazione());

				List<DumpMessaggio> list = dumpMessaggioSearchDAO.findAll(expr);

				// posso trovare 0/1/2 entries nella tabella dump_messaggi per
				// ogni transazione
				for (DumpMessaggio dumpMessaggio : list) {
					
					boolean update = updateResources(dumpMessaggio, transaction);

					// Se e' necessario aggiornare il database procedo.
					if (update) {
						IdDumpMessaggio idDumpMsg = new IdDumpMessaggio();
						idDumpMsg.setIdTransazione(transaction.getIdTransazione());
						idDumpMsg.setTipoMessaggio(dumpMessaggio.getTipoMessaggio());
						dumpMessaggioDAO.update(idDumpMsg, dumpMessaggio);
					}
				}
			
			}
		} catch (Exception e) {
			transaction.getLogger().error(
					"TransactionManager.updateContentResources() ha generato un errore: "
							+ e.getMessage(), e);
			throw new TransactionException(TransactionExceptionCode.GENERIC_ERROR,e.getMessage(),e);
		}
	}

	public static boolean updateResources(DumpMessaggio dumpMessaggio, Transaction transaction) throws Exception{
		
		boolean update = false;
		
		List<ContentResource> resList = transaction.getContentResourcesByType(ContentResource.class);
		if (resList.size() != 0) {
		
			// aggiorno i valori di proprieta' esistenti e rimuovo quelle presenti che non sono nella nuova immagine passata come parametro al metodo
			List<DumpContenuto> lstContenuto = dumpMessaggio.getContenutoList();
			for (DumpContenuto dumpContenuto : lstContenuto) {
				String resName = dumpContenuto.getNome();
				ContentResource resource = (ContentResource) transaction.getContentResourceByName(resName);
				if (resource != null) {
					//if(!resource.getValue().equals(dumpContenuto.getValore())){
					if(!resource.getValue().equals(TransactionContentUtils.getDumpContenutoValue(dumpContenuto))){
						TransactionContentUtils.setDumpContenutoValue(dumpContenuto, resource.getValue());
						update = true;
					}
				} else{
					lstContenuto.remove(dumpContenuto);
					update = true;
				}
				resList.remove(resource);
			}
	
			// aggiungo le nuove proprieta' presenti nel parametro passato al metodo e non presenti su database
			for (int i = 0; i < resList.size(); i++) {
				ContentResource cr = (ContentResource) resList.get(i);
				if(resList.get(i).getName()==null){
					throw new Exception("Trovata risorsa di contenuto senza nome");
				}
				if(resList.get(i).getValue()==null){
					throw new Exception("Trovata risorsa di contenuto con nome ["+resList.get(i).getName()+"] con valore non definito");
				}
				DumpContenuto c = 
						TransactionContentUtils.createDumpContenuto(resList.get(i).getName(), 
								resList.get(i).getValue(), 
								DateManager.getDate());
				if(dumpMessaggio.getTipoMessaggio().equals(TipoMessaggio.RICHIESTA_INGRESSO) || dumpMessaggio.getTipoMessaggio().equals(TipoMessaggio.RICHIESTA_USCITA)){
					if(cr.isRequest()){
						dumpMessaggio.addContenuto(c);
						update = true;
					}
				}
				else{
					if(cr.isResponse()){
						dumpMessaggio.addContenuto(c);
						update = true;
					}
				}
				
			}
			
		}
		
		
			
		TransportHeaderResource resource = null;
		if(TipoMessaggio.RICHIESTA_INGRESSO.equals(dumpMessaggio.getTipoMessaggio()) || TipoMessaggio.RICHIESTA_USCITA.equals(dumpMessaggio.getTipoMessaggio())){
			resource = (TransportHeaderResource) transaction.getContentResourceByName(ContentResourceNames.REQ_TRANSPORT_HEADER);
		}
		else{
			resource = (TransportHeaderResource) transaction.getContentResourceByName(ContentResourceNames.RES_TRANSPORT_HEADER);
		}
		List<String> keys = new ArrayList<>();
		if(resource!=null && resource.keys()!=null && resource.keys().size()>0){
			keys.addAll(resource.keys());
		}
		
		// aggiorno i valori di proprieta' esistenti e rimuovo quelle presenti che non sono nella nuova immagine passata come parametro al metodo
		List<DumpHeaderTrasporto> lstHeader = dumpMessaggio.getHeaderTrasportoList();
		for (DumpHeaderTrasporto dumpHeader : lstHeader) {
			String resName = dumpHeader.getNome();
			if (resource != null) {
				String valore = resource.getProperty(resName);
				if(valore!=null){
					if(!dumpHeader.getValore().equals(valore)){
						dumpHeader.setValore(valore);	
						update = true;
					}
				} else{
					lstHeader.remove(dumpHeader);
					update = true;
				}
			} else{
				lstHeader.remove(dumpHeader);
				update = true;
			}
			for (int i = 0; i < keys.size(); i++) {
				if(keys.get(i).equals(resName)){
					keys.remove(i);
					break;
				}
			}
		}

		// aggiungo le nuove proprieta' presenti nel parametro passato al metodo e non presenti su database
		for (int i = 0; i < keys.size(); i++) {
			DumpHeaderTrasporto c = new DumpHeaderTrasporto();
			if(keys.get(i)==null){
				throw new Exception("Trovato header di trasporto senza nome");
			}
			if(resource.getProperty(keys.get(i))==null){
				throw new Exception("Trovato header di trasporto con nome ["+keys.get(i)+"] con valore non definito");
			}
			c.setNome(keys.get(i));
			c.setValore(resource.getProperty(keys.get(i)));
			c.setDumpTimestamp(DateManager.getDate());
			dumpMessaggio.addHeaderTrasporto(c);
			update = true;
		}
		
		
		
		
		
		
		AttachmentResource attachResource = null;
		if(TipoMessaggio.RICHIESTA_INGRESSO.equals(dumpMessaggio.getTipoMessaggio()) || TipoMessaggio.RICHIESTA_USCITA.equals(dumpMessaggio.getTipoMessaggio())){
			attachResource = (AttachmentResource) transaction.getContentResourceByName(ContentResourceNames.REQ_ATTACHMENT);
		}
		else{
			attachResource = (AttachmentResource) transaction.getContentResourceByName(ContentResourceNames.RES_ATTACHMENT);
		}
		List<String> cids = null;
		if(attachResource!=null){
			cids = attachResource.cids();
		}
		
		// aggiorno i valori di proprieta' esistenti e rimuovo quelle presenti che non sono nella nuova immagine passata come parametro al metodo
		List<DumpAllegato> lstAllegati = dumpMessaggio.getAllegatoList();
		for (DumpAllegato dumpAllegato : lstAllegati) {
			String cid = dumpAllegato.getContentId();
			if (attachResource != null) {
				Attachment attach = attachResource.getAttachmentByContentId(cid);
				if(attach.isUpdated()){
					dumpAllegato.setContentType(attach.getContentType());
					dumpAllegato.setAllegato(attach.getContentAsByte());
					update = true;
				} 
			} else{
				lstAllegati.remove(dumpAllegato);
				update = true;
			}
			for (int i = 0; i < cids.size(); i++) {
				if(cids.get(i).equals(cid)){
					cids.remove(i);
					break;
				}
			}
		}

		// aggiungo i nuovi attach presenti nel parametro passato al metodo e non presenti su database
		if(cids!=null) {
			for (int i = 0; i < cids.size(); i++) {
				Attachment attach = attachResource.getAttachmentByContentId(cids.get(i));
				DumpAllegato c = new DumpAllegato();
				c.setAllegato(attach.getContentAsByte());
				c.setContentId(attach.getContentID());
				c.setContentType(attach.getContentType());
				c.setDumpTimestamp(DateManager.getDate());
				dumpMessaggio.addAllegato(c);
				update = true;
			}
		}
		
		
		
		return update;		
	}
	
	private static void addContentResource(Transaction transaction, AbstractContentResource res){
		try {
			transaction.addContentResource(res);
		} catch (TransactionException e) {
			if (TransactionExceptionCode.ADD_RES_EXIST.equals(e.getCode()) ) {
				transaction.getLogger().error(e.getMessage(),e);
			} else {
				// si sta aggiungendo una risorsa giĆ  presente,
				try {
					transaction.updateContentResource(res);
				} catch (TransactionException e1) {
					transaction.getLogger().error(e1.getMessage(),e1);
				}
			}
		}
	}
	
	private static void retrieveContentResources(
			IDumpMessaggioServiceSearch dumpMessaggioSearchDAO,
			Transaction transaction)  throws Exception{

		IPaginatedExpression expr = dumpMessaggioSearchDAO.newPaginatedExpression();
		expr.
			limit(1000).
			equals(DumpMessaggio.model().ID_TRANSAZIONE,
				transaction.getIdTransazione());

		List<DumpMessaggio> list = dumpMessaggioSearchDAO.findAll(expr);

		for (DumpMessaggio dumpMessaggio : list) {
			
			setContentResourcesInTransaction(transaction, dumpMessaggio);
			
		}



	}
	
	public static void setContentResourcesInTransaction(Transaction transaction, DumpMessaggio dumpMessaggio){
		MessageType tipoMessaggio = MessageType.valueOf(dumpMessaggio
				.getTipoMessaggioRawEnumValue());

		
		// **** SOAP ENVELOPE **** 
		
		SOAPEnvelopeResource soapEnvelope = new SOAPEnvelopeResource(tipoMessaggio);
		addContentResource(transaction, soapEnvelope);
		
		
		
		
		// **** RISORSE NOME VALORE **** 
		
		for (DumpContenuto dumpContenuto : dumpMessaggio.getContenutoList()) {
							
			ContentResource res = new ContentResource(tipoMessaggio);
			res.setName(dumpContenuto.getNome());
			res.setValue(TransactionContentUtils.getDumpContenutoValue(dumpContenuto));

			addContentResource(transaction, res);
		}
		
		
		
		// **** HEADER HTTP *****
		
		TransportHeaderResource res = new TransportHeaderResource(tipoMessaggio);
		for (DumpHeaderTrasporto dumpHeader : dumpMessaggio.getHeaderTrasportoList()) {
			res.setProperty(dumpHeader.getNome(),dumpHeader.getValore());
		}
		addContentResource(transaction, res);
		
		
		
		
		// **** ATTACHMENTS *****

		AttachmentResource attRes = new AttachmentResource(tipoMessaggio);
		for (DumpAllegato dumpAllegato : dumpMessaggio.getAllegatoList()) {
			Attachment attach = new Attachment(
					dumpAllegato.getAllegato(),
					dumpAllegato.getContentId(),
					dumpAllegato.getContentType());

			attRes.addAttachment(attach);
		}
		addContentResource(transaction, attRes);
	}




}