# Pb Java Tomcat Postgresql



## Jean38 (3 Janvier 2007)

Bonjour,
je suis bloqué sur un projet Java Web, avec des problèmes de liaisons avec le jdbc.
Je travaille sur mac os x (powerbook g4), avec eclipse et une base postgresql.
Lorsque j'essaye d'accéder à ma base (caracas6), ça marche.
Par contre au premier select, tout plante : 


Voici les logs et les classes .java


Le log de Tomcat
22 déc. 2006 20:03:13 org.apache.catalina.startup.Catalina start
INFO: Server startup in 12327 ms
22 déc. 2006 20:03:39 org.apache.catalina.core.ApplicationContext log
INFO: IntroForm: ======================VERSION : 10022004_1======================
Il n'y a pas de connection encore, dbReference =carracas6
genericURL, database, login, password + genericURL: caracas6,bdsis,bdsis
Connected to the database: jdbcostgresql:caracas6
LAST_EVENT_NUMBER = 8
ic
ici
22 déc. 2006 20:04:47 org.apache.catalina.core.StandardWrapperValve invoke
GRAVE: "Servlet.service()" pour la servlet IntroForm a généré une exception
java.lang.NullPointerException
    at org.postgresql.jdbc2.AbstractJdbc2ResultSet.first(AbstractJdbc2ResultSet.java:235)
    at fr.ujfgrenoble.obs.lgit.bdsis.distribForms.util.SQLEngine.getEventNumber(SQLEngine.java:90)
    at fr.ujfgrenoble.obs.lgit.bdsis.distribForms.IntroForm.makeHTML(IntroForm.java:172)
    at fr.ujfgrenoble.obs.lgit.bdsis.distribForms.IntroForm.doGet(IntroForm.java:145)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
    at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)
    at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
    at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
    at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
    at java.lang.Thread.run(Thread.java:613)




La partie de la classe incriminée :
    /**
    * Genere le formulaire HTML.
    *
    * @param database nom de la base de donnees concernee.
    * @param networks liste des reseaux.
    * @param conn objet connection a la base de donnees
    * @return la page HTML creee.
    */
    private Html makeHTML(String database) throws UnavailableException{

        //Nom du logo (en fonction de la base utilisee)
        String jpgLogoReseau="Logo_"+database.toUpperCase()+".jpg";


        //creation du paragraphe d'entete:
        int stationsNumber, eventNumber, eventRecordNumber;

        try {
            System.out.println("ic");
            stationsNumber = sqlEngine.getStationsNumber();      // nombre total de stations
            System.out.println("ici");
            eventNumber = sqlEngine.getEventNumber();        // nombre total d'evenements
            System.out.println("ici2");
            eventRecordNumber= sqlEngine.getEventRecordNumber();    // nombre d'evenements ayant au moins 1 enregistrement
            System.out.println("ici3");
        } catch (SQLException er) {
            throw new UnavailableException(er.getMessage());
        }
        P paragrapheEntete = HTMLUtil.createParagrapheEntete(stationsNumber, eventNumber, eventRecordNumber);
        //

        Form form;
        Body body;

        Html html = new Html()

        .addElement(HTMLUtil.createHeader("DataSelectionForm"))
        // etc..
        }





La partie de la classe sql liée :
    /**
    * Renvoit le nombre d'evenements stockes dans la base de donnees.
    *
    * @return le nombre d'evenements stockes dans la base de donnees.
    */
    public int getEventNumber() throws SQLException {

        Statement statement = conn.createStatement();
        //ResultSet resultSet = statement.executeQuery("SELECT COUNT(*) from tg_event WHERE ev_id <> 0");
        ResultSet resultSet = statement.executeQuery("SELECT nb_events FROM parametres_application");
        //ResultSet resultSet = statement.execute("SELECT nb_events FROM parametres_application");

        statement.close();

        resultSet.first();
        int n = resultSet.getInt(1);
        resultSet.close();
        return n;
    }



Avez-vous une idée? 
J'ai bien les dernières versions du driver jdbc, j'utilise le bon java (1.5)..


----------



## GrandGibus (3 Janvier 2007)

Il te manquerait pas des fois l'instantiation du driver JDBC ?


```
// Attempt to load database driver
try
{
	// Load Sun's jdbc-odbc driver
	Class.forName("sun.jdbc.odbc.JdbcOdbcDriver").newInstance();
}
catch (ClassNotFoundException cnfe) // driver not found
{
	System.err.println ("Unable to load database driver");
	System.err.println ("Details : " + cnfe);
	System.exit(0);
}
```

Il faut voir avec ton driver pour la classe à utiliser, dans ce cas: _sun.jdbc.odbc.JdbcOdbcDriver_


----------



## Jean38 (4 Janvier 2007)

Merci GrandGibus !
Mais il me semble que je fais l'instantiation dans plusieurs classes, dont les classes de selection de mes servlets, de gestion des events servlets, et dans ma classe principale introform, toujours lors des initialisation de servlets



/* ------------------------------------------------------------------ */
/**
* Methode declaree dans la classe abstraite, sert a gerer les ressources qui tienent tout au long de la vie de la servlet
* @param c l'object <code>ServletConfig</code> utilise par le conteneur (TomCat) pour passer les parametres d'initialisation de la servlet
*/    
    public void init (ServletConfig c) throws ServletException {

        //DEBUG
        //System.out.println("-->[SelectionServlet]init");
        //DEBUG
        super.init (c);

        /* -----------------initialisation de constantes ------------------ */        

        BORDER = (String) constantes.get("BORDER");
        CELL_SPACING = (String) constantes.get("CELL_SPACING");
        CELL_PADDING = (String) constantes.get("CELL_PADDING");

        GENERIC_URL = (String) constantes.get("GENERIC_URL");
        DRIVER = (String) constantes.get("DRIVER");
        LOGIN = (String) constantes.get("LOGIN");
        PASSWORD = (String) constantes.get("PASSWORD");

        DATABASE= (String) constantes.get("DATABASE");
        STATION_LIST = (String) constantes.get("STATION_LIST");
        NETWORK_LIST = (String) constantes.get("NETWORK_LIST");

        NOT_SPECIFIED = (String) constantes.get("NOT_SPECIFIED");
        SPECIFIED = (String) constantes.get("SPECIFIED");

        /* ------------------------------------------------------------------ */

        /* ----- Chargement des parametres d'acces a la base de donnees ------- */
        // Les valeurs de ces parametres se trouvent dans le fichier web.xml

        genericURL = c.getInitParameter(GENERIC_URL);
        String driver = c.getInitParameter(DRIVER);
        login = c.getInitParameter(LOGIN);
        password = c.getInitParameter(PASSWORD);

        if ( genericURL==null || driver==null || login==null || password==null) {
            throw new UnavailableException("Init parameter not found.");
        }
        try { //recuperation de la classe driver de la base de donnnees
            Class.forName(driver);
        } catch (ClassNotFoundException er) {
            throw new UnavailableException("Cannot load database driver.");
        }
        /* ------------------------------------------------------------------ */

        //DEBUG
        //System.out.println("<--[SelectionServlet]init");
        //DEBUG

    }


par contre j'ai lu sur un post (http://java.developpez.com/faq/javaee/?page=TOMCAT#TOMCAT_JDBC_GESTION_CONNEXION) qu'il fallait adapter les fichiers de configuration tomcat pour utiliser le jdbc. J'essaye de voir si ca change quelque chose et je vous tiens au courant. Encore merci!


----------



## GrandGibus (4 Janvier 2007)

Oui, c'est pour utiliser ta base par l'intermédiaire d'une data-source. 

Attention, la méthode décrite n'est valable que sous Tomcat. Mais cela ne résoudra en rien ton problème d'accès à la base... 

Ton erreur est une NPE, est-ce que tu as essayé d'exécuter ta requête dans un programme Java simple (tout mettre dans une méthode main) ?

Tu peux également augmenter la verbosité des traces Tomcat pour le rendre un peu plus bavard. 

Dans la trace de l'exception, quel est le _caused by_ ? (s'il y en a un)


----------



## Jean38 (4 Janvier 2007)

OK compris pour les data-sources, d&#233;sol&#233;.
J'ai essay&#233; de lancer tomcat en mode debug mais les logs ne sont gu&#232;res diff&#233;rents, pas de trace d'un "_caused by_".. 
Existe t'il d'autre moyen pour augmenter la verbosit&#233; des logs?

Sinon je vais essayer de mettre ma requete dans une classe &#224; part, et pi je reviens..


Au cas ou, les derniers logs obtenus (r&#233;cup&#233;r&#233;s dans "apache/logs/localhost.2007-01-04.log") :

4 janv. 2007 14:31:52 org.apache.catalina.core.ApplicationContext log
INFO: org.apache.webapp.balancer.BalancerFilter: init(): ruleChain: [org.apache.webapp.balancer.RuleChain: [org.apache.webapp.balancer.rules.URLStringMatchRule: Target string: News / Redirect URL: http://www.cnn.com], [org.apache.webapp.balancer.rules.RequestParameterRule: Target param name: paramName / Target param value: paramValue / Redirect URL: http://www.yahoo.com], [org.apache.webapp.balancer.rules.AcceptEverythingRule: Redirect URL: http://jakarta.apache.org]]
4 janv. 2007 14:31:53 org.apache.catalina.core.ApplicationContext log
INFO: ContextListener: contextInitialized()
4 janv. 2007 14:31:53 org.apache.catalina.core.ApplicationContext log
INFO: SessionListener: contextInitialized()
4 janv. 2007 14:31:54 org.apache.catalina.core.ApplicationContext log
INFO: ContextListener: contextInitialized()
4 janv. 2007 14:31:54 org.apache.catalina.core.ApplicationContext log
INFO: SessionListener: contextInitialized()
4 janv. 2007 14:32:14 org.apache.catalina.core.ApplicationContext log
INFO: IntroForm: ======================VERSION : 10022004_1======================
4 janv. 2007 14:32:17 org.apache.catalina.core.StandardWrapperValve invoke
ATTENTION: "Servlet.service()" pour la servlet IntroForm a g&#233;n&#233;r&#233; une exception
javax.servlet.UnavailableException: Result set not positioned properly, perhaps you need to call next().
    at fr.ujfgrenoble.obs.lgit.bdsis.distribForms.IntroForm.makeHTML(IntroForm.java:177)
    at fr.ujfgrenoble.obs.lgit.bdsis.distribForms.IntroForm.doGet(IntroForm.java:145)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
    at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)
    at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
    at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
    at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
    at java.lang.Thread.run(Thread.java:613)
4 janv. 2007 14:32:17 org.apache.catalina.core.ApplicationContext log
INFO: La servlet IntroForm est marqu&#233; comme indisponible


+ Les 2 fonctions de la classe IntroForm incrimin&#233;e :

/**
    * Analyse la requete HTML recue a travers la methode GET, et permet de construire le formulaire d'interrogation.
    * @param req comme decrit dans la classe abstraite HttpServlet: requete passee par l'URL apelante
    * @param res comme decrit dans la classe abstraite HttpServlet: reponse envoyee sur l'URL destination
    */
    protected void doGet(HttpServletRequest req, HttpServletResponse res)
        throws ServletException, IOException {

        // recuperation du nom de la base a interroger, a partir de la requete HTTP
        String databaseFromURL = req.getParameter(DATABASE);
        if ( databaseFromURL==null || databaseFromURL.equals("") ) {
            res.sendError(HttpServletResponse.SC_BAD_REQUEST);
            return;
        }

        HttpSession session = req.getSession();
        if ( session == null ) {
            //MODIF_LS 16122003
            res.setContentType("text/html");
            PrintWriter out = res.getWriter();
            out.println(HTMLUtil.createHTMLMessage(null, "Your session was expired !"));
            out.close();
            //FIN_MODIF_LS
        }


        // recuperation de la connection a la BD
        boolean permetCreationConnection = true; 
        ConnectionHolder connectionHolder = UtilPostgres.testeCoherenceConnection(session, permetCreationConnection, databaseFromURL, res, genericURL, login, password);

        sqlEngine = connectionHolder.getSQLEngine();
        // 

        res.setContentType("text/html");
        PrintWriter out = res.getWriter();
out.println(makeHTML(databaseFromURL).toString());* ------->Ligne 145 (cf log)*
        out.close();
    }



    /**
    * Genere le formulaire HTML.
    *
    * @param database nom de la base de donnees concernee.
    * @param networks liste des reseaux.
    * @param conn objet connection a la base de donnees
    * @return la page HTML creee.
    */
    private Html makeHTML(String database) throws UnavailableException{

        //Nom du logo (en fonction de la base utilisee)
        String jpgLogoReseau="Logo_"+database.toUpperCase()+".jpg";


        //creation du paragraphe d'entete:
        int stationsNumber, eventNumber, eventRecordNumber;

        try {
            System.out.println("ic");
            stationsNumber = sqlEngine.getStationsNumber();      // nombre total de stations
            System.out.println("ici");
            eventNumber = sqlEngine.getEventNumber();        // nombre total d'evenements
            System.out.println("ici2");
            eventRecordNumber= sqlEngine.getEventRecordNumber();    // nombre d'evenements ayant au moins 1 enregistrement
            System.out.println("ici3");
        } catch (SQLException er) {
            throw new UnavailableException(er.getMessage());   *------->Ligne 177 (cf log)*
        }
        P paragrapheEntete = HTMLUtil.createParagrapheEntete(stationsNumber, eventNumber, eventRecordNumber);
        //

        Form form;

       ..etc
}


----------



## GrandGibus (4 Janvier 2007)

Euh.... Dans le code: 

```
/**
* Renvoit le nombre d'evenements stockes dans la base de donnees.
*
* @return le nombre d'evenements stockes dans la base de donnees.
*/
public int getEventNumber() throws SQLException {

Statement statement = conn.createStatement();
//ResultSet resultSet = statement.executeQuery("SELECT COUNT(*) from tg_event WHERE ev_id <> 0");
ResultSet resultSet = statement.executeQuery("SELECT nb_events FROM parametres_application");
//ResultSet resultSet = statement.execute("SELECT nb_events FROM parametres_application");

statement.close();

resultSet.first();
int n = resultSet.getInt(1);
resultSet.close();
return n;
}
```

Tu ne ferais pas le statement.close(); un peu trop tôt :mouais:  ?

Sinon, tous les détails ici.


----------



## Jean38 (5 Janvier 2007)

Super ça se débloque! enfin je peux avancer d'une servlet.
Je vais maintenant voir d'ou proviennent ces effets de bord.. a suivre


----------



## Jean38 (5 Janvier 2007)

Bon en fait je me suis emballé, je ne comprend pas pourquoi ça a marché, mais ça ne l'a fait qu'une fois, maintenant je retombe sur la même erreur, dû à cette classe. j'ai déplacer le statement.close();, au bon endroit ?


/**
    * Renvoit un tableau de strings contenant st_code + st_extenso + ne_code pour toutes les stations de la campagne.
    * @return le tableau des stations de la campagne (st_code + st_extenso + ne_code), classees par
    * ordre lexicographique.
    * @exception SQLException si une erreur se produit lors de l'interogation
    * de la base de donnees.
    */
    public String[] getStations() throws SQLException {

        Statement statement = conn.createStatement();

        // determination du nombre de stations
        ResultSet resultSet = statement.executeQuery
        ("SELECT COUNT(x.st_code) FROM ("+
            "SELECT distinct st_code,tpn.ne_code FROM tg_station tgs, tg_channel tgc, tp_network tpn "+
            "WHERE st_code!='#' AND ne_code!='#' AND tpn.ne_id = tgc.ne_id AND tgs.st_id = tgc.st_id) x");
        resultSet.first();
        int n = resultSet.getInt(1);
        resultSet.close();


        // determination de la liste des stations
        String[] stations = new String[n];

        resultSet = statement.executeQuery
        ("SELECT DISTINCT st_code, st_extenso , ne_code FROM tg_station tgs, tg_channel tgc, tp_network tpn "+
        "WHERE st_code!='#' AND ne_code!='#' AND tpn.ne_id = tgc.ne_id AND tgs.st_id = tgc.st_id "+
        "ORDER BY st_code");


        //statement.close();  -----> Avant le statement.close était ici


        resultSet.first();
        String s;
        for (int i=0; i<n; i++) {

        s = resultSet.getString("st_extenso");
        if ( s.startsWith("#") )
            stations_ = resultSet.getString("st_code")+ " : "+" ... "+" ("+resultSet.getString("ne_code")+") ";
        else
            stations = resultSet.getString("st_code")+ " : "+ s +" ("+resultSet.getString("ne_code")+") ";

        resultSet.next();
        }
        resultSet.close();
        statement.close();  // ------> Je l'ai déplacé ici, mais j'ai toujours le même pb
        return stations;
    }__
_


----------



## GrandGibus (6 Janvier 2007)

Essaie de tout mettre dans un seul main() pour voir ce que ça donne... au moins, tu sauras après ça dans quelle direction chercher (Tomcat, ou ton source) .


----------



## OlivierL (10 Janvier 2007)

Encore plus mieux bien que le main, écrit une classe de test JUnit qui appelle ta classe à tester. Avec Eclipse, c'est très facile à faire.


----------



## Jean38 (11 Janvier 2007)

Je continue a chercher sur internet, je passais mes partiels en ce moment excuser pour l'absence.

GrandGibus 
je veux bien tout mettre dans un main(), ms quoi? ya bcp de classes, ca demanderé un sacré travail.. je suis entrain d'y reflechir ms ca prendra du temps..

Olivieri
J'essaye avec les classes JUnit mais pour l'instant je comprend po tro commen qu'ça marche. 

Du coup encore bcp de boulot en vu, je vous tiens au courant


----------



## Jean38 (11 Janvier 2007)

Par contre j'ai oubli&#233; de pr&#233;ciser que cette appli web fonctionne bien sur un pc sous lynux, avec tomcat et postgres. Donc je ne pense pas que les erreurs viennent du code.. mais je n'en suis pas vraiment sur. En effet, j'ai l'impression d'avoir tout bien configur&#233;, et j'utilise le dernier driver jdbc nomm&#233; "postgresql-8.2-504.jdbc4.jar" que j'ai ajout&#233; dans les librairies du projet Eclipse et dans le dossier WEB-INF/lib de mon appli..


----------



## Jean38 (22 Janvier 2007)

Bon après de nombreux test sur la configuration et sur le code, le problème se précise : il s'agit d'un problème de liaisons entre ma base de données (postgres 8.0) et mon application java Web.

La connexion marche, par contre je rencontre des problèmes sur ma première requête avec SELECT, avec l'implémentation des resultSet, et notamment avec ce bout de code tout bête : 



```
public int getStationsNumber() throws SQLException {

        Statement statement = conn.createStatement();   
        ResultSet resultSet = statement.executeQuery("SELECT nb_stations FROM parametres_application");

        resultSet.first();
        
        System.out.println("Resultset : "+resultSet); => OK

        int n = resultSet.getInt(1); => ECHEC

        System.out.println("Result :"+n);

        resultSet.close();
        statement.close();   
        return n;
    }
```


J'ai essayé la requête toute seule sur postgres, ça marche très bien..
J'ai essayé de changer de place le statement.close(), d'utiliser d'autres fonctions que le .getInt(), rien n'y fait.
Je rappelle que pour la connexion à la base postgres, j'utilise les packages jdbc7.0-1.2.jar et pg73jdbc3.jar pour la connexion à ma base POSTGRESQL 8.0


Voici le message d'erreur sur Eclipse :


```
INFO: IntroForm: ======================VERSION : 10022004_1======================
Il n'y a pas de connection encore, dbReference =kunlun01
genericURL, database, login, password + genericURL: kunlun01,bdsis,bdsis
Connected to the database: jdbc:postgresql:kunlun01
LAST_EVENT_NUMBER = 8
1
Resultset : org.postgresql.jdbc3.Jdbc3ResultSet@3f0860
22 janv. 2007 11:03:09 org.apache.catalina.core.StandardWrapperValve invoke
ATTENTION: "Servlet.service()" pour la servlet IntroForm a généré une exception
javax.servlet.UnavailableException: Result set not positioned properly, perhaps you need to call next().
    at fr.ujfgrenoble.obs.lgit.bdsis.distribForms.IntroForm.makeHTML(IntroForm.java:178)
    at fr.ujfgrenoble.obs.lgit.bdsis.distribForms.IntroForm.doGet(IntroForm.java:145)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
    at org.apache.catalina.valves.FastCommonAccessLogValve.invoke(FastCommonAccessLogValve.java:495)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
    at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)
    at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
    at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
    at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
    at java.lang.Thread.run(Thread.java:613)
22 janv. 2007 11:03:09 org.apache.catalina.core.ApplicationContext log
INFO: La servlet IntroForm est marqué comme indisponible
```



Est-ce plus clair et voyez-vous une solution ?


----------



## GrandGibus (22 Janvier 2007)

A quel endroit tu fais le 


> Class.forName("sun.jdbc.odbc.JdbcOdbcDriver").newInstance();


----------



## Jean38 (22 Janvier 2007)

C'est assez compliqué :
dans la classe introForm.java, la première servlet affichée :


```
public void init (ServletConfig c) throws ServletException {
        
        String version;
        super.init (c);

        //initialisation des constantes
        GENERIC_URL = (String) Constantes.get("GENERIC_URL");
        DRIVER = (String) Constantes.get("DRIVER");
        LOGIN = (String) Constantes.get("LOGIN");
        PASSWORD = (String) Constantes.get("PASSWORD");
        DATABASE = (String) Constantes.get("DATABASE");
        VERSION = (String) Constantes.get("VERSION");
      
        genericURL = c.getInitParameter(GENERIC_URL);
[B]        String driver = c.getInitParameter(DRIVER);[/B]
        login = c.getInitParameter(LOGIN);
        version = c.getInitParameter(VERSION);
        password = c.getInitParameter(PASSWORD);
        log("======================VERSION : "+version+"======================");

       [B] if ( genericURL==null || driver==null || login==null || password==null) {
            throw new UnavailableException("Init parameter not found.");
        }
        try { Class.forName(driver);} 
        catch (ClassNotFoundException er) {throw new UnavailableException("Cannot load database driver.");}[/B]
    }
```

On fait donc appel à un fichier de configuration Constantes.java qui contient :


```
//------------------------
        //IntroForm
        /**
        * Cle identifiant les parametres d'initialisation de la servlet.
        */
        put("GENERIC_URL", "database.genericURL");
        [B]put("DRIVER", "database.driver");[/B]
        put("LOGIN","database.login");
        put("PASSWORD", "database.password");

        /**
        * Cle identifiant le parametre contenant le nom de la base de donnees. Ce
        * parametre est transmis a la servlet par la methode get et permet de
        * construire le formulaire. Il est exporte lors de la soumission grace a un
        * champ cache.
        */
        put("DATABASE","database");

        /**
        * Cle identifiant les informations concernant les radioboxes dans le
        * formulaire d'interrogation.
        */
        put("VERSION","version");
```

Et là tout se complique car apparement, l'instruction database.driver permet de récupérer le driver utilisé, mais je ne sais pas comment, ni quel driver est récupéré...


----------



## Jean38 (22 Janvier 2007)

Ah si, en fait il va chercher cette info dans le fichier web.xml, sous le repertoire web/WEB-INF de mon appli, ici :


```
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
    "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">

<web-app>
   <display-name>BDsis</display-name>
   
   <servlet>
     <servlet-name>IntroForm</servlet-name>
     <servlet-class>fr.ujfgrenoble.obs.lgit.bdsis.distribForms.IntroForm</servlet-class>
     
      <init-param>
            <param-name>version</param-name>
        <param-value>10022004_1</param-value>
      </init-param>

      <init-param>
            <param-name>database.genericURL</param-name>
            <param-value>jdbc:postgresql:</param-value>
      </init-param>

     [B] <init-param>
            <param-name>database.driver</param-name>
            <param-value>org.postgresql.Driver</param-value>
      </init-param>[/B]
```


----------



## Jean38 (22 Janvier 2007)

J'ai essay&#233; de changer le 


```
<init-param>
            <param-name>database.driver</param-name>
        <param-value>[B]org.postgresql.Driver[/B]</param-value>
      </init-param>
```
par


```
<init-param>
            <param-name>database.driver</param-name>
        <param-value>[B][COLOR=Red]sun.jdbc.odbc.JdbcOdbcDriver[/COLOR][/B]</param-value>
      </init-param>
```

mais &#231;a ne donne rien, l'appli ne marche plus..

J'ai mis les drivers &#224; jour, j'utilise maintenant : 
- jdbc7.1-1.2.jar
- pg74.216.jdbc3.jar

mais &#231;a ne change rien, toujours la m&#234;me erreur... :sick:


----------



## OlivierL (24 Janvier 2007)

GrandGibus, on lui dit que m&#233;langer la couche de pr&#233;sentation et la couche d'acc&#232;s aux donn&#233;es c'est mal ? 


Essaye un truc genre :
Statement statement = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE);

ou alors :
while (resultSet.next()) {
  System.out.println(resultSet.getInt(1));
}

Je pense que ton ResultSet est TYPE_FORWARD_ONLY par d&#233;faut...

Cf. http://java.sun.com/j2se/1.4.2/docs/api/java/sql/ResultSet.html


_public boolean *first*()
              throws SQLException_ _Moves the cursor to the first row in  this ResultSet object. _ 
_*Returns:*__true if the cursor is on a valid row;  false if there are no rows in the result set __*Throws:*_ _SQLException - if a database access error  occurs or the result set type is TYPE_FORWARD_ONLY_


----------



## OlivierL (25 Janvier 2007)

Au fait, tu charges bien le driver, mais tu fais bien un DriverMAnager.getConnexion() quelque part aussi ?

Si ton truc marche, saches qu'il ne faut surtout pas gérer les connexions ainsi pour une application Web. C'est un excellent moyen de plomber les perfs. Il est nécessaire de passer par un pool de connexion (Cf. javax.sql.DataSource)
Il te faudra déclarer la DataSource au niveau de la configuration de la WeppApp dans Tomcat, puis récupérer une connexion via un lookup JNDI avec un truc du genre :

```
/**
     * Connexion à la base de données avec la DataSource.
     * @return La connexion
     * @throws MonException
     */
    public Connection getConnexion() throws MonException {
        Connection connexion = null;
        DataSource ds = null;

        try {
            // Récupération de la DataSource
            Context initCtx = new InitialContext();
            ds = (DataSource) initCtx.lookup(MesConstantes.DATASOURCE);
        } catch (NamingException e) {
            throw new MonException("Problème de récupération de la DataSource.", e);
        }
        
        try {
            // Récupération d'une connexion depuis la DataSource
            connexion = ds.getConnection();
        } catch (SQLException e) {
            throw new MonException("Problème de connexion à la base de données.", e);
        }
        return connexion;
    }
```


----------



## Jean38 (26 Janvier 2007)

OK c'est vraiment l'échec.. 
En fait je dois reprendre tout le code SQL, car ce qui marche sur lynux ne fonctionne pas sur mac (car oui l'application telle qu'elle marche très bien sur lynux).

En appliquant le code de OlivierL,  

while (resultSet.next()) {
   System.out.println(resultSet.getInt(1));
}

Je peux avancer, mais ensuite je dois faire la même chose avec toutes les requêtes de ma classe SQLEngine.

Je vais donc abandonner pour l'instant, puisque le but premier du projet n'est pas de faire fonctionner cette appli sur mac (pas dans le cahier des charges) mais d'améliorer cette application en général.


Je reste quand même profondément frustré de ne trouver aucune explication sur les différences qu'il peut exister entre les 2 systemes d'exploitation au niveau du jdbc, car encore une fois tout cela marche très bien sur lynux, sans changer une ligne de code.
J'ai du chercher dans tous les sens pendant près de 2 mois pour en arriver à cette sombre conclusion : apple déteste les développeurs, pour preuve la complexité de changer les variables d'environnement, info que j'ai mis plus d'une semaine à trouver ici : http://developer.apple.com/qa/qa2001/qa1067.html (encore grace a vos forums ) et si c'était tout.. bref pa mal de découragement, mais merci qd meme.

A bientot


----------



## OlivierL (26 Janvier 2007)

tss, tss, tes problèmes ne sont pas liés à Apple.

La notion de variable d'environnement, c'est pas trop Java ça.
Ensuite, ceux sont tes drivers qui sont spécifiques à un OS.
Le fait est que JDBC est une norme et non pas une implémentation.

Tu as ici le cas précis d'un driver dont les 2 implémentations respectent bien la norme JDBC mais ont des comportements différents ! C'est la base même du polymorphisme et de l'intérêt de passer par JDBC.

Allez courage, Java rules


----------



## GrandGibus (26 Janvier 2007)

Jean38 a dit:


> OK c'est vraiment l'échec..



En effet... d'un autre coté, tu ne veux toujours pas faire un simple main avec ton Class.forName et un requête afin de cerner un peu plus près la cause du souci :sleep:.



Jean38 a dit:


> En fait je dois reprendre tout le code SQL, car ce qui marche sur lynux ne fonctionne pas sur mac (car oui l'application telle qu'elle marche très bien sur lynux).



Comme le dit OlivierL précédemment, il n'y a absolument aucune raison à cela..... 

J'ai pour ma part un assez gros projet (300tables) qui tourne en Java, sous serveur d'appli, avec de l'hibernate (et du jdbc) sur du oracle, db2, mssql et postgresql... on est une trentaine de dev, tous OS confondus.... 




Jean38 a dit:


> Je vais donc abandonner pour l'instant, puisque le but premier du projet n'est pas de faire fonctionner cette appli sur mac (pas dans le cahier des charges) mais d'améliorer cette application en général.



Ca sera considérablement amélioré si ça tournait nativement sans modif sur les 3 plateformes ! C'est qu'il y a un souci dans le design de l'appli en général si cela ne fonctionne pas. 




Jean38 a dit:


> Je reste quand même profondément frustré de ne trouver aucune explication sur les différences qu'il peut exister entre les 2 systemes d'exploitation au niveau du jdbc, car encore une fois tout cela marche très bien sur lynux, sans changer une ligne de code.
> J'ai du chercher dans tous les sens pendant près de 2 mois pour en arriver à cette sombre conclusion : apple déteste les développeurs, pour preuve la complexité de changer les variables d'environnement, info que j'ai mis plus d'une semaine à trouver ici : http://developer.apple.com/qa/qa2001/qa1067.html/QUOTE]
> 
> Une preuve de plus qu'il y a qq chose qui cloche... Je ne vois pas pour quelle raison tu aurais besoin d'avoir des variables d'environnement !!!


----------



## Jean38 (30 Janvier 2007)

Ok j'ai bien compris pour le message d'OliverL, c'est vrai que mes problèmes de driver mettent bien en relief l'intérêt de passer par le JDBC, je pense que je rajouterais ça dans mon dossier!! merci
C'est vrai que je m'exite un peu sur Apple qui n'y est surement pour rien, le vrai pb vient de ma lassitude, mais qu'est-ce qui pouvait me faire croire que ce serait facile?

Pour GrandGibus, j'essaye de faire ce main, mais pour montrer toute la procédure j'ai besoin de bien comprendre chaque méthode de chaque classe, car le code est incroyablement touffu et complexe, et l'architecture.. ben y'en a pas! C'est une appli développer dans les années 90, plusieurs fois reprises, et très mal pensée à la base. C'est pourquoi faire un main s'avère bien compliqué, dès que c'est près je l'envois. Je pensais que le problème venait du code, mais tu sembles dire que c'est impossible.. Franchement j'en serais ravi..

Le mieux serait de reprendre l'appli à la base et de tout refaire, mais hélas je n'ai que 2 mois impartis à ce projet, donc pour l'instant je résoud les bugs du cahier des charges, je fais les ajouts demandés, mais si j'ai fini en avance, ce qui sera surement le cas, j'aimerais faire quelques changements d'archi un peu plus important, et notamment réussir à faire tourner ça sur mac.

Bref il faut que je me remotive vite, et grâce a vous c'est plus facile. merci bien, je suis vraiment content d'avoir découvert ce forum , a bientot

PS : la variable d'env c'est pour éviter d'utiliser l'un des moultes chemins en dur qui trainent au long de l'appli, bien que cette solution ne soit finalement guère efficace, puisque l'utilisateur doit alors être capable d'ajouter une de ces variables manuellement ( Je pensais naïvement au début que lors de l'installation de tomcat par exemple, un script magique aller ajouter la variable d'env TOMCAT_HOME - maintenant CATALINA_HOME - dans les variables d'env.. C'est juste une illusion, a peine une sensa.. enfin vous connaissez la suite )


----------



## GrandGibus (30 Janvier 2007)

Jean38 a dit:


> Pour GrandGibus, j'essaye de faire ce main, mais pour montrer toute la procédure j'ai besoin de bien comprendre chaque méthode de chaque classe, car le code est incroyablement touffu et complexe, et l'architecture.. ben y'en a pas! C'est une appli développer dans les années 90, plusieurs fois reprises, et très mal pensée à la base. C'est pourquoi faire un main s'avère bien compliqué, dès que c'est près je l'envois. Je pensais que le problème venait du code, mais tu sembles dire que c'est impossible.. Franchement j'en serais ravi..



Le but n'est pas de mettre toute ton appli dans un main, mais juste deux/trois instructions avec:

l'instanciation du driver JDBC
l'exécution d'une requête type
l'affichage des résultats (System.out.println...)
Ca sera ainsi bien plus aisé de faire le diagnostic, tu pourras aussi déboguer facilement...




Jean38 a dit:


> PS : la variable d'env c'est pour éviter d'utiliser l'un des moultes chemins en dur qui trainent au long de l'appli, bien que cette solution ne soit finalement guère efficace, puisque l'utilisateur doit alors être capable d'ajouter une de ces variables manuellement ( Je pensais naïvement au début que lors de l'installation de tomcat par exemple, un script magique aller ajouter la variable d'env TOMCAT_HOME - maintenant CATALINA_HOME - dans les variables d'env.. C'est juste une illusion, a peine une sensa.. enfin vous connaissez la suite )


Une manière plus élégante serait de:

passer par un fichier .properties (lui-même inclu dans le jar) qui contiendrait les chemins d'accés
de passer par des -DmyPath="C:\toto" au lancement de la jvm (et dans le code un System.getProperties(...))
donc, pas de nécessité de passer par des variables d'environnement .


----------



## OlivierL (31 Janvier 2007)

J'approuve totalement le passage par des paramètres de la JVM proposé par GrandGibus.
Dans Eclipse, Window>Preference>Tomcat>Paramètrages de la JVM.

Par contre, je persiste à dire qu'une batterie de test JUnit, c'est mieux que des simples main().
D'autant plus qu'avec Eclipse, ca se fait tout seul...


----------



## Jean38 (7 Février 2007)

Pour le main, ça ne servirait à rien, car ma connexion marche bien.

Par contre quand je modifie le code : 
- en fermant correctement les statements (après la fermeture du resultset)

- en modifiant des classes pour que les resultset, statement et connexion soit dans la meme classe (car actuellement certaines classes appellent des fonctions d'une classe SQL qui récupère la connexion et renvoi un statement créé sur cette connexion)

En corrigeant ça, tout fonctionne, sur mac et linux! mais c'est trop long a faire pour tout le code..




> Une manière plus élégante serait de:
> passer par un fichier .properties (lui-même inclu dans le jar) qui contiendrait les chemins d'accés


=> un fichier .properties est déjà utilisé, mais les variables ne sont pas accessibles depuis une classe java.. (sauf en lisant le fichier mais c'est pas génial)



> de passer par des -DmyPath="C:\toto" au lancement de la jvm (et dans le code un System.getProperties(...))


=> je vais essayer ça merci, meme si ma solution à été validée par mon maitre de stage.;-)

En tout cas merci bcp  ces forums sont fantastiques! très longue vie, vous aurez vite de mes nouvelles


----------

