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.lazy;
019
020import java.sql.SQLException;
021import java.util.HashMap;
022import java.util.List;
023import java.util.Map;
024import java.util.Map.Entry;
025import java.util.concurrent.atomic.AtomicReference;
026
027import net.sf.hajdbc.QualifiedName;
028import net.sf.hajdbc.SequenceProperties;
029import net.sf.hajdbc.SequencePropertiesFactory;
030import net.sf.hajdbc.SequenceSupport;
031import net.sf.hajdbc.TableProperties;
032import net.sf.hajdbc.cache.AbstractDatabaseProperties;
033import net.sf.hajdbc.cache.DatabaseMetaDataProvider;
034import net.sf.hajdbc.dialect.Dialect;
035
036/**
037 * @author Paul Ferraro
038 *
039 */
040public class LazyDatabaseProperties extends AbstractDatabaseProperties
041{
042        private final Dialect dialect;
043        private final DatabaseMetaDataProvider provider;
044        private final SequencePropertiesFactory sequenceFactory;
045        
046        private final AtomicReference<Map<QualifiedName, TableProperties>> tablesRef = new AtomicReference<Map<QualifiedName, TableProperties>>();
047        private final AtomicReference<Map<QualifiedName, SequenceProperties>> sequencesRef = new AtomicReference<Map<QualifiedName, SequenceProperties>>();
048        private final AtomicReference<List<String>> defaultSchemasRef = new AtomicReference<List<String>>();
049        private final AtomicReference<Map<Integer, Map.Entry<String, Integer>>> typesRef = new AtomicReference<Map<Integer, Map.Entry<String, Integer>>>();
050        
051        public LazyDatabaseProperties(DatabaseMetaDataProvider provider, Dialect dialect) throws SQLException
052        {
053                super(provider.getDatabaseMetaData(), dialect);
054
055                this.provider = provider;
056                this.dialect = dialect;
057                SequenceSupport support = dialect.getSequenceSupport();
058                this.sequenceFactory = (support != null) ? support.createSequencePropertiesFactory(this.nameFactory) : null;
059        }
060        
061        @Override
062        protected Map<QualifiedName, TableProperties> tables() throws SQLException
063        {
064                Map<QualifiedName, TableProperties> tables = this.tablesRef.get();
065                
066                if (tables == null)
067                {
068                        tables = new HashMap<QualifiedName, TableProperties>();
069                        
070                        for (QualifiedName table: this.dialect.getTables(this.provider.getDatabaseMetaData(), this.nameFactory))
071                        {
072                                TableProperties properties = new LazyTableProperties(table, this.provider, this.dialect, this.nameFactory);
073                                
074                                tables.put(properties.getName(), properties);
075                        }
076                        
077                        if (!this.tablesRef.compareAndSet(null, tables))
078                        {
079                                return this.tablesRef.get();
080                        }
081                }
082                
083                return tables;
084        }
085        
086        @Override
087        protected Map<QualifiedName, SequenceProperties> sequences() throws SQLException
088        {
089                Map<QualifiedName, SequenceProperties> sequences = this.sequencesRef.get();
090
091                if (sequences == null)
092                {
093                        sequences = new HashMap<QualifiedName, SequenceProperties>();
094                        
095                        if (this.sequenceFactory != null)
096                        {
097                                for (SequenceProperties sequence: this.dialect.getSequenceSupport().getSequences(this.provider.getDatabaseMetaData(), this.sequenceFactory))
098                                {
099                                        sequences.put(sequence.getName(), sequence);
100                                }
101                        }
102                        
103                        if (!this.sequencesRef.compareAndSet(null, sequences))
104                        {
105                                return this.sequencesRef.get();
106                        }
107                }
108
109                return sequences;
110        }
111        
112        @Override
113        protected List<String> defaultSchemas() throws SQLException
114        {
115                List<String> schemas = this.defaultSchemasRef.get();
116                
117                if (schemas == null)
118                {
119                        schemas = this.dialect.getDefaultSchemas(this.provider.getDatabaseMetaData());
120                        
121                        if (!this.defaultSchemasRef.compareAndSet(null, schemas))
122                        {
123                                return this.defaultSchemasRef.get();
124                        }
125                }
126                
127                return schemas;
128        }
129
130        @Override
131        protected Map<Integer, Entry<String, Integer>> types() throws SQLException
132        {
133                Map<Integer, Map.Entry<String, Integer>> types = this.typesRef.get();
134                
135                if (types == null)
136                {
137                        types = this.dialect.getTypes(this.provider.getDatabaseMetaData());
138                        
139                        if (!this.typesRef.compareAndSet(null, types))
140                        {
141                                return this.typesRef.get();
142                        }
143                }
144                
145                return types;
146        }
147}