001/* 002 * HA-JDBC: High-Availability JDBC 003 * Copyright (c) 2004-2007 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.sql.Connection; 024import java.sql.DriverManager; 025import java.sql.DriverPropertyInfo; 026import java.sql.SQLException; 027import java.sql.SQLFeatureNotSupportedException; 028import java.util.Properties; 029import java.util.regex.Matcher; 030import java.util.regex.Pattern; 031 032import net.sf.hajdbc.Database; 033import net.sf.hajdbc.DatabaseCluster; 034import net.sf.hajdbc.DatabaseClusterFactory; 035import net.sf.hajdbc.Messages; 036import net.sf.hajdbc.util.SQLExceptionFactory; 037import net.sf.hajdbc.util.Strings; 038import net.sf.hajdbc.util.reflect.ProxyFactory; 039 040import org.slf4j.Logger; 041import org.slf4j.LoggerFactory; 042 043/** 044 * @author Paul Ferraro 045 * @version $Revision: 2015 $ 046 */ 047public final class Driver implements java.sql.Driver 048{ 049 private static final Pattern URL_PATTERN = Pattern.compile("jdbc:ha-jdbc:(.+)"); //$NON-NLS-1$ 050 private static final String CONFIG = "config"; //$NON-NLS-1$ 051 052 private static Logger logger = LoggerFactory.getLogger(Driver.class); 053 054 static 055 { 056 try 057 { 058 DriverManager.registerDriver(new Driver()); 059 } 060 catch (SQLException e) 061 { 062 logger.error(Messages.getMessage(Messages.DRIVER_REGISTER_FAILED, Driver.class.getName()), e); 063 } 064 } 065 066 /** 067 * @see java.sql.Driver#acceptsURL(java.lang.String) 068 */ 069 @Override 070 public boolean acceptsURL(String url) 071 { 072 return (this.parse(url) != null); 073 } 074 075 /** 076 * @see java.sql.Driver#connect(java.lang.String, java.util.Properties) 077 */ 078 @Override 079 public Connection connect(String url, final Properties properties) throws SQLException 080 { 081 String id = this.parse(url); 082 083 if (id == null) return null; 084 085 DatabaseCluster<java.sql.Driver> cluster = this.getDatabaseCluster(id, properties); 086 087 DriverInvocationHandler handler = new DriverInvocationHandler(cluster); 088 089 java.sql.Driver driver = ProxyFactory.createProxy(java.sql.Driver.class, handler); 090 091 Invoker<java.sql.Driver, java.sql.Driver, Connection> invoker = new Invoker<java.sql.Driver, java.sql.Driver, Connection>() 092 { 093 public Connection invoke(Database<java.sql.Driver> database, java.sql.Driver driver) throws SQLException 094 { 095 String url = ((DriverDatabase) database).getUrl(); 096 097 return driver.connect(url, properties); 098 } 099 }; 100 101 TransactionContext<java.sql.Driver> context = new LocalTransactionContext<java.sql.Driver>(cluster); 102 103 try 104 { 105 return new ConnectionInvocationStrategy<java.sql.Driver, java.sql.Driver>(cluster, driver, context).invoke(handler, invoker); 106 } 107 catch (Exception e) 108 { 109 throw SQLExceptionFactory.createSQLException(e); 110 } 111 } 112 113 /** 114 * @see java.sql.Driver#getMajorVersion() 115 */ 116 @Override 117 public int getMajorVersion() 118 { 119 return Integer.parseInt(version()[0]); 120 } 121 122 /** 123 * @see java.sql.Driver#getMinorVersion() 124 */ 125 @Override 126 public int getMinorVersion() 127 { 128 return Integer.parseInt(version()[1]); 129 } 130 131 private String[] version() 132 { 133 return DatabaseClusterFactory.getVersion().split(Strings.DASH)[0].split(Pattern.quote(Strings.DOT)); 134 } 135 136 /** 137 * @see java.sql.Driver#getPropertyInfo(java.lang.String, java.util.Properties) 138 */ 139 @Override 140 public DriverPropertyInfo[] getPropertyInfo(String url, final Properties properties) throws SQLException 141 { 142 String id = this.parse(url); 143 144 if (id == null) return null; 145 146 DatabaseCluster<java.sql.Driver> cluster = this.getDatabaseCluster(id, properties); 147 148 DriverInvocationHandler handler = new DriverInvocationHandler(cluster); 149 150 Invoker<java.sql.Driver, java.sql.Driver, DriverPropertyInfo[]> invoker = new Invoker<java.sql.Driver, java.sql.Driver, DriverPropertyInfo[]>() 151 { 152 public DriverPropertyInfo[] invoke(Database<java.sql.Driver> database, java.sql.Driver driver) throws SQLException 153 { 154 String url = ((DriverDatabase) database).getUrl(); 155 156 return driver.getPropertyInfo(url, properties); 157 } 158 }; 159 160 try 161 { 162 return new DriverReadInvocationStrategy<java.sql.Driver, java.sql.Driver, DriverPropertyInfo[]>().invoke(handler, invoker); 163 } 164 catch (Exception e) 165 { 166 throw SQLExceptionFactory.createSQLException(e); 167 } 168 } 169 170 /** 171 * @see java.sql.Driver#jdbcCompliant() 172 */ 173 @Override 174 public boolean jdbcCompliant() 175 { 176 return true; 177 } 178 179 private DatabaseCluster<java.sql.Driver> getDatabaseCluster(String id, Properties properties) throws SQLException 180 { 181 DatabaseCluster<java.sql.Driver> cluster = DatabaseClusterFactory.getDatabaseCluster(id, DriverDatabaseCluster.class, DriverDatabaseClusterMBean.class, properties.getProperty(CONFIG)); 182 183 if (cluster == null) 184 { 185 throw new SQLException(Messages.getMessage(Messages.INVALID_DATABASE_CLUSTER, id)); 186 } 187 188 return cluster; 189 } 190 191 private String parse(String url) 192 { 193 Matcher matcher = URL_PATTERN.matcher(url); 194 195 if (!matcher.matches()) 196 { 197 return null; 198 } 199 200 return matcher.group(1); 201 } 202 203 public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { 204 throw new SQLFeatureNotSupportedException(); 205 } 206 207}