TransactionContext.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.core.transazioni;

  21. import java.util.ArrayList;
  22. import java.util.List;
  23. import java.util.Map;
  24. import java.util.Set;
  25. import java.util.concurrent.ConcurrentHashMap;

  26. import org.openspcoop2.pdd.config.OpenSPCoop2Properties;
  27. import org.openspcoop2.pdd.logger.OpenSPCoop2Logger;
  28. import org.openspcoop2.utils.SemaphoreLock;

  29. /**    
  30.  * TransactionContext
  31.  *
  32.  * @author Poli Andrea (poli@link.it)
  33.  * @author $Author$
  34.  * @version $Rev$, $Date$
  35.  */
  36. public class TransactionContext {

  37.     private static final String INDICAZIONE_GESTIONE_STATEFUL_ERRATA = "Indicazione sulla gestione stateful errata: ";
  38.    
  39.     private static Boolean gestioneStateful = null;
  40.     public static synchronized void initGestioneStateful() throws Exception{
  41.         if(gestioneStateful==null){
  42.             gestioneStateful = OpenSPCoop2Properties.getInstance().isTransazioniStatefulEnabled();
  43.         }
  44.     }
  45.    
  46.     private static boolean useThreadLocal = true;
  47.     private static Map<String, TransactionInfo> setTransactionInfoThreadLocal = new ConcurrentHashMap<>(); // 1 sola insert per ogni thread, poi acceduta tramite getTransactionKeys
  48.     private static final ThreadLocal<TransactionInfo> transactionContext_threadLocal =  new ThreadLocal<>() {
  49.          @Override
  50.          protected TransactionInfo initialValue() {
  51.              String tName = Thread.currentThread().getName();
  52.              TransactionInfo info = new TransactionInfo(tName);
  53.              setTransactionInfoThreadLocal.put(tName, info);
  54.              return info;
  55.          }
  56.     };
  57.        
  58.     public static void removeTransactionContext_threadLocal() {
  59.         if(transactionContext_threadLocal!=null) {
  60.             transactionContext_threadLocal.remove();
  61.         }
  62.     }
  63.    
  64.     private static Map<String, Transaction> transactionContextShared = null;
  65.     public static synchronized void initResources() throws Exception{
  66.         if(!useThreadLocal) {
  67.             if(OpenSPCoop2Properties.getInstance().isConfigurazioneCache_transactionContext_accessiSynchronized()) {
  68.                 transactionContextShared = new java.util.Hashtable<>();
  69.             }
  70.             else {
  71.                 transactionContextShared = new ConcurrentHashMap<>();
  72.             }
  73.         }
  74.     }
  75.     public static String getTransactionContextType() {
  76.         if(useThreadLocal) {
  77.             return "ThreadLocal";
  78.         }
  79.         else {
  80.             return transactionContextShared.getClass().getName();
  81.         }
  82.     }
  83.     /**public static String getTransactionContextType() {
  84.         return transactionContext.getClass().getName();
  85.     }*/
  86.    
  87.     public static List<String> getTransactionKeys() {
  88.         // Lo clono per non incorrere in errori di modifica durante il runtime
  89.         List<String> keys = new ArrayList<>();
  90.         if(useThreadLocal) {
  91.            
  92.             List<String> thNames = new ArrayList<>();
  93.             thNames.addAll(setTransactionInfoThreadLocal.keySet());
  94.            
  95.             for (String tName : thNames) {
  96.                 TransactionInfo tInfo = setTransactionInfoThreadLocal.get(tName);
  97.                 if(tInfo!=null && tInfo.transaction!=null) {
  98.                     String id = null;
  99.                     try {
  100.                         id = tInfo.transaction.getId();
  101.                     }catch(Throwable t) {
  102.                         // potrebbe diventare null
  103.                     }
  104.                     if(id!=null) {
  105.                         keys.add(id);
  106.                     }
  107.                 }
  108.             }
  109.         }
  110.         else {
  111.             keys.addAll(transactionContextShared.keySet());
  112.         }
  113.         return keys;
  114.     }
  115.            
  116.     public static void createTransaction(String id, String originator) throws TransactionNotExistsException{
  117.         if(useThreadLocal) {
  118.             if(transactionContext_threadLocal.get().transaction==null || !id.equals(transactionContext_threadLocal.get().transaction.getId()) ) {
  119.                 try{
  120.                     if(gestioneStateful==null){
  121.                         initGestioneStateful();
  122.                     }
  123.                 }catch(Exception e){
  124.                     throw new TransactionNotExistsException("Indicazione sulla gestione stateful errata: "+e.getMessage(),e);
  125.                 }
  126.                 transactionContext_threadLocal.get().transaction = new Transaction(id, originator, gestioneStateful);
  127.             }
  128.         }
  129.         else {
  130.             if(!transactionContextShared.containsKey(id)) {
  131.                 try{
  132.                     if(gestioneStateful==null){
  133.                         initGestioneStateful();
  134.                     }
  135.                 }catch(Exception e){
  136.                     throw new TransactionNotExistsException(INDICAZIONE_GESTIONE_STATEFUL_ERRATA+e.getMessage(),e);
  137.                 }
  138.                 Transaction transaction = new Transaction(id, originator, gestioneStateful);
  139.                 transactionContextShared.put(id, transaction);
  140.             }
  141.         }
  142.     }
  143.    
  144.     // usato per trasferire l'oggetto in un altro thread
  145.     public static void setTransactionThreadLocal(String id, Transaction transaction) throws TransactionNotExistsException {
  146.         if(useThreadLocal &&
  147.                 (transactionContext_threadLocal.get().transaction==null || !id.equals(transactionContext_threadLocal.get().transaction.getId()) )
  148.             ){
  149.             try{
  150.                 if(gestioneStateful==null){
  151.                     initGestioneStateful();
  152.                 }
  153.             }catch(Exception e){
  154.                 throw new TransactionNotExistsException(INDICAZIONE_GESTIONE_STATEFUL_ERRATA+e.getMessage(),e);
  155.             }
  156.             transactionContext_threadLocal.get().transaction = transaction;
  157.         }
  158.     }
  159.        
  160.     public static Transaction getTransaction(String id) throws TransactionNotExistsException{
  161.         return getTransaction(id, null, false);
  162.     }
  163.     private static Transaction getTransaction(String id,String originator, boolean createIfNotExists) throws TransactionNotExistsException{
  164.         if(useThreadLocal) {
  165.             if(transactionContext_threadLocal.get().transaction==null || !id.equals(transactionContext_threadLocal.get().transaction.getId()) ) {
  166.                 if(createIfNotExists){
  167.                     createTransaction(id, originator);
  168.                 }
  169.                 else{
  170.                     throw new TransactionNotExistsException("Transaction con id ["+id+"] non esiste");
  171.                 }
  172.             }
  173.             return transactionContext_threadLocal.get().transaction;
  174.         }
  175.         else {
  176.             /**if(transactionContext==null){
  177.             //  System.out.println("TX IS NULL??");
  178.             //}
  179.             //System.out.println("TX get ("+id+")");*/
  180.             Transaction transaction = transactionContextShared.get(id);
  181.             /**System.out.println("TX get ("+id+") query fatta");*/
  182.             if(transaction==null){
  183.                 if(createIfNotExists){
  184.                     createTransaction(id, originator);
  185.                 }
  186.                 else{
  187.                     throw new TransactionNotExistsException("Transaction con id ["+id+"] non esiste");
  188.                 }
  189.             }
  190.             return transaction;
  191.         }
  192.     }
  193.    
  194.     public static Transaction removeTransaction(String id){
  195.         if(useThreadLocal) {
  196.             Transaction t = transactionContext_threadLocal.get().transaction;
  197.             transactionContext_threadLocal.get().transaction = null;
  198.             return t;
  199.         }
  200.         else {
  201.             return transactionContextShared.remove(id);
  202.         }
  203.     }
  204.    
  205.    
  206.     private static Set<String> idBustaFiltroDuplicati = ConcurrentHashMap.newKeySet();
  207.    
  208.     public static List<String> getIdBustaKeys() {
  209.         // Lo clono per non incorrere in errori di modifica durante il runtime
  210.         List<String> keys = new ArrayList<>();
  211.         keys.addAll(idBustaFiltroDuplicati);
  212.         return keys;
  213.     }
  214.    
  215.     private static org.openspcoop2.utils.Semaphore semaphoreIdentificativoProtocollo = new org.openspcoop2.utils.Semaphore("TransactionContext.idProtocollo");
  216.     public static void registraIdentificativoProtocollo(String idBusta, String idTransazione) throws Exception{
  217.         SemaphoreLock lock = semaphoreIdentificativoProtocollo.acquire("registraIdentificativoProtocollo_"+idBusta, idTransazione);
  218.         try {
  219.             if(idBustaFiltroDuplicati.contains(idBusta)){
  220.                 throw new Exception("DUPLICATA");
  221.             }
  222.             idBustaFiltroDuplicati.add(idBusta);
  223.         }finally{
  224.             semaphoreIdentificativoProtocollo.release(lock, "registraIdentificativoProtocollo_"+idBusta, idTransazione);
  225.         }
  226.     }
  227.     public static boolean containsIdentificativoProtocollo(String idBusta){
  228.         return idBustaFiltroDuplicati.contains(idBusta);
  229.     }
  230.     public static void removeIdentificativoProtocollo(String idBusta){
  231.         idBustaFiltroDuplicati.remove(idBusta);
  232.     }
  233. }

  234. class TransactionInfo {
  235.    
  236.     Transaction transaction = null;
  237.    
  238.     public TransactionInfo(String threadName) {
  239.         OpenSPCoop2Logger.getLoggerOpenSPCoopConnettori().debug("ThreadLocal transaction context created for thread '"+threadName+"'");
  240.     }
  241.    
  242. }