001package org.javasimon.jdbc4; 002 003import java.io.IOException; 004import java.io.InputStream; 005import java.util.Properties; 006import java.util.StringTokenizer; 007import java.util.regex.Matcher; 008import java.util.regex.Pattern; 009 010/** 011 * JDBC configuration contains Simon JDBC connection URL, real JDBC connection URL and Simon properties. 012 * <p/> 013 * It parses given url and than provides getters for driver's properties if provided or default values. 014 * Prior to Simon 3.4, this class was known as org.javasimon.jdbc4.Driver.Url and only used in {@link Driver}. 015 * It was externalized and is now used in both {@code org.javasimon.jdbc4.Driver} 016 * and {@link org.javasimon.jdbcx4.SimonDataSource} and other Simon DataSources. 017 * 018 * @author Radovan Sninsky 019 * @author gquintana 020 * @since 3.4 021 */ 022public class SimonConnectionConfiguration { 023 /** 024 * Default hierarchy prefix for Simon JDBC driver. All Simons created by Simon JDBC 025 * driver without explicitly specified prefix are started with default prefix. 026 */ 027 public static final String DEFAULT_PREFIX = "org.javasimon.jdbc"; 028 029 /** 030 * Prefix used in JDBC connection URLs. 031 */ 032 public static final String URL_PREFIX = "jdbc:simon"; 033 034 /** 035 * Regex used to parse JDBC connection URL. 036 */ 037 private static final Pattern URL_PATTERN = Pattern.compile("jdbc:(simon:)?([\\w]*):.*"); 038 039 /** 040 * Name for the property holding the real driver class value. 041 */ 042 public static final String REAL_DRIVER = "simon_real_drv"; 043 /** 044 * Name for the driver property holding the hierarchy prefix given to JDBC Simons. 045 */ 046 public static final String PREFIX = "simon_prefix"; 047 048 private static final Properties PROPERTIES = initProperties(); 049 050 /** 051 * JDBC connection URL with Simon prefix. 052 */ 053 private final String simonUrl; 054 055 /** 056 * JDBC connection URL without Simon prefix. 057 */ 058 private final String realUrl; 059 060 /** 061 * Driver Id. 062 */ 063 private final String driverId; 064 065 /** 066 * Real Driver class name. 067 */ 068 private final String realDriver; 069 070 /** 071 * Simon hierarchy prefix. 072 */ 073 private final String prefix; 074 075 /** 076 * Loads {@code driver.properties} file. 077 */ 078 private static Properties initProperties() { 079 InputStream stream = null; 080 try { 081 // TODO: limited to known drivers, better find driver later based on JDBC connection URL without "simon" word 082 Properties properties = new Properties(); 083 stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("org/javasimon/jdbc4/drivers.properties"); 084 if (stream != null) { 085 properties.load(stream); 086 } 087 return properties; 088 } catch (IOException e) { 089 throw new IllegalStateException(e); 090 } finally { 091 if (stream != null) { 092 try { 093 stream.close(); 094 } catch (IOException e) { 095 // Doesn't matter 096 } 097 } 098 } 099 } 100 101 /** 102 * Class constructor, parses given connection URL and recognizes driver's properties. 103 * 104 * @param url given JDBC connection URL 105 */ 106 public SimonConnectionConfiguration(String url) { 107 Matcher m = URL_PATTERN.matcher(url); 108 if (!m.matches()) { 109 throw new IllegalArgumentException(url + " is not a valid JDBC connection URL"); 110 } 111 driverId = m.group(2); 112 if (m.group(1) == null) { 113 // java:oracle: 114 simonUrl = url.replaceFirst("jdbc", URL_PREFIX); 115 realUrl = url; 116 realDriver = getProperty(driverId, "driver"); 117 prefix = DEFAULT_PREFIX; 118 } else { 119 //java:simon:oracle 120 simonUrl = url; 121 StringTokenizer st = new StringTokenizer(url, ";"); 122 String lRealDriver = getProperty(driverId, "driver"); 123 String lPrefix = DEFAULT_PREFIX; 124 StringBuilder realUrlBuilder = new StringBuilder(); 125 while (st.hasMoreTokens()) { 126 String tokenPairStr = st.nextToken().trim(); 127 128 if (tokenPairStr.startsWith(URL_PREFIX)) { 129 realUrlBuilder.append(tokenPairStr.replaceFirst(URL_PREFIX, "jdbc")); 130 } else { 131 String[] tokenPair = tokenPairStr.split("=", 2); 132 String token = tokenPair[0]; 133 String tokenValue = tokenPair.length == 2 ? tokenPair[1].trim() : null; 134 if (token.equalsIgnoreCase(REAL_DRIVER)) { 135 lRealDriver = tokenValue; 136 } else if (token.equalsIgnoreCase(PREFIX)) { 137 lPrefix = tokenValue; 138 } else { 139 realUrlBuilder.append(';').append(tokenPairStr); 140 } 141 } 142 } 143 realUrl = realUrlBuilder.toString(); 144 realDriver = lRealDriver; 145 prefix = lPrefix; 146 } 147 } 148 149 /** 150 * Gets value of the specified property. 151 * 152 * @param driverId Driver Id 153 * @param propertyName Property name 154 * @return property value or {@code null} 155 */ 156 private static String getProperty(String driverId, String propertyName) { 157 String propertyValue = PROPERTIES.getProperty(DEFAULT_PREFIX + "." + driverId + "." + propertyName); 158 if (propertyValue != null) { 159 propertyValue = propertyValue.trim(); 160 if (propertyValue.isEmpty()) { 161 propertyValue = null; 162 } 163 } 164 return propertyValue; 165 } 166 167 /** 168 * Returns orignal JDBC connection URL without any Simon stuff. 169 * 170 * @return original JDBC connection URL 171 */ 172 public String getRealUrl() { 173 return realUrl; 174 } 175 176 /** 177 * Returns driver identifier (eg. oracle, postgres, mysql, h2, etc.). 178 * 179 * @return driver identifier 180 */ 181 public String getDriverId() { 182 return driverId; 183 } 184 185 /** 186 * Returns fully qualified class name of the real driver. 187 * 188 * @return driver class FQN 189 */ 190 public String getRealDriver() { 191 return realDriver; 192 } 193 194 /** 195 * Returns prefix for hierarchy of JDBC connection related Simons. 196 * 197 * @return prefix for JDBC Simons 198 */ 199 public String getPrefix() { 200 return prefix; 201 } 202 203 /** 204 * Simon JDBC connection URL prefixed with {@code jdbc:simon:}. 205 * 206 * @return Simon JDBC connection URL 207 */ 208 public String getSimonUrl() { 209 return simonUrl; 210 } 211 212 /** 213 * Tests whether URL is a Simon JDBC connection URL. 214 */ 215 public static boolean isSimonUrl(String url) { 216 return url != null && url.toLowerCase().startsWith(SimonConnectionConfiguration.URL_PREFIX); 217 } 218 219 /** 220 * Gets the name of the class implementing {@link javax.sql.ConnectionPoolDataSource}. 221 */ 222 public String getRealConnectionPoolDataSourceName() { 223 return getProperty(driverId, "cpdatasource"); 224 } 225 226 /** 227 * Gets the name of the class implementing {@link javax.sql.DataSource}. 228 */ 229 public String getRealDataSourceName() { 230 return getProperty(driverId, "datasource"); 231 } 232 233 /** 234 * Gets the name of the class implementing {@link javax.sql.XADataSource}. 235 */ 236 public String getRealXADataSourceName() { 237 return getProperty(driverId, "xadatasource"); 238 } 239}