DataSource.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.datasource;

  21. import java.io.PrintWriter;
  22. import java.sql.Connection;
  23. import java.sql.SQLException;
  24. import java.sql.SQLFeatureNotSupportedException;
  25. import java.text.SimpleDateFormat;
  26. import java.util.ArrayList;
  27. import java.util.Collection;
  28. import java.util.Collections;
  29. import java.util.Date;
  30. import java.util.Iterator;
  31. import java.util.List;
  32. import java.util.Map;
  33. import java.util.concurrent.Callable;
  34. import java.util.concurrent.ConcurrentHashMap;
  35. import java.util.concurrent.TimeoutException;

  36. import org.openspcoop2.utils.TipiDatabase;
  37. import org.openspcoop2.utils.Utilities;
  38. import org.openspcoop2.utils.UtilsException;
  39. import org.openspcoop2.utils.date.DateManager;
  40. import org.openspcoop2.utils.date.DateUtils;
  41. import org.openspcoop2.utils.id.UUIDUtilsGenerator;
  42. import org.openspcoop2.utils.jdbc.JDBCUtilities;
  43. import org.slf4j.Logger;

  44. /**
  45.  * Datasource
  46.  *  
  47.  * @author Poli Andrea (apoli@link.it)
  48.  * @author $Author$
  49.  * @version $Rev$, $Date$
  50.  */
  51. public class DataSource implements javax.sql.DataSource,java.sql.Wrapper {

  52.     static Logger checkLogger = null;
  53.     static boolean checkIsClosed = true;
  54.     static boolean checkAutocommit = true;
  55.     public static boolean isCheckIsClosed() {
  56.         return checkIsClosed;
  57.     }
  58.     public static void setCheckIsClosed(boolean checkIsClosed) {
  59.         DataSource.checkIsClosed = checkIsClosed;
  60.     }
  61.     public static boolean isCheckAutocommit() {
  62.         return checkAutocommit;
  63.     }
  64.     public static void setCheckAutocommit(boolean checkAutocommit) {
  65.         DataSource.checkAutocommit = checkAutocommit;
  66.     }
  67.     public static Logger getCheckLogger() {
  68.         return checkLogger;
  69.     }
  70.     public static void setCheckLogger(Logger checkLogger) {
  71.         DataSource.checkLogger = checkLogger;
  72.     }
  73.    
  74.     private javax.sql.DataSource wrappedDatasource;
  75.     private TipiDatabase tipoDatabase;
  76.     private boolean wrapOriginalMethods;
  77.     private String uuidDatasource;
  78.     private String applicativeIdDatasource;
  79.    
  80.     /** Data di rilascio della risorsa */
  81.     private Date date = null;

  82.     private int transactionIsolationLevelDefault;
  83.     private String jndiName;
  84.    
  85.     private boolean closed = false;

  86.     private Map<String,org.openspcoop2.utils.datasource.Connection> releasedConnections = new ConcurrentHashMap<>();
  87.    
  88.     public String[] getJmxStatus() {    
  89.         String[] sNull = null;
  90.         if(this.releasedConnections==null || this.releasedConnections.size()<=0)
  91.             return sNull;
  92.    
  93.         org.openspcoop2.utils.datasource.Connection[] list = this.releasedConnections.values().toArray(new org.openspcoop2.utils.datasource.Connection[1]);
  94.         List<String> listResource = new ArrayList<>();
  95.         for (int i = 0; i < list.length; i++) {
  96.             org.openspcoop2.utils.datasource.Connection connection = list[i];
  97.             StringBuilder bf = new StringBuilder();
  98.             SimpleDateFormat dateformat = DateUtils.getSimpleDateFormatMs();
  99.             bf.append("(").append(dateformat.format(connection.getDate())).append(") ");
  100.             if(connection.getIdTransazione()!=null){
  101.                 if(bf.length() > 0){
  102.                     bf.append(" ");
  103.                 }
  104.                 bf.append("idTransazione:");
  105.                 bf.append(connection.getIdTransazione());
  106.             }
  107.             if(connection.getModuloFunzionale() instanceof String){
  108.                 if(bf.length() > 0){
  109.                     bf.append(" ");
  110.                 }
  111.                 bf.append("moduloFunzionale:");
  112.                 bf.append(connection.getModuloFunzionale());
  113.             }
  114.            
  115.             listResource.add(bf.toString());
  116.         }
  117.         if(!listResource.isEmpty()){
  118.             Collections.sort(listResource);
  119.             return listResource.toArray(new String[1]);
  120.         }else
  121.             return sNull;
  122.        
  123.     }
  124.    
  125.     public String getInformazioniDatabase() throws TimeoutException, UtilsException {
  126.         InformazioniDatabaseChecker versioneBaseDatiChecker = new InformazioniDatabaseChecker(this);
  127.         return Utilities.execute(5, versioneBaseDatiChecker);
  128.     }
  129.    
  130.     protected DataSource(javax.sql.DataSource datasource, TipiDatabase tipoDatabase, boolean wrapOriginalMethods, String jndiName, String applicativeIdDatasource) throws SQLException{
  131.         try{
  132.             this.wrappedDatasource = datasource;
  133.             this.tipoDatabase = tipoDatabase;
  134.             this.wrapOriginalMethods = wrapOriginalMethods;
  135.             this.uuidDatasource = UUIDUtilsGenerator.newUUID();
  136.             this.jndiName = jndiName;
  137.             this.applicativeIdDatasource = applicativeIdDatasource;
  138.             this.date = DateManager.getDate();
  139.         }catch(Exception e){
  140.             throw new SQLException(e.getMessage(),e);
  141.         }
  142.         java.sql.Connection connectionTest = null;
  143.         try{
  144.             // Prelevo livello di transaction isolation
  145.             connectionTest = this.wrappedDatasource.getConnection();
  146.             this.transactionIsolationLevelDefault = connectionTest.getTransactionIsolation();
  147.         }catch(Exception e){
  148.             throw new SQLException("Test getConnection failed: "+e.getMessage(),e);
  149.         }finally {
  150.             if(connectionTest!=null) {
  151.                 JDBCUtilities.closeConnection(checkLogger, connectionTest, checkAutocommit, checkIsClosed);
  152.             }
  153.         }
  154.     }
  155.    
  156.     public String getUuidDatasource() {
  157.         return this.uuidDatasource;
  158.     }
  159.    
  160.     public String getApplicativeIdDatasource() {
  161.         return this.applicativeIdDatasource;
  162.     }
  163.    
  164.     public int size() {
  165.         return this.releasedConnections.size();
  166.     }
  167.    
  168.     public int getTransactionIsolationLevelDefault() {
  169.         return this.transactionIsolationLevelDefault;
  170.     }
  171.    
  172.     public String getJndiName() {
  173.         return this.jndiName;
  174.     }
  175.    
  176.     public Date getDate() {
  177.         return this.date;
  178.     }
  179.    
  180.     public TipiDatabase getTipoDatabase() {
  181.         return this.tipoDatabase;
  182.     }
  183.    
  184.     // Metodi utilizzati dallo shutdown
  185.     boolean isClosed() {
  186.         return this.closed;
  187.     }
  188.     void setClosed(boolean closed) {
  189.         this.closed = closed;
  190.     }
  191.     void releaseConnnections(){
  192.         Collection<org.openspcoop2.utils.datasource.Connection> list = this.releasedConnections.values();
  193.         Iterator<org.openspcoop2.utils.datasource.Connection> it = list.iterator();
  194.         while (it.hasNext()) {
  195.             org.openspcoop2.utils.datasource.Connection connection = it.next();
  196.             try{
  197.                 connection.close();
  198.             }catch(Exception eclose){
  199.                 // ignore
  200.             }
  201.         }
  202.     }
  203.    
  204.     @Override
  205.     public Connection getConnection() throws SQLException {
  206.         if(this.wrapOriginalMethods){
  207.             // wrap verso getConnection sottostante.
  208.             return this.getWrappedConnection(null, null);
  209.         }
  210.         else{
  211.             throw new SQLException("Not Supported, use getWrappedConnection");
  212.         }
  213.     }

  214.     @Override
  215.     public Connection getConnection(String idTransazione, String moduloFunzionale) throws SQLException {
  216.         if(this.wrapOriginalMethods){
  217.             // wrap verso getConnection sottostante.
  218.             return this.getWrappedConnection(idTransazione, moduloFunzionale);
  219.         }
  220.         else{
  221.             throw new SQLException("Not Supported, use getWrappedConnection");
  222.         }
  223.     }
  224.    
  225.     public org.openspcoop2.utils.datasource.Connection getWrappedConnection() throws SQLException {
  226.         return this.getWrappedConnection(null, null);
  227.     }
  228.    
  229.     public org.openspcoop2.utils.datasource.Connection getWrappedConnection(String idTransazione) throws SQLException {
  230.         return this.getWrappedConnection(idTransazione, null);
  231.     }
  232.    
  233.     public org.openspcoop2.utils.datasource.Connection getWrappedConnection(String idTransazione, Object moduloFunzionale) throws SQLException {
  234.         if(this.closed){
  235.             throw new SQLException("Shutdown in progress");
  236.         }
  237.         try{
  238.             org.openspcoop2.utils.datasource.Connection c = new org.openspcoop2.utils.datasource.Connection(this.wrappedDatasource.getConnection(), this.tipoDatabase,
  239.                         idTransazione, moduloFunzionale, this.uuidDatasource);
  240.             this.releasedConnections.put(c.getId(), c);
  241.             return c;
  242.         }catch(Exception e){
  243.             throw new SQLException(e.getMessage(),e);
  244.         }
  245.     }

  246.    
  247.     protected void unregisterConnection(org.openspcoop2.utils.datasource.Connection connection) throws SQLException{
  248.         if(this.releasedConnections.containsKey(connection.getId())){
  249.             this.releasedConnections.remove(connection.getId()).closeWrappedConnection();
  250.         }
  251.     }
  252.     public void closeConnection(org.openspcoop2.utils.datasource.Connection connection) throws SQLException{
  253.        
  254.         if(connection==null){
  255.             throw new SQLException("Parameter undefined");
  256.         }
  257.        
  258.         connection.close();
  259.     }
  260.    
  261.     public void closeConnection(Connection connection) throws SQLException{
  262.        
  263.         if(connection==null){
  264.             throw new SQLException("Parameter undefined");
  265.         }
  266.            
  267.         if(connection instanceof org.openspcoop2.utils.datasource.Connection){
  268.             ((org.openspcoop2.utils.datasource.Connection)connection).close();
  269.         }
  270.         else{
  271.             throw new SQLException("Connection type unsupported, expected:"+org.openspcoop2.utils.datasource.Connection.class+" found:"+connection.getClass().getName());
  272.         }
  273.     }
  274.    
  275.    
  276.    
  277.     // **** METODI SU CUI E' STATO SOLAMENTE EFFETTUATO IL WRAP ******
  278.    
  279.     @Override
  280.     public PrintWriter getLogWriter() throws SQLException {
  281.         return this.wrappedDatasource.getLogWriter();
  282.     }

  283.     @Override
  284.     public void setLogWriter(PrintWriter pw) throws SQLException {
  285.         this.wrappedDatasource.setLogWriter(pw);
  286.     }
  287.    
  288.     @Override
  289.     public int getLoginTimeout() throws SQLException {
  290.         return this.wrappedDatasource.getLoginTimeout();
  291.     }

  292.     @Override
  293.     public void setLoginTimeout(int timeout) throws SQLException {
  294.         this.wrappedDatasource.setLoginTimeout(timeout);
  295.     }

  296.     @Override
  297.     public <T> T unwrap(Class<T> iface) throws SQLException {
  298.         if(this.wrappedDatasource instanceof java.sql.Wrapper){
  299.             return ((java.sql.Wrapper)this.wrappedDatasource).unwrap(iface);
  300.         }
  301.         return null;
  302.     }

  303.     @Override
  304.     public boolean isWrapperFor(Class<?> iface) throws SQLException {
  305.         if(this.wrappedDatasource instanceof java.sql.Wrapper){
  306.             return ((java.sql.Wrapper)this.wrappedDatasource).isWrapperFor(iface);
  307.         }
  308.         return false;
  309.     }

  310.     @Override
  311.     public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException {
  312.         return this.wrappedDatasource.getParentLogger();
  313.     }
  314.    


  315. }

  316. class InformazioniDatabaseChecker implements Callable<String>{

  317.     private DataSource dataSource;
  318.    
  319.     public InformazioniDatabaseChecker(DataSource dataSource) {
  320.         this.dataSource = dataSource;
  321.     }
  322.    
  323.     @Override
  324.     public String call() throws Exception {
  325.         StringBuilder bf = new StringBuilder();

  326.         if(this.dataSource.getTipoDatabase()!=null){
  327.             bf.append("TipoDatabase: "+this.dataSource.getTipoDatabase().getNome());
  328.         }
  329.         else{
  330.             throw new UtilsException("Tipo di Database non disponibile");
  331.         }

  332.         Connection c = null;
  333.         try{
  334.             c = this.dataSource.getConnection();

  335.             JDBCUtilities.addInformazioniDatabaseFromMetaData(c, bf);
  336.            
  337.             if(bf.length()<=0){
  338.                 throw new UtilsException("Non sono disponibili informazioni sul database");
  339.             }else{
  340.                 return bf.toString();
  341.             }

  342.         }finally{
  343.             try{
  344.                 if(c!=null)
  345.                     this.dataSource.closeConnection(c);
  346.             }catch(Exception eClose){
  347.                 // close
  348.             }
  349.         }
  350.     }
  351.    
  352. }