DataSource.java
/*
* GovWay - A customizable API Gateway
* https://govway.org
*
* Copyright (c) 2005-2024 Link.it srl (https://link.it).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3, as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openspcoop2.utils.datasource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import org.openspcoop2.utils.TipiDatabase;
import org.openspcoop2.utils.Utilities;
import org.openspcoop2.utils.UtilsException;
import org.openspcoop2.utils.date.DateManager;
import org.openspcoop2.utils.date.DateUtils;
import org.openspcoop2.utils.id.UUIDUtilsGenerator;
import org.openspcoop2.utils.jdbc.JDBCUtilities;
/**
* Datasource
*
* @author Poli Andrea (apoli@link.it)
* @author $Author$
* @version $Rev$, $Date$
*/
public class DataSource implements javax.sql.DataSource,java.sql.Wrapper {
private javax.sql.DataSource datasource;
private TipiDatabase tipoDatabase;
private boolean wrapOriginalMethods;
private String uuidDatasource;
private String applicativeIdDatasource;
/** Data di rilascio della risorsa */
private Date date = null;
private int transactionIsolationLevelDefault;
private String jndiName;
private boolean closed = false;
private Map<String,org.openspcoop2.utils.datasource.Connection> releasedConnections = new ConcurrentHashMap<String,org.openspcoop2.utils.datasource.Connection>();
public String[] getJmxStatus() throws UtilsException{
if(this.releasedConnections==null || this.releasedConnections.size()<=0)
return null;
org.openspcoop2.utils.datasource.Connection[] list = this.releasedConnections.values().toArray(new org.openspcoop2.utils.datasource.Connection[1]);
List<String> listResource = new ArrayList<>();
for (int i = 0; i < list.length; i++) {
org.openspcoop2.utils.datasource.Connection connection = (org.openspcoop2.utils.datasource.Connection) list[i];
StringBuilder bf = new StringBuilder();
SimpleDateFormat dateformat = DateUtils.getSimpleDateFormatMs();
bf.append("(").append(dateformat.format(connection.getDate())).append(") ");
if(connection.getIdTransazione()!=null){
if(bf.length() > 0){
bf.append(" ");
}
bf.append("idTransazione:");
bf.append(connection.getIdTransazione());
}
if(connection.getModuloFunzionale()!=null && (connection.getModuloFunzionale() instanceof String)){
if(bf.length() > 0){
bf.append(" ");
}
bf.append("moduloFunzionale:");
bf.append(connection.getModuloFunzionale());
}
listResource.add(bf.toString());
}
if(listResource.size()>0){
Collections.sort(listResource);
return listResource.toArray(new String[1]);
}else
return null;
}
public String getInformazioniDatabase() throws Exception{
InformazioniDatabaseChecker versioneBaseDatiChecker = new InformazioniDatabaseChecker(this);
return Utilities.execute(5, versioneBaseDatiChecker);
}
protected DataSource(javax.sql.DataSource datasource, TipiDatabase tipoDatabase, boolean wrapOriginalMethods, String jndiName, String applicativeIdDatasource) throws SQLException{
try{
this.datasource = datasource;
this.tipoDatabase = tipoDatabase;
this.wrapOriginalMethods = wrapOriginalMethods;
this.uuidDatasource = UUIDUtilsGenerator.newUUID();
this.jndiName = jndiName;
this.applicativeIdDatasource = applicativeIdDatasource;
this.date = DateManager.getDate();
}catch(Exception e){
throw new SQLException(e.getMessage(),e);
}
java.sql.Connection connectionTest = null;
try{
// Prelevo livello di transaction isolation
connectionTest = this.datasource.getConnection();
this.transactionIsolationLevelDefault = connectionTest.getTransactionIsolation();
}catch(Exception e){
throw new SQLException("Test getConnection failed: "+e.getMessage(),e);
}finally {
if(connectionTest!=null) {
connectionTest.close();
}
}
}
public String getUuidDatasource() {
return this.uuidDatasource;
}
public String getApplicativeIdDatasource() {
return this.applicativeIdDatasource;
}
public int size() {
return this.releasedConnections.size();
}
public int getTransactionIsolationLevelDefault() {
return this.transactionIsolationLevelDefault;
}
public String getJndiName() {
return this.jndiName;
}
public Date getDate() {
return this.date;
}
public TipiDatabase getTipoDatabase() {
return this.tipoDatabase;
}
// Metodi utilizzati dallo shutdown
boolean isClosed() {
return this.closed;
}
void setClosed(boolean closed) {
this.closed = closed;
}
void releaseConnnections(){
Collection<org.openspcoop2.utils.datasource.Connection> list = this.releasedConnections.values();
Iterator<org.openspcoop2.utils.datasource.Connection> it = list.iterator();
while (it.hasNext()) {
org.openspcoop2.utils.datasource.Connection connection = (org.openspcoop2.utils.datasource.Connection) it.next();
try{
connection.close();
}catch(Exception eclose){}
}
}
@Override
public Connection getConnection() throws SQLException {
if(this.wrapOriginalMethods){
// wrap verso getConnection sottostante.
return this.getWrappedConnection(null, null);
}
else{
throw new SQLException("Not Supported, use getWrappedConnection");
}
}
@Override
public Connection getConnection(String idTransazione, String moduloFunzionale) throws SQLException {
if(this.wrapOriginalMethods){
// wrap verso getConnection sottostante.
return this.getWrappedConnection(idTransazione, moduloFunzionale);
}
else{
throw new SQLException("Not Supported, use getWrappedConnection");
}
}
public org.openspcoop2.utils.datasource.Connection getWrappedConnection() throws SQLException {
return this.getWrappedConnection(null, null);
}
public org.openspcoop2.utils.datasource.Connection getWrappedConnection(String idTransazione) throws SQLException {
return this.getWrappedConnection(idTransazione, null);
}
public org.openspcoop2.utils.datasource.Connection getWrappedConnection(String idTransazione, Object moduloFunzionale) throws SQLException {
if(this.closed){
throw new SQLException("Shutdown in progress");
}
try{
org.openspcoop2.utils.datasource.Connection c = new org.openspcoop2.utils.datasource.Connection(this.datasource.getConnection(), this.tipoDatabase,
idTransazione, moduloFunzionale, this.uuidDatasource);
this.releasedConnections.put(c.getId(), c);
return c;
}catch(Exception e){
throw new SQLException(e.getMessage(),e);
}
}
protected void unregisterConnection(org.openspcoop2.utils.datasource.Connection connection) throws SQLException{
if(this.releasedConnections.containsKey(connection.getId())){
this.releasedConnections.remove(connection.getId()).closeWrappedConnection();
}
}
public void closeConnection(org.openspcoop2.utils.datasource.Connection connection) throws SQLException{
if(connection==null){
throw new SQLException("Parameter undefined");
}
connection.close();
}
public void closeConnection(Connection connection) throws SQLException{
if(connection==null){
throw new SQLException("Parameter undefined");
}
if(connection instanceof org.openspcoop2.utils.datasource.Connection){
((org.openspcoop2.utils.datasource.Connection)connection).close();
}
else{
throw new SQLException("Connection type unsupported, expected:"+org.openspcoop2.utils.datasource.Connection.class+" found:"+connection.getClass().getName());
}
}
// **** METODI SU CUI E' STATO SOLAMENTE EFFETTUATO IL WRAP ******
@Override
public PrintWriter getLogWriter() throws SQLException {
return this.datasource.getLogWriter();
}
@Override
public void setLogWriter(PrintWriter pw) throws SQLException {
this.datasource.setLogWriter(pw);
}
@Override
public int getLoginTimeout() throws SQLException {
return this.datasource.getLoginTimeout();
}
@Override
public void setLoginTimeout(int timeout) throws SQLException {
this.datasource.setLoginTimeout(timeout);
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
if(this.datasource instanceof java.sql.Wrapper){
return ((java.sql.Wrapper)this.datasource).unwrap(iface);
}
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
if(this.datasource instanceof java.sql.Wrapper){
return ((java.sql.Wrapper)this.datasource).isWrapperFor(iface);
}
return false;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return this.datasource.getParentLogger();
}
}
class InformazioniDatabaseChecker implements Callable<String>{
private DataSource dataSource;
public InformazioniDatabaseChecker(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public String call() throws Exception {
StringBuilder bf = new StringBuilder();
if(this.dataSource.getTipoDatabase()!=null){
bf.append("TipoDatabase: "+this.dataSource.getTipoDatabase().getNome());
}
else{
throw new Exception("Tipo di Database non disponibile");
}
Connection c = null;
try{
c = (Connection) this.dataSource.getConnection();
JDBCUtilities.addInformazioniDatabaseFromMetaData(c, bf);
if(bf.length()<=0){
throw new Exception("Non sono disponibili informazioni sul database");
}else{
return bf.toString();
}
}finally{
try{
if(c!=null)
this.dataSource.closeConnection(c);
}catch(Exception eClose){
// close
}
}
}
}