JDBC non si connette e per giunta senza errori

di il
8 risposte

JDBC non si connette e per giunta senza errori

Ho configurato su Ubuntu un server con Tomcat e PostgreSQL usando DockerCompose che non funziona e non riesco a capire se il problema è legato alla mia webapp in Java oppure a DockerCompose.
La mia webapp se testata con DockerCompose su Windows 10 funziona quindi penso sia un problema di DockerCompose ma ho qualche dubbio.
Il problema è in questa classe:

    public Connection connect() {
        try {
            DBMS db = this.dbms;
            String url;
            String user;
            String password;
            Connection conn;
            try {
                url = db.getUrl();
                user = db.getUser();
                password = db.getPassword();
                conn = DriverManager.getConnection(url, user, password);
            } catch(Exception e) {
                db = DBMSConnessione();
                url = db.getUrl();
                user = db.getUser();
                password = db.getPassword();
		// url = "jdbc:postgresql://localhost:5432/gis";
		// user = "eb";
		// password = "password";
                conn = DriverManager.getConnection(url, user, password);
		// Quando Java cerca di creare l'oggetto "conn" il server va in errore.
            }
            System.out.println("Connesso al server PostgreSQL con successo.");
            return conn;
        } catch (Exception e) {
            throw new DBMSEccezione("Impossibile connettersi al server PostgreSQL.", e);
        }
    }
Il punto in cui la webapp si blocca è qui:

conn = DriverManager.getConnection(url, user, password);
La cosa strana è che JDBC non si connette e per giunta senza errori.
Il codice di risposta che ottengo è "500 Internal Server Error" che indica che il server ha riscontrato una condizione imprevista, che gli ha impedito di andare avanti.
Sembrerebbe un problema di server e quindi di DockerCompose ma c’è una cosa che non vi ho detto. Se mi connetto, sempre da Ubuntu, con SQuirreL SQL Client usando il driver JDBC ed usando le credenziali date in pasto alla classe ovvero:
url = "jdbc:postgresql://localhost:5432/gis";
user = "eb";
password = "password";
mi connetto senza problemi e riesco anche ad inviare delle query.
Va detto che SQuirreL SQL Client è installato direttamente su Ubuntu mentre la mia webapp viene salvata in un container Tomcat che comunica a sua volta con un altro container PostgreSQL. Per questo motivo penso che sia un problema di configurazione di rete e che la mia webapp sia perfetta.
Resto comunque deluso per non riuscire a leggere questa eccezione sulla shell:

try{
conn = DriverManager.getConnection(url, user, password);
}catch(Exception g){
throw g;
}
e neppure questa:

try{
conn = DriverManager.getConnection(url, user, password);
}catch(Exception g){
throw new DBMSEccezione("Impossibile connettersi al server PostgreSQL.", g);
}
né tantomeno quella generale:

} catch (Exception e) {
            throw new DBMSEccezione("Impossibile connettersi al server PostgreSQL.", e);
}
In pratica ho aggiunto delle eccezioni che non mi servono a nulla.
L’unica soluzione che funziona è questa:

try{
conn = DriverManager.getConnection(url, user, password);
}catch(Exception g){
System.out.println("Impossibile connettersi al server PostgreSQL.");
throw new DBMSEccezione("Impossibile connettersi al server PostgreSQL.", e);
} 
Non so se la mia soluzione è prudente e formalmente buona oppure no ma non ho trovato altre strategie.
Ho anche letto qui:
https://www.slacky.eu/forum/viewtopic.php?t=3663
ma non mi ha aiutato molto perché DockerCompose non da la possibilità di intervenire sulla configurazione del server.
La mia classe eccezione è questa:

public class DBMSEccezione extends RuntimeException {
    public DBMSEccezione(String message, Throwable cause) {
        super(message, cause);
    }
    public DBMSEccezione(String message) {
        super(message);
    }
    public DBMSEccezione(Throwable cause) {
        super(cause);
    }
}

8 Risposte

  • Re: JDBC non si connette e per giunta senza errori

    Hai guardato i log di Tomcat?? È una delle prime cose da fare ...
  • Re: JDBC non si connette e per giunta senza errori

    andbin ha scritto:


    Hai guardato i log di Tomcat?? È una delle prime cose da fare ...
    Se intendi le stringhe che vengono mostrate nella shell di Ubuntu dopo aver avviato Docker si.
    Se intendi le stringhe che vengono mostrate nella shell di IntelliJ dopo aver avviato la webapp si.
    Se intendi i file log scritti da Tomcat e salvati sul server no perché non ho la minima idea di come si possa fare ad accedere fisicamente ad un container o ad un'immagine, inoltre non so neppure se tale operazione è fattibile/consentita.

    Nei primi due casi, nella shell non vedo nulla, il programma si blocca in quel punto e stop, l'ultima stringa letta è quella relativa ad un'altra classe.

    Se rimuovo questo in web.xml:
    <!--<error-page>
            <location>/WEB-INF/error.jsp</location>
        </error-page>-->
    ottengo questo:
    HTTP Status 500 – Internal Server Error
    Type Exception Report
    
    Message Non è stato possibile autenticare l'utente.
    
    Description The server encountered an unexpected condition that prevented it from fulfilling the request.
    
    Exception
    
    DBMS.DBMSEccezione: Non è stato possibile autenticare l'utente.
    	web1.Database.authenticateUser(Database.java:69)
    	web1.ServletAutenticazione.doPost(ServletAutenticazione.java:39)
    	javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
    	javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    Root Cause
    
    DBMS.DBMSEccezione: Non è stato possibile recuperare il record dalla tabella.
    	DBMS.DBMSUtenteDAOPostgreSQL.findByNome(DBMSUtenteDAOPostgreSQL.java:108)
    	web1.Database.authenticateUser(Database.java:62)
    	web1.ServletAutenticazione.doPost(ServletAutenticazione.java:39)
    	javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
    	javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    Root Cause
    
    DBMS.DBMSEccezione: Impossibile connettersi al server PostgreSQL.
    	DBMS.DBMSConnessione.connect(DBMSConnessione.java:113)
    	DBMS.DBMSUtenteDAOPostgreSQL.findByNome(DBMSUtenteDAOPostgreSQL.java:85)
    	web1.Database.authenticateUser(Database.java:62)
    	web1.ServletAutenticazione.doPost(ServletAutenticazione.java:39)
    	javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
    	javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    Root Cause
    
    DBMS.DBMSEccezione: Impossibile connettersi al server PostgreSQL.
    	DBMS.DBMSConnessione.connect(DBMSConnessione.java:107)
    	DBMS.DBMSUtenteDAOPostgreSQL.findByNome(DBMSUtenteDAOPostgreSQL.java:85)
    	web1.Database.authenticateUser(Database.java:62)
    	web1.ServletAutenticazione.doPost(ServletAutenticazione.java:39)
    	javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
    	javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    Root Cause
    
    java.lang.NullPointerException
    	DBMS.DBMSConnessione.connect(DBMSConnessione.java:90)
    	DBMS.DBMSUtenteDAOPostgreSQL.findByNome(DBMSUtenteDAOPostgreSQL.java:85)
    	web1.Database.authenticateUser(Database.java:62)
    	web1.ServletAutenticazione.doPost(ServletAutenticazione.java:39)
    	javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
    	javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    Note The full stack trace of the root cause is available in the server logs.
    
    Apache Tomcat/9.0.17
  • Re: JDBC non si connette e per giunta senza errori

    giannino1995 ha scritto:


    
    java.lang.NullPointerException
    	DBMS.DBMSConnessione.connect(DBMSConnessione.java:90)
    	DBMS.DBMSUtenteDAOPostgreSQL.findByNome(DBMSUtenteDAOPostgreSQL.java:85)
    
    Hai un NullPointerException a quella riga 90 ..... verifica ..
  • Re: JDBC non si connette e per giunta senza errori

    andbin ha scritto:


    giannino1995 ha scritto:


    
    java.lang.NullPointerException
    	DBMS.DBMSConnessione.connect(DBMSConnessione.java:90)
    	DBMS.DBMSUtenteDAOPostgreSQL.findByNome(DBMSUtenteDAOPostgreSQL.java:85)
    
    Hai un NullPointerException a quella riga 90 ..... verifica ..
    E' la classe incriminata, corrisponde al primo tentativo di recuperare url:
    url = db.getUrl();
    Quell'eccezione è giusta che si verifichi.
    Però quella che non pizzica è questa (dentro il catch):
    conn = DriverManager.getConnection(url, user, password);
    Se io metto delle credenziali volutamente sbagliate per accedere al DBMS, questo però succede anche su Windows 10, ho lo stesso ed identico problema, la creazione dell'oggetto conn fallisce e JAVA non mi fornisce alcun riscontro. Per esempio su Windows 10, dove tutto funziona se scrivo una password sbagliata, il codice seguente:
        public Connection connect() {
            try {
                DBMS db = this.dbms;
                String url;
                String user;
                String password;
                Connection conn;
                try {
                    url = db.getUrl();
                    user = db.getUser();
                    password = db.getPassword();
                    conn = DriverManager.getConnection(url, user, password);
                } catch(Exception e) {
                    db = DBMSConnessione();
                    url = db.getUrl();
                    user = db.getUser();
                    password = db.getPassword();
                    try{
                        conn = DriverManager.getConnection(url, user, password);
                    }catch(Exception g){
                        System.out.println("ATTENZIONE: Impossibile connettersi al server PostgreSQL.");
                        throw new DBMSEccezione("Impossibile connettersi al server PostgreSQL.", g);
                    }
                }
                System.out.println("Connesso al server PostgreSQL con successo.");
                return conn;
            } catch (Exception e) {
                throw new DBMSEccezione("Impossibile connettersi al server PostgreSQL.", e);
            }
        }
    nella shell di IntelliJ fornisce questo:
    Credenziali del DBMS lette dal file con successo.
    ATTENZIONE: Impossibile connettersi al server PostgreSQL.
    e dell'eccezione finale "e" neanche l'ombra.
  • Re: JDBC non si connette e per giunta senza errori

    giannino1995 ha scritto:


    Quell'eccezione è giusta che si verifichi.
    No, una eccezione come NullPointerException non è praticamente mai "giusto" che accada. Se accade generalmente è il sintomo di un "baco" nel codice.

    giannino1995 ha scritto:


    Però quella che non pizzica è questa (dentro il catch):
    Il punto è che il codice nel tuo connect() non ha molto senso ...

    giannino1995 ha scritto:


    Se io metto delle credenziali volutamente sbagliate per accedere al DBMS,
    Le credenziali di accesso al DB devono essere configurate in un file di configurazione, interno alla webapp o esterno alla webapp ma comunque sul server.
    E se dovessero essere sbagliate è giusto che l'applicazione non riesca a "salire" oppure che riesca sì a partire ma poi qualunque richiesta fallisca. Ma bisogna comunque notarlo subito e quindi sistemare prontamente le credenziali.
  • Re: JDBC non si connette e per giunta senza errori

    Il secondo try va in eccezione una volta sola (è una cosa voluta), quando il client digita per la prima volta l’URL della webapp. Ho aggiunto questo try (se noti c’è del codice che si ripete) perché vorrei evitare di usare il pezzo seguente:
    db = DBMSConnessione();
    ogni volta che il programma usa il metodo connect(). DBMSConnessione() è il metodo che legge fisicamente il file JSON su cui sono salvate le credenziali del DBMS.
    Mi piacerebbe che quando la connessione al DBMS non avvenga per qualche natura, perché per esempio le credenziali riportate nel file JSON sono errate, la classe connect() lanci un’eccezione e io venga reindirizzato alla pagina di errore. In questo modo vado nella shell, leggo "ATTENZIONE: Impossibile connettersi al server PostgreSQL." e capisco che una delle cause è il file JSON. Non so se mi sono spiegato.
    Al momento io uso questa soluzione:
    public Connection connect() {
            try {
                DBMS db = this.dbms;
                String url;
                String user;
                String password;
                Connection conn;
                try {
                    url = db.getUrl();
                    user = db.getUser();
                    password = db.getPassword();
                    conn = DriverManager.getConnection(url, user, password);
                } catch(Exception e) {
                    db = DBMSConnessione();
                    url = db.getUrl();
                    user = db.getUser();
                    password = db.getPassword();
                    try{
                        conn = DriverManager.getConnection(url, user, password);
                    }catch(Exception g){
                        System.out.println("ATTENZIONE: Impossibile connettersi al server PostgreSQL.");
                        throw new DBMSEccezione("Impossibile connettersi al server PostgreSQL.", g);
                    }
                }
                System.out.println("Connesso al server PostgreSQL con successo.");
                return conn;
            } catch (Exception e) {
                throw new DBMSEccezione("Impossibile connettersi al server PostgreSQL.", e);
            }
        }
    E’ l’unica soluzione che mi permette di capire che il DBMS non è raggiungibile per problemi di rete o mi sto connettendo con delle credenziali sbagliate senza impazzire. Ovviamente non capisco perché "Impossibile connettersi al server PostgreSQL." non venga visualizzata in questa seconda soluzione, quando il DBMS non è raggiungibile o il file JSON contiene credenziali errate:
    public Connection connect() {
            try {
                DBMS db = this.dbms;
                String url;
                String user;
                String password;
                Connection conn;
                try {
                    url = db.getUrl();
                    user = db.getUser();
                    password = db.getPassword();
                    conn = DriverManager.getConnection(url, user, password);
                } catch(Exception e) {
                    db = DBMSConnessione();
                    url = db.getUrl();
                    user = db.getUser();
                    password = db.getPassword();
                    conn = DriverManager.getConnection(url, user, password);
                }
                System.out.println("Connesso al server PostgreSQL con successo.");
                return conn;
            } catch (Exception e) {
                throw new DBMSEccezione("Impossibile connettersi al server PostgreSQL.", e);
            }
        }
    Non so se hai compreso i miei discorsi contorti.
    Mi sembra strano che non si possa dire a JAVA di avvertire il programmatore che le credenziali del DBMS siano sbagliate o il DBMS non sia raggiungibile.
    Grazie
  • Re: JDBC non si connette e per giunta senza errori

    Se vuoi che DBMSConnessione() venga invocato ad ogni esecuzione di connect(), allora:
    public Connection connect() {
        try {
            DBMS db = DBMSConnessione();
            String url = db.getUrl();
            String user = db.getUser();
            String password = db.getPassword();
            Connection conn = DriverManager.getConnection(url, user, password);
    
            // eventuale logging successo
            return conn;
        } catch (Exception e) {
            // eventuale logging errore
            throw new DBMSEccezione("Impossibile connettersi al server PostgreSQL.", e);
        }
    }
    Se vuoi che DBMSConnessione() venga invocato solo alla prima esecuzione di connect(), allora bisogna vedere COME/DOVE vengono usati gli oggetti della tua classe che contiene il connect(). Se hai sempre e solo una istanza, puoi tenere "cachato" il DBMS in un campo di istanza.
  • Re: JDBC non si connette e per giunta senza errori

    Voglio che DBMSConnessione() venga invocato solo alla prima esecuzione di connect() ma non è questo il problema che mi assilla.
    Semplifico la questione:
    Ho riscritto la classe in questo modo:
        public Connection connect() {
            try {
                DBMS db = this.dbms;
                if (this.recupera_credenziali_db) db = DBMSConnessione();
                String url = db.getUrl();
                String user = db.getUser();
                String password = db.getPassword();
                Connection conn = DriverManager.getConnection(url, user, password);
                System.out.println("Connesso al server PostgreSQL con successo.");
                this.recupera_credenziali_db = false;
                return conn;
            } catch (Exception e) {
                this.recupera_credenziali_db = true;
                throw new DBMSEccezione("Impossibile connettersi al server PostgreSQL.", e);
            }
        }
    Ho installato pdAdmin con un database, lasciando stare per un attimo Docker che a mio avviso è solo spazzatura.
    Se le credenziali sono corrette va tutto bene ma se le credenziali sono errate il programma in questo punto si blocca:
    Connection conn = DriverManager.getConnection(url, user, password);
    e il throw non parte. La webapp mi rimanda alla pagina di errore ma nella shell di IntelliJ non leggo:
    "Impossibile connettersi al server PostgreSQL."
    È normale questo comportamento secondo te?
    Se ti infastidisce recupera_credenziali_db leggi questo metodo, il discorso non cambia:
        public Connection connect() {
            try {
                DBMS db = this.dbms;
                db = DBMSConnessione();
                String url = db.getUrl();
                String user = db.getUser();
                String password = db.getPassword();
                Connection conn = DriverManager.getConnection(url, user, password);
                System.out.println("Connesso al server PostgreSQL con successo.");
                return conn;
            } catch (Exception e) {
                throw new DBMSEccezione("Impossibile connettersi al server PostgreSQL.", e);
            }
        }
    Per risolvere devo scrivere questo:
        public Connection connect() {
            try {
                DBMS db = this.dbms;
                if (this.recupera_credenziali_db) db = DBMSConnessione();
                String url = db.getUrl();
                String user = db.getUser();
                String password = db.getPassword();
                Connection conn = DriverManager.getConnection(url, user, password);
                System.out.println("Connesso al server PostgreSQL con successo.");
                this.recupera_credenziali_db = false;
                return conn;
            } catch (Exception e) {
                this.recupera_credenziali_db = true;
                System.out.println("Impossibile connettersi al server PostgreSQL o le credenziali usate sono errate.");
                throw new RuntimeException();
            }
        }
    Come posso modificare DBMSEccezione() affinché esso funzioni anche quando il DBMS non è accessibile oppure le credenziali sono sbagliate?
    package DBMS;
    public class DBMSEccezione extends RuntimeException {
        public DBMSEccezione(String message, Throwable cause) {
            super(message, cause);
        }
        public DBMSEccezione(String message) {
            super(message);
        }
        public DBMSEccezione(Throwable cause) {
            super(cause);
        }
    }
    Ho provato a scrivere:
    public class DBMSEccezione extends Exception {...
    ma non risolvo...

    Io vorrei "Impossibile connettersi al server PostgreSQL o le credenziali usate sono errate." dentro un DBMSEccezione() ovvero avere un'eccezione personalizzata pure qui...
Devi accedere o registrarti per scrivere nel forum
8 risposte