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;
019
020import java.io.IOException;
021import java.io.ObjectInputStream;
022import java.io.ObjectOutputStream;
023import java.sql.SQLException;
024import java.util.Hashtable;
025import java.util.Map;
026
027import javax.naming.Context;
028import javax.naming.InitialContext;
029import javax.naming.NamingException;
030
031/**
032 * @author Paul Ferraro
033 */
034public class ContextDatabaseClusterConfigurationFactory<Z, D extends Database<Z>> implements DatabaseClusterConfigurationFactory<Z, D>
035{
036        private static final long serialVersionUID = -914797510468986091L;
037
038        private final Class<? extends DatabaseClusterConfiguration<Z, D>> targetClass;
039        private final String name;
040        private transient Context context;
041        
042        public ContextDatabaseClusterConfigurationFactory(Class<? extends DatabaseClusterConfiguration<Z, D>> targetClass, String name) throws NamingException
043        {
044                this(targetClass, name, new InitialContext());
045        }
046        
047        public ContextDatabaseClusterConfigurationFactory(Class<? extends DatabaseClusterConfiguration<Z, D>> targetClass, String name, Hashtable<?, ?> env) throws NamingException
048        {
049                this(targetClass, name, new InitialContext(env));
050        }
051        
052        public ContextDatabaseClusterConfigurationFactory(Class<? extends DatabaseClusterConfiguration<Z, D>> targetClass, String name, Context context)
053        {
054                this.targetClass = targetClass;
055                this.name = name;
056                this.context = context;
057        }
058        
059        /**
060         * {@inheritDoc}
061         * @see net.sf.hajdbc.DatabaseClusterConfigurationFactory#createConfiguration()
062         */
063        @Override
064        public DatabaseClusterConfiguration<Z, D> createConfiguration() throws SQLException
065        {
066                try
067                {
068                        return this.targetClass.cast(this.context.lookup(this.name));
069                }
070                catch (NamingException e)
071                {
072                        throw new SQLException(e);
073                }
074        }
075        
076        /**
077         * {@inheritDoc}
078         * @see net.sf.hajdbc.DatabaseClusterConfigurationListener#added(net.sf.hajdbc.Database, net.sf.hajdbc.DatabaseClusterConfiguration)
079         */
080        @Override
081        public void added(D database, DatabaseClusterConfiguration<Z, D> configuration)
082        {
083                this.rebind(configuration);
084        }
085
086        /**
087         * {@inheritDoc}
088         * @see net.sf.hajdbc.DatabaseClusterConfigurationListener#removed(net.sf.hajdbc.Database, net.sf.hajdbc.DatabaseClusterConfiguration)
089         */
090        @Override
091        public void removed(D database, DatabaseClusterConfiguration<Z, D> configuration)
092        {
093                this.rebind(configuration);
094        }
095
096        private void rebind(DatabaseClusterConfiguration<Z, D> configuration)
097        {
098                try
099                {
100                        this.context.rebind(this.name, configuration);
101                }
102                catch (NamingException e)
103                {
104                        
105                }
106        }
107        
108        private void writeObject(ObjectOutputStream output) throws IOException
109        {
110                output.defaultWriteObject();
111
112                try
113                {
114                        Hashtable<?, ?> env = this.context.getEnvironment();
115                        
116                        output.writeInt((env != null) ? env.size() : 0);
117                        
118                        for (Map.Entry<?, ?> entry: env.entrySet())
119                        {
120                                output.writeUTF((String) entry.getKey());
121                                output.writeUTF((String) entry.getValue());
122                        }
123                }
124                catch (NamingException e)
125                {
126                        throw new IOException(e);
127                }
128        }
129        
130        private void readObject(ObjectInputStream input) throws IOException, ClassNotFoundException
131        {
132                input.defaultReadObject();
133                
134                int size = input.readInt();
135                
136                Hashtable<String, String> env = (size > 0) ? new Hashtable<String, String>() : null;
137                
138                for (int i = 0; i < input.readInt(); ++i)
139                {
140                        env.put(input.readUTF(), input.readUTF());
141                }
142                
143                try
144                {
145                        this.context = new InitialContext(env);
146                }
147                catch (NamingException e)
148                {
149                        throw new IOException(e);
150                }
151        }
152}