HttpServletConnectorOutMessage.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.services.connector.messages;

  21. import java.io.FileInputStream;
  22. import java.io.OutputStream;
  23. import java.util.Iterator;
  24. import java.util.List;

  25. import javax.servlet.http.HttpServletResponse;

  26. import org.apache.commons.lang.StringUtils;
  27. import org.openspcoop2.core.config.PortaApplicativa;
  28. import org.openspcoop2.core.config.PortaDelegata;
  29. import org.openspcoop2.core.config.Proprieta;
  30. import org.openspcoop2.core.id.IDPortaApplicativa;
  31. import org.openspcoop2.core.id.IDPortaDelegata;
  32. import org.openspcoop2.message.OpenSPCoop2Message;
  33. import org.openspcoop2.message.OpenSPCoop2MessageProperties;
  34. import org.openspcoop2.message.OpenSPCoop2RestMessage;
  35. import org.openspcoop2.message.OpenSPCoop2SoapMessage;
  36. import org.openspcoop2.message.constants.ServiceBinding;
  37. import org.openspcoop2.message.exception.MessageException;
  38. import org.openspcoop2.pdd.config.ConfigurazionePdDManager;
  39. import org.openspcoop2.pdd.config.CostantiProprieta;
  40. import org.openspcoop2.pdd.config.OpenSPCoop2Properties;
  41. import org.openspcoop2.pdd.services.connector.ConnectorException;
  42. import org.openspcoop2.protocol.sdk.IProtocolFactory;
  43. import org.openspcoop2.protocol.sdk.constants.IDService;
  44. import org.openspcoop2.protocol.sdk.state.RequestInfo;
  45. import org.openspcoop2.utils.LoggerWrapperFactory;
  46. import org.openspcoop2.utils.Utilities;
  47. import org.openspcoop2.utils.UtilsException;
  48. import org.openspcoop2.utils.io.DumpByteArrayOutputStream;
  49. import org.openspcoop2.utils.resources.Charset;
  50. import org.openspcoop2.utils.transport.http.RFC2047Encoding;
  51. import org.openspcoop2.utils.transport.http.RFC2047Utilities;

  52. /**
  53.  * HttpServletConnectorOutMessage
  54.  *
  55.  * @author Andrea Poli (apoli@link.it)
  56.  * @author $Author$
  57.  * @version $Rev$, $Date$
  58.  */
  59. public class HttpServletConnectorOutMessage implements ConnectorOutMessage {

  60.     protected HttpServletResponse res;
  61.     protected OutputStream outNullable;
  62.     protected IProtocolFactory<?> protocolFactory;
  63.     protected RequestInfo requestInfo;
  64.     protected String idModulo;
  65.     protected IDService idModuloAsIDService;
  66.     protected OpenSPCoop2Properties openspcoopProperties;
  67.    
  68.    
  69.     public HttpServletConnectorOutMessage(RequestInfo requestInfo,IProtocolFactory<?> protocolFactory, HttpServletResponse res,
  70.             IDService idModuloAsIDService, String idModulo) throws ConnectorException{
  71.         try{
  72.             this.res = res;
  73.             this.protocolFactory = protocolFactory;
  74.             this.requestInfo = requestInfo;
  75.             this.idModuloAsIDService = idModuloAsIDService;
  76.             this.idModulo = idModulo;
  77.             this.openspcoopProperties =  OpenSPCoop2Properties.getInstance();
  78.         }catch(Exception e){
  79.             throw new ConnectorException(e.getMessage(),e);
  80.         }
  81.     }

  82.     private void sendHeadersEngine(OpenSPCoop2Message msg) throws ConnectorException, MessageException {
  83.         if(msg==null) {
  84.             throw new ConnectorException("Message is null");
  85.         }
  86.         // Propago eventuali header http
  87.         OpenSPCoop2MessageProperties forwardHeader = null;
  88.         if(ServiceBinding.REST.equals(msg.getServiceBinding())) {
  89.             forwardHeader = msg.getForwardTransportHeader(this.openspcoopProperties.getRESTServicesHeadersForwardConfig(false));
  90.         }
  91.         else {
  92.             forwardHeader = msg.getForwardTransportHeader(this.openspcoopProperties.getSOAPServicesHeadersForwardConfig(false));
  93.         }
  94.         if(forwardHeader!=null && forwardHeader.size()>0){
  95.             Iterator<String> keys = forwardHeader.getKeys();
  96.             while (keys.hasNext()) {
  97.                 String key = keys.next();
  98.                 List<String> values = forwardHeader.getPropertyValues(key);
  99.                 if(values!=null && !values.isEmpty()) {
  100.                     for (String value : values) {
  101.                         this.addHeader(key, value);
  102.                     }
  103.                 }
  104.             }
  105.         }
  106.     }
  107.    
  108.     @Override
  109.     public void sendResponse(OpenSPCoop2Message msg, boolean consume) throws ConnectorException {
  110.         try{
  111.             if(msg==null) {
  112.                 throw new ConnectorException("Message is null");
  113.             }
  114.            
  115.             // Propago eventuali header http
  116.             this.sendHeadersEngine(msg);
  117.            
  118.             boolean hasContent = false;
  119.            
  120.             // il save e' necessario con i connettori directVM in caso di errori di validazione
  121.             if(ServiceBinding.SOAP.equals(msg.getServiceBinding())){
  122.                 hasContent = true;
  123.                 OpenSPCoop2SoapMessage soap = msg.castAsSoap();
  124.                 if(soap.hasSOAPFault()){
  125.                     soap.saveChanges();
  126.                 }
  127.             }
  128.             if(ServiceBinding.REST.equals(msg.getServiceBinding())){
  129.                 OpenSPCoop2RestMessage<?> rest = msg.castAsRest();
  130.                 hasContent = rest.hasContent();
  131.             }
  132.            
  133.             if(hasContent) {
  134.                 this.outNullable = this.res.getOutputStream();
  135.                 msg.writeTo(this.outNullable,consume);
  136.             }
  137.         }catch(Exception e){
  138.             throw new ConnectorException(e.getMessage(),e);
  139.         }
  140.     }
  141.    
  142.     @Override
  143.     public void sendResponse(DumpByteArrayOutputStream message) throws ConnectorException{
  144.         try{
  145.             if(message!=null && message.size()>0) {
  146.                 this.outNullable = this.res.getOutputStream();
  147.                 if(message.isSerializedOnFileSystem()) {
  148.                     try(FileInputStream fin = new FileInputStream(message.getSerializedFile())) {
  149.                         Utilities.copy(fin, this.outNullable);
  150.                     }
  151.                 }
  152.                 else {
  153.                     this.outNullable.write(message.toByteArray());
  154.                 }
  155.             }
  156.         }catch(Exception e){
  157.             throw new ConnectorException(e.getMessage(),e);
  158.         }
  159.     }
  160.    
  161.     @Override
  162.     public void sendResponseHeaders(OpenSPCoop2Message message) throws ConnectorException{
  163.         try{
  164.             // Propago eventuali header http
  165.             this.sendHeadersEngine(message);
  166.         }catch(Exception e){
  167.             throw new ConnectorException(e.getMessage(),e);
  168.         }
  169.     }
  170.    
  171.     @Override
  172.     public void setHeader(String key,String value) throws ConnectorException{
  173.         putHeaderEngine(key,value,false);
  174.     }
  175.     @Override
  176.     public void addHeader(String key,String value) throws ConnectorException{
  177.         putHeaderEngine(key,value,true);
  178.     }
  179.     private void putHeaderEngine(String key,String value, boolean add) throws ConnectorException{
  180.         try{
  181.             if(value==null) {
  182.                 return;
  183.             }
  184.            
  185.             boolean encodingRFC2047 = false;
  186.             Charset charsetRFC2047 = null;
  187.             RFC2047Encoding encodingAlgorithmRFC2047 = null;
  188.             boolean validazioneHeaderRFC2047 = false;
  189.             List<Proprieta> listProprieta = null;
  190.             if(this.idModuloAsIDService!=null){
  191.                 switch (this.idModuloAsIDService) {
  192.                 case PORTA_DELEGATA:
  193.                 case PORTA_DELEGATA_INTEGRATION_MANAGER:
  194.                 case PORTA_DELEGATA_XML_TO_SOAP:
  195.                     encodingRFC2047 = this.openspcoopProperties.isEnabledEncodingRFC2047HeaderValueRicezioneContenutiApplicativi();
  196.                     charsetRFC2047 = this.openspcoopProperties.getCharsetEncodingRFC2047HeaderValueRicezioneContenutiApplicativi();
  197.                     encodingAlgorithmRFC2047 = this.openspcoopProperties.getEncodingRFC2047HeaderValueRicezioneContenutiApplicativi();
  198.                     validazioneHeaderRFC2047 = this.openspcoopProperties.isEnabledValidazioneRFC2047HeaderNameValueRicezioneContenutiApplicativi();
  199.                     listProprieta = readProprietaPortaDelegata();
  200.                     break;
  201.                 case PORTA_APPLICATIVA:
  202.                     encodingRFC2047 = this.openspcoopProperties.isEnabledEncodingRFC2047HeaderValueRicezioneBuste();
  203.                     charsetRFC2047 = this.openspcoopProperties.getCharsetEncodingRFC2047HeaderValueRicezioneBuste();
  204.                     encodingAlgorithmRFC2047 = this.openspcoopProperties.getEncodingRFC2047HeaderValueRicezioneBuste();
  205.                     validazioneHeaderRFC2047 = this.openspcoopProperties.isEnabledValidazioneRFC2047HeaderNameValueRicezioneBuste();
  206.                     listProprieta = readProprietaPortaApplicativa();
  207.                     break;
  208.                 default:
  209.                     break;
  210.                 }
  211.             }
  212.            
  213.             encodingRFC2047 = CostantiProprieta.isConnettoriHeaderValueEncodingRFC2047ResponseEnabled(listProprieta, encodingRFC2047);
  214.             charsetRFC2047 = CostantiProprieta.getConnettoriHeaderValueEncodingRFC2047ResponseCharset(listProprieta, charsetRFC2047);
  215.             encodingAlgorithmRFC2047 = CostantiProprieta.getConnettoriHeaderValueEncodingRFC2047ResponseType(listProprieta, encodingAlgorithmRFC2047);
  216.             validazioneHeaderRFC2047 = CostantiProprieta.isConnettoriHeaderValidationResponseEnabled(listProprieta, validazioneHeaderRFC2047);
  217.             /**System.out.println("@@@@ encodingRFC2047["+encodingRFC2047+"] charsetRFC2047["+charsetRFC2047+"] encodingAlgorithmRFC2047["+encodingAlgorithmRFC2047+"] validazioneHeaderRFC2047["+validazioneHeaderRFC2047+"]");*/
  218.             if(encodingRFC2047){
  219.                 /**System.out.println("@@@@ CONTROLLO '"+value+" rispetto a '"+charsetRFC2047+"': "+RFC2047Utilities.isAllCharactersInCharset(value, charsetRFC2047));*/
  220.                 if(!RFC2047Utilities.isAllCharactersInCharset(value, charsetRFC2047)){
  221.                     String encoded = RFC2047Utilities.encode((value+""), charsetRFC2047, encodingAlgorithmRFC2047);
  222.                     /**System.out.println("@@@@ RESPONSE CODIFICA ["+value+"] in ["+encoded+"]");*/
  223.                     this.putResponseHeader(validazioneHeaderRFC2047, key, encoded, add);
  224.                 }
  225.                 else{
  226.                     this.putResponseHeader(validazioneHeaderRFC2047, key, value, add);
  227.                 }
  228.             }
  229.             else{
  230.                 this.putResponseHeader(validazioneHeaderRFC2047, key, value, add);
  231.             }  
  232.            
  233.         }catch(Exception e){
  234.             throw new ConnectorException(e.getMessage(),e);
  235.         }
  236.     }
  237.    
  238.     private List<Proprieta> readProprietaPortaApplicativa(){
  239.         if(this.requestInfo!=null && this.requestInfo.getProtocolContext()!=null && this.requestInfo.getProtocolContext().getInterfaceName()!=null &&
  240.                 StringUtils.isNotEmpty(this.requestInfo.getProtocolContext().getInterfaceName())) {
  241.             IDPortaApplicativa idPA = new IDPortaApplicativa();
  242.             idPA.setNome(this.requestInfo.getProtocolContext().getInterfaceName());
  243.             try {
  244.                 PortaApplicativa pa = ConfigurazionePdDManager.getInstance().getPortaApplicativaSafeMethod(idPA, this.requestInfo);
  245.                 if(pa!=null && pa.sizeProprieta()>0) {
  246.                     return pa.getProprieta();
  247.                 }
  248.             }catch(Exception e) {
  249.                 if(this.protocolFactory!=null && this.protocolFactory.getLogger()!=null) {
  250.                     this.protocolFactory.getLogger().error("Accesso porta applicativa ["+this.requestInfo.getProtocolContext().getInterfaceName()+"] fallito: "+e.getMessage(),e);
  251.                 }
  252.             }
  253.         }
  254.         return null;
  255.     }
  256.     private List<Proprieta> readProprietaPortaDelegata(){
  257.         if(this.requestInfo!=null && this.requestInfo.getProtocolContext()!=null && this.requestInfo.getProtocolContext().getInterfaceName()!=null &&
  258.                 StringUtils.isNotEmpty(this.requestInfo.getProtocolContext().getInterfaceName())) {
  259.             IDPortaDelegata idPD = new IDPortaDelegata();
  260.             idPD.setNome(this.requestInfo.getProtocolContext().getInterfaceName());
  261.             try {
  262.                 PortaDelegata pd = ConfigurazionePdDManager.getInstance().getPortaDelegataSafeMethod(idPD, this.requestInfo);
  263.                 if(pd!=null && pd.sizeProprieta()>0) {
  264.                     return pd.getProprieta();
  265.                 }
  266.             }catch(Exception e) {
  267.                 if(this.protocolFactory!=null && this.protocolFactory.getLogger()!=null) {
  268.                     this.protocolFactory.getLogger().error("Accesso porta applicativa ["+this.requestInfo.getProtocolContext().getInterfaceName()+"] fallito: "+e.getMessage(),e);
  269.                 }
  270.             }
  271.         }
  272.         return null;
  273.     }
  274.    
  275.     private void putResponseHeader(boolean validazioneHeaderRFC2047, String key, String value, boolean add) {
  276.        
  277.         if(validazioneHeaderRFC2047){
  278.             try{
  279.                 RFC2047Utilities.validHeader(key, value);
  280.                 if(add) {
  281.                     this.res.addHeader(key,value);
  282.                 }
  283.                 else {
  284.                     this.res.setHeader(key,value);
  285.                 }
  286.             }catch(UtilsException e){
  287.                 if(this.protocolFactory!=null && this.protocolFactory.getLogger()!=null){
  288.                     this.protocolFactory.getLogger().error(e.getMessage(),e);
  289.                 }
  290.                 else{
  291.                     LoggerWrapperFactory.getLogger(HttpServletConnectorOutMessage.class).error(e.getMessage(),e);      
  292.                 }
  293.             }
  294.         }
  295.         else{
  296.             if(add) {
  297.                 this.res.addHeader(key,value);
  298.             }
  299.             else {
  300.                 this.res.setHeader(key,value);
  301.             }
  302.         }
  303.        
  304.     }
  305.    
  306.     @Override
  307.     public void setContentLength(int length) throws ConnectorException{
  308.         try{
  309.             this.res.setContentLength(length);
  310.         }catch(Exception e){
  311.             throw new ConnectorException(e.getMessage(),e);
  312.         }
  313.     }
  314.    
  315.     @Override
  316.     public void setContentType(String type) throws ConnectorException{
  317.         try{
  318.             this.res.setContentType(type);
  319.         }catch(Exception e){
  320.             throw new ConnectorException(e.getMessage(),e);
  321.         }
  322.     }
  323.    
  324.     private int status = -1;
  325.     @Override
  326.     public void setStatus(int status) throws ConnectorException{
  327.         try{
  328.             this.res.setStatus(status);
  329.             this.status = status;
  330.         }catch(Exception e){
  331.             throw new ConnectorException(e.getMessage(),e);
  332.         }
  333.     }
  334.     @Override
  335.     public int getResponseStatus() throws ConnectorException{
  336.         return this.status;
  337.     }
  338.    
  339.     @Override
  340.     public void flush(boolean throwException) throws ConnectorException{
  341.         try{
  342.             // Flush and close response
  343.             // NOTA: per poter ottenere l'errore di BrokenPipe sempre, deve essere disabilitato il socketBufferOutput sul servlet container.
  344.             // Se non lo si disabilta, l'errore viene ritornato solo se il messaggio supera la dimensione del buffer (default: 8192K)
  345.             // Ad esempio in tomcat utilizzare (socketBuffer="-1"):
  346.             //    <Connector protocol="HTTP/1.1" port="8080" address="${jboss.bind.address}"
  347.             //       connectionTimeout="20000" redirectPort="8443" socketBuffer="-1" />
  348.             if(this.res!=null){
  349.                 try{
  350.                     this.res.flushBuffer();
  351.                 }catch(Exception e){
  352.                     if(throwException){
  353.                         throw e;
  354.                     }
  355.                 }
  356.             }
  357.             if(this.outNullable!=null){
  358.                 try{
  359.                     this.outNullable.flush();
  360.                 }catch(Exception e){
  361.                     if(throwException){
  362.                         throw e;
  363.                     }
  364.                 }
  365.             }
  366.         }catch(Exception e){
  367.             throw new ConnectorException(e.getMessage(),e);
  368.         }  
  369.     }
  370.    
  371.     @Override
  372.     public void close(boolean throwException) throws ConnectorException{
  373.         try{
  374.             if(this.outNullable!=null){
  375.                 try{
  376.                     this.outNullable.close();
  377.                     this.outNullable = null;
  378.                 }catch(Exception e){
  379.                     if(throwException){
  380.                         throw e;
  381.                     }
  382.                 }
  383.             }
  384.         }catch(Exception e){
  385.             throw new ConnectorException(e.getMessage(),e);
  386.         }  
  387.     }
  388. }