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.sql;
019
020import java.io.PrintWriter;
021import java.sql.SQLException;
022import java.sql.SQLFeatureNotSupportedException;
023import java.util.concurrent.TimeUnit;
024import java.util.logging.Logger;
025
026import javax.naming.BinaryRefAddr;
027import javax.naming.Reference;
028import javax.naming.Referenceable;
029import javax.naming.StringRefAddr;
030
031import net.sf.hajdbc.Database;
032import net.sf.hajdbc.DatabaseCluster;
033import net.sf.hajdbc.DatabaseClusterConfiguration;
034import net.sf.hajdbc.DatabaseClusterConfigurationFactory;
035import net.sf.hajdbc.DatabaseClusterFactory;
036import net.sf.hajdbc.ExceptionType;
037import net.sf.hajdbc.util.Objects;
038import net.sf.hajdbc.util.TimePeriod;
039import net.sf.hajdbc.util.concurrent.ReferenceRegistryStoreFactory;
040import net.sf.hajdbc.util.concurrent.LifecycleRegistry;
041import net.sf.hajdbc.util.concurrent.Registry;
042import net.sf.hajdbc.xml.XMLDatabaseClusterConfigurationFactory;
043
044/**
045 * @author Paul Ferraro
046 * @param <Z> data source class
047 */
048public abstract class CommonDataSource<Z extends javax.sql.CommonDataSource, D extends Database<Z>, F extends CommonDataSourceProxyFactory<Z, D>> implements Referenceable, javax.sql.CommonDataSource, CommonDataSourceProxyFactoryFactory<Z, D, F>, Registry.Factory<Void, DatabaseCluster<Z, D>, Void, SQLException>
049{
050        private final Class<? extends DatabaseClusterConfiguration<Z, D>> configurationClass;
051        
052        private final Registry<Void, DatabaseCluster<Z, D>, Void, SQLException> registry = new LifecycleRegistry<Void, DatabaseCluster<Z, D>, Void, SQLException>(this, new ReferenceRegistryStoreFactory(), ExceptionType.SQL.<SQLException>getExceptionFactory());
053        
054        private volatile TimePeriod timeout = new TimePeriod(10, TimeUnit.SECONDS);
055        private volatile String cluster;
056        private volatile String config;
057        private volatile String user;
058        private volatile String password;
059        private volatile DatabaseClusterFactory<Z, D> factory = new DatabaseClusterFactoryImpl<Z, D>();
060        private volatile DatabaseClusterConfigurationFactory<Z, D> configurationFactory;  
061        
062        protected CommonDataSource(Class<? extends DatabaseClusterConfiguration<Z, D>> configurationClass)
063        {
064                this.configurationClass = configurationClass;
065        }
066        
067        public void stop() throws SQLException
068        {
069                this.registry.remove(null);
070        }
071
072        /**
073         * {@inheritDoc}
074         */
075        @Override
076        public DatabaseCluster<Z, D> create(Void key, Void context) throws SQLException
077        {
078                DatabaseClusterConfigurationFactory<Z, D> factory = (this.configurationFactory != null) ? this.configurationFactory : new XMLDatabaseClusterConfigurationFactory<Z, D>(this.configurationClass, this.cluster, this.config);
079                
080                return this.factory.createDatabaseCluster(this.cluster, factory);
081        }
082
083        public Z getProxy() throws SQLException
084        {
085                return this.createProxyFactory(this.registry.get(null, null)).createProxy();
086        }
087        
088        /**
089         * @return the cluster
090         */
091        public String getCluster()
092        {
093                return this.cluster;
094        }
095
096        /**
097         * @param cluster the cluster to set
098         */
099        public void setCluster(String cluster)
100        {
101                this.cluster = cluster;
102        }
103
104        /**
105         * @return the config
106         */
107        public String getConfig()
108        {
109                return this.config;
110        }
111
112        /**
113         * @param config the config to set
114         */
115        public void setConfig(String config)
116        {
117                this.config = config;
118        }
119        
120        public String getUser()
121        {
122                return this.user;
123        }
124        
125        public void setUser(String user)
126        {
127                this.user = user;
128        }
129        
130        public String getPassword()
131        {
132                return this.password;
133        }
134        
135        public void setPassword(String password)
136        {
137                this.password = password;
138        }
139        
140        public DatabaseClusterConfigurationFactory<Z, D> getConfigurationFactory()
141        {
142                return this.configurationFactory;
143        }
144        
145        public void setConfigurationFactory(DatabaseClusterConfigurationFactory<Z, D> configurationFactory)
146        {
147                this.configurationFactory = configurationFactory;
148        }
149        
150        public DatabaseClusterFactory<Z, D> getFactory()
151        {
152                return this.factory;
153        }
154        
155        public void setFactory(DatabaseClusterFactory<Z, D> clusterFactory)
156        {
157                this.factory = clusterFactory;
158        }
159        
160        /**
161         * @return the timeout
162         */
163        @Override
164        public TimePeriod getTimeout()
165        {
166                return this.timeout;
167        }
168
169        /**
170         * @param value the timeout to set, expressed in the specified units
171         * @param unit the time unit with which to qualify the specified timeout value
172         */
173        public void setTimeout(long value, TimeUnit unit)
174        {
175                this.timeout = new TimePeriod(value, unit);
176        }
177
178        /**
179         * @throws SQLFeatureNotSupportedException 
180         * @see javax.sql.CommonDataSource#getParentLogger()
181         */
182        @Override
183        public Logger getParentLogger() throws SQLFeatureNotSupportedException
184        {
185                try
186                {
187                        return this.getProxy().getParentLogger();
188                }
189                catch (SQLFeatureNotSupportedException e)
190                {
191                        throw e;
192                }
193                catch (SQLException e)
194                {
195                        throw new SQLFeatureNotSupportedException(e.getMessage(), e.getSQLState(), e.getErrorCode(), e.getCause());
196                }
197        }
198
199        /**
200         * @see javax.sql.CommonDataSource#getLoginTimeout()
201         */
202        @Override
203        public int getLoginTimeout() throws SQLException
204        {
205                return this.getProxy().getLoginTimeout();
206        }
207
208        /**
209         * @see javax.sql.CommonDataSource#getLogWriter()
210         */
211        @Override
212        public PrintWriter getLogWriter() throws SQLException
213        {
214                return this.getProxy().getLogWriter();
215        }
216
217        /**
218         * @see javax.sql.CommonDataSource#setLoginTimeout(int)
219         */
220        @Override
221        public void setLoginTimeout(int timeout) throws SQLException
222        {
223                this.getProxy().setLoginTimeout(timeout);
224        }
225
226        /**
227         * @see javax.sql.CommonDataSource#setLogWriter(java.io.PrintWriter)
228         */
229        @Override
230        public void setLogWriter(PrintWriter writer) throws SQLException
231        {
232                this.getProxy().setLogWriter(writer);
233        }
234
235        @Override
236        public Reference getReference()
237        {
238                Reference reference = new Reference(this.getClass().getName(), CommonDataSourceFactory.class.getName(), null);
239                reference.add(new StringRefAddr(CommonDataSourceFactory.CLUSTER, this.cluster));
240                DatabaseClusterConfigurationFactory<Z, D> factory = this.getConfigurationFactory();
241                if (factory != null)
242                {
243                        reference.add(new BinaryRefAddr(CommonDataSourceFactory.CONFIG, Objects.serialize(factory)));
244                }
245                else
246                {
247                        reference.add(new StringRefAddr(CommonDataSourceFactory.CONFIG, this.config));
248                }
249                if (this.user != null)
250                {
251                        reference.add(new StringRefAddr(CommonDataSourceFactory.USER, this.user));
252                }
253                if (this.password != null)
254                {
255                        reference.add(new StringRefAddr(CommonDataSourceFactory.PASSWORD, this.password));
256                }
257                return reference;
258        }
259}