InResponseHandler.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.handlers.transazioni;
import java.io.ByteArrayOutputStream;
import java.util.Date;
import org.apache.commons.lang.StringUtils;
import org.openspcoop2.core.constants.Costanti;
import org.openspcoop2.core.constants.TipoPdD;
import org.openspcoop2.message.OpenSPCoop2RestMessage;
import org.openspcoop2.message.OpenSPCoop2SoapMessage;
import org.openspcoop2.message.constants.MessageRole;
import org.openspcoop2.message.constants.ServiceBinding;
import org.openspcoop2.message.xml.MessageXMLUtils;
import org.openspcoop2.pdd.config.OpenSPCoop2Properties;
import org.openspcoop2.pdd.core.CostantiPdD;
import org.openspcoop2.pdd.core.connettori.ConnettoreBase;
import org.openspcoop2.pdd.core.handlers.HandlerException;
import org.openspcoop2.pdd.core.handlers.InResponseContext;
import org.openspcoop2.pdd.core.transazioni.InResponseStatefulObject;
import org.openspcoop2.pdd.core.transazioni.RepositoryGestioneStateful;
import org.openspcoop2.pdd.core.transazioni.Transaction;
import org.openspcoop2.pdd.core.transazioni.TransactionContext;
import org.openspcoop2.pdd.core.transazioni.TransactionDeletedException;
import org.openspcoop2.pdd.core.transazioni.TransactionNotExistsException;
import org.openspcoop2.pdd.core.transazioni.TransactionStatefulNotSupportedException;
import org.openspcoop2.pdd.logger.DumpUtility;
import org.openspcoop2.pdd.logger.OpenSPCoop2Logger;
import org.openspcoop2.utils.json.JSONUtils;
import org.openspcoop2.utils.transport.http.HttpRequestMethod;
import org.slf4j.Logger;
import com.fasterxml.jackson.databind.JsonNode;
/**
* InResponseHandler
*
* @author Poli Andrea (poli@link.it)
* @author $Author$
* @version $Rev$, $Date$
*/
public class InResponseHandler extends FirstPositionHandler implements org.openspcoop2.pdd.core.handlers.InResponseHandler{
@Override
public void invoke(InResponseContext context) throws HandlerException {
OpenSPCoop2Properties op2Properties = OpenSPCoop2Properties.getInstance();
if(op2Properties.isTransazioniEnabled()==false) {
return;
}
String idTransazione = null;
if(context!=null && context.getPddContext()!=null) {
idTransazione = (String) context.getPddContext().getObject(Costanti.ID_TRANSAZIONE);
}
//System.out.println("------------- InResponseHandler ("+idTransazione+")("+context.getTipoPorta().getTipo()+") -------------------");
// Gestione FAULT
String fault = null;
String formatoFault = null;
try{
if(context!=null && context.getMessaggio()!=null){
if(ServiceBinding.SOAP.equals(context.getMessaggio().getServiceBinding())) {
OpenSPCoop2SoapMessage soapMsg = context.getMessaggio().castAsSoap();
if(soapMsg.hasSOAPFault()){
ByteArrayOutputStream bout = new ByteArrayOutputStream();
bout.write(context.getMessaggio().getAsByte(soapMsg.getSOAPPart().getEnvelope(), false));
bout.flush();
bout.close();
Logger log = OpenSPCoop2Logger.getLoggerOpenSPCoopTransazioni(op2Properties.isTransazioniDebug());
if(op2Properties.isTransazioniFaultPrettyPrint()){
// Faccio una pretty-print: potevo fare anche direttamente passando il fault a metodo prettyPrint,
// Pero' non veniva stampato correttamente il SOAPFault. Mi appoggio allora a SoapUtils.
//byte [] content = org.openspcoop2.message.soap.TunnelSoapUtils.sbustamentoMessaggio(context.getMessaggio());
byte [] content = bout.toByteArray();
fault = DumpUtility.toString(MessageXMLUtils.getInstance(soapMsg.getFactory()).newDocument(content), log, context.getMessaggio());
//System.out.println("IMPOSTATO FAULT IN TRANSACTION ["+fault+"]");
}
else{
fault = bout.toString();
}
formatoFault = soapMsg.getMessageType().name();
}
}
else {
OpenSPCoop2RestMessage<?> restMsg = context.getMessaggio().castAsRest();
if(restMsg.isProblemDetailsForHttpApis_RFC7807() || MessageRole.FAULT.equals(restMsg.getMessageRole())) {
switch (restMsg.getMessageType()) {
case XML:
ByteArrayOutputStream bout = new ByteArrayOutputStream();
restMsg.writeTo(bout, false);
bout.flush();
bout.close();
Logger log = OpenSPCoop2Logger.getLoggerOpenSPCoopTransazioni(op2Properties.isTransazioniDebug());
if(op2Properties.isTransazioniFaultPrettyPrint()){
// Faccio una pretty-print: potevo fare anche direttamente passando il fault a metodo prettyPrint,
// Pero' non veniva stampato correttamente il SOAPFault. Mi appoggio allora a SoapUtils.
//byte [] content = org.openspcoop2.message.soap.TunnelSoapUtils.sbustamentoMessaggio(context.getMessaggio());
byte [] content = bout.toByteArray();
fault = DumpUtility.toString(MessageXMLUtils.getInstance(restMsg.getFactory()).newDocument(content), log, context.getMessaggio());
//System.out.println("IMPOSTATO FAULT IN TRANSACTION ["+fault+"]");
}
else{
fault = bout.toString();
}
formatoFault = restMsg.getMessageType().name();
break;
case JSON:
bout = new ByteArrayOutputStream();
restMsg.writeTo(bout, false);
bout.flush();
bout.close();
if(op2Properties.isTransazioniFaultPrettyPrint()){
JSONUtils jsonUtils = JSONUtils.getInstance(true);
byte [] content = bout.toByteArray();
JsonNode jsonNode = jsonUtils.getAsNode(content);
fault = jsonUtils.toString(jsonNode);
}
else{
fault = bout.toString();
}
formatoFault = restMsg.getMessageType().name();
break;
default:
break;
}
}
}
}
}catch(Exception e){
throw new HandlerException("Errore durante il dump del soap fault",e);
}
if(context!=null && context.getTransazioneApplicativoServer()!=null) {
try{
// date
context.getTransazioneApplicativoServer().setDataAccettazioneRisposta(context.getDataAccettazioneRisposta());
Date dataIngressoRisposta = context.getDataElaborazioneMessaggio();
if(context.getDataTerminataInvocazioneConnettore()!=null) {
dataIngressoRisposta = context.getDataTerminataInvocazioneConnettore(); // nella latenza porta deve rientrare anche la negoziazione della connessione
}
context.getTransazioneApplicativoServer().setDataIngressoRisposta(dataIngressoRisposta);
if(context.getDataPrimaInvocazioneConnettore()!=null) {
// aggiorno informazione sulla data, poiche' piu' precisa (nella latenza porta deve rientrare anche il dump ed il rilascio della connessione)
context.getTransazioneApplicativoServer().setDataUscitaRichiesta(context.getDataPrimaInvocazioneConnettore());
}
if(context.getDataRichiestaInoltrata()!=null) {
context.getTransazioneApplicativoServer().setDataUscitaRichiestaStream(context.getDataRichiestaInoltrata());
}
// return code
context.getTransazioneApplicativoServer().setCodiceRisposta(context.getReturnCode()+"");
// eventuali errori
context.getTransazioneApplicativoServer().setUltimoErrore(context.getErroreConsegna());
// aggiorno location
if(context.getConnettore()!=null){
context.getTransazioneApplicativoServer().setLocationConnettore(context.getConnettore().getLocation());
}
// fault
if(fault!=null){
context.getTransazioneApplicativoServer().setFault(fault);
context.getTransazioneApplicativoServer().setFormatoFault(formatoFault);
}
}catch(Exception e){
throw new HandlerException("Errore durante il processamento delle informazioni relative alla consegna per l'applicativo '"+context.getTransazioneApplicativoServer().getServizioApplicativoErogatore()+"': "+e.getMessage(),e);
}
}
else {
boolean gestioneStateful = false;
Transaction tr = null;
try{
tr = TransactionContext.getTransaction(idTransazione);
}catch(TransactionNotExistsException e){
gestioneStateful = true;
}
try{
InResponseStatefulObject sObject = null;
if(tr==null && gestioneStateful){
sObject = new InResponseStatefulObject();
//System.out.println("@@@@@REPOSITORY@@@@@ InResponseHandler ID TRANSAZIONE ["+idTransazione+"] GESTIONE COMPLETA");
Date dataRichiestaInoltrata = context.getDataRichiestaInoltrata();
// La porta di dominio mi passa sempre questa informazione.
// Nel PddMonitor, invece, la data deve essere visualizzata solo se la dimensione e' diverso da 0 e cioe' se c'e' un messaggio di risposta.
//if(dimensione!=null && dimensione>0){
// L'INFORMAZIONE DEVE INVECE ESSERE SEMPRE SALVATA PER LA SIMULAZIONE DEI MESSAGGI DIAGNOSTICI
// INEFFICIENTE: RepositoryGestioneStateful.addDataAccettazioneRisposta(idTransazione, dataAccettazioneRisposta);
sObject.setDataRichiestaInoltrata(dataRichiestaInoltrata);
Date dataAccettazioneRisposta = context.getDataAccettazioneRisposta();
// La porta di dominio mi passa sempre questa informazione.
// Nel PddMonitor, invece, la data deve essere visualizzata solo se la dimensione e' diverso da 0 e cioe' se c'e' un messaggio di risposta.
//if(dimensione!=null && dimensione>0){
// L'INFORMAZIONE DEVE INVECE ESSERE SEMPRE SALVATA PER LA SIMULAZIONE DEI MESSAGGI DIAGNOSTICI
// INEFFICIENTE: RepositoryGestioneStateful.addDataAccettazioneRisposta(idTransazione, dataAccettazioneRisposta);
sObject.setDataAccettazioneRisposta(dataAccettazioneRisposta);
Date dataIngressoRisposta = context.getDataElaborazioneMessaggio();
if(context.getDataTerminataInvocazioneConnettore()!=null) {
dataIngressoRisposta = context.getDataTerminataInvocazioneConnettore(); // nella latenza porta deve rientrare anche la negoziazione della connessione
}
// La porta di dominio mi passa sempre questa informazione.
// Nel PddMonitor, invece, la data deve essere visualizzata solo se la dimensione e' diverso da 0 e cioe' se c'e' un messaggio di risposta.
//if(dimensione!=null && dimensione>0){
// L'INFORMAZIONE DEVE INVECE ESSERE SEMPRE SALVATA PER LA SIMULAZIONE DEI MESSAGGI DIAGNOSTICI
// INEFFICIENTE: RepositoryGestioneStateful.addDataIngressoRisposta(idTransazione, dataElaborazioneMessaggio);
sObject.setDataIngressoRisposta(dataIngressoRisposta);
if(context.getDataPrimaInvocazioneConnettore()!=null) {
// aggiorno informazione sulla data, poiche' piu' precisa (nella latenza porta deve rientrare anche il dump ed il rilascio della connessione)
sObject.setDataUscitaRichiesta(context.getDataPrimaInvocazioneConnettore());
}
// INEFFICIENTE: RepositoryGestioneStateful.addCodiceTrasportoRichiesta(idTransazione, context.getReturnCode()+"");
sObject.setReturnCode(context.getReturnCode()+"");
if(context.getConnettore()!=null){
// INEFFICIENTE: RepositoryGestioneStateful.addLocation(idTransazione, context.getConnettore().getLocation());
sObject.setLocation(context.getConnettore().getLocation());
}
if(fault!=null){
if(TipoPdD.APPLICATIVA.equals(context.getTipoPorta())){
sObject.setFaultIntegrazione(fault);
sObject.setFormatoFaultIntegrazione(formatoFault);
}
else{
sObject.setFaultCooperazione(fault);
sObject.setFormatoFaultCooperazione(formatoFault);
}
}
}else{
if(tr==null) {
throw new HandlerException("Transaction is null");
}
if(context==null) {
throw new HandlerException("Context is null");
}
Date dataRichiestaInoltrata = context.getDataRichiestaInoltrata();
// La porta di dominio mi passa sempre questa informazione.
// Nel PddMonitor, invece, la data deve essere visualizzata solo se la dimensione e' diverso da 0 e cioe' se c'e' un messaggio di risposta.
//if(dimensione!=null && dimensione>0){
// L'INFORMAZIONE DEVE INVECE ESSERE SEMPRE SALVATA PER LA SIMULAZIONE DEI MESSAGGI DIAGNOSTICI
try{
tr.setDataRichiestaInoltrata(dataRichiestaInoltrata);
//System.out.println("SET DATA ("+dataAccettazioneRisposta.toString()+")");
}catch(TransactionDeletedException e){
//System.out.println("@@@@@REPOSITORY@@@@@ InResponseHandler SET DATA ("+dataAccettazioneRisposta.toString()+")");
// INEFFICIENTE: RepositoryGestioneStateful.addDataAccettazioneRisposta(idTransazione, dataAccettazioneRisposta);
if(sObject==null)
sObject = new InResponseStatefulObject();
sObject.setDataRichiestaInoltrata(dataRichiestaInoltrata);
}
Date dataAccettazioneRisposta = context.getDataAccettazioneRisposta();
// La porta di dominio mi passa sempre questa informazione.
// Nel PddMonitor, invece, la data deve essere visualizzata solo se la dimensione e' diverso da 0 e cioe' se c'e' un messaggio di risposta.
//if(dimensione!=null && dimensione>0){
// L'INFORMAZIONE DEVE INVECE ESSERE SEMPRE SALVATA PER LA SIMULAZIONE DEI MESSAGGI DIAGNOSTICI
try{
tr.setDataAccettazioneRisposta(dataAccettazioneRisposta);
//System.out.println("SET DATA ("+dataAccettazioneRisposta.toString()+")");
}catch(TransactionDeletedException e){
//System.out.println("@@@@@REPOSITORY@@@@@ InResponseHandler SET DATA ("+dataAccettazioneRisposta.toString()+")");
// INEFFICIENTE: RepositoryGestioneStateful.addDataAccettazioneRisposta(idTransazione, dataAccettazioneRisposta);
if(sObject==null)
sObject = new InResponseStatefulObject();
sObject.setDataAccettazioneRisposta(dataAccettazioneRisposta);
}
Date dataIngressoRisposta = context.getDataElaborazioneMessaggio();
if(context.getDataTerminataInvocazioneConnettore()!=null) {
dataIngressoRisposta = context.getDataTerminataInvocazioneConnettore(); // nella latenza porta deve rientrare anche la negoziazione della connessione
}
// La porta di dominio mi passa sempre questa informazione.
// Nel PddMonitor, invece, la data deve essere visualizzata solo se la dimensione e' diverso da 0 e cioe' se c'e' un messaggio di risposta.
//if(dimensione!=null && dimensione>0){
// L'INFORMAZIONE DEVE INVECE ESSERE SEMPRE SALVATA PER LA SIMULAZIONE DEI MESSAGGI DIAGNOSTICI
try{
tr.setDataIngressoRisposta(dataIngressoRisposta);
//System.out.println("SET DATA ("+dataElaborazioneMessaggio.toString()+")");
}catch(TransactionDeletedException e){
//System.out.println("@@@@@REPOSITORY@@@@@ InResponseHandler SET DATA ("+dataElaborazioneMessaggio.toString()+")");
// INEFFICIENTE: RepositoryGestioneStateful.addDataIngressoRisposta(idTransazione, dataElaborazioneMessaggio);
if(sObject==null)
sObject = new InResponseStatefulObject();
sObject.setDataIngressoRisposta(dataIngressoRisposta);
}
if(context.getDataPrimaInvocazioneConnettore()!=null) {
// aggiorno informazione sulla data, poiche' piu' precisa (nella latenza porta deve rientrare anche il dump ed il rilascio della connessione)
try{
tr.setDataUscitaRichiesta(context.getDataPrimaInvocazioneConnettore());
//System.out.println("SET DATA ("+dataElaborazioneMessaggio.toString()+")");
}catch(TransactionDeletedException e){
//System.out.println("@@@@@REPOSITORY@@@@@ InResponseHandler SET DATA ("+dataElaborazioneMessaggio.toString()+")");
// INEFFICIENTE: RepositoryGestioneStateful.addDataIngressoRisposta(idTransazione, dataElaborazioneMessaggio);
if(sObject==null)
sObject = new InResponseStatefulObject();
sObject.setDataUscitaRichiesta(context.getDataPrimaInvocazioneConnettore());
}
}
try{
//System.out.println("SET CODICE TRASPORTO RICHIESTA ["+context.getReturnCode()+"]");
if(context!=null) {
tr.setCodiceTrasportoRichiesta(context.getReturnCode()+"");
}
}catch(TransactionDeletedException e){
//System.out.println("@@@@@REPOSITORY@@@@@ InResponseHandler SET CODICE TRASPORTO RICHIESTA ["+context.getReturnCode()+"]");
// INEFFICIENTE: RepositoryGestioneStateful.addCodiceTrasportoRichiesta(idTransazione, context.getReturnCode()+"");
if(sObject==null)
sObject = new InResponseStatefulObject();
sObject.setReturnCode(context.getReturnCode()+"");
}
try{
// update location impostata nel OutRequest (location modificata dal connettore)
//System.out.println("SET LOCATION ["+context.getConnettore().getLocation()+"]");
String connettoreRequestUrl = null;
String connettoreRequestMethod = null;
if(context.getPddContext()!=null) {
if(context.getPddContext().containsKey(CostantiPdD.CONNETTORE_REQUEST_URL)) {
connettoreRequestUrl = (String) context.getPddContext().getObject(CostantiPdD.CONNETTORE_REQUEST_URL);
}
if(context.getPddContext().containsKey(CostantiPdD.CONNETTORE_REQUEST_METHOD)) {
Object o = context.getPddContext().getObject(CostantiPdD.CONNETTORE_REQUEST_METHOD);
if(o instanceof String) {
connettoreRequestMethod = (String) o;
}
else if(o instanceof HttpRequestMethod) {
HttpRequestMethod oConnettoreRequestMethod = (HttpRequestMethod) o;
connettoreRequestMethod = oConnettoreRequestMethod.name();
}
}
}
if(!StringUtils.isEmpty(connettoreRequestUrl) && !StringUtils.isEmpty(connettoreRequestMethod)) {
String prefix = "";
if(ConnettoreBase.LOCATION_CACHED.equals(context.getConnettore().getLocation())){
prefix = context.getConnettore().getLocation()+ConnettoreBase.LOCATION_CACHED_SEPARATOR_REQUEST_URL;
}
tr.setLocation(prefix+CostantiPdD.getConnettoreRequest(connettoreRequestUrl, connettoreRequestMethod));
}
else {
if(context!=null && context.getConnettore()!=null) {
tr.setLocation(context.getConnettore().getLocation());
}
}
}catch(TransactionDeletedException e){
//System.out.println("@@@@@REPOSITORY@@@@@ OutRequestHandler SET LOCATION ["+context.getConnettore().getLocation()+"]");
// INEFFICIENTE: RepositoryGestioneStateful.addLocation(idTransazione, context.getConnettore().getLocation());
if(sObject==null)
sObject = new InResponseStatefulObject();
sObject.setLocation(context.getConnettore().getLocation());
}
try{
if(fault!=null){
if(TipoPdD.APPLICATIVA.equals(context.getTipoPorta())){
tr.setFaultIntegrazione(fault);
tr.setFormatoFaultIntegrazione(formatoFault);
}
else{
tr.setFaultCooperazione(fault);
tr.setFormatoFaultCooperazione(formatoFault);
}
}
}catch(TransactionDeletedException e){
if(fault!=null){
if(sObject==null)
sObject = new InResponseStatefulObject();
if(TipoPdD.APPLICATIVA.equals(context.getTipoPorta())){
sObject.setFaultIntegrazione(fault);
sObject.setFormatoFaultIntegrazione(formatoFault);
}
else{
sObject.setFaultCooperazione(fault);
sObject.setFormatoFaultCooperazione(formatoFault);
}
}
}
}
if(sObject!=null){
// Gestione stateful
RepositoryGestioneStateful.addInResponseStatefulObject(context.getProtocolFactory().getProtocol(),idTransazione, sObject);
}
}catch(TransactionStatefulNotSupportedException e){
throw new HandlerException("Errore durante il processamento dell'handler: "+e.getMessage(),e);
}
}
}
}