001    /*
002      Copyright (C) 2001-2003 Laurent Martelli <laurent@aopsys.com>
003    
004      This program is free software; you can redistribute it and/or modify
005      it under the terms of the GNU Lesser General Public License as
006      published by the Free Software Foundation; either version 2 of the
007      License, or (at your option) any later version.
008    
009      This program is distributed in the hope that it will be useful,
010      but WITHOUT ANY WARRANTY; without even the implied warranty of
011      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012      GNU Lesser General Public License for more details.
013    
014      You should have received a copy of the GNU Lesser General Public License
015      along with this program; if not, write to the Free Software
016      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
017    
018    package org.objectweb.jac.aspects.persistence;
019    
020    import java.sql.Connection;
021    import java.sql.DriverManager;
022    import java.sql.ResultSet;
023    import java.sql.SQLException;
024    import java.util.HashSet;
025    import java.util.Iterator;
026    import java.util.Map.Entry;
027    import java.util.Map;
028    import org.apache.log4j.Logger;
029    import org.objectweb.jac.util.Log;
030    import org.objectweb.jac.util.Strings;
031    
032    
033    /**
034     * Implements the storage to store within a PostgreSQL database.
035     */
036    
037    public class PostgresStorage extends SQLStorage {
038        static Logger logger = Logger.getLogger("persistence.storage");
039    
040        /**
041         * Creates a new storage for a PostgreSQL database.
042         *
043         * @param database the database. It may take on eof the following form:
044         * <ul>
045         *   <li>database</li>
046         *   <li>//host/database</li>
047         *   <li>//host:port/database</li>
048         * </ul>
049         * @param user the user name
050         * @param password the password for this user
051         */
052    
053        public PostgresStorage(PersistenceAC ac, 
054                               String database, String user, String password) 
055            throws SQLException 
056        {
057            super(ac);
058            try {
059                Class.forName("org.postgresql.Driver");
060            } catch (ClassNotFoundException e) {
061                logger.error("failed to load postgresql JDBC driver : "+e);
062                return;
063            }
064            try {
065                Connection db;
066                db = DriverManager.getConnection("jdbc:postgresql:"+database,user,password);
067                setConnection(db);
068            } catch (SQLException e) {
069                logger.error("failed to connect to the database with "+
070                             "jdbc:postgresql:"+database+","+user+","+password+": "+e);
071                e.printStackTrace();
072            }
073        }
074    
075        public long getNextVal(String sequence) throws Exception {
076            ensureSequenceExists(sequence);
077            return getLong("select nextval('"+sequence+"')");
078        }
079    
080        public long getCurrVal(String sequence) throws Exception {
081            ensureSequenceExists(sequence);
082            return getLong("select last_value from "+sequence);
083        }
084    
085        protected boolean ensureSequenceExists(String sequence) throws Exception {
086            boolean created = false;
087            if (!createdSequences.contains(sequence)) {
088                if (!hasSequence(sequence)) {
089                    execute("create sequence \""+sequence+"\"");
090                    created = true;
091                }
092                createdSequences.add(sequence);
093            }
094            return created;
095        }
096    
097        HashSet createdSequences = new HashSet();
098        public String newName(String className) throws Exception {
099            String prefix = Strings.getShortClassName(className).toLowerCase();
100            String seq = getClassSeqName(className);
101            return prefix+"#"+(getNextVal(seq)-1);
102        }
103    
104        protected String getClassSeqName(String className) {
105            return Strings.getShortClassName(className).toLowerCase()+"_seq";
106        }
107    
108        protected boolean hasTable(String name) throws Exception {
109            ResultSet rs = 
110                executeQuery("select * from pg_tables where tablename='"+name+"'"); 
111            return rs.next();
112        }
113    
114        protected boolean hasSequence(String name) throws Exception {
115            ResultSet rs = 
116                executeQuery("select * from pg_class where relname='"+name+"' and relkind='S'"); 
117            return rs.next();
118        }
119    
120        public void updateNameCounters(Map counters) throws Exception {
121            Iterator i = counters.entrySet().iterator();
122            while (i.hasNext()) {
123                Entry entry = (Entry)i.next();
124                String sequence = getClassSeqName((String)entry.getKey());
125                ensureSequenceExists(sequence);
126                if (getCurrVal(sequence)<((Long)entry.getValue()).longValue()) 
127                    execute("select setval('"+sequence+"',"+entry.getValue()+",false)");
128            }
129       }
130    
131    }