IDSerialGenerator_numeric.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.utils.id.serial;

  21. import java.io.ByteArrayOutputStream;
  22. import java.io.PrintStream;
  23. import java.security.SecureRandom;
  24. import java.sql.Connection;
  25. import java.sql.PreparedStatement;
  26. import java.sql.ResultSet;
  27. import java.util.ArrayList;
  28. import java.util.List;

  29. import org.openspcoop2.utils.TipiDatabase;
  30. import org.openspcoop2.utils.Utilities;
  31. import org.openspcoop2.utils.UtilsException;
  32. import org.openspcoop2.utils.date.DateManager;
  33. import org.openspcoop2.utils.jdbc.JDBCUtilities;
  34. import org.openspcoop2.utils.sql.ISQLQueryObject;
  35. import org.openspcoop2.utils.sql.SQLObjectFactory;
  36. import org.slf4j.Logger;

  37. /**
  38.  * IDSerialGenerator_numeric
  39.  *
  40.  * @author Andrea Poli (apoli@link.it)
  41.  * @author $Author$
  42.  * @version $Rev$, $Date$
  43.  */
  44. public class IDSerialGenerator_numeric {

  45.     private static SecureRandom _rnd = null;
  46.     private static synchronized void initRandom() {
  47.         if(_rnd==null) {
  48.             _rnd = new SecureRandom();
  49.         }
  50.     }
  51.     private static java.util.Random getRandom() {
  52.         if(_rnd==null) {
  53.             initRandom();
  54.         }
  55.         return _rnd;
  56.     }
  57.    
  58.    
  59.     public static String generate(Connection conDB,TipiDatabase tipoDatabase,
  60.             IDSerialGeneratorParameter param,Logger log, InfoStatistics infoStatistics) throws UtilsException{
  61.                
  62.         long attesaAttivaJDBC = param.getSerializableTimeWaitMs();
  63.         int checkIntervalloJDBC = param.getSerializableNextIntervalTimeMs();
  64.         String protocollo = param.getProtocollo();
  65.        
  66.         long counterTmp = -1;
  67.        
  68.         boolean idBuildOK = false;

  69.         long scadenzaWhile = DateManager.getTimeMillis()
  70.                 + attesaAttivaJDBC;

  71.         ByteArrayOutputStream out = new ByteArrayOutputStream();
  72.         PrintStream ps = new PrintStream(out);
  73.        
  74.         int iteration = 0;
  75.        
  76.         List<String> messageException = new ArrayList<>();
  77.        
  78.         String table = param.getTableName();
  79.         if(table==null){
  80.             if(param.getInformazioneAssociataAlProgressivo()!=null){
  81.                 table = Constants.TABELLA_ID_RELATIVO_AS_LONG;
  82.             }
  83.             else{
  84.                 table = Constants.TABELLA_ID_AS_LONG;
  85.             }
  86.         }
  87.        
  88.         String columnInfoAssociata = param.getColumnRelativeInfo();
  89.         if(columnInfoAssociata==null){
  90.             columnInfoAssociata = Constants.TABELLA_ID_COLONNA_INFO_ASSOCIATA;
  91.         }
  92.        
  93.         String columnPrg = param.getColumnPrg();
  94.         if(columnPrg==null){
  95.             columnPrg = Constants.TABELLA_ID_COLONNA_COUNTER;
  96.         }
  97.        
  98.         String columnProtocollo = param.getColumnProtocol();
  99.         if(columnProtocollo==null){
  100.             columnProtocollo = Constants.TABELLA_ID_COLONNA_PROTOCOLLO;
  101.         }
  102.        
  103. //      String columnCondition = "";
  104. //      String columnValueCondition = "";
  105. //      String condition = "";
  106. //      if(param.getInformazioneAssociataAlProgressivo()!=null){
  107. //          condition = " AND "+columnInfoAssociata+"=?";
  108. //          columnCondition = ","+columnInfoAssociata;
  109. //          columnValueCondition = ",?";
  110. //      }
  111.        
  112.         boolean maxValueAndWrapDisabled = false;
  113.        
  114.         List<String> valuesGenerated = new ArrayList<>();
  115.        
  116.         boolean rowNotExistsAndSerializableLevelNotFound = false;
  117.        
  118.         while(maxValueAndWrapDisabled==false && rowNotExistsAndSerializableLevelNotFound==false && idBuildOK==false &&
  119.                 DateManager.getTimeMillis() < scadenzaWhile){

  120.             valuesGenerated = new ArrayList<>();
  121.            
  122.             iteration++;

  123.             // Prima provo ad utilizzare il buffer (può darsi che un altro thread l'abbia riempito)
  124.             if(param.getSizeBuffer()>1){
  125.                 String valueFromBuffer = IDSerialGeneratorBuffer.nextValue(IDSerialGenerator_numeric.class,param.getInformazioneAssociataAlProgressivo());
  126.                 if(valueFromBuffer!=null){
  127.                     //System.out.println("GET ["+valueFromBuffer+"] FROM BUFFER");
  128.                     return valueFromBuffer;
  129.                 }
  130.             }
  131.            
  132.             //log.info("ancoraImbustamento interval["+checkInterval+"]   secondi "+(scadenzaWhile-DateManager.getTimeMillis())/1000);

  133.             counterTmp = -1;
  134.             PreparedStatement pstmt = null;
  135.             PreparedStatement pstmtInsert = null;
  136.             ResultSet rs = null;
  137.             try{
  138.                 // Lettura attuale valore
  139.                 ISQLQueryObject sqlGet = SQLObjectFactory.createSQLQueryObject(tipoDatabase);
  140.                 sqlGet.addSelectField(columnPrg);
  141.                 sqlGet.addFromTable(table);
  142.                 sqlGet.setANDLogicOperator(true);
  143.                 sqlGet.addWhereCondition(columnProtocollo+"=?");
  144.                 if(param.getInformazioneAssociataAlProgressivo()!=null){
  145.                     sqlGet.addWhereCondition(columnInfoAssociata+"=?");
  146.                 }
  147.                 sqlGet.setSelectForUpdate(true);
  148.                
  149.                 StringBuilder query = new StringBuilder();
  150. //              query.append("SELECT "+columnPrg+" FROM ");
  151. //              query.append(table);
  152. //              query.append(" WHERE "+columnProtocollo+"=?");
  153. //              query.append(condition);
  154. //              query.append(" FOR UPDATE");
  155.                 query.append(sqlGet.createSQLQuery());
  156.                 //System.out.println("SELECT ["+query.toString()+"]");
  157.                 pstmt = conDB.prepareStatement(query.toString());
  158.                 pstmt.setString(1, protocollo);
  159.                 if(param.getInformazioneAssociataAlProgressivo()!=null){
  160.                     pstmt.setString(2, param.getInformazioneAssociataAlProgressivo());
  161.                 }
  162.                 rs = pstmt.executeQuery();
  163.                 if(rs == null) {
  164.                     pstmt.close();
  165.                     log.error("Creazione serial non riuscita: ResultSet is null?");
  166.                     throw new UtilsException("Creazione serial non riuscita: ResultSet is null?");      
  167.                 }
  168.                 boolean exist = rs.next();
  169.                 if(!exist) {
  170.                     if(JDBCUtilities.isTransactionIsolationSerializable(conDB.getTransactionIsolation(), tipoDatabase)==false) {
  171.                         rowNotExistsAndSerializableLevelNotFound = true;
  172.                         continue;
  173.                     }
  174.                 }
  175.                
  176.                 // incremento se esiste
  177.                 if(exist){
  178.                     counterTmp = rs.getLong(columnPrg);
  179.                     for (int i = 0; i < param.getSizeBuffer(); i++) {
  180.                         if ((counterTmp + 1) > param.getMaxValue()) {
  181.                             if(param.isWrap()){
  182.                                 counterTmp = 0;
  183.                             }else{
  184.                                 if(valuesGenerated.size()<=0){
  185.                                     maxValueAndWrapDisabled = true;
  186.                                     throw new Exception("Max Value of identifier has been reached");
  187.                                 }
  188.                                 else{
  189.                                     break; // utilizzo gli identificativi che ho generato fino ad ora.
  190.                                 }
  191.                             }
  192.                         }
  193.                         counterTmp++;
  194.                         valuesGenerated.add(counterTmp+"");
  195.                     }
  196.                 }      
  197.                 rs.close();
  198.                 pstmt.close();

  199.                 if(exist==false){
  200.                     counterTmp = 1;
  201.                     // CREO PRIMO COUNT!
  202.                     StringBuilder queryInsert = new StringBuilder();
  203.                     ISQLQueryObject sqlInsert = SQLObjectFactory.createSQLQueryObject(tipoDatabase);
  204.                     sqlInsert.addInsertTable(table);
  205.                     sqlInsert.addInsertField(columnPrg, "?");
  206.                     sqlInsert.addInsertField(columnProtocollo, "?");
  207.                     if(param.getInformazioneAssociataAlProgressivo()!=null){
  208.                         sqlInsert.addInsertField(columnInfoAssociata, "?");
  209.                     }
  210. //                  queryInsert.append("INSERT INTO "+table+" ("+columnPrg+","+columnProtocollo+columnCondition+") ");
  211. //                  queryInsert.append(" VALUES ( ? , ? "+columnValueCondition+")");
  212.                     queryInsert.append(sqlInsert.createSQLInsert());
  213.                     //System.out.println("INSERT ["+queryInsert.toString()+"]");
  214.                     pstmtInsert = conDB.prepareStatement(queryInsert
  215.                             .toString());
  216.                     pstmtInsert.setLong(1, 1);
  217.                     pstmtInsert.setString(2, protocollo);
  218.                     if(param.getInformazioneAssociataAlProgressivo()!=null){
  219.                         pstmtInsert.setString(3, param.getInformazioneAssociataAlProgressivo());
  220.                     }
  221.                     pstmtInsert.execute();
  222.                     pstmtInsert.close();
  223.                    
  224.                     valuesGenerated.add(counterTmp+"");
  225.                    
  226.                 }else{
  227.                     // Incremento!
  228.                     StringBuilder queryUpdate = new StringBuilder();
  229.                     ISQLQueryObject sqlUpdate = SQLObjectFactory.createSQLQueryObject(tipoDatabase);
  230.                     sqlUpdate.addUpdateTable(table);
  231.                     sqlUpdate.addUpdateField(columnPrg, "?");
  232.                     sqlUpdate.setANDLogicOperator(true);
  233.                     sqlUpdate.addWhereCondition(columnProtocollo+"=?");
  234.                     if(param.getInformazioneAssociataAlProgressivo()!=null){
  235.                         sqlUpdate.addWhereCondition(columnInfoAssociata+"=?");
  236.                     }
  237. //                  queryUpdate.append("UPDATE ");
  238. //                  queryUpdate.append(table);
  239. //                  queryUpdate.append(" SET "+columnPrg+" = ? WHERE "+columnProtocollo+"=?"+condition);
  240.                     queryUpdate.append(sqlUpdate.createSQLUpdate());
  241.                     //System.out.println("UPDATE ["+queryUpdate.toString()+"]");
  242.                     pstmtInsert = conDB.prepareStatement(queryUpdate
  243.                             .toString());
  244.                     pstmtInsert.setLong(1, counterTmp);
  245.                     pstmtInsert.setString(2, protocollo);
  246.                     if(param.getInformazioneAssociataAlProgressivo()!=null){
  247.                         pstmtInsert.setString(3, param.getInformazioneAssociataAlProgressivo());
  248.                     }
  249.                     pstmtInsert.execute();
  250.                     pstmtInsert.close();
  251.                 }

  252.                 // Chiusura Transazione
  253.                 conDB.commit();

  254.                 // ID Costruito
  255.                 idBuildOK = true;

  256.             } catch(Throwable e) {
  257.                 ps.append("********* Exception Iteration ["+iteration+"] **********\n");
  258.                 String msg = e.getMessage(); // per evitare out of memory
  259.                 if(msg==null){
  260.                     msg = "NULL-MESSAGE";
  261.                 }
  262.                 if(messageException.contains(msg)){
  263.                     ps.append("Message already occurs: "+msg);
  264.                 }
  265.                 else{
  266.                     e.printStackTrace(ps);
  267.                     messageException.add(msg);
  268.                 }
  269.                 ps.append("\n\n");
  270.                
  271.                 if(infoStatistics!=null){
  272.                     infoStatistics.addErrorSerializableAccess(e);
  273.                 }
  274.                
  275.                 //System.out.println("ERRORE: "+e.getMessage());
  276.                 //log.info("ERROR GET SERIAL SQL ["+e.getMessage()+"]");
  277.                 try{
  278.                     if( rs != null )
  279.                         rs.close();
  280.                 } catch(Exception er) {}
  281.                 try{
  282.                     if( pstmt != null )
  283.                         pstmt.close();
  284.                 } catch(Exception er) {}
  285.                 try{
  286.                     if( pstmtInsert != null )
  287.                         pstmtInsert.close();
  288.                 } catch(Exception er) {}
  289.                 try{
  290.                     conDB.rollback();
  291.                 } catch(Exception er) {}
  292.             }

  293.             if(idBuildOK == false){
  294.                 // Per aiutare ad evitare conflitti
  295.                 try{
  296.                     int intervalloDestro = checkIntervalloJDBC;
  297.                     if(param.isSerializableNextIntervalTimeMsIncrementMode()){
  298.                         intervalloDestro = intervalloDestro + (iteration*param.getSerializableNextIntervalTimeMsIncrement());
  299.                         if(intervalloDestro>param.getMaxSerializableNextIntervalTimeMs()){
  300.                             intervalloDestro = param.getMaxSerializableNextIntervalTimeMs();
  301.                         }
  302.                     }
  303.                    
  304.                     int sleep = getRandom().nextInt(intervalloDestro);
  305.                     //System.out.println("Sleep: "+sleep);
  306.                     Utilities.sleep(sleep); // random
  307.                 }catch(Exception eRandom){}
  308.             }
  309.         }

  310.         try{
  311.             if( ps != null ){
  312.                 ps.flush();
  313.             }
  314.         } catch(Exception er) {}
  315.         try{
  316.             if( out != null ){
  317.                 out.flush();
  318.             }
  319.         } catch(Exception er) {}
  320.         try{
  321.             if( ps != null ){
  322.                 ps.close();
  323.             }
  324.         } catch(Exception er) {}
  325.         try{
  326.             if( out != null ){
  327.                 out.close();
  328.             }
  329.         } catch(Exception er) {}
  330.        
  331.         if(maxValueAndWrapDisabled){
  332.             String msgError = "Max Value ["+param.getMaxValue()+"] of identifier has been reached";
  333.             log.error(msgError+": "+out.toString()); // in out è presente l'intero stackTrace
  334.             throw new UtilsException(msgError);
  335.         }
  336.                
  337.         if(rowNotExistsAndSerializableLevelNotFound){
  338.             String msgError = "Raw not exists and serializable level is disabled";
  339.             log.error(msgError); // in out è presente l'intero stackTrace
  340.             throw new UtilsException(msgError);
  341.         }
  342.        
  343.         if(idBuildOK==false || counterTmp<=0){
  344.             String msgError = "Creazione serial non riuscita: l'accesso serializable non ha permesso la creazione del numero sequenziale";
  345.             log.error(msgError+": "+out.toString()); // in out è presente l'intero stackTrace
  346.             throw new UtilsException(msgError);
  347.         }

  348.         String vRet = valuesGenerated.remove(0);
  349.        
  350.         if(valuesGenerated.size()>0){
  351.             IDSerialGeneratorBuffer.putAll(valuesGenerated,IDSerialGenerator_numeric.class,param.getInformazioneAssociataAlProgressivo());
  352.         }
  353.        
  354.         //System.out.println("GET ["+vRet+"] AND SET BUFFER AT SIZE ["+valuesGenerated.size()+"]");
  355.        
  356.         return vRet;
  357.     }
  358.    
  359. }