001/*
002 * HA-JDBC: High-Availability JDBC
003 * Copyright (c) 2004-2008 Paul Ferraro
004 * 
005 * This library is free software; you can redistribute it and/or modify it 
006 * under the terms of the GNU Lesser General Public License as published by the 
007 * Free Software Foundation; either version 2.1 of the License, or (at your 
008 * option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful, but WITHOUT
011 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
012 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 
013 * for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public License
016 * along with this library; if not, write to the Free Software Foundation, 
017 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018 * 
019 * Contact: ferraro@users.sourceforge.net
020 */
021package net.sf.hajdbc.sql;
022
023import java.beans.IntrospectionException;
024import java.beans.Introspector;
025import java.beans.PropertyDescriptor;
026import java.beans.PropertyEditor;
027import java.beans.PropertyEditorManager;
028import java.lang.reflect.InvocationTargetException;
029import java.util.Properties;
030
031import javax.management.DynamicMBean;
032import javax.management.NotCompliantMBeanException;
033import javax.management.StandardMBean;
034import javax.naming.Context;
035import javax.naming.InitialContext;
036import javax.naming.NamingException;
037
038import net.sf.hajdbc.Messages;
039
040/**
041 * A database described by a data source.
042 * @author Paul Ferraro
043 * @param <D> <code>javax.sql</code> data source interface
044 */
045public abstract class CommonDataSourceDatabase<D> extends AbstractDatabase<D> implements InactiveDataSourceDatabaseMBean
046{
047        private String name;
048        private Class<D> targetClass;
049        
050        protected CommonDataSourceDatabase(Class<D> targetClass)
051        {
052                this.targetClass = targetClass;
053        }
054        
055        /**
056         * @see net.sf.hajdbc.sql.ActiveDataSourceDatabaseMBean#getName()
057         */
058        @Override
059        public String getName()
060        {
061                return this.name;
062        }
063
064        /**
065         * @see net.sf.hajdbc.sql.InactiveDataSourceDatabaseMBean#setName(java.lang.String)
066         */
067        @Override
068        public void setName(String name)
069        {
070                this.checkDirty(this.name, name);
071                this.name = name;
072        }
073
074        /**
075         * @see net.sf.hajdbc.Database#createConnectionFactory()
076         */
077        @Override
078        public D createConnectionFactory()
079        {
080                try
081                {
082                        Class<?> dataSourceClass = Class.forName(this.name);
083                        
084                        return this.createDataSource(dataSourceClass.asSubclass(this.targetClass));
085                }
086                catch (ClassNotFoundException e)
087                {
088                        return this.createDataSource();
089                }
090        }
091
092        private D createDataSource()
093        {
094                try
095                {
096                        Context context = new InitialContext(this.getProperties());
097        
098                        return this.targetClass.cast(context.lookup(this.name));
099                }
100                catch (NamingException e)
101                {
102                        throw new IllegalArgumentException(Messages.getMessage(Messages.JNDI_LOOKUP_FAILED, this.name), e);
103                }
104        }
105
106        private D createDataSource(Class<? extends D> dataSourceClass)
107        {
108                Properties properties = this.getProperties();
109                
110                try
111                {
112                        D dataSource = dataSourceClass.newInstance();
113                        
114                        for (PropertyDescriptor descriptor: Introspector.getBeanInfo(dataSourceClass).getPropertyDescriptors())
115                        {
116                                String value = properties.getProperty(descriptor.getName());
117                                
118                                if (value != null)
119                                {
120                                        PropertyEditor editor = PropertyEditorManager.findEditor(descriptor.getPropertyType());
121                                        
122                                        editor.setAsText(value);
123                                        
124                                        descriptor.getWriteMethod().invoke(dataSource, editor.getValue());
125                                }
126                        }
127                        
128                        return dataSource;
129                }
130                catch (InstantiationException e)
131                {
132                        throw new IllegalArgumentException(e.toString(), e);
133                }
134                catch (IllegalAccessException e)
135                {
136                        throw new IllegalArgumentException(e.toString(), e);
137                }
138                catch (IntrospectionException e)
139                {
140                        throw new IllegalArgumentException(e.toString(), e);
141                }
142                catch (InvocationTargetException e)
143                {
144                        throw new IllegalArgumentException(e.getTargetException().toString(), e);
145                }
146        }
147        
148        /**
149         * @see net.sf.hajdbc.Database#getActiveMBean()
150         */
151        @Override
152        public DynamicMBean getActiveMBean()
153        {
154                try
155                {
156                        return new StandardMBean(this, ActiveDataSourceDatabaseMBean.class);
157                }
158                catch (NotCompliantMBeanException e)
159                {
160                        throw new IllegalStateException(e);
161                }
162        }
163
164        /**
165         * @see net.sf.hajdbc.Database#getInactiveMBean()
166         */
167        @Override
168        public DynamicMBean getInactiveMBean()
169        {
170                try
171                {
172                        return new StandardMBean(this, InactiveDataSourceDatabaseMBean.class);
173                }
174                catch (NotCompliantMBeanException e)
175                {
176                        throw new IllegalStateException(e);
177                }
178        }
179}