DigestServiceParamsDriver.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.config;

  21. import java.sql.Connection;
  22. import java.sql.PreparedStatement;
  23. import java.sql.ResultSet;
  24. import java.sql.SQLException;
  25. import java.sql.Timestamp;
  26. import java.time.Duration;
  27. import java.time.Instant;

  28. import org.openspcoop2.core.config.driver.DriverConfigurazioneException;
  29. import org.openspcoop2.core.config.driver.db.DriverConfigurazioneDB;
  30. import org.openspcoop2.core.constants.CostantiDB;
  31. import org.openspcoop2.core.id.IDServizio;
  32. import org.openspcoop2.pdd.core.GestoreMessaggi;
  33. import org.openspcoop2.utils.SemaphoreLock;
  34. import org.openspcoop2.utils.TipiDatabase;
  35. import org.openspcoop2.utils.Utilities;
  36. import org.openspcoop2.utils.UtilsException;
  37. import org.openspcoop2.utils.digest.DigestType;
  38. import org.openspcoop2.utils.id.serial.InfoStatistics;
  39. import org.openspcoop2.utils.semaphore.Semaphore;
  40. import org.openspcoop2.utils.semaphore.SemaphoreConfiguration;
  41. import org.openspcoop2.utils.semaphore.SemaphoreMapping;
  42. import org.openspcoop2.utils.sql.ISQLQueryObject;
  43. import org.openspcoop2.utils.sql.SQLObjectFactory;
  44. import org.openspcoop2.utils.sql.SQLQueryObjectException;
  45. import org.slf4j.Logger;
  46. import org.slf4j.LoggerFactory;

  47. /**
  48.  * DigestServiceParamsDriver
  49.  *
  50.  * @author Burlon Tommaso (tommaso.burlon@link.it)
  51.  * @author $Author$
  52.  * @version $Rev$, $Date$
  53.  */
  54. public class DigestServiceParamsDriver {

  55.     private static final String DB_LOCK_ID = "ServiziDigestParamsUpdate";
  56.     private static final org.openspcoop2.utils.Semaphore THREAD_LOCK = new org.openspcoop2.utils.Semaphore("DigestServiceParamsDriver-threadLock");
  57.     private Logger logger = LoggerFactory.getLogger(getClass());
  58.    
  59.     private DriverConfigurazioneDB driverConfigurazioneDB;

  60.     private String getKey(IDServizio idServizio, Long serialNumber) {
  61.         return "DigestServiceParams" + idServizio.toString() + "-" + serialNumber;
  62.     }
  63.    
  64.     private Long getIdServizio(Connection conn, String tipoDB, IDServizio idServizio) throws SQLQueryObjectException, SQLException {
  65.         ISQLQueryObject query = SQLObjectFactory.createSQLQueryObject(tipoDB);
  66.         query.addFromTable(CostantiDB.SOGGETTI);
  67.         query.addSelectField("id");
  68.         query.setANDLogicOperator(true);
  69.         query.addWhereCondition(CostantiDB.SOGGETTI_COLUMN_NOME_SOGGETTO + "= ?");
  70.         query.addWhereCondition(CostantiDB.SOGGETTI_COLUMN_TIPO_SOGGETTO + "= ?");
  71.        
  72.         Long idSoggetto = null;
  73.         try( PreparedStatement stmt = conn.prepareStatement(query.createSQLQuery())) {
  74.             int index = 1;
  75.             stmt.setString(index++, idServizio.getSoggettoErogatore().getNome());
  76.             stmt.setString(index++, idServizio.getSoggettoErogatore().getTipo());
  77.            
  78.             try (ResultSet rs = stmt.executeQuery()) {
  79.                 if (rs.next()) {
  80.                     idSoggetto = rs.getLong("id");
  81.                 }
  82.             }
  83.         }
  84.        
  85.         if (idSoggetto == null)
  86.             return null;
  87.        
  88.         query = SQLObjectFactory.createSQLQueryObject(tipoDB);
  89.         query.addFromTable(CostantiDB.SERVIZI);
  90.         query.addSelectField("id");
  91.         query.setANDLogicOperator(true);
  92.         query.addWhereCondition(CostantiDB.SERVIZI_COLUMN_NOME_SERVIZIO + "= ?");
  93.         query.addWhereCondition(CostantiDB.SERVIZI_COLUMN_TIPO_SERVIZIO + "= ?");
  94.         query.addWhereCondition(CostantiDB.SERVIZI_COLUMN_VERSIONE_SERVIZIO + "= ?");
  95.         query.addWhereCondition(CostantiDB.SERVIZI_COLUMN_ID_SOGGETTO_REF + "= ?");
  96.         try( PreparedStatement stmt = conn.prepareStatement(query.createSQLQuery())) {
  97.             int index = 1;
  98.             stmt.setString(index++, idServizio.getNome());
  99.             stmt.setString(index++, idServizio.getTipo());
  100.             stmt.setInt(index++, idServizio.getVersione());
  101.             stmt.setLong(index++, idSoggetto);
  102.            
  103.             try (ResultSet rs = stmt.executeQuery()) {
  104.                 if (rs.next()) {
  105.                     return rs.getLong("id");
  106.                 }
  107.             }
  108.         }
  109.        
  110.         return null;
  111.     }
  112.    
  113.     private DigestServiceParams paramsFromResultSet(IDServizio idServizio, ResultSet rs) throws SQLException {
  114.         DigestServiceParams params = new DigestServiceParams();
  115.         params.setIdServizio(idServizio);
  116.         params.setSerialNumber(rs.getLong(CostantiDB.SERVIZI_DIGEST_PARAMS_COLUMN_SERIAL_NUMBER));
  117.         params.setDataRegistrazione(rs.getTimestamp(CostantiDB.SERVIZI_DIGEST_PARAMS_COLUMN_DATE).toInstant());
  118.         params.setDurata(rs.getInt(CostantiDB.SERVIZI_DIGEST_PARAMS_COLUMN_PERIOD));
  119.         params.setSeed(rs.getString(CostantiDB.SERVIZI_DIGEST_PARAMS_COLUMN_SEED).getBytes());
  120.         params.setDigestAlgorithm(DigestType.valueOf(rs.getString(CostantiDB.SERVIZI_DIGEST_PARAMS_COLUMN_ALGORITHM)));
  121.         return params;
  122.     }
  123.    
  124.     public DigestServiceParamsDriver(DriverConfigurazioneDB driverConfigurazioneDB) {
  125.         this.driverConfigurazioneDB = driverConfigurazioneDB;
  126.     }
  127.    
  128.     /**
  129.      * Rimuove tutte le informazioni crittografiche per la generazione dei digest per un determinato
  130.      * servizio.
  131.      * @param idServizio servizio di cui rimuovere le informazioni crittografiche
  132.      * @return
  133.      * @throws DriverConfigurazioneException nel caso la rimozione non avvenga correttamente
  134.      */
  135.     public boolean removeEntries(IDServizio idServizio) throws DriverConfigurazioneException {
  136.         Connection conn = null;
  137.         String tipoDB = this.driverConfigurazioneDB.getTipoDB();
  138.         try {
  139.             conn = this.driverConfigurazioneDB.getConnection("removeEntries");
  140.            
  141.             // ottengo l'id di riferimento del servizio
  142.             Long idServizioRef = this.getIdServizio(conn, tipoDB, idServizio);
  143.             if (idServizioRef == null)
  144.                 return false;
  145.            
  146.             ISQLQueryObject query = SQLObjectFactory.createSQLQueryObject(tipoDB);
  147.             query.addDeleteTable(CostantiDB.SERVIZI_DIGEST_PARAMS);
  148.             query.addWhereCondition(CostantiDB.SERVIZI_DIGEST_PARAMS_COLUMN_ID_SERVIZIO_REF + "= ?");
  149.            
  150.             try (PreparedStatement stmt = conn.prepareStatement(query.createSQLDelete())) {
  151.                 stmt.setLong(1, idServizioRef);
  152.                 stmt.execute();
  153.             }
  154.         } catch (SQLQueryObjectException | SQLException e) {
  155.             throw new DriverConfigurazioneException("Errore nella rimozione di un record di tipo DigestServiceParam", e);
  156.         } finally {
  157.             this.driverConfigurazioneDB.closeConnection(conn);
  158.         }
  159.        
  160.         return true;
  161.     }
  162.    
  163.    
  164.     /**
  165.      * Rimuove partendo dalle informazioni piu vecchie tutte le informazioni crittografiche relative ad un determinato
  166.      * servizio fino ad averne al piu n
  167.      * @param idServizio: id del servizio relativo
  168.      * @param n: numero di informazioni massimo da tenere in memoria
  169.      * @return
  170.      * @throws DriverConfigurazioneException: nel caso la rimozione non vada a buon fine
  171.      */
  172.     public boolean removeOldEntries(IDServizio idServizio, int n) throws DriverConfigurazioneException {
  173.         Connection conn = null;
  174.         String tipoDB = this.driverConfigurazioneDB.getTipoDB();
  175.         try {
  176.             conn = this.driverConfigurazioneDB.getConnection("removeEntries");
  177.            
  178.             // ottengo l'id di riferimento del servizio
  179.             Long idServizioRef = this.getIdServizio(conn, tipoDB, idServizio);
  180.             if (idServizioRef == null)
  181.                 return false;
  182.            
  183.             // ottengo il timestamp della n-esimo record
  184.             Timestamp lastQuery = null;
  185.             ISQLQueryObject query = SQLObjectFactory.createSQLQueryObject(tipoDB);
  186.             query.addFromTable(CostantiDB.SERVIZI_DIGEST_PARAMS);
  187.             query.addSelectField(CostantiDB.SERVIZI_DIGEST_PARAMS_COLUMN_DATE);
  188.             query.addWhereCondition(CostantiDB.SERVIZI_DIGEST_PARAMS_COLUMN_ID_SERVIZIO_REF + "= ?");
  189.             query.addOrderBy(CostantiDB.SERVIZI_DIGEST_PARAMS_COLUMN_DATE, false);
  190.             query.setANDLogicOperator(true);
  191.             query.setLimit(1);
  192.             query.setOffset(n);
  193.             try (PreparedStatement stmt = conn.prepareStatement(query.createSQLQuery())) {
  194.                 stmt.setLong(1, idServizioRef);
  195.                
  196.                 try (ResultSet rs = stmt.executeQuery()) {
  197.                     if (rs.next()) {
  198.                         lastQuery = rs.getTimestamp(CostantiDB.SERVIZI_DIGEST_PARAMS_COLUMN_DATE);
  199.                     }
  200.                 }
  201.             }
  202.            
  203.             // se non esiste ci sono meno di n records
  204.             if (lastQuery == null)
  205.                 return true;
  206.            
  207.             // elimino tutti i record con un timestamp precedente
  208.             query = SQLObjectFactory.createSQLQueryObject(tipoDB);
  209.             query.addDeleteTable(CostantiDB.SERVIZI_DIGEST_PARAMS);
  210.             query.setANDLogicOperator(true);
  211.             query.addWhereCondition(CostantiDB.SERVIZI_DIGEST_PARAMS_COLUMN_ID_SERVIZIO_REF + "= ?");
  212.             query.addWhereCondition(CostantiDB.SERVIZI_DIGEST_PARAMS_COLUMN_DATE + "<= ?");
  213.            
  214.             try (PreparedStatement stmt = conn.prepareStatement(query.createSQLDelete())) {
  215.                 int index = 1;
  216.                 stmt.setLong(index++, idServizioRef);
  217.                 stmt.setTimestamp(index++, lastQuery);
  218.                 stmt.execute();
  219.             }
  220.         } catch (SQLQueryObjectException | SQLException e) {
  221.             throw new DriverConfigurazioneException("Errore nell'aggiunta di un record di tipo DigestServiceParam", e);
  222.         } finally {
  223.             this.driverConfigurazioneDB.closeConnection(conn);
  224.         }
  225.        
  226.         return true;
  227.     }
  228.    
  229.     /**
  230.      * Aggiunge una nuova informazioni crittografica, questa funzione deve essere chiamata usando il lock fornito dalla classe,
  231.      * nel caso l'aggiunta vada a buon fine la nuova informazione aggiunta verra registrata in cache come informazione piu
  232.      * recente
  233.      * @param params: informazione crittografica da aggiungere
  234.      * @return
  235.      * @throws DriverConfigurazioneException: nel caso l'aggiunta non vada a buon fine
  236.      */
  237.     public boolean addNewEntry(DigestServiceParams params)  throws DriverConfigurazioneException {
  238.         Connection conn = null;
  239.         String tipoDB = this.driverConfigurazioneDB.getTipoDB();
  240.    
  241.         try {
  242.             conn = this.driverConfigurazioneDB.getConnection("addEntry");
  243.            
  244.             // ottengo l'id di riferimento del servizio
  245.             Long idServizioRef = this.getIdServizio(conn, tipoDB, params.getIdServizio());
  246.             if (idServizioRef == null)
  247.                 return false;
  248.            
  249.             // aggiungo il nuovo elemento nel db
  250.             ISQLQueryObject query = SQLObjectFactory.createSQLQueryObject(tipoDB);
  251.             query.addInsertTable(CostantiDB.SERVIZI_DIGEST_PARAMS);
  252.             if (params.getSerialNumber() != null)
  253.                 query.addInsertField(CostantiDB.SERVIZI_DIGEST_PARAMS_COLUMN_SERIAL_NUMBER, "?");
  254.             query.addInsertField(CostantiDB.SERVIZI_DIGEST_PARAMS_COLUMN_ALGORITHM, "?");
  255.             query.addInsertField(CostantiDB.SERVIZI_DIGEST_PARAMS_COLUMN_DATE, "?");
  256.             query.addInsertField(CostantiDB.SERVIZI_DIGEST_PARAMS_COLUMN_ID_SERVIZIO_REF, "?");
  257.             query.addInsertField(CostantiDB.SERVIZI_DIGEST_PARAMS_COLUMN_PERIOD, "?");
  258.             query.addInsertField(CostantiDB.SERVIZI_DIGEST_PARAMS_COLUMN_SEED, "?");
  259.            
  260.             try (PreparedStatement stmt = conn.prepareStatement(query.createSQLInsert())) {
  261.                 int index = 1;
  262.                 if (params.getSerialNumber() != null)
  263.                     stmt.setLong(index++, params.getSerialNumber());
  264.                 stmt.setString(index++, params.getDigestAlgorithm().toString());
  265.                 stmt.setTimestamp(index++, Timestamp.from(params.getDataRegistrazione()));
  266.                 stmt.setLong(index++, idServizioRef);
  267.                 stmt.setInt(index++, params.getDurata());
  268.                 stmt.setString(index++, new String(params.getSeed()));
  269.                 stmt.execute();
  270.             }
  271.         } catch (SQLQueryObjectException | SQLException e) {
  272.             throw new DriverConfigurazioneException (e);
  273.         } finally {
  274.             this.driverConfigurazioneDB.closeConnection(conn);
  275.         }
  276.        
  277.         // aggiungo i parametri in cache (se ottengo un exception posso ignorarla in quanto non invalida il processo)
  278.         try {
  279.             ConfigurazionePdDReader.getCache().put(getKey(params.getIdServizio(), null), params);
  280.         } catch (UtilsException e) {
  281.             this.logger.warn("Errore nell'aggiunta di un valore in cache", e);
  282.         }
  283.        
  284.         return true;
  285.     }
  286.    
  287.     public boolean isValid(DigestServiceParams param) {
  288.         if (param == null)
  289.             return false;
  290.         Instant now = Instant.now();
  291.         Instant expiration = param
  292.                 .getDataRegistrazione()
  293.                 .plus(Duration.ofDays(param.getDurata()));
  294.        
  295.         return now.isBefore(expiration);
  296.     }
  297.    
  298.     /**
  299.      * Funzione che se possible ritorna l'informazione crittografica piu recente se e solo se e' ancora valida
  300.      * @param idServizio
  301.      * @return null se l'informazione crittografica piu recente non risulta valida
  302.      * @throws DriverConfigurazioneException
  303.      */
  304.     public DigestServiceParams getValidEntry(IDServizio idServizio) throws DriverConfigurazioneException {
  305.         DigestServiceParams param = this.getLastEntry(idServizio);
  306.         if (isValid(param))
  307.             return param;
  308.         return null;
  309.     }
  310.    
  311.     /**
  312.      * Funzione che ritorna l'informazione crittografica piu recente
  313.      * @param idServizio
  314.      * @return
  315.      * @throws DriverConfigurazioneException
  316.      */
  317.     public DigestServiceParams getLastEntry(IDServizio idServizio) throws DriverConfigurazioneException {
  318.         return this.getEntry(idServizio, null);
  319.     }
  320.    
  321.     /**
  322.      * Metodo che ritorna l'informazione crittografica relativa ad un servizio dato un determinato numero seriale
  323.      * @param idServizio
  324.      * @param serialNumber
  325.      * @return
  326.      * @throws DriverConfigurazioneException
  327.      */
  328.     public DigestServiceParams getEntry(IDServizio idServizio, Long serialNumber) throws DriverConfigurazioneException {
  329.         Connection conn = null;
  330.         String tipoDB = this.driverConfigurazioneDB.getTipoDB();
  331.         DigestServiceParams param  = null;
  332.        
  333.         try {
  334.             // cerco di ottenere i parametri dalla cache se e solo se il numero seriale e' definito o se il record piu recente e' ancora valido
  335.             param = (DigestServiceParams) ConfigurazionePdDReader.getRawObjectCache(getKey(idServizio, serialNumber));
  336.             if (param != null && (serialNumber != null || isValid(param)))
  337.                 return param;
  338.            
  339.             conn = this.driverConfigurazioneDB.getConnection("getEntry");
  340.            
  341.             // ottengo l'id di riferimento del servizio
  342.             Long idServizioRef = this.getIdServizio(conn, tipoDB, idServizio);
  343.             if (idServizioRef == null)
  344.                 throw new DriverConfigurazioneException("idServizio riferito non presente nella tabella servizio");
  345.            
  346.             ISQLQueryObject query = SQLObjectFactory.createSQLQueryObject(tipoDB);
  347.             query.addFromTable(CostantiDB.SERVIZI_DIGEST_PARAMS);
  348.             query.setANDLogicOperator(true);
  349.             query.addWhereCondition(CostantiDB.SERVIZI_DIGEST_PARAMS_COLUMN_ID_SERVIZIO_REF + "= ?");
  350.             if (serialNumber != null)
  351.                 query.addWhereCondition(CostantiDB.SERVIZI_DIGEST_PARAMS_COLUMN_SERIAL_NUMBER + "= ?");
  352.             query.addOrderBy(CostantiDB.SERVIZI_DIGEST_PARAMS_COLUMN_DATE, false);
  353.             query.setLimit(1);
  354.            
  355.             try (PreparedStatement stmt = conn.prepareStatement(query.createSQLQuery())) {
  356.                 int index = 1;
  357.                 stmt.setLong(index++, idServizioRef);
  358.                 if (serialNumber != null)
  359.                     stmt.setLong(index++, serialNumber);
  360.                 stmt.execute();
  361.                
  362.                 try (ResultSet rs = stmt.executeQuery()) {
  363.                     if (rs.next()) {
  364.                         param = this.paramsFromResultSet(idServizio, rs);
  365.                     }
  366.                 }
  367.             }
  368.            
  369.         } catch (SQLQueryObjectException | SQLException e) {
  370.             throw new DriverConfigurazioneException("Errore nella get del DigestServiceParam", e);
  371.         } finally {
  372.             this.driverConfigurazioneDB.closeConnection(conn);
  373.         }
  374.    
  375.         // aggiorno la cache se e solo se il numero seriale e' esplicitato o il record e' valido
  376.         try {
  377.             if (param != null && (serialNumber != null || isValid(param)))
  378.                 ConfigurazionePdDReader.getCache().put(getKey(idServizio, serialNumber), param);
  379.         } catch (UtilsException e) {
  380.             this.logger.warn("Errore nell'aggiunta di un valore in cache", e);
  381.         }
  382.        
  383.         return param;
  384.     }
  385.    
  386.     private Semaphore semaphore;
  387.     private SemaphoreLock lock;
  388.    
  389.     private Semaphore getSemaphore() throws UtilsException {
  390.         if (this.semaphore == null) {
  391.             InfoStatistics semaphoreStatistics = new InfoStatistics();
  392.            
  393.             SemaphoreConfiguration config = GestoreMessaggi.newSemaphoreConfiguration(1000, 1000);
  394.            
  395.             this.semaphore = new Semaphore(semaphoreStatistics, SemaphoreMapping.newInstance(DB_LOCK_ID),
  396.                 config,
  397.                 TipiDatabase.toEnumConstant(this.driverConfigurazioneDB.getTipoDB()),
  398.                 DriverConfigurazioneDB.getCheckLogger());
  399.         }
  400.        
  401.         return this.semaphore;
  402.     }
  403.    
  404.     /**
  405.      * Ottiene un lock (globale e locale) sulla tabella delle informazioni crittografiche
  406.      * @param idTransazione, id della transazione corrente
  407.      * @throws UtilsException
  408.      * @throws DriverConfigurazioneException
  409.      */
  410.     public void acquireLock(String idTransazione) throws UtilsException, DriverConfigurazioneException {
  411.         Connection con = null;
  412.         try {
  413.             con = this.driverConfigurazioneDB.getConnection("acquireLockDigestService");
  414.            
  415.             while(!this.getSemaphore().newLock(con, "acquireLockDigestService")) {
  416.                 Utilities.sleep(1);
  417.             }
  418.            
  419.             this.lock = THREAD_LOCK.acquire("acquireLock", idTransazione);
  420.            
  421.         } catch (UtilsException | DriverConfigurazioneException e) {
  422.             this.releaseLock();
  423.         } finally {
  424.             this.driverConfigurazioneDB.releaseConnection(con);
  425.         }
  426.     }
  427.    
  428.     /**
  429.      * Rilascia il lock (globale e locale) sulla tabella delle informazioni crittografiche
  430.      * @throws UtilsException
  431.      * @throws DriverConfigurazioneException
  432.      */
  433.     public void releaseLock() throws UtilsException, DriverConfigurazioneException {
  434.         Connection con = null;
  435.         try {
  436.             THREAD_LOCK.release(this.lock, "acquireLock");
  437.             con = this.driverConfigurazioneDB.getConnection("releaseLockDigestService");
  438.             this.getSemaphore().releaseLock(con, "releaseLockDigestService");
  439.         } finally {
  440.             this.driverConfigurazioneDB.releaseConnection(con);
  441.         }
  442.     }
  443.    
  444.    
  445.    
  446. }