ConnettoreBaseWithResponse.java

  1. /*
  2.  * GovWay - A customizable API Gateway
  3.  * https://govway.org
  4.  *
  5.  * Copyright (c) 2005-2025 Link.it srl (https://link.it).
  6.  *
  7.  * This program is free software: you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License version 3, as published by
  9.  * the Free Software Foundation.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  *
  19.  */

  20. package org.openspcoop2.pdd.core.connettori;

  21. import java.io.ByteArrayInputStream;
  22. import java.io.FileInputStream;
  23. import java.io.InputStream;
  24. import java.util.List;
  25. import java.util.Map;

  26. import org.apache.commons.io.input.CountingInputStream;
  27. import org.openspcoop2.core.config.driver.DriverConfigurazioneException;
  28. import org.openspcoop2.core.transazioni.constants.TipoMessaggio;
  29. import org.openspcoop2.message.OpenSPCoop2MessageParseResult;
  30. import org.openspcoop2.message.constants.MessageRole;
  31. import org.openspcoop2.message.constants.MessageType;
  32. import org.openspcoop2.message.exception.ParseExceptionUtils;
  33. import org.openspcoop2.message.soap.AbstractOpenSPCoop2Message_soap_impl;
  34. import org.openspcoop2.message.soap.SoapUtils;
  35. import org.openspcoop2.message.soap.TunnelSoapUtils;
  36. import org.openspcoop2.pdd.core.CostantiPdD;
  37. import org.openspcoop2.pdd.core.controllo_traffico.DimensioneMessaggiUtils;
  38. import org.openspcoop2.pdd.core.controllo_traffico.LimitExceededNotifier;
  39. import org.openspcoop2.pdd.core.controllo_traffico.ReadTimeoutConfigurationUtils;
  40. import org.openspcoop2.pdd.core.controllo_traffico.ReadTimeoutContextParam;
  41. import org.openspcoop2.pdd.core.controllo_traffico.SogliaReadTimeout;
  42. import org.openspcoop2.pdd.core.controllo_traffico.TimeoutNotifier;
  43. import org.openspcoop2.pdd.core.controllo_traffico.TimeoutNotifierType;
  44. import org.openspcoop2.pdd.logger.DiagnosticInputStream;
  45. import org.openspcoop2.pdd.logger.MsgDiagnosticiProperties;
  46. import org.openspcoop2.pdd.logger.OpenSPCoop2Logger;
  47. import org.openspcoop2.pdd.mdb.ConsegnaContenutiApplicativi;
  48. import org.openspcoop2.protocol.sdk.ProtocolException;
  49. import org.openspcoop2.utils.CopyStream;
  50. import org.openspcoop2.utils.LimitedInputStream;
  51. import org.openspcoop2.utils.TimeoutInputStream;
  52. import org.openspcoop2.utils.Utilities;
  53. import org.openspcoop2.utils.dch.MailcapActivationReader;
  54. import org.openspcoop2.utils.io.DumpByteArrayOutputStream;
  55. import org.openspcoop2.utils.io.notifier.NotifierInputStreamParams;
  56. import org.openspcoop2.utils.transport.TransportResponseContext;
  57. import org.openspcoop2.utils.transport.TransportUtils;
  58. import org.openspcoop2.utils.transport.http.ContentTypeUtilities;
  59. import org.openspcoop2.utils.transport.http.HttpConstants;

  60. /**
  61.  * ConnettoreBaseWithResponse
  62.  *
  63.  *
  64.  * @author Poli Andrea (apoli@link.it)
  65.  * @author $Author$
  66.  * @version $Rev$, $Date$
  67.  */

  68. public abstract class ConnettoreBaseWithResponse extends ConnettoreBase {

  69.     /** InputStream Risposta */
  70.     protected InputStream isResponse = null;
  71.    
  72.     /** MessageType Risposta */
  73.     protected MessageType messageTypeResponse = null;
  74.    
  75.     /** ContentType Risposta */
  76.     protected String tipoRisposta = null;
  77.    
  78.     /** Check ContentType */
  79.     protected boolean checkContentType = true;
  80.    
  81.     /** NotifierInputStreamParams */
  82.     protected NotifierInputStreamParams notifierInputStreamParams;
  83.    
  84.     /** Imbustamento SOAP */
  85.     protected boolean imbustamentoConAttachment;
  86.     protected String mimeTypeAttachment;
  87.    
  88.     /** acceptOnlyReturnCode_202_200 SOAP */
  89.     protected boolean acceptOnlyReturnCode_202_200 = true;
  90.            
  91.     protected void normalizeInputStreamResponse(int timeout, boolean configurazioneGlobale) throws Exception{
  92.         //Se non e' null, controllo che non sia vuoto.
  93.         if(this.isResponse!=null){
  94.             this.isResponse = Utilities.normalizeStream(this.isResponse, false);
  95.         }
  96.         else{
  97.             this.logger.info("Stream di risposta (return-code:"+this.codice+") is null",true);
  98.         }
  99.        
  100.         if(this.isResponse!=null && this.useLimitedInputStream) {
  101.             if(this.limitBytes!=null && this.limitBytes.getSogliaKb()>0) {
  102.                 LimitExceededNotifier notifier = new LimitExceededNotifier(this.getPddContext(), this.limitBytes, this.logger.getLogger());
  103.                
  104.                 if(this.limitBytes.isUseContentLengthHeader()) {
  105.                     List<String> l = TransportUtils.getValues(this.propertiesTrasportoRisposta, HttpConstants.CONTENT_LENGTH);
  106.                     if(l!=null && !l.isEmpty()) {
  107.                         DimensioneMessaggiUtils.verifyByContentLength(this.logger.getLogger(), l, this.limitBytes, notifier, this.getPddContext(), DimensioneMessaggiUtils.RESPONSE);
  108.                     }
  109.                 }
  110.                
  111.                 long limitBytes = this.limitBytes.getSogliaKb()*1024; // trasformo kb in bytes
  112.                 this.isResponse = new LimitedInputStream(this.isResponse, limitBytes,
  113.                         CostantiPdD.PREFIX_LIMITED_RESPONSE,
  114.                         this.getPddContext(),
  115.                         notifier);
  116.             }
  117.         }
  118.         if(this.isResponse!=null && this.useTimeoutInputStream) {
  119.             if(timeout>0) {
  120.                 TimeoutNotifier notifier = getTimeoutNotifier(timeout, configurazioneGlobale, TimeoutNotifierType.RECEIVE_RESPONSE);
  121.                 this.isResponse = new TimeoutInputStream(this.isResponse, timeout,
  122.                         CostantiPdD.PREFIX_TIMEOUT_RESPONSE,
  123.                         this.getPddContext(),
  124.                         notifier);
  125.             }
  126.         }
  127.         if(this.isResponse!=null && this.useDiagnosticInputStream && this.msgDiagnostico!=null) {
  128.             String idModuloFunzionale =
  129.                     ConsegnaContenutiApplicativi.ID_MODULO.equals(this.idModulo) ?
  130.                             MsgDiagnosticiProperties.MSG_DIAG_CONSEGNA_CONTENUTI_APPLICATIVI : MsgDiagnosticiProperties.MSG_DIAG_INOLTRO_BUSTE;
  131.             this.isResponse = new DiagnosticInputStream(this.isResponse, idModuloFunzionale, "letturaPayloadRisposta", false, this.msgDiagnostico,
  132.                     (this.logger!=null && this.logger.getLogger()!=null) ? this.logger.getLogger() : OpenSPCoop2Logger.getLoggerOpenSPCoopCore(),
  133.                     this.getPddContext());
  134.         }
  135.     }
  136.    
  137.     protected TimeoutNotifier getTimeoutNotifier(int timeout, boolean configurazioneGlobale, TimeoutNotifierType type) throws DriverConfigurazioneException, ProtocolException {
  138.         SogliaReadTimeout soglia = null;
  139.         if(ConsegnaContenutiApplicativi.ID_MODULO.equals(this.idModulo) || this.pa!=null) {
  140.             soglia = (this.pa!=null) ?
  141.                     ReadTimeoutConfigurationUtils.buildSogliaResponseTimeout(timeout, configurazioneGlobale, this.pa, this.nomeConnettoreAsincrono, this.policyTimeoutConfig,
  142.                             new ReadTimeoutContextParam(this.requestInfo, this.getProtocolFactory(), this.getPddContext(), this.state)) :
  143.                         ReadTimeoutConfigurationUtils.buildSogliaResponseTimeout(timeout, false, this.getProtocolFactory());
  144.         }
  145.         else {
  146.             soglia = (this.pd!=null) ?
  147.                     ReadTimeoutConfigurationUtils.buildSogliaResponseTimeout(timeout, configurazioneGlobale, this.pd, this.policyTimeoutConfig,
  148.                             new ReadTimeoutContextParam(this.requestInfo, this.getProtocolFactory(), this.getPddContext(), this.state)) :
  149.                         ReadTimeoutConfigurationUtils.buildSogliaResponseTimeout(timeout, true, this.getProtocolFactory());
  150.         }
  151.         boolean saveInContext = !(this.policyTimeoutConfig!=null &&
  152.                                     (this.policyTimeoutConfig.getAttributeAuthority()!=null || this.policyTimeoutConfig.getAttributeAuthorityResponseJwt()!=null)
  153.                                 );
  154.         return new TimeoutNotifier(this.getPddContext(), this.getProtocolFactory(),
  155.                 soglia, type, this.logger.getLogger(), saveInContext);
  156.     }
  157.    
  158.     public static boolean isReadTimeoutException(Exception e, String message){
  159.         return "Read timed out".equals(message) && (e instanceof java.net.SocketTimeoutException);
  160.     }
  161.     public static boolean containsReadTimeoutException(Exception e, String message){
  162.         return message!=null && message.contains("Read timed out") && (e instanceof java.net.SocketTimeoutException || Utilities.existsInnerException(e, java.net.SocketTimeoutException.class));
  163.     }
  164.     protected void processReadTimeoutException(int timeout, boolean configurazioneGlobale, Exception e, String message) {
  165.         try {
  166.             if(timeout>0 && isReadTimeoutException(e, message)) {
  167.                 TimeoutNotifier notifier = getTimeoutNotifier(timeout, configurazioneGlobale, TimeoutNotifierType.WAIT_RESPONSE);
  168.                 notifier.notify(timeout);
  169.             }
  170.         }catch(Exception error) {
  171.             if(this.logger!=null) {
  172.                 this.logger.error("Errore avvenuto durante la registrazione dell'evento di read timeout: "+error.getMessage(),error);
  173.             }
  174.         }
  175.     }
  176.    
  177.     public static boolean isConnectionTimeoutException(Exception e, String message){
  178.         return "connect timed out".equals(message) && (e instanceof java.net.SocketTimeoutException);
  179.     }
  180.     public static boolean containsConnectionTimeoutException(Exception e, String message){
  181.         return message!=null && message.contains("connect timed out") && (e instanceof java.net.SocketTimeoutException || Utilities.existsInnerException(e, java.net.SocketTimeoutException.class));
  182.     }
  183.     protected void processConnectionTimeoutException(int timeout, boolean configurazioneGlobale, Exception e, String message) {
  184.         try {
  185.             if(timeout>0 && isConnectionTimeoutException(e, message)) {
  186.                 TimeoutNotifier notifier = getTimeoutNotifier(timeout, configurazioneGlobale, TimeoutNotifierType.CONNECTION);
  187.                 notifier.notify(timeout);
  188.             }
  189.         }catch(Exception error) {
  190.             if(this.logger!=null) {
  191.                 this.logger.error("Errore avvenuto durante la registrazione dell'evento di connection timeout: "+error.getMessage(),error);
  192.             }
  193.         }
  194.     }
  195.    
  196.     protected void initCheckContentTypeConfiguration(){    
  197.         this.checkContentType = true;
  198.         if(this.idModulo!=null){
  199.             if(ConsegnaContenutiApplicativi.ID_MODULO.equals(this.idModulo)){
  200.                 this.checkContentType = this.openspcoopProperties.isControlloContentTypeAbilitatoRicezioneBuste();
  201.             }else{
  202.                 this.checkContentType = this.openspcoopProperties.isControlloContentTypeAbilitatoRicezioneContenutiApplicativi();
  203.             }
  204.         }
  205.     }
  206.    
  207.     protected void initConfigurationAcceptOnlyReturnCode_202_200(){
  208.         this.acceptOnlyReturnCode_202_200 = true;
  209.         if(this.isRest){
  210.             this.acceptOnlyReturnCode_202_200 = false;
  211.         }
  212.         else{
  213.             if(ConsegnaContenutiApplicativi.ID_MODULO.equals(this.idModulo)){
  214.                 this.acceptOnlyReturnCode_202_200 = this.openspcoopProperties.isAcceptOnlyReturnCode_200_202_consegnaContenutiApplicativi();
  215.             }
  216.             else{
  217.                 // InoltroBuste e InoltroRisposte
  218.                 this.acceptOnlyReturnCode_202_200 = this.openspcoopProperties.isAcceptOnlyReturnCode_200_202_inoltroBuste();
  219.             }
  220.         }
  221.     }
  222.    
  223.     protected boolean dumpResponse(Map<String, List<String>> trasporto) throws Exception{
  224.        
  225.         Exception exceptionCheck = null;
  226.         try {
  227.             if(this.isRest){
  228.                 checkRestResponseMessageType();
  229.             }
  230.             else {
  231.                 checkSoapResponseMessageType();
  232.             }
  233.         }catch(Exception e) {
  234.             exceptionCheck = e;
  235.         }
  236.        
  237.         boolean returnValue = false;
  238.         try {
  239.             returnValue = _dumpResponse(trasporto);
  240.         }
  241.         catch(Exception e) {
  242.             if(exceptionCheck!=null) {
  243.                 throw exceptionCheck;
  244.             }
  245.             else {
  246.                 throw e;
  247.             }
  248.         }
  249.        
  250.         if(exceptionCheck!=null) {
  251.             throw exceptionCheck;
  252.         }
  253.         else {
  254.             return returnValue;
  255.         }

  256.     }
  257.    
  258.    
  259.     private DumpByteArrayOutputStream readResponseForDump() throws Exception{
  260.         DumpByteArrayOutputStream bout = null;
  261.         try {
  262.             bout = new DumpByteArrayOutputStream(this.dumpBinario_soglia, this.dumpBinario_repositoryFile, this.idTransazione,
  263.                     TipoMessaggio.RISPOSTA_INGRESSO_DUMP_BINARIO.getValue());
  264.            
  265.             this.emitDiagnosticStartDumpBinarioRispostaIngresso();
  266.            
  267. //              byte [] readB = new byte[Utilities.DIMENSIONE_BUFFER];
  268. //              int readByte = 0;
  269. //              while((readByte = this.isResponse.read(readB))!= -1){
  270. //                  bout.write(readB,0,readByte);
  271. //              }
  272.             //System.out.println("READ FROM ["+this.isResponse.getClass().getName()+"] ...");
  273.             CopyStream.copy(this.isResponse, bout);
  274.             //System.out.println("READ FROM ["+this.isResponse.getClass().getName()+"] complete");
  275.             this.isResponse.close();
  276.         }finally {
  277.             try {
  278.                 if(bout!=null) {
  279.                     bout.flush();
  280.                 }
  281.             }catch(Throwable t) {
  282.                 // ignore
  283.             }
  284.             try {
  285.                 if(bout!=null) {
  286.                     bout.close();
  287.                 }
  288.             }catch(Throwable t) {
  289.                 // ignore
  290.             }
  291.         }
  292.         return bout;
  293.     }
  294.    
  295.     private boolean _dumpResponse(Map<String, List<String>> trasporto) throws Exception{
  296.         if(this.isResponse!=null){
  297.            
  298.             this.emitDiagnosticResponseRead(this.isResponse);
  299.            
  300.             // Registro Debug.
  301.             DumpByteArrayOutputStream bout = null;
  302.             try {
  303.                 bout = readResponseForDump();
  304.                 if(this.debug) {
  305.                     this.logger.info("Messaggio ricevuto (ContentType:"+this.tipoRisposta+") :\n"+bout.toString(),false);
  306.                 }
  307.                 // Creo nuovo inputStream
  308.                 if(bout.isSerializedOnFileSystem()) {
  309.                     this.isResponse = new FileInputStream(bout.getSerializedFile());
  310.                 }
  311.                 else {
  312.                     this.isResponse = new ByteArrayInputStream(bout.toByteArray());
  313.                 }
  314.                
  315.                 this.dumpBinarioRispostaIngresso(bout, this.messageTypeResponse, trasporto);
  316.             }finally {
  317.                 try {
  318.                     if(bout!=null) {
  319.                         bout.clearResources();
  320.                     }
  321.                 }catch(Throwable t) {
  322.                     this.logger.error("Release resources failed: "+t.getMessage(),t);
  323.                 }
  324.             }
  325.         }
  326.         else {
  327.             if(this.debug) {
  328.                 if(this.tipoRisposta!=null) {
  329.                     this.logger.info("Messaggio ricevuto (ContentType:"+this.tipoRisposta+") senza contenuto nell'http-reply",false);
  330.                 }
  331.                 else {
  332.                     this.logger.info("Messaggio ricevuto senza contenuto nell'http-reply",false);
  333.                 }
  334.             }
  335.            
  336.             // devo registrare almeno gli header HTTP
  337.             this.emitDiagnosticStartDumpBinarioRispostaIngresso();
  338.             this.dumpBinarioRispostaIngresso(null, null, trasporto);
  339.         }
  340.        
  341.         return true;
  342.     }
  343.    
  344.     private void checkRestResponseMessageType() throws Exception{
  345.        
  346.         if(this.messageTypeResponse!=null) {
  347.             return; // gia' calcolato
  348.         }
  349.        
  350.         String msgErrore = null;
  351.         Exception exErrore = null;
  352.                
  353.         String contentTypeString = "N.D.";
  354.         if(this.tipoRisposta!=null && !"".equals(this.tipoRisposta)){
  355.             contentTypeString = this.tipoRisposta;
  356.            
  357.             // Verifico correttezza Content-Type
  358.             try {
  359.                 ContentTypeUtilities.validateContentType(contentTypeString);
  360.             }catch(Exception error){
  361.                 exErrore = error;
  362.                 msgErrore = "Content-Type '"+contentTypeString+"' presente nella risposta non valido: "+error.getMessage();
  363.             }
  364.         }
  365.        
  366.         if(msgErrore==null) {
  367.             try{
  368.                 this.messageTypeResponse = this.requestInfo.getBindingConfig().getResponseMessageType(this.requestMsg.getServiceBinding(),
  369.                         this.requestMsg.getTransportRequestContext(),
  370.                         this.tipoRisposta,
  371.                         this.codice>0?this.codice:null);                
  372.                 if(this.messageTypeResponse==null){
  373.                     String ctConosciuti = this.requestInfo.getBindingConfig().getContentTypesSupportedAsString(this.requestMsg.getServiceBinding(), MessageRole.RESPONSE,
  374.                             this.requestMsg.getTransportRequestContext());
  375.                     if(this.tipoRisposta==null){
  376.                         throw new Exception("Header Content-Type non risulta definito nell'http reply e non esiste una configurazione che supporti tale casistica. Content-Type conosciuti: "+ctConosciuti);
  377.                     }
  378.                     else {
  379.                         throw new Exception("Header Content-Type definito nell'http reply non è tra quelli conosciuti: "+ctConosciuti);
  380.                     }
  381.                    
  382.                 }
  383.             }catch(Exception e){
  384.                 exErrore = e;
  385.                 msgErrore = "Non è stato possibile comprendere come trattare il messaggio ricevuto (Content-Type: "+contentTypeString+"): "+e.getMessage();
  386.             }
  387.         }
  388.        
  389.         if(msgErrore!=null){
  390.             if(this.checkContentType){
  391.                 //if(exErrore!=null){
  392.                 this.logger.error(msgErrore,exErrore);
  393.                 //}
  394.                 //else{
  395.                 //  this.logger.error(msgErrore);
  396.                 //}
  397.                 Exception e = new Exception(msgErrore);
  398.                 this.getPddContext().addObject(org.openspcoop2.core.constants.Costanti.CONTENUTO_RISPOSTA_NON_RICONOSCIUTO, true);
  399.                 this.getPddContext().addObject(org.openspcoop2.core.constants.Costanti.CONTENUTO_RISPOSTA_NON_RICONOSCIUTO_PARSE_EXCEPTION,
  400.                         ParseExceptionUtils.buildParseException(e, MessageRole.RESPONSE));
  401.                 throw e;
  402.             }else{
  403.                 msgErrore = msgErrore+"; viene utilizzata forzatamente la tipologia "+MessageType.BINARY.name() +" come modalità di gestione del messaggio";
  404.                 //if(exErrore!=null){
  405.                 this.logger.warn(msgErrore,exErrore);
  406.                 //}
  407.                 //else{
  408.                 //  this.logger.warn(msgErrore);
  409.                 //}
  410.                 this.messageTypeResponse = MessageType.BINARY;
  411.             }
  412.         }
  413.     }
  414.    
  415.     protected boolean doRestResponse() throws Exception{
  416.         if(this.debug)
  417.             this.logger.debug("gestione REST in corso ...");
  418.        
  419.         checkRestResponseMessageType();
  420.        
  421.         InputStream isParam = null;
  422.         if(this.contentLength>=0){
  423.             isParam = this.isResponse;
  424.             if(this.contentLength==0){
  425.                 isParam = null;
  426.             }
  427.         }
  428.         else{
  429.             //non ho trovato ContentLength. Devo scoprire se c'e' un payload.
  430.             isParam = this.isResponse; // è stato normalizzato, quindi se non c'è un contenuto è null
  431.         }
  432.        
  433.         TransportResponseContext responseContext = new TransportResponseContext(this.logger.getLogger());
  434.         responseContext.setCodiceTrasporto(this.codice+"");
  435.         responseContext.setContentLength(this.contentLength);
  436.         responseContext.setHeaders(this.propertiesTrasportoRisposta);
  437.        
  438.         if(isParam!=null) {
  439.             this.emitDiagnosticResponseRead(isParam);
  440.         }
  441.        
  442.         OpenSPCoop2MessageParseResult pr = org.openspcoop2.pdd.core.Utilities.getOpenspcoop2MessageFactory(this.logger.getLogger(),this.requestMsg, this.requestInfo,MessageRole.RESPONSE).
  443.                 createMessage(this.messageTypeResponse,responseContext,
  444.                         isParam,this.notifierInputStreamParams,
  445.                         this.openspcoopProperties.getAttachmentsProcessingMode());  
  446.         if(pr.getParseException()!=null){
  447.             this.getPddContext().addObject(org.openspcoop2.core.constants.Costanti.CONTENUTO_RISPOSTA_NON_RICONOSCIUTO_PARSE_EXCEPTION, pr.getParseException());
  448.         }
  449.         try{
  450.             this.responseMsg = pr.getMessage_throwParseException();
  451.         }catch(Exception e){
  452.             this.responseMsg=null;
  453.             // L'errore 'premature end of file' consiste solo nel fatto che una risposta non e' stata ricevuta.
  454.             boolean result2XX = (this.codice>=200 && this.codice<=299);
  455.             boolean premature =  Utilities.existsInnerMessageException(e, "Premature end of file", true) && result2XX;
  456.             // Se non ho un premature, ed un errore di lettura in 200, allora devo segnalare l'errore, altrimenti comunque
  457.             // il msg ritornato e' null e nel codiceStato vi e' l'errore.
  458.            
  459.             if( premature == false ){
  460.                 this.eccezioneProcessamento = e;
  461.                 this.errore = "Errore avvenuto durante il parsing della risposta: " + this.readExceptionMessageFromException(e);
  462.                 this.logger.error("Errore avvenuto durante il parsing della risposta: " + this.readExceptionMessageFromException(e),e);
  463.                 if(result2XX){
  464.                     return false;
  465.                 }
  466.             }
  467.         }
  468.        
  469.         return true;
  470.     }
  471.    
  472.     private void checkSoapResponseMessageType() throws Exception{
  473.        
  474.         if(this.messageTypeResponse!=null) {
  475.             return; // gia' calcolato
  476.         }
  477.        
  478.         this.contentTypeMessaggioOriginale_tunnelSoap = this.tipoRisposta; // serve per funzionalità TunnelSOAP
  479.        
  480.         if(this.isResponse!=null){
  481.            
  482.             if(this.sbustamentoSoap==false){
  483.                
  484.                 String msgErrore = null;
  485.                 Exception exErrore = null;
  486.                                
  487.                 String contentTypeString = "N.D.";
  488.                 if(this.tipoRisposta!=null && !"".equals(this.tipoRisposta)){
  489.                     contentTypeString = this.tipoRisposta;
  490.                    
  491.                     // Verifico correttezza Content-Type
  492.                     try {
  493.                         ContentTypeUtilities.validateContentType(contentTypeString);
  494.                     }catch(Exception error){
  495.                         exErrore = error;
  496.                         msgErrore = "Content-Type '"+contentTypeString+"' presente nella risposta non valido: "+error.getMessage();
  497.                     }
  498.                 }
  499.                
  500.                 if(msgErrore==null) {
  501.                     try{
  502.                    
  503.                         if(this.tipoRisposta==null){
  504.                             // obbligatorio in SOAP
  505.                             msgErrore = "Header Content-Type non definito nell'http reply";
  506.                         }
  507.                         else{
  508.                             if(this.requestInfo==null) {
  509.                                 throw new Exception("BindingConfig is null");
  510.                             }
  511.                             if(this.requestInfo.getBindingConfig()==null) {
  512.                                 throw new Exception("BindingConfig is null");
  513.                             }
  514.                             if(this.requestMsg==null) {
  515.                                 throw new Exception("RequestMsg is null");
  516.                             }
  517.                             this.messageTypeResponse = this.requestInfo.getBindingConfig().getResponseMessageType(this.requestMsg.getServiceBinding(),
  518.                                     this.requestMsg.getTransportRequestContext(),
  519.                                     this.tipoRisposta,
  520.                                     this.codice>0?this.codice:null);
  521.                         }  
  522.                    
  523.                         if(this.messageTypeResponse==null){
  524.                            
  525.                             String ctConosciuti = this.requestInfo.getBindingConfig().getContentTypesSupportedAsString(this.requestMsg.getServiceBinding(), MessageRole.RESPONSE,
  526.                                     this.requestMsg.getTransportRequestContext());
  527.                            
  528.                             if(this.tipoRisposta==null){
  529.                                 throw new Exception("Header Content-Type non risulta definito nell'http reply e non esiste una configurazione che supporti tale casistica. Content-Type conosciuti: "+ctConosciuti);
  530.                             }
  531.                             else {
  532.                                 throw new Exception("Header Content-Type definito nell'http reply non è tra quelli conosciuti: "+ctConosciuti);
  533.                             }
  534.                         }
  535.                         else{
  536.                             if(this.requestMsg.getMessageType().equals(this.messageTypeResponse)==false){
  537.                                 msgErrore = "Header Content-Type definito nell'http reply associato ad un tipo ("+this.messageTypeResponse.name()
  538.                                             +") differente da quello associato al messaggio di richiesta ("+this.requestMsg.getMessageType().name()+")";
  539.                             }
  540.                         }
  541.                     }catch(Exception e){
  542.                         exErrore = e;
  543.                         msgErrore = "Non è stato possibile comprendere come trattare il messaggio ricevuto (Content-Type: "+contentTypeString+"): "+e.getMessage();
  544.                     }
  545.                 }
  546.                
  547.                 if(msgErrore!=null){
  548.                     if(this.checkContentType){
  549.                         Exception e = null;
  550.                         if(exErrore!=null){
  551.                             this.logger.error(msgErrore,exErrore);
  552.                             e = new Exception(msgErrore, exErrore);
  553.                         }
  554.                         else{
  555.                             this.logger.error(msgErrore);
  556.                             e = new Exception(msgErrore);
  557.                         }
  558.                         this.getPddContext().addObject(org.openspcoop2.core.constants.Costanti.CONTENUTO_RISPOSTA_NON_RICONOSCIUTO, true);
  559.                         this.getPddContext().addObject(org.openspcoop2.core.constants.Costanti.CONTENUTO_RISPOSTA_NON_RICONOSCIUTO_PARSE_EXCEPTION,
  560.                                 ParseExceptionUtils.buildParseException(e, MessageRole.RESPONSE));
  561.                         throw e;
  562.                     }else{
  563.                         this.messageTypeResponse = MessageType.SOAP_11;
  564.                         this.tipoRisposta = SoapUtils.getSoapContentTypeForMessageWithoutAttachments(this.messageTypeResponse);
  565.                         msgErrore = msgErrore+"; per trattare il messaggio viene utilizzato forzatamente il content-type "+this.tipoRisposta+" e la tipologia "+MessageType.SOAP_11.name();
  566.                         if(exErrore!=null){
  567.                             this.logger.warn(msgErrore,exErrore);
  568.                         }
  569.                         else{
  570.                             this.logger.warn(msgErrore);
  571.                         }                      
  572.                     }
  573.                 }
  574.             }
  575.             else{
  576.                 this.messageTypeResponse = this.requestMsg.getMessageType();
  577.                 this.tipoRisposta = SoapUtils.getSoapContentTypeForMessageWithoutAttachments(this.messageTypeResponse);
  578.             }
  579.         }
  580.     }
  581.    
  582.     private String contentTypeMessaggioOriginale_tunnelSoap = null; // serve per funzionalità TunnelSOAP;
  583.    
  584.     protected boolean doSoapResponse() throws Exception{

  585.         String tipoLetturaRisposta = null;
  586.        
  587.         // gestione ordinaria via WS/SOAP
  588.        
  589.         if(this.debug)
  590.             this.logger.debug("gestione WS/SOAP in corso ...");
  591.        
  592.         checkSoapResponseMessageType();
  593.        
  594.         if(this.isResponse!=null){
  595.            
  596.             TransportResponseContext responseContext = new TransportResponseContext(this.logger.getLogger());
  597.             responseContext.setCodiceTrasporto(this.codice+"");
  598.             responseContext.setContentLength(this.contentLength);
  599.             responseContext.setHeaders(this.propertiesTrasportoRisposta);
  600.            
  601.             this.emitDiagnosticResponseRead(this.isResponse);
  602.            
  603.             try{
  604.                
  605.                 if(this.sbustamentoSoap==false){
  606.                     if(this.debug)
  607.                         this.logger.debug("Ricostruzione normale...");
  608.                    
  609.                     // Ricostruzione messaggio soap: secondo parametro a false, indica che il messaggio e' gia un SOAPMessage
  610.                     tipoLetturaRisposta = "Parsing Risposta SOAP";
  611.                        
  612.                     if(this.contentLength>0){
  613.                         OpenSPCoop2MessageParseResult pr = org.openspcoop2.pdd.core.Utilities.getOpenspcoop2MessageFactory(this.logger.getLogger(),this.requestMsg, this.requestInfo,MessageRole.RESPONSE).
  614.                                 createMessage(this.messageTypeResponse,responseContext,
  615.                                         this.isResponse,this.notifierInputStreamParams,
  616.                                         this.openspcoopProperties.getAttachmentsProcessingMode());  
  617.                         if(pr.getParseException()!=null){
  618.                             this.getPddContext().addObject(org.openspcoop2.core.constants.Costanti.CONTENUTO_RISPOSTA_NON_RICONOSCIUTO_PARSE_EXCEPTION, pr.getParseException());
  619.                         }
  620.                         this.responseMsg = pr.getMessage_throwParseException();
  621.                     }
  622.                     else if(this.contentLength==0){
  623.                         this.responseMsg = null;
  624.                     }
  625.                     else{
  626.                         // non ho trovato ContentLength. Devo scoprire se c'e' un payload.
  627.                         // L'inputstream è stato normalizzato, quindi se non c'è un contenuto è null
  628.                         // Devo scoprire se c'e' un payload. Costruisco il messaggio e poi provo ad accedere all'envelope
  629.                         try{
  630.                             OpenSPCoop2MessageParseResult pr = org.openspcoop2.pdd.core.Utilities.getOpenspcoop2MessageFactory(this.logger.getLogger(),this.requestMsg, this.requestInfo,MessageRole.RESPONSE)
  631.                                     .createMessage(this.messageTypeResponse,responseContext,
  632.                                             this.isResponse,this.notifierInputStreamParams,
  633.                                             this.openspcoopProperties.getAttachmentsProcessingMode());
  634.                             if(pr.getParseException()!=null){
  635.                                 this.getPddContext().addObject(org.openspcoop2.core.constants.Costanti.CONTENUTO_RISPOSTA_NON_RICONOSCIUTO_PARSE_EXCEPTION, pr.getParseException());
  636.                             }
  637.                             this.responseMsg = pr.getMessage_throwParseException();
  638.                         }catch(Exception e){
  639.                             this.responseMsg=null;
  640.                             // L'errore 'premature end of file' consiste solo nel fatto che una risposta non e' stata ricevuta.
  641.                             boolean result2XX = (this.codice>=200 && this.codice<=299);
  642.                             boolean premature =  Utilities.existsInnerMessageException(e, "Premature end of file", true) && result2XX;
  643.                             // Se non ho un premature, ed un errore di lettura in 200, allora devo segnalare l'errore, altrimenti comunque
  644.                             // il msg ritornato e' null e nel codiceStato vi e' l'errore.
  645.                            
  646.                             if( premature == false ){
  647.                                 this.eccezioneProcessamento = e;
  648.                                 this.errore = "Errore avvenuto durante il parsing della risposta: " + this.readExceptionMessageFromException(e);
  649.                                 this.logger.error("Errore avvenuto durante il parsing della risposta: " + this.readExceptionMessageFromException(e),e);
  650.                                 if(result2XX){
  651.                                     return false;
  652.                                 }
  653.                             }
  654.                         }
  655.                     }
  656.                    
  657.                 }else{
  658.                     InputStream isParam = null;
  659.                     if(this.contentLength>=0){
  660.                         isParam = this.isResponse;
  661.                         if(this.contentLength==0){
  662.                             isParam = null;
  663.                         }
  664.                     }
  665.                     else{
  666.                         //non ho trovato ContentLength. Devo scoprire se c'e' un payload.
  667.                         isParam = this.isResponse; // è stato normalizzato, quindi se non c'è un contenuto è null
  668.                     }
  669.                     if(isParam!=null){
  670.                    
  671.                         CountingInputStream cis = null;
  672.                         try{
  673.                             cis = new CountingInputStream(isParam);
  674.                            
  675.                             if(this.imbustamentoConAttachment){
  676.                                 if(this.debug)
  677.                                     this.logger.debug("Imbustamento con attachments...");
  678.                                
  679.                                 // Imbustamento per Tunnel OpenSPCoop
  680.                                 tipoLetturaRisposta = "Costruzione messaggio SOAP per Tunnel con mimeType "+this.mimeTypeAttachment;
  681.                                 this.responseMsg = TunnelSoapUtils.imbustamentoMessaggioConAttachment(org.openspcoop2.pdd.core.Utilities.getOpenspcoop2MessageFactory(this.logger.getLogger(),this.requestMsg, this.requestInfo,MessageRole.RESPONSE),
  682.                                         this.messageTypeResponse,MessageRole.RESPONSE,
  683.                                         cis,this.mimeTypeAttachment,
  684.                                         MailcapActivationReader.existsDataContentHandler(this.mimeTypeAttachment),this.contentTypeMessaggioOriginale_tunnelSoap,
  685.                                         this.openspcoopProperties.getHeaderSoapActorIntegrazione());
  686.                             }else{
  687.                                 if(this.debug)
  688.                                     this.logger.debug("Imbustamento messaggio...");
  689.                                 tipoLetturaRisposta = "Imbustamento messaggio in un messaggio SOAP";
  690.                                
  691.                                 // Per ottenere il corretto content length in questo caso devo leggere tutto il messaggio
  692.                                 // ALtrimenti dopo effettuando la close, nel caso di saaj instreaming otterrei un errore (o il msg non viene cmq costruito)
  693.                                 byte[] msg = Utilities.getAsByteArray(cis);
  694.                                 if(msg==null || msg.length<=0){
  695.                                     throw new Exception("Contenuto messaggio da imbustare non presente");
  696.                                 }
  697.                                 this.isResponse.close();
  698.                                 // Creo nuovo inputStream
  699.                                 this.isResponse = new ByteArrayInputStream(msg);
  700.                                
  701.                                 OpenSPCoop2MessageParseResult pr = org.openspcoop2.pdd.core.Utilities.getOpenspcoop2MessageFactory(this.logger.getLogger(),this.requestMsg, this.requestInfo,MessageRole.RESPONSE).
  702.                                         envelopingMessage(this.messageTypeResponse, this.tipoRisposta, this.soapAction, responseContext,
  703.                                                 this.isResponse, this.notifierInputStreamParams,
  704.                                                 this.openspcoopProperties.getAttachmentsProcessingMode(),
  705.                                                 true,
  706.                                                 this.openspcoopProperties.useSoapMessageReader(), this.openspcoopProperties.getSoapMessageReaderBufferThresholdKb());
  707.                                 if(pr.getParseException()!=null){
  708.                                     this.getPddContext().addObject(org.openspcoop2.core.constants.Costanti.CONTENUTO_RISPOSTA_NON_RICONOSCIUTO_PARSE_EXCEPTION, pr.getParseException());
  709.                                 }
  710.                                 this.responseMsg = pr.getMessage_throwParseException();
  711.    
  712.                             }
  713.                            
  714.                             if(this.responseMsg!=null){
  715.                                 this.responseMsg.updateIncomingMessageContentLength(cis.getByteCount());
  716.                             }
  717.                            
  718.                         }finally{
  719.                             try{
  720.                                 if(cis!=null){
  721.                                     cis.close();
  722.                                 }
  723.                             }catch(Exception eClose){
  724.                                 // close
  725.                             }
  726.                         }
  727.                     }
  728.                    
  729.                 }
  730.                 try{
  731.                     if(this.responseMsg!=null){
  732.                         if(this.responseMsg instanceof AbstractOpenSPCoop2Message_soap_impl) {
  733.                             AbstractOpenSPCoop2Message_soap_impl<?> soap = (AbstractOpenSPCoop2Message_soap_impl<?>) this.responseMsg;
  734.                             if(!soap.hasContent()) {
  735.                                 this.responseMsg = null;
  736.                             }
  737.                         }
  738.                         else {
  739.                             this.responseMsg.castAsSoap().getSOAPPart().getEnvelope();
  740.                         }
  741.                     }
  742.                 }
  743.                 catch(Exception e){
  744.                     this.responseMsg=null;
  745.                     // L'errore 'premature end of file' consiste solo nel fatto che una risposta non e' stata ricevuta.
  746.                     boolean result2XX = (this.codice>=200 && this.codice<=299);
  747.                     boolean premature =  Utilities.existsInnerMessageException(e, "Premature end of file", true) && result2XX;
  748.                     // Se non ho un premature, ed un errore di lettura in 200, allora devo segnalare l'errore, altrimenti comunque
  749.                     // il msg ritornato e' null e nel codiceStato vi e' l'errore.
  750.                    
  751.                     if( premature == false ){
  752.                         this.eccezioneProcessamento = e;
  753.                         this.errore = "Errore avvenuto durante il parsing della risposta: " + this.readExceptionMessageFromException(e);
  754.                         this.logger.error("Errore avvenuto durante il parsing della risposta: " + this.readExceptionMessageFromException(e),e);
  755.                         if(result2XX){
  756.                             return false;
  757.                         }
  758.                     }
  759.                 }
  760.             }catch(Exception e){
  761.                 this.eccezioneProcessamento = e;
  762.                 String msgErrore = this.readExceptionMessageFromException(e);
  763.                 this.errore = "Errore avvenuto durante il processamento della risposta ("+tipoLetturaRisposta+"): " + msgErrore;
  764.                 this.logger.error("Errore avvenuto durante il processamento della risposta ("+tipoLetturaRisposta+"): " + msgErrore,e);
  765.                 return false;
  766.             }

  767.            

  768.             // save Msg
  769.             if(this.debug)
  770.                 this.logger.debug("Save messaggio...");
  771.             try{
  772.                 if(this.responseMsg!=null){
  773.                     // save changes.
  774.                     // N.B. il countAttachments serve per il msg con attachments come saveMessage!
  775.                     if(this.responseMsg.castAsSoap().hasAttachments()) {
  776.                         if(this.responseMsg.castAsSoap().countAttachments()==0){
  777.                             this.responseMsg.castAsSoap().getSOAPPart();
  778.                         }
  779.                     }
  780.                 }
  781.             }catch(Exception e){
  782.                 this.eccezioneProcessamento = e;
  783.                 this.errore = "Errore avvenuto durante il salvataggio della risposta: " + this.readExceptionMessageFromException(e);
  784.                 this.logger.error("Errore avvenuto durante il salvataggio della risposta: " + this.readExceptionMessageFromException(e),e);
  785.                 return false;
  786.             }

  787.         }
  788.        
  789.         return true;
  790.     }
  791. }