AbstractBaseOpenSPCoop2MessageDynamicContent.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.message;

  21. import java.io.ByteArrayInputStream;
  22. import java.io.File;
  23. import java.io.FileInputStream;
  24. import java.io.InputStream;
  25. import java.io.OutputStream;
  26. import java.io.SequenceInputStream;

  27. import org.apache.commons.io.input.CountingInputStream;
  28. import org.apache.commons.io.output.CountingOutputStream;
  29. import org.openspcoop2.message.constants.Costanti;
  30. import org.openspcoop2.message.exception.MessageException;
  31. import org.openspcoop2.message.exception.MessageNotSupportedException;
  32. import org.openspcoop2.message.soap.reader.OpenSPCoop2MessageSoapStreamReader;
  33. import org.openspcoop2.utils.CopyStream;
  34. import org.openspcoop2.utils.Utilities;
  35. import org.openspcoop2.utils.io.DumpByteArrayOutputStream;
  36. import org.openspcoop2.utils.resources.Charset;
  37. import org.openspcoop2.utils.transport.http.ContentTypeUtilities;

  38. /**
  39.  * AbstractBaseOpenSPCoop2RestMessage
  40.  *
  41.  * @author Andrea Poli (apoli@link.it)
  42.  * @author $Author$
  43.  * @version $Rev$, $Date$
  44.  */
  45. public abstract class AbstractBaseOpenSPCoop2MessageDynamicContent<T> extends AbstractBaseOpenSPCoop2Message {

  46.     protected CountingInputStream _countingInputStream;
  47.     protected String contentType;
  48.     protected String contentTypeCharsetName = Charset.UTF_8.getValue();

  49.     protected boolean supportReadOnly = true;

  50.     protected boolean contentUpdatable = false;
  51.     protected T content;
  52.     protected boolean hasContent = false;

  53.     protected OpenSPCoop2MessageSoapStreamReader soapStreamReader;

  54.     protected DumpByteArrayOutputStream contentBuffer;
  55.     private static int soglia;
  56.     private static File repositoryFile;

  57.     public static void setSoglia(int soglia) {
  58.         AbstractBaseOpenSPCoop2MessageDynamicContent.soglia = soglia;
  59.     }

  60.     public static void setRepositoryFile(File repositoryFile) {
  61.         AbstractBaseOpenSPCoop2MessageDynamicContent.repositoryFile = repositoryFile;
  62.     }

  63.     private static boolean soapReader = false; // attivato sul gateway tramite il metodo sottostante; in modo che le
  64.                                                 // altre applicazioni non utilizzino questa funzionalità
  65.                                                 // (TestService,Console...)
  66.     private static int soapReaderBufferThresholdKb = 10;

  67.     public static void setSoapReader(boolean soapReader) {
  68.         AbstractBaseOpenSPCoop2MessageDynamicContent.soapReader = soapReader;
  69.     }

  70.     public static void setSoapReaderBufferThresholdKb(int bufferThresholdKb) {
  71.         AbstractBaseOpenSPCoop2MessageDynamicContent.soapReaderBufferThresholdKb = bufferThresholdKb;
  72.     }

  73.     /* Costruttore */

  74.     protected AbstractBaseOpenSPCoop2MessageDynamicContent(OpenSPCoop2MessageFactory messageFactory) {
  75.         super(messageFactory);
  76.         this.hasContent = false;
  77.     }

  78.     protected AbstractBaseOpenSPCoop2MessageDynamicContent(OpenSPCoop2MessageFactory messageFactory,
  79.             InputStream isParam, String contentType, boolean soap, OpenSPCoop2MessageSoapStreamReader soapStreamReader)
  80.             throws MessageException {
  81.         super(messageFactory);
  82.         try {
  83.             this.contentType = contentType;
  84.             if (contentType != null) {
  85.                 String ch = ContentTypeUtilities.readCharsetFromContentType(contentType);
  86.                 if (ch != null) {
  87.                     this.contentTypeCharsetName = ch;
  88.                 }
  89.             }
  90.             if (isParam != null) {

  91.                 if (soap && soapStreamReader != null) {
  92.                     soapStreamReader.checkException(); // senno si entra nell'if dello stream vuoto prima
  93.                 }

  94.                 // check se esiste del contenuto nello stream, lo stream può essere diverso da
  95.                 // null però vuoto.
  96.                 InputStream normalizedIs = Utilities.normalizeStream(isParam, false);
  97.                 if (normalizedIs == null) {
  98.                     // stream vuoto
  99.                     this.hasContent = false;
  100.                 } else {

  101.                     if (soap) {
  102.                         if (soapStreamReader == null) {
  103.                             if (AbstractBaseOpenSPCoop2MessageDynamicContent.soapReader) {
  104.                                 this.soapStreamReader = new OpenSPCoop2MessageSoapStreamReader(messageFactory,
  105.                                         this.contentType, normalizedIs,
  106.                                         AbstractBaseOpenSPCoop2MessageDynamicContent.soapReaderBufferThresholdKb);
  107.                                 try {
  108.                                     this.soapStreamReader.read();
  109.                                 } finally {
  110.                                     // anche in caso di eccezione devo cmq aggiornare is
  111.                                     normalizedIs = this.soapStreamReader.getBufferedInputStream();
  112.                                 }
  113.                             }
  114.                         } else {
  115.                             this.soapStreamReader = soapStreamReader;
  116.                             if (this.soapStreamReader != null) {
  117.                                 this.soapStreamReader.checkException();
  118.                             }
  119.                         }
  120.                     }

  121.                     this._countingInputStream = new CountingInputStream(normalizedIs);
  122.                     this.hasContent = true;
  123.                 }

  124.             }
  125.         } catch (Exception e) {
  126.             throw new MessageException(e.getMessage(), e);
  127.         }
  128.     }

  129.     /* Metodi richiesti da chi implementa questa classe base */

  130.     protected abstract T buildContent() throws MessageException;

  131.     protected abstract T buildContent(DumpByteArrayOutputStream contentBuffer) throws MessageException;

  132.     protected abstract String buildContentAsString() throws MessageException;

  133.     protected abstract byte[] buildContentAsByteArray() throws MessageException;

  134.     protected abstract void serializeContent(OutputStream os, boolean consume) throws MessageException;

  135.     protected void setUpdatableContent() throws MessageException {
  136.     }

  137.     /* Informazioni SOAP (senza costruire il DOM) */

  138.     public OpenSPCoop2MessageSoapStreamReader getSoapReader() {
  139.         return this.soapStreamReader;
  140.     }

  141.     public void releaseSoapReader() {
  142.         if (this.soapStreamReader != null) {
  143.             this.soapStreamReader.releaseBufferedInputStream();
  144.             this.soapStreamReader.clearHeader();
  145.             this.soapStreamReader = null;
  146.         }
  147.     }

  148.     /* Input Stream con costruzione del buffer incrementale */
  149.    
  150.     public boolean setInputStreamLazyBuffer(String idTransazione) throws MessageException{
  151.        
  152.         if(this._countingInputStream==null) {
  153.             return false;
  154.         }
  155.         if(this.content != null || this.contentBuffer!=null) {
  156.             return false;
  157.         }
  158.         if(! (this._countingInputStream instanceof OpenSPCoop2InputStreamDynamicContent) ) {
  159.             DumpByteArrayOutputStream contentBuffer = new DumpByteArrayOutputStream(
  160.                     AbstractBaseOpenSPCoop2MessageDynamicContent.soglia,
  161.                     AbstractBaseOpenSPCoop2MessageDynamicContent.repositoryFile, idTransazione,
  162.                     this.getMessageRole().name());
  163.             this._countingInputStream = new OpenSPCoop2InputStreamDynamicContent(this._countingInputStream, contentBuffer);
  164.         }
  165.         return true; // se è già OpenSPCoop2InputStreamDynamicContent torno true

  166.     }
  167.    
  168.     /* Contenuto */

  169.     private synchronized void initializeContent(boolean readOnly, String idTransazione) throws MessageException {
  170.         if (this.hasContent) {
  171.             if (this.content == null) {

  172.                 if (readOnly && this.supportReadOnly) {
  173.                     if(this._countingInputStream instanceof OpenSPCoop2InputStreamDynamicContent) {
  174.                         // se e' un OpenSPCoop2InputStreamDynamicContent dovrebbe gia' essere stato inizializzato il buffer
  175.                         this._countingInputStream = ((OpenSPCoop2InputStreamDynamicContent)this._countingInputStream).getWrappedInputStream();
  176.                         this.contentBuffer = ((OpenSPCoop2InputStreamDynamicContent)this._countingInputStream).getBuffer();
  177.                     }
  178.                     else {
  179.                         this.contentBuffer = new DumpByteArrayOutputStream(
  180.                                 AbstractBaseOpenSPCoop2MessageDynamicContent.soglia,
  181.                                 AbstractBaseOpenSPCoop2MessageDynamicContent.repositoryFile, idTransazione,
  182.                                 this.getMessageRole().name());
  183.                     }
  184.                     try {
  185.                         CopyStream.copy(this._countingInputStream, this.contentBuffer); // se e' un OpenSPCoop2InputStreamDynamicContent riverso quello che rimane nel buffer
  186.                         this.content = this.buildContent(this.contentBuffer);
  187.                     } catch (Throwable t) {
  188.                         MessageUtils.registerParseException(this, t, true);
  189.                         throw new MessageException(t.getMessage(), t);
  190.                     } finally {
  191.                         try {
  192.                             this._countingInputStream.close();
  193.                         } catch (Exception eClose) {
  194.                         }
  195.                     }
  196.                 } else {
  197.                     try {
  198.                         this.content = this.buildContent();
  199.                     } catch (Throwable t) {
  200.                         MessageUtils.registerParseException(this, t, true);
  201.                         throw new MessageException(t.getMessage(), t);
  202.                     }
  203.                 }

  204.             }
  205.         }
  206.     }

  207.     @Override
  208.     public boolean isContentBuilded() {
  209.         return this.content != null;
  210.     }

  211.     public InputStream getInputStreamFromContentBuffer() throws MessageException {
  212.         if(this.contentBuffer==null) {
  213.             return null;
  214.         }
  215.         try {
  216.             if(this.contentBuffer.isSerializedOnFileSystem()) {
  217.                 return new FileInputStream(this.contentBuffer.getSerializedFile());
  218.             }
  219.             else {
  220.                 return new ByteArrayInputStream(this.contentBuffer.toByteArray());
  221.             }
  222.         }catch(Exception e) {
  223.             throw new MessageException(e.getMessage(),e);
  224.         }
  225.     }

  226.     public InputStream getInputStream() {
  227.         return this._countingInputStream;
  228.     }

  229.     protected InputStream _getInputStream() throws MessageException {
  230.         if(this._countingInputStream instanceof OpenSPCoop2InputStreamDynamicContent) {
  231.             OpenSPCoop2InputStreamDynamicContent di = ((OpenSPCoop2InputStreamDynamicContent)this._countingInputStream);
  232.             DumpByteArrayOutputStream bf = di.getBuffer();
  233.             if(bf!=null && bf.size()>0) {
  234.                 this._countingInputStream = di.getWrappedInputStream();
  235.                 InputStream isBuffered = bf.getInputStream();
  236.                 try {
  237.                     InputStream isRemained = Utilities.normalizeStream(this._countingInputStream, false);
  238.                     if(di.isInputStreamConsumed() || (isRemained==null) ) {
  239.                         return isBuffered;
  240.                     }
  241.                     else {
  242.                         return new SequenceInputStream(isBuffered,isRemained);
  243.                     }
  244.                 }catch(Exception e) {
  245.                     throw new MessageException(e.getMessage(),e);
  246.                 }
  247.             }
  248.             else {
  249.                 return this._countingInputStream;
  250.             }
  251.         }
  252.         else {
  253.             return this._countingInputStream;
  254.         }
  255.     }
  256.    
  257.     public boolean hasContent() throws MessageException, MessageNotSupportedException {
  258.         return this.hasContent;
  259.     }

  260.     public void initContent() throws MessageException,MessageNotSupportedException{
  261.         getContent();
  262.     }
  263.     public void initContent(boolean readOnly, String idTransazione) throws MessageException,MessageNotSupportedException{
  264.         getContent(readOnly, idTransazione);
  265.     }
  266.    
  267.     public T getContent() throws MessageException, MessageNotSupportedException {
  268.         return getContent(false, null);
  269.     }

  270.     public T getContent(boolean readOnly, String idTransazione) throws MessageException, MessageNotSupportedException {
  271.         if (this.hasContent) {
  272.             if (!readOnly) {
  273.                 boolean aggiornaContenuto = false;
  274.                 if (this.content != null && !this.contentUpdatable) {
  275.                     aggiornaContenuto = true;
  276.                 }
  277.                 this.contentUpdatable = true;
  278.                 if (aggiornaContenuto) {
  279.                     // contenuto precedentemente già creato in modalità read-only
  280.                     // il metodo ha bisogno che contentUpdatable sia a true
  281.                     setUpdatableContent();
  282.                 }
  283.             }
  284.             // nota l'assegnazione di contentUpdatable viene usata poi dentro
  285.             // l'inizializzaizone del contenuto per rilasciare le risorse
  286.             if (this.content == null) {
  287.                 this.initializeContent(readOnly, idTransazione);
  288.             }
  289.         }
  290.         return this.content; // può tornare null
  291.     }

  292.     public String getContentAsString() throws MessageException, MessageNotSupportedException {
  293.         return getContentAsString(false, null);
  294.     }

  295.     public String getContentAsString(boolean readOnly, String idTransazione)
  296.             throws MessageException, MessageNotSupportedException {
  297.         try {
  298.             if (this.hasContent) {
  299.                 if (this.content == null) {
  300.                     this.initializeContent(readOnly, idTransazione);
  301.                 }

  302.                 if (!readOnly) {
  303.                     this.contentUpdatable = true;
  304.                 }

  305.                 return this.buildContentAsString();
  306.             }
  307.             return null;
  308.         } catch (MessageException e) {
  309.             throw e;
  310.         } catch (Exception e) {
  311.             throw new MessageException(e.getMessage(), e);
  312.         }
  313.     }

  314.     public byte[] getContentAsByteArray() throws MessageException, MessageNotSupportedException {
  315.         return getContentAsByteArray(false, null);
  316.     }

  317.     public byte[] getContentAsByteArray(boolean readOnly, String idTransazione)
  318.             throws MessageException, MessageNotSupportedException {
  319.         try {
  320.             if (this.hasContent) {
  321.                 if (this.content == null) {
  322.                     this.initializeContent(readOnly, idTransazione);
  323.                 }

  324.                 if (!readOnly) {
  325.                     this.contentUpdatable = true;
  326.                 }

  327.                 return this.buildContentAsByteArray();
  328.             }
  329.             return null;
  330.         } catch (MessageException e) {
  331.             throw e;
  332.         } catch (Exception e) {
  333.             throw new MessageException(e.getMessage(), e);
  334.         }
  335.     }

  336.     public void updateContent(T content) throws MessageException, MessageNotSupportedException {
  337.         this.content = content;
  338.         this.contentUpdatable = true;
  339.         if (this.contentBuffer != null) {
  340.             this.contentBuffer.clearResources();
  341.             this.contentBuffer = null;
  342.         }
  343.         if (this.content != null) {
  344.             this.hasContent = true;
  345.         } else {
  346.             this.hasContent = false;
  347.             this.contentType = null;
  348.         }
  349.     }

  350.     public void setContentUpdatable() {
  351.         this.contentUpdatable = true;
  352.     }

  353.     /* ContentType */

  354.     @Override
  355.     public void updateContentType() throws MessageException {
  356.         // nop;
  357.     }

  358.     @Override
  359.     public void setContentType(String type) {
  360.         this.contentType = type;
  361.     }

  362.     @Override
  363.     public String getContentType() {
  364.         return this.contentType;
  365.     }

  366.     /* WriteTo e Save */

  367.     @Override
  368.     public void writeTo(OutputStream os, boolean consume) throws MessageException {
  369.         this.writeTo(os, consume, false, null);
  370.     }

  371.     public void writeTo(OutputStream os, boolean consume, boolean readOnly, String idTransazione)
  372.             throws MessageException {
  373.         writeTo(os, consume, readOnly, idTransazione, null);
  374.     }

  375.     public void writeTo(OutputStream os, boolean consume, boolean readOnly, String idTransazione, StringBuilder debug)
  376.             throws MessageException {
  377.         try {
  378.             if (this.hasContent) {

  379.                 if (!consume && this.content == null) {
  380.                     if (!readOnly) {
  381.                         this.contentUpdatable = true; // riverso soap header eventuale nel content che verrà costruito
  382.                     }
  383.                     this.initializeContent(readOnly, idTransazione); // per poi entrare nel ramo sotto serializeContent
  384.                 }

  385.                 CountingOutputStream cos = new CountingOutputStream(os);
  386.                 if (this.contentBuffer != null && !this.contentUpdatable) {
  387.                     if (this.soapStreamReader != null && this.soapStreamReader.isSoapHeaderModified()
  388.                             && this.contentType != null) {
  389.                         if (debug != null) {
  390.                             debug.append(Costanti.WRITE_MODE_SERIALIZE_BUFFER_WITH_HEADER);
  391.                         }
  392.                         this.soapStreamReader.writeOptimizedHeaderTo(this.contentBuffer.getInputStream(), cos, true);
  393.                     } else {
  394.                         if (debug != null) {
  395.                             debug.append(Costanti.WRITE_MODE_SERIALIZE_BUFFER);
  396.                         }
  397.                         this.contentBuffer.writeTo(cos);
  398.                     }
  399.                 } else if (this.content != null) {
  400.                     if (debug != null) {
  401.                         debug.append(Costanti.WRITE_MODE_SERIALIZE_CONTENT);
  402.                     }
  403.                     this.serializeContent(cos, consume);
  404.                 } else {
  405.                     if (this.soapStreamReader != null && this.soapStreamReader.isSoapHeaderModified()) {
  406.                         if (debug != null) {
  407.                             debug.append(Costanti.WRITE_MODE_SERIALIZE_STREAM_WITH_HEADER);
  408.                         }
  409.                         this.soapStreamReader.writeOptimizedHeaderTo(this._getInputStream(), cos, true);
  410.                     } else {
  411.                         if (debug != null) {
  412.                             debug.append(Costanti.WRITE_MODE_SERIALIZE_STREAM);
  413.                         }
  414.                         Utilities.copy(this._getInputStream(), cos);
  415.                         this._getInputStream().close();
  416.                     }
  417.                 }
  418.                 this.outgoingsize = cos.getByteCount();
  419.             }
  420.         } catch (MessageException e) {
  421.             throw e;
  422.         } catch (Exception e) {
  423.             throw new MessageException(e.getMessage(), e);
  424.         } finally {
  425.             if (consume) {
  426.                 try {
  427.                     if (this.contentBuffer != null) {
  428.                         this.contentBuffer.unlock();
  429.                         this.contentBuffer.clearResources();
  430.                         this.contentBuffer = null;
  431.                     }
  432.                 } catch (Throwable t) {
  433.                 }
  434.             }
  435.         }
  436.     }

  437.     @Override
  438.     public void saveChanges() throws MessageException {
  439.         // nop;
  440.     }

  441.     @Override
  442.     public boolean saveRequired() {
  443.         return false;
  444.     }

  445.     /* Content Length */

  446.     @Override
  447.     public long getIncomingMessageContentLength() {
  448.         if (this._countingInputStream != null) {
  449.             return this._countingInputStream.getByteCount();
  450.         } else {
  451.             return super.getIncomingMessageContentLength();
  452.         }
  453.     }

  454. }