SemaphoreEngine.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.semaphore;

  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.sql.Timestamp;
  28. import java.text.SimpleDateFormat;
  29. import java.util.ArrayList;
  30. import java.util.List;

  31. import org.openspcoop2.utils.TipiDatabase;
  32. import org.openspcoop2.utils.Utilities;
  33. import org.openspcoop2.utils.UtilsException;
  34. import org.openspcoop2.utils.date.DateManager;
  35. import org.openspcoop2.utils.date.DateUtils;
  36. import org.openspcoop2.utils.id.serial.InfoStatistics;
  37. import org.openspcoop2.utils.jdbc.JDBCParameterUtilities;
  38. import org.openspcoop2.utils.jdbc.JDBCUtilities;
  39. import org.openspcoop2.utils.sql.ISQLQueryObject;
  40. import org.openspcoop2.utils.sql.SQLObjectFactory;
  41. import org.slf4j.Logger;

  42. /**
  43.  * Semaphore
  44.  *
  45.  * @author Andrea Poli (apoli@link.it)
  46.  * @author $Author$
  47.  * @version $Rev$, $Date$
  48.  */
  49. public class SemaphoreEngine {

  50.     private static SecureRandom _rnd = null;
  51.     private static synchronized void initRandom() {
  52.         if(_rnd==null) {
  53.             _rnd = new SecureRandom();
  54.         }
  55.     }
  56.     private static java.util.Random getRandom() {
  57.         if(_rnd==null) {
  58.             initRandom();
  59.         }
  60.         return _rnd;
  61.     }
  62.    
  63.     protected static SemaphoreEngine getSemaphore(SemaphoreMapping mapping, SemaphoreConfiguration config, TipiDatabase databaseType, Logger log) throws UtilsException {
  64.         return new SemaphoreEngine(mapping, config, databaseType, log);
  65.     }
  66.    
  67.     private SemaphoreMapping mapping;
  68.     private SemaphoreConfiguration config;
  69.     private TipiDatabase databaseType;
  70.     private JDBCParameterUtilities jdbcParameterUtils;
  71.     private Logger log;
  72.    
  73.     public SemaphoreEngine(SemaphoreMapping mapping, SemaphoreConfiguration config, TipiDatabase databaseType, Logger log) throws UtilsException {
  74.         this.mapping = mapping;
  75.         this.config = config;
  76.         this.databaseType = databaseType;
  77.         this.log = log;
  78.        
  79.         // Check
  80.         if(this.mapping.getTable()==null) {
  81.             throw new UtilsException("Table name not defined in SemaphoreMapping");
  82.         }
  83.         if(this.mapping.getIdNode()==null) {
  84.             throw new UtilsException("IdNode column name not defined in SemaphoreMapping");
  85.         }
  86.         if(this.mapping.getLockDate()==null) {
  87.             throw new UtilsException("Lock Date column name not defined in SemaphoreMapping");
  88.         }
  89.         if(this.mapping.getUpdateDate()==null) {
  90.             throw new UtilsException("Update Date column name not defined in SemaphoreMapping");
  91.         }
  92.         if(this.databaseType==null) {
  93.             throw new UtilsException("Database Type not defined");
  94.         }
  95.         try {
  96.             this.jdbcParameterUtils = new JDBCParameterUtilities(this.databaseType);
  97.         }catch(Exception e) {
  98.             throw new UtilsException(e.getMessage(),e);
  99.         }
  100.     }

  101.     protected boolean createEmptyLock(Connection conDB, boolean throwExceptionIfExists) throws UtilsException{
  102.        
  103.         String table = this.mapping.getTable();
  104.        
  105.         PreparedStatement pstmt = null;
  106.         ResultSet rs = null;
  107.        
  108.         boolean exist = false;
  109.         try{
  110.             // Lettura attuale valore
  111.             ISQLQueryObject sqlGet = SQLObjectFactory.createSQLQueryObject(this.databaseType);
  112.             sqlGet.addFromTable(table);
  113.             sqlGet.setANDLogicOperator(true);
  114.             if(this.mapping.sizeUniqueConditionValues()>0) {
  115.                 for (int i = 0; i < this.mapping.sizeUniqueConditionValues(); i++) {
  116.                     Object o = this.mapping.getUniqueConditionValue(i);
  117.                     if(o!=null) {
  118.                         sqlGet.addWhereCondition(this.mapping.getUniqueConditionColumnName(i)+"=?");
  119.                     }
  120.                     else {
  121.                         sqlGet.addWhereIsNullCondition(this.mapping.getUniqueConditionColumnName(i));
  122.                     }
  123.                 }
  124.             }
  125.            
  126.             //System.out.println("SELECT ["+sqlGet.createSQLQuery()+"]");
  127.             pstmt = conDB.prepareStatement(sqlGet.createSQLQuery());
  128.             int index = 1;
  129.             if(this.mapping.sizeUniqueConditionValues()>0) {
  130.                 for (int i = 0; i < this.mapping.sizeUniqueConditionValues(); i++) {
  131.                     Object o = this.mapping.getUniqueConditionValue(i);
  132.                     if(o!=null) {
  133.                         this.jdbcParameterUtils.setParameter(pstmt, index++,
  134.                                 this.mapping.getUniqueConditionValue(i),
  135.                                 this.mapping.getUniqueConditionType(i));
  136.                     }
  137.                 }
  138.             }
  139.             rs = pstmt.executeQuery();
  140.             if(rs == null) {
  141.                 pstmt.close();
  142.                 this.log.error("Creazione empty lock non riuscita: ResultSet is null?");
  143.                 throw new UtilsException("Creazione empty lock non riuscita: ResultSet is null?");      
  144.             }
  145.             exist = rs.next();
  146.         } catch(Throwable e) {
  147.             this.log.error("Creazione empty lock non riuscita: "+e.getMessage(),e);
  148.             throw new UtilsException("Creazione empty lock non riuscita: "+e.getMessage(),e);      
  149.         } finally {
  150.             try{
  151.                 if( rs != null )
  152.                     rs.close();
  153.             } catch(Exception er) {}
  154.             try{
  155.                 if( pstmt != null )
  156.                     pstmt.close();
  157.             } catch(Exception er) {
  158.                 // close
  159.             }
  160.         }
  161.            
  162.         if(exist) {
  163.             if(throwExceptionIfExists) {
  164.                 throw new UtilsException("Entry already exists");
  165.             }
  166.             return false;
  167.         }
  168.         else {
  169.             try{
  170.                 // INSERT
  171.                 ISQLQueryObject sqlGet = SQLObjectFactory.createSQLQueryObject(this.databaseType);
  172.                 sqlGet.addInsertTable(table);
  173.                 if(this.mapping.sizeUniqueConditionValues()>0) {
  174.                     for (int i = 0; i < this.mapping.sizeUniqueConditionValues(); i++) {
  175.                         sqlGet.addInsertField(this.mapping.getUniqueConditionColumnName(i),"?");
  176.                     }
  177.                 }
  178.                
  179.                 //System.out.println("INSERT ["+sqlGet.createSQLInsert()+"]");
  180.                 pstmt = conDB.prepareStatement(sqlGet.createSQLInsert());
  181.                 int index = 1;
  182.                 if(this.mapping.sizeUniqueConditionValues()>0) {
  183.                     for (int i = 0; i < this.mapping.sizeUniqueConditionValues(); i++) {
  184.                         Object o = this.mapping.getUniqueConditionValue(i);
  185.                         if(o!=null) {
  186.                             this.jdbcParameterUtils.setParameter(pstmt, index++,
  187.                                     this.mapping.getUniqueConditionValue(i),
  188.                                     this.mapping.getUniqueConditionType(i));
  189.                         }
  190.                     }
  191.                 }
  192.                 int n = pstmt.executeUpdate();
  193.                 return n>0;
  194.             } catch(Throwable e) {
  195.                 this.log.error("Creazione empty lock non riuscita: "+e.getMessage(),e);
  196.                 throw new UtilsException("Creazione empty lock non riuscita: "+e.getMessage(),e);      
  197.             } finally {
  198.                 try{
  199.                     if( pstmt != null )
  200.                         pstmt.close();
  201.                 } catch(Exception er) {
  202.                     // close
  203.                 }
  204.             }
  205.         }
  206.        
  207.     }
  208.    
  209.     protected boolean lock(Connection conDB, String details, InfoStatistics infoStatistics,SemaphoreOperationType operationType) throws UtilsException{
  210.                
  211.         boolean operazioneConclusaConSuccesso = false;
  212.         // nel caso di newLock, termina con successo se si ottiene il lock.
  213.         // nel caso di updateLock, termina con successo se cmq il lock è sempre in possesso del nodo cluster
  214.         // nel caso di releaseLock termina sempre con successo.
  215.        
  216.         long attesaAttivaJDBC = this.config.getSerializableTimeWaitMs();
  217.         int checkIntervalloJDBC = this.config.getSerializableNextIntervalTimeMs();
  218.        
  219.         boolean processOK = false;

  220.         long scadenzaWhile = DateManager.getTimeMillis()
  221.                 + attesaAttivaJDBC;

  222.         ByteArrayOutputStream out = new ByteArrayOutputStream();
  223.         PrintStream ps = new PrintStream(out);
  224.        
  225.         int iteration = 0;
  226.        
  227.         List<String> messageException = new ArrayList<>();
  228.        
  229.         String table = this.mapping.getTable();
  230.         String columnIdNode = this.mapping.getIdNode();
  231.         String columnLockDate = this.mapping.getLockDate();
  232.         String columnUpdateDate = this.mapping.getUpdateDate();
  233.         String columnDetails = this.mapping.getDetails();

  234.         boolean rowNotExistsAndSerializableLevelNotFound = false;
  235.        
  236.         while(processOK==false && rowNotExistsAndSerializableLevelNotFound==false &&
  237.                 DateManager.getTimeMillis() < scadenzaWhile){

  238.             iteration++;

  239.             //log.info("process interval["+checkInterval+"]   secondi "+(scadenzaWhile-DateManager.getTimeMillis())/1000);

  240.             operazioneConclusaConSuccesso = false;
  241.             PreparedStatement pstmt = null;
  242.             PreparedStatement pstmtInsert = null;
  243.             ResultSet rs = null;
  244.             try{
  245.                 // Lettura attuale valore
  246.                 ISQLQueryObject sqlGet = SQLObjectFactory.createSQLQueryObject(this.databaseType);
  247.                 sqlGet.addSelectField(columnIdNode);
  248.                 sqlGet.addSelectField(columnLockDate);
  249.                 sqlGet.addSelectField(columnUpdateDate);
  250.                 sqlGet.addFromTable(table);
  251.                 sqlGet.setANDLogicOperator(true);
  252.                 if(this.mapping.sizeUniqueConditionValues()>0) {
  253.                     for (int i = 0; i < this.mapping.sizeUniqueConditionValues(); i++) {
  254.                         Object o = this.mapping.getUniqueConditionValue(i);
  255.                         if(o!=null) {
  256.                             sqlGet.addWhereCondition(this.mapping.getUniqueConditionColumnName(i)+"=?");
  257.                         }
  258.                         else {
  259.                             sqlGet.addWhereIsNullCondition(this.mapping.getUniqueConditionColumnName(i));
  260.                         }
  261.                     }
  262.                 }
  263.                 sqlGet.setSelectForUpdate(true);
  264.                
  265.                 //System.out.println("SELECT ["+sqlGet.createSQLQuery()+"]");
  266.                 pstmt = conDB.prepareStatement(sqlGet.createSQLQuery());
  267.                 int index = 1;
  268.                 if(this.mapping.sizeUniqueConditionValues()>0) {
  269.                     for (int i = 0; i < this.mapping.sizeUniqueConditionValues(); i++) {
  270.                         Object o = this.mapping.getUniqueConditionValue(i);
  271.                         if(o!=null) {
  272.                             this.jdbcParameterUtils.setParameter(pstmt, index++,
  273.                                     this.mapping.getUniqueConditionValue(i),
  274.                                     this.mapping.getUniqueConditionType(i));
  275.                         }
  276.                     }
  277.                 }
  278.                 rs = pstmt.executeQuery();
  279.                 if(rs == null) {
  280.                     pstmt.close();
  281.                     this.log.error("Creazione serial non riuscita: ResultSet is null?");
  282.                     throw new UtilsException("Creazione serial non riuscita: ResultSet is null?");      
  283.                 }
  284.                 boolean exist = rs.next();
  285.                 String idNode = null;
  286.                 Timestamp lockDate = null;
  287.                 Timestamp updateDate = null;
  288.                 if(exist){
  289.                     idNode = rs.getString(columnIdNode);
  290.                     lockDate = rs.getTimestamp(columnLockDate);
  291.                     updateDate = rs.getTimestamp(columnUpdateDate);
  292.                 }      
  293.                 rs.close();
  294.                 pstmt.close();

  295.                 if(!exist) {
  296.                     if(JDBCUtilities.isTransactionIsolationSerializable(conDB.getTransactionIsolation(), this.databaseType)==false) {
  297.                         rowNotExistsAndSerializableLevelNotFound = true;
  298.                         continue;
  299.                     }
  300.                 }
  301.                
  302.                 Timestamp now = DateManager.getTimestamp();
  303.                
  304.                 SimpleDateFormat dateformat = DateUtils.getSimpleDateFormatMs();
  305.                 StringBuilder statoLock = new StringBuilder("Lock per tabella ["+table+"]");
  306.                 if(this.mapping.sizeUniqueConditionValues()>0) {
  307.                     for (int i = 0; i < this.mapping.sizeUniqueConditionValues(); i++) {
  308.                         statoLock.append(" ["+this.mapping.getUniqueConditionColumnName(i)+"="+this.mapping.getUniqueConditionValue(i)+"]");
  309.                     }
  310.                 }
  311.                 statoLock.append("\n");
  312.                 if(exist && idNode!=null){
  313.                     statoLock.append("OldIdNode["+idNode+"] OldcreateTime["+dateformat.format(lockDate)+"] OldupdateTime["+dateformat.format(updateDate)+"]");
  314.                     statoLock.append("\n");
  315.                 }
  316.                 statoLock.append("IdNode["+this.config.getIdNode()+"] ");
  317.                 statoLock.append("Now["+dateformat.format(now)+"]");
  318.                 if(details!=null) {
  319.                     statoLock.append(" Details["+details+"]");
  320.                 }
  321.                
  322.                 SemaphoreEvent semaphoreEvent = new SemaphoreEvent();
  323.                 semaphoreEvent.setDate(now);
  324.                 semaphoreEvent.setOperationType(operationType);
  325.                 semaphoreEvent.setIdNode(this.config.getIdNode());
  326.                 boolean emitSemaphoreEvent = false;
  327.                
  328.                 if(SemaphoreOperationType.NEW.equals(operationType)) {
  329.                
  330.                     if(!exist){
  331.    
  332.                         // CREO ENTRY
  333.                         ISQLQueryObject sqlInsert = SQLObjectFactory.createSQLQueryObject(this.databaseType);
  334.                         sqlInsert.addInsertTable(table);
  335.                         sqlInsert.addInsertField(columnIdNode, "?");
  336.                         sqlInsert.addInsertField(columnLockDate, "?");
  337.                         sqlInsert.addInsertField(columnUpdateDate, "?");
  338.                         sqlInsert.addInsertField(columnDetails, "?");
  339.                         if(this.mapping.sizeUniqueConditionValues()>0) {
  340.                             for (int i = 0; i < this.mapping.sizeUniqueConditionValues(); i++) {
  341.                                 sqlInsert.addInsertField(this.mapping.getUniqueConditionColumnName(i),"?");
  342.                             }
  343.                         }
  344.                         //System.out.println("INSERT ["+sqlInsert.createSQLInsert()+"]");
  345.                         pstmtInsert = conDB.prepareStatement(sqlInsert.createSQLInsert());
  346.                         index = 1;
  347.                         pstmtInsert.setString(index++, this.config.getIdNode());
  348.                         pstmtInsert.setTimestamp(index++, now);
  349.                         pstmtInsert.setTimestamp(index++, now);
  350.                         this.jdbcParameterUtils.setParameter(pstmtInsert, index++, details, String.class);
  351.                         if(this.mapping.sizeUniqueConditionValues()>0) {
  352.                             for (int i = 0; i < this.mapping.sizeUniqueConditionValues(); i++) {
  353.                                 this.jdbcParameterUtils.setParameter(pstmtInsert, index++,
  354.                                         this.mapping.getUniqueConditionValue(i),
  355.                                         this.mapping.getUniqueConditionType(i));
  356.                             }
  357.                         }
  358.                         pstmtInsert.execute();
  359.                         pstmtInsert.close();
  360.                        
  361.                         operazioneConclusaConSuccesso = true;
  362.                        
  363.                         if(this.config.isEmitEvent()) {
  364.                            
  365.                             semaphoreEvent.setDetails(statoLock.toString());
  366.                             semaphoreEvent.setSeverity(SemaphoreEventSeverity.INFO);
  367.                             semaphoreEvent.setLock(operazioneConclusaConSuccesso);
  368.                             emitSemaphoreEvent = true;
  369.                         }
  370.                                                                    
  371.                     }else{
  372.                            
  373.                         String errore = null;
  374.                        
  375.                         if(idNode==null) {
  376.                            
  377.                             // non esiste un altro thread che possiede il lock, lo prendo
  378.                             operazioneConclusaConSuccesso = true;
  379.                            
  380.                         }
  381.                         else {
  382.                                                        
  383.                             // Controllo idleTime
  384.                             if(this.config.getMaxIdleTime()>0) {
  385.                                
  386.                                 long diff = now.getTime() - updateDate.getTime();
  387.                                 if(diff>this.config.getMaxIdleTime()) {
  388.                                     errore = "Idle Time ("+this.config.getMaxIdleTime()+"ms) exceeded (actual: "+diff+"ms). Lock obtained for idNode '"+this.config.getIdNode()+"'";
  389.                                     operazioneConclusaConSuccesso = true;
  390.                                 }
  391.                                
  392.                             }
  393.                             if(errore==null) {
  394.                                 // Controllo MaxLife
  395.                                 if(this.config.getMaxLife()>0) {
  396.                                    
  397.                                     long diff = now.getTime() - lockDate.getTime();
  398.                                     if(diff>this.config.getMaxLife()) {
  399.                                         errore = "Max Life Time ("+this.config.getMaxLife()+"ms) exceeded (actual: "+diff+"ms). Lock obtained for idNode '"+this.config.getIdNode()+"'";
  400.                                         operazioneConclusaConSuccesso = true;
  401.                                     }
  402.                                    
  403.                                 }
  404.                             }
  405.                            
  406.                             if(errore!=null) {
  407.                                 String dettaglioErrore = statoLock.toString()+"\n"+errore;
  408.                                 this.log.warn(dettaglioErrore);
  409.                             }
  410.                            
  411.                         }
  412.                        
  413.                         if(operazioneConclusaConSuccesso) {
  414.                            
  415.                             ISQLQueryObject sqlUpdate = SQLObjectFactory.createSQLQueryObject(this.databaseType);
  416.                             sqlUpdate.addUpdateTable(table);
  417.                             sqlUpdate.addUpdateField(columnIdNode, "?");
  418.                             sqlUpdate.addUpdateField(columnLockDate, "?");
  419.                             sqlUpdate.addUpdateField(columnUpdateDate, "?");
  420.                             sqlUpdate.addUpdateField(columnDetails, "?");
  421.                             sqlUpdate.setANDLogicOperator(true);
  422.                             if(this.mapping.sizeUniqueConditionValues()>0) {
  423.                                 for (int i = 0; i < this.mapping.sizeUniqueConditionValues(); i++) {
  424.                                     Object o = this.mapping.getUniqueConditionValue(i);
  425.                                     if(o!=null) {
  426.                                         sqlUpdate.addWhereCondition(this.mapping.getUniqueConditionColumnName(i)+"=?");
  427.                                     }
  428.                                     else {
  429.                                         sqlUpdate.addWhereIsNullCondition(this.mapping.getUniqueConditionColumnName(i));
  430.                                     }
  431.                                 }
  432.                             }
  433.                             //System.out.println("UPDATE ["+sqlUpdate.createSQLUpdate()+"]");
  434.                             pstmtInsert = conDB.prepareStatement(sqlUpdate.createSQLUpdate());
  435.                             index = 1;
  436.                             pstmtInsert.setString(index++, this.config.getIdNode());
  437.                             pstmtInsert.setTimestamp(index++, now);
  438.                             pstmtInsert.setTimestamp(index++, now);
  439.                             this.jdbcParameterUtils.setParameter(pstmtInsert, index++, details, String.class);
  440.                             if(this.mapping.sizeUniqueConditionValues()>0) {
  441.                                 for (int i = 0; i < this.mapping.sizeUniqueConditionValues(); i++) {
  442.                                     Object o = this.mapping.getUniqueConditionValue(i);
  443.                                     if(o!=null) {
  444.                                         this.jdbcParameterUtils.setParameter(pstmtInsert, index++,
  445.                                                 this.mapping.getUniqueConditionValue(i),
  446.                                                 this.mapping.getUniqueConditionType(i));
  447.                                     }
  448.                                 }
  449.                             }
  450.                             pstmtInsert.executeUpdate();
  451.                             pstmtInsert.close();
  452.                            
  453.                             if(this.config.isEmitEvent()) {
  454.                                 if(errore!=null) {
  455.                                     semaphoreEvent.setDetails(errore+"\n"+statoLock.toString()); // non e' un errore vero, ma la spiegazione del perche' ho levato il lock ad un altro
  456.                                 }
  457.                                 else {
  458.                                     semaphoreEvent.setDetails(statoLock.toString());
  459.                                 }
  460.                                 semaphoreEvent.setSeverity(SemaphoreEventSeverity.INFO);
  461.                                 semaphoreEvent.setLock(operazioneConclusaConSuccesso);
  462.                                 emitSemaphoreEvent = true;
  463.                             }
  464.                         }
  465.                     }

  466.                 }
  467.                 else if(SemaphoreOperationType.UPDATE.equals(operationType)
  468.                         ||
  469.                         SemaphoreOperationType.RELEASE.equals(operationType)) {
  470.                    
  471.                     if(idNode!=null && idNode.equals(this.config.getIdNode())) {
  472.                        
  473.                         // update valore della colonna di update
  474.                         ISQLQueryObject sqlUpdate = SQLObjectFactory.createSQLQueryObject(this.databaseType);
  475.                         sqlUpdate.addUpdateTable(table);
  476.                         if(SemaphoreOperationType.UPDATE.equals(operationType)){
  477.                             sqlUpdate.addUpdateField(columnUpdateDate, "?");
  478.                             sqlUpdate.addUpdateField(columnDetails, "?");
  479.                         }
  480.                         else {
  481.                             sqlUpdate.addUpdateField(columnIdNode, "?");
  482.                             sqlUpdate.addUpdateField(columnLockDate, "?");
  483.                             sqlUpdate.addUpdateField(columnUpdateDate, "?");
  484.                             sqlUpdate.addUpdateField(columnDetails, "?");
  485.                         }
  486.                         sqlUpdate.setANDLogicOperator(true);
  487.                         if(this.mapping.sizeUniqueConditionValues()>0) {
  488.                             for (int i = 0; i < this.mapping.sizeUniqueConditionValues(); i++) {
  489.                                 Object o = this.mapping.getUniqueConditionValue(i);
  490.                                 if(o!=null) {
  491.                                     sqlUpdate.addWhereCondition(this.mapping.getUniqueConditionColumnName(i)+"=?");
  492.                                 }
  493.                                 else {
  494.                                     sqlUpdate.addWhereIsNullCondition(this.mapping.getUniqueConditionColumnName(i));
  495.                                 }
  496.                             }
  497.                         }
  498.                         //System.out.println("UPDATE ["+sqlUpdate.createSQLUpdate()+"]");
  499.                         pstmtInsert = conDB.prepareStatement(sqlUpdate.createSQLUpdate());
  500.                         index = 1;
  501.                         if(SemaphoreOperationType.UPDATE.equals(operationType)){
  502.                             pstmtInsert.setTimestamp(index++, now);
  503.                             this.jdbcParameterUtils.setParameter(pstmtInsert, index++, details, String.class);
  504.                         }
  505.                         else {
  506.                             this.jdbcParameterUtils.setParameter(pstmtInsert, index++, null, String.class);
  507.                             this.jdbcParameterUtils.setParameter(pstmtInsert, index++, null, Timestamp.class);
  508.                             this.jdbcParameterUtils.setParameter(pstmtInsert, index++, null, Timestamp.class);
  509.                             this.jdbcParameterUtils.setParameter(pstmtInsert, index++, null, String.class);
  510.                         }
  511.                         if(this.mapping.sizeUniqueConditionValues()>0) {
  512.                             for (int i = 0; i < this.mapping.sizeUniqueConditionValues(); i++) {
  513.                                 Object o = this.mapping.getUniqueConditionValue(i);
  514.                                 if(o!=null) {
  515.                                     this.jdbcParameterUtils.setParameter(pstmtInsert, index++,
  516.                                             this.mapping.getUniqueConditionValue(i),
  517.                                             this.mapping.getUniqueConditionType(i));
  518.                                 }
  519.                             }
  520.                         }
  521.                         pstmtInsert.executeUpdate();
  522.                         pstmtInsert.close();
  523.                        
  524.                         operazioneConclusaConSuccesso = true;
  525.                        
  526.                         if(this.config.isEmitEvent()) {
  527.                             semaphoreEvent.setDetails(statoLock.toString());
  528.                             semaphoreEvent.setSeverity(SemaphoreEventSeverity.DEBUG);
  529.                             semaphoreEvent.setLock(operazioneConclusaConSuccesso);
  530.                             emitSemaphoreEvent = true;
  531.                         }

  532.                     }
  533.                     else {
  534.                        
  535.                         // if idCluster e' null o diverso dal mio
  536.                         // Puo' darsi che qualche altro batch si e' preso il lock perchè era scaduto il tempo, e poi addirittura l'ha anche rilascato
  537.                         String msgErrore = "IdNode is null, lock without owner";
  538.                         if(idNode!=null) {
  539.                             msgErrore = "IdNode owner ["+idNode+"] different";
  540.                         }
  541.                        
  542.                         operazioneConclusaConSuccesso = false;
  543.                        
  544.                         if(this.config.isEmitEvent()) {
  545.                             semaphoreEvent.setDetails(statoLock.toString()+"\n"+msgErrore);
  546.                             //semaphoreEvent.setSeverity(SemaphoreEventSeverity.ERROR);
  547.                             semaphoreEvent.setSeverity(SemaphoreEventSeverity.WARN);
  548.                             semaphoreEvent.setLock(operazioneConclusaConSuccesso);
  549.                             emitSemaphoreEvent = true;
  550.                         }
  551.                                                
  552.                     }
  553.                
  554.                 }
  555.                

  556.                 // Chiusura Transazione
  557.                 conDB.commit();

  558.                 // Emetto evento dopo il commit
  559.                 if(emitSemaphoreEvent) {
  560.                     this.config.getEventGenerator().emitEvent(conDB, semaphoreEvent);
  561.                 }
  562.                
  563.                 // Analisi Lock effettuata
  564.                 processOK = true;

  565.             } catch(Throwable e) {
  566.                 ps.append("********* Exception Iteration ["+iteration+"] **********\n");
  567.                 String msg = e.getMessage(); // per evitare out of memory
  568.                 if(msg==null){
  569.                     msg = "NULL-MESSAGE";
  570.                 }
  571.                 if(messageException.contains(msg)){
  572.                     ps.append("Message already occurs: "+msg);
  573.                 }
  574.                 else{
  575.                     e.printStackTrace(ps);
  576.                     messageException.add(msg);
  577.                 }
  578.                 ps.append("\n\n");
  579.                
  580.                 if(infoStatistics!=null){
  581.                     infoStatistics.addErrorSerializableAccess(e);
  582.                 }
  583.                
  584.                 //System.out.println("ERRORE ["+operationType+"] Iteration ["+iteration+"]: "+e.getMessage());
  585.                 //this.log.info("ERROR ["+operationType+"] Iteration ["+iteration+"] GET SERIAL SQL ["+e.getMessage()+"]");
  586.                 try{
  587.                     if( rs != null )
  588.                         rs.close();
  589.                 } catch(Exception er) {}
  590.                 try{
  591.                     if( pstmt != null )
  592.                         pstmt.close();
  593.                 } catch(Exception er) {}
  594.                 try{
  595.                     if( pstmtInsert != null )
  596.                         pstmtInsert.close();
  597.                 } catch(Exception er) {}
  598.                 try{
  599.                     conDB.rollback();
  600.                 } catch(Exception er) {}
  601.             }

  602.             if(processOK == false){
  603.                 // Per aiutare ad evitare conflitti
  604.                 try{
  605.                     int intervalloDestro = checkIntervalloJDBC;
  606.                     if(this.config.isSerializableNextIntervalTimeMsIncrementMode()){
  607.                         intervalloDestro = intervalloDestro + (iteration*this.config.getSerializableNextIntervalTimeMsIncrement());
  608.                         if(intervalloDestro>this.config.getMaxSerializableNextIntervalTimeMs()){
  609.                             intervalloDestro = this.config.getMaxSerializableNextIntervalTimeMs();
  610.                         }
  611.                     }
  612.                    
  613.                     int sleep = getRandom().nextInt(intervalloDestro);
  614.                     //System.out.println("Sleep: "+sleep);
  615.                     Utilities.sleep(sleep); // random
  616.                 }catch(Exception eRandom){}
  617.             }
  618.         }

  619.         try{
  620.             if( ps != null ){
  621.                 ps.flush();
  622.             }
  623.         } catch(Exception er) {}
  624.         try{
  625.             if( out != null ){
  626.                 out.flush();
  627.             }
  628.         } catch(Exception er) {}
  629.         try{
  630.             if( ps != null ){
  631.                 ps.close();
  632.             }
  633.         } catch(Exception er) {}
  634.         try{
  635.             if( out != null ){
  636.                 out.close();
  637.             }
  638.         } catch(Exception er) {}
  639.        
  640.         if(rowNotExistsAndSerializableLevelNotFound){
  641.             String msgError = "Raw not exists and serializable level is disabled";
  642.             this.log.error(msgError); // in out è presente l'intero stackTrace
  643.             throw new UtilsException(msgError);
  644.         }
  645.        
  646.         if(processOK==false){
  647.             String msgError = "Lock process failed: l'accesso serializable non ha permesso il recupero del lock";
  648.             this.log.error(msgError+": "+out.toString()); // in out è presente l'intero stackTrace
  649.            
  650.             if(this.config.isEmitEvent()) {
  651.                 SemaphoreEvent event = new SemaphoreEvent();
  652.                 event.setDate(DateManager.getDate());
  653.                 event.setOperationType(operationType);
  654.                 event.setDetails(msgError);
  655.                 event.setSeverity(SemaphoreEventSeverity.ERROR);
  656.                 event.setLock(false);
  657.                 this.config.getEventGenerator().emitEvent(conDB, event);
  658.             }
  659.            
  660.             throw new UtilsException(msgError);
  661.         }

  662.         //System.out.println("TERMINO ["+operationType+"] (attesaWhile:"+attesaAttivaJDBC+"): "+operazioneConclusaConSuccesso);
  663.        
  664.         return operazioneConclusaConSuccesso;
  665.                
  666.     }
  667.    
  668. }