001/*
002 * HA-JDBC: High-Availability JDBC
003 * Copyright (C) 2012  Paul Ferraro
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Lesser General Public License as published by
007 * the Free Software Foundation, either version 3 of the License, or
008 * (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Lesser General Public License for more details.
014 *
015 * You should have received a copy of the GNU Lesser General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018package net.sf.hajdbc.cache;
019
020import java.sql.DatabaseMetaData;
021import java.sql.SQLException;
022import java.util.Arrays;
023import java.util.Collection;
024import java.util.Iterator;
025import java.util.List;
026import java.util.Map;
027import java.util.Map.Entry;
028
029import net.sf.hajdbc.DatabaseProperties;
030import net.sf.hajdbc.QualifiedName;
031import net.sf.hajdbc.QualifiedNameFactory;
032import net.sf.hajdbc.SequenceProperties;
033import net.sf.hajdbc.TableProperties;
034import net.sf.hajdbc.dialect.Dialect;
035
036/**
037 * @author Paul Ferraro
038 *
039 */
040public abstract class AbstractDatabaseProperties implements DatabaseProperties
041{
042        protected final QualifiedNameFactory nameFactory;
043        private final boolean supportsSelectForUpdate;
044        private final boolean locatorsUpdateCopy;
045        
046        public AbstractDatabaseProperties(DatabaseMetaData metaData, Dialect dialect) throws SQLException
047        {
048                this.supportsSelectForUpdate = metaData.supportsSelectForUpdate();
049                this.locatorsUpdateCopy = metaData.locatorsUpdateCopy();
050                this.nameFactory = dialect.createQualifiedNameFactory(metaData, dialect.createIdentifierNormalizer(metaData));
051        }
052        
053        /**
054         * @see net.sf.hajdbc.DatabaseProperties#supportsSelectForUpdate()
055         */
056        @Override
057        public final boolean supportsSelectForUpdate()
058        {
059                return this.supportsSelectForUpdate;
060        }
061        
062        /**
063         * {@inheritDoc}
064         * @see net.sf.hajdbc.DatabaseProperties#locatorsUpdateCopy()
065         */
066        @Override
067        public boolean locatorsUpdateCopy()
068        {
069                return this.locatorsUpdateCopy;
070        }
071
072        /**
073         * @see net.sf.hajdbc.DatabaseProperties#getTables()
074         */
075        @Override
076        public final Collection<TableProperties> getTables() throws SQLException
077        {
078                return this.tables().values();
079        }
080
081        protected abstract Map<QualifiedName, TableProperties> tables() throws SQLException;
082
083        /**
084         * @see net.sf.hajdbc.DatabaseProperties#getSequences()
085         */
086        @Override
087        public final Collection<SequenceProperties> getSequences() throws SQLException
088        {
089                return this.sequences().values();
090        }
091
092        protected abstract Map<QualifiedName, SequenceProperties> sequences() throws SQLException;
093        
094        /**
095         * @see net.sf.hajdbc.DatabaseProperties#findTable(java.lang.String)
096         */
097        @Override
098        public final TableProperties findTable(String table) throws SQLException
099        {
100                return this.find(this.tables(), table, this.defaultSchemas());
101        }
102
103        /**
104         * @see net.sf.hajdbc.DatabaseProperties#findSequence(java.lang.String)
105         */
106        @Override
107        public final SequenceProperties findSequence(String sequence) throws SQLException
108        {
109                return this.find(this.sequences(), sequence, this.defaultSchemas());
110        }
111        
112        private <T> T find(Map<QualifiedName, T> map, String raw, List<String> defaultSchemaList)
113        {
114                QualifiedName name = this.nameFactory.parse(raw);
115
116                T properties = map.get(name);
117                
118                if ((properties == null) && (name.getSchema() == null))
119                {
120                        Iterator<String> schemas = defaultSchemaList.iterator();
121                        while ((properties == null) && schemas.hasNext())
122                        {
123                                properties = map.get(this.nameFactory.createQualifiedName(schemas.next(), raw));
124                        }
125                }
126
127                return properties;
128        }
129
130        protected abstract List<String> defaultSchemas() throws SQLException;
131        
132        /**
133         * {@inheritDoc}
134         * @see net.sf.hajdbc.DatabaseProperties#findType(int, int[])
135         */
136        @Override
137        public String findType(int precision, int... types) throws SQLException
138        {
139                Map<Integer, Map.Entry<String, Integer>> map = this.types();
140
141                for (int type: types)
142                {
143                        Map.Entry<String, Integer> entry = map.get(type);
144                        if (entry != null)
145                        {
146                                String name = entry.getKey();
147                                Integer maxPrecision = entry.getValue();
148                                if (maxPrecision != null)
149                                {
150                                        String qualifier = "(" + ((precision == 0) ? maxPrecision : precision) + ")";
151                                        return name.contains("()") ? name.replace("()", qualifier) : name + qualifier;
152                                }
153                                
154                                return name;
155                        }
156                }
157                throw new SQLException("No native type found for " + Arrays.asList(types));
158        }
159        
160        protected abstract Map<Integer, Entry<String, Integer>> types() throws SQLException;
161}