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.lang.ref.Reference;
021import java.lang.ref.SoftReference;
022import java.sql.Connection;
023import java.sql.DatabaseMetaData;
024import java.sql.SQLException;
025import java.util.AbstractMap;
026import java.util.Map;
027
028import net.sf.hajdbc.Database;
029import net.sf.hajdbc.DatabaseCluster;
030import net.sf.hajdbc.DatabaseProperties;
031import net.sf.hajdbc.cache.DatabaseMetaDataCache;
032import net.sf.hajdbc.dialect.Dialect;
033
034
035/**
036 * DatabaseMetaDataCache implementation that lazily caches data when requested.
037 * Used when a compromise between memory usage and performance is desired.
038 * Caches DatabaseProperties using a soft reference to prevent <code>OutOfMemoryError</code>s.
039 * 
040 * @author Paul Ferraro
041 * @since 2.0
042 */
043public class SharedLazyDatabaseMetaDataCache<Z, D extends Database<Z>> implements DatabaseMetaDataCache<Z, D>
044{
045        private final DatabaseCluster<Z, D> cluster;
046        
047        private volatile Reference<Map.Entry<DatabaseProperties, LazyDatabaseMetaDataProvider>> entryRef = new SoftReference<Map.Entry<DatabaseProperties, LazyDatabaseMetaDataProvider>>(null);
048        
049        public SharedLazyDatabaseMetaDataCache(DatabaseCluster<Z, D> cluster)
050        {
051                this.cluster = cluster;
052        }
053        
054        /**
055         * @see net.sf.hajdbc.cache.DatabaseMetaDataCache#flush()
056         */
057        @Override
058        public synchronized void flush()
059        {
060                this.entryRef.clear();
061        }
062
063        /**
064         * {@inheritDoc}
065         * @see net.sf.hajdbc.cache.DatabaseMetaDataCache#getDatabaseProperties(net.sf.hajdbc.Database, java.sql.Connection)
066         */
067        @Override
068        public DatabaseProperties getDatabaseProperties(D database, Connection connection) throws SQLException
069        {
070                Map.Entry<DatabaseProperties, LazyDatabaseMetaDataProvider> entry = this.entryRef.get();
071                
072                if (entry == null)
073                {
074                        DatabaseMetaData metaData = connection.getMetaData();
075                        Dialect dialect = this.cluster.getDialect();
076                        LazyDatabaseMetaDataProvider provider = new LazyDatabaseMetaDataProvider(metaData);
077                        DatabaseProperties properties = new LazyDatabaseProperties(provider, dialect);
078                        
079                        entry = new AbstractMap.SimpleImmutableEntry<DatabaseProperties, LazyDatabaseMetaDataProvider>(properties, provider);
080                
081                        this.entryRef = new SoftReference<Map.Entry<DatabaseProperties, LazyDatabaseMetaDataProvider>>(entry);
082                }
083                else
084                {
085                        entry.getValue().setConnection(connection);
086                }
087                
088                return entry.getKey();
089        }
090}