001/** 002 * Copyright (C) 2010-2015 The Roslin Institute <contact andy.law@roslin.ed.ac.uk> 003 * 004 * This file is part of JEnsembl: a Java API to Ensembl data sources developed by the 005 * Bioinformatics Group at The Roslin Institute, The Royal (Dick) School of 006 * Veterinary Studies, University of Edinburgh. 007 * 008 * Project hosted at: http://jensembl.sourceforge.net 009 * 010 * This is free software: you can redistribute it and/or modify 011 * it under the terms of the GNU General Public License (version 3) as published by 012 * the Free Software Foundation. 013 * 014 * This software is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public License 020 * in this software distribution. If not, see: http://opensource.org/licenses/gpl-3.0.html 021 */ 022package uk.ac.roslin.ensembl.config; 023 024import java.io.Serializable; 025import java.sql.Connection; 026import java.sql.DriverManager; 027import java.sql.SQLException; 028import java.sql.SQLWarning; 029import java.util.*; 030import org.slf4j.Logger; 031import org.slf4j.LoggerFactory; 032import uk.ac.roslin.ensembl.exception.ConfigurationException; 033 034public class DBConnection { 035 036 protected String newline = (System.getProperty("line.separator") != null) ? System.getProperty("line.separator") : "\r\n"; 037 String datasourceStyle = "ensembldb"; 038 String driver = null; 039 String url = null; 040 String username = "anonymous"; 041 String password = null; 042 String[] invalidDBMatches = null; 043 String[] invalidDBContains = null; 044 String[] invalidDBStart = null; 045 String[] invalidDBEnd = null; 046 DataSource configuredDatasource; 047 Properties dbProperties; 048 protected HashMap<String, String> renamedDBs = new HashMap<String, String>(); 049 050 final static Logger LOGGER = LoggerFactory.getLogger(DBConnection.class); 051 052 public static enum DataSource implements Serializable { 053 054 ENSEMBLDB("EnsemblDB"), 055 ENSEMBLDB_ARCHIVES("EnsemblDB Archives"), 056 ENSEMBLGENOMES("EnsemblGenomes"), 057 ENSEMBLBACTERIA("EnsemblBacteria"), 058 LOCAL("Local Data Source"); 059 private String label; 060 061 DataSource(String label) { 062 this.label = label; 063 } 064 065 @Override 066 public String toString() { 067 return label; 068 } 069 } 070 071 public static DataSource getDataSource(String value) { 072 073 if (value==null) { 074 return null; 075 } 076 if (value.equals("EnsemblDB")) { 077 return DataSource.ENSEMBLDB; 078 } 079 else if (value.equals("EnsemblGenomes")) { 080 return DataSource.ENSEMBLGENOMES; 081 } 082 else if (value.equals("EnsemblBacteria")) { 083 return DataSource.ENSEMBLBACTERIA; 084 } 085 else if (value.equals("EnsemblDB Archives")) { 086 return DataSource.ENSEMBLDB_ARCHIVES; 087 } 088 else if (value.equals("Local Data Source")) { 089 return DataSource.LOCAL; 090 } else { 091 return null; 092 } 093 094 } 095 096 public DBConnection(DataSource datasource) throws ConfigurationException { 097 configuredDatasource = datasource; 098 if (datasource == DataSource.ENSEMBLDB) { 099 dbProperties = this.readResource("uk.ac.roslin.ensembl.configfiles.ensembldb"); 100 } else if (datasource == DataSource.ENSEMBLDB_ARCHIVES) { 101 dbProperties = this.readResource("uk.ac.roslin.ensembl.configfiles.ensembldb_archives"); 102 } else if (datasource == DataSource.ENSEMBLGENOMES || datasource == DataSource.ENSEMBLBACTERIA) { 103 dbProperties = this.readResource("uk.ac.roslin.ensembl.configfiles.ensemblgenomes"); 104 } else { 105 throw new ConfigurationException("Unrecognized type of DataSource specified for DBConnection"); 106 } 107 initialize(); 108 } 109 110 public Properties getConfigurationProperties() { 111 return dbProperties; 112 } 113 114 public DataSource getConfiguredDatasource() { 115 return configuredDatasource; 116 } 117 118 public DBConnection(DataSource datasource, Properties local_datasource) throws ConfigurationException { 119 if (datasource != DataSource.LOCAL || local_datasource == null) { 120 throw new ConfigurationException("Invalid attempt to configure DBConnection with unrecognized local DataSource."); 121 } 122 configuredDatasource = datasource; 123 dbProperties = local_datasource; 124 initialize(); 125 } 126 127 private Properties readResource(String id) throws ConfigurationException { 128 Properties p = null; 129 try { 130 //NB: need to pass in the classloader to get this to work in a test environment! 131 ResourceBundle rb = ResourceBundle.getBundle(id, Locale.getDefault(), 132 this.getClass().getClassLoader()); 133 p = new Properties(); 134 for (Enumeration keys = rb.getKeys(); keys.hasMoreElements();) { 135 final String key = (String) keys.nextElement(); 136 final String value = rb.getString(key); 137 p.put(key, value); 138 } 139 } catch (Exception ex) { 140 throw new ConfigurationException("System can't read the configuration file: " + id); 141 } 142 return p; 143 } 144 145 private void initialize() { 146 147 //at v68 this was changed to iterate through the properties rather than get them by name 148 //this was necessary to allow us to discover dbrename pairs 149 for (String s: dbProperties.stringPropertyNames()) { 150 151 if ( s.equalsIgnoreCase("invalidDBStartsWith") ) { 152 invalidDBStart = dbProperties.getProperty(s).split(" "); 153 } 154 else if (s.equalsIgnoreCase("invalidDBEndsWith") ) { 155 invalidDBEnd = dbProperties.getProperty(s).split(" "); 156 } 157 else if (s.equalsIgnoreCase("invalidDBContains") ) { 158 invalidDBContains = dbProperties.getProperty(s).split(" "); 159 } 160 else if (s.equalsIgnoreCase("invalidDBMatches") ) { 161 invalidDBMatches = dbProperties.getProperty(s).split(" "); 162 } 163 164 else if (s.equalsIgnoreCase("datasource") ) { 165 datasourceStyle = dbProperties.getProperty(s).trim(); 166 } 167 else if (s.equalsIgnoreCase("url")) { 168 url = dbProperties.getProperty(s).trim(); 169 } 170 else if (s.equalsIgnoreCase("driver")) { 171 driver = dbProperties.getProperty(s).trim(); 172 } 173 else if (s.equalsIgnoreCase("username") ) { 174 username = dbProperties.getProperty(s).trim(); 175 } 176 else if (s.equalsIgnoreCase("password") ) { 177 password = dbProperties.getProperty(s).trim(); 178 } 179 //parse the DB renames into a HashSet 180 else if (s.startsWith("rename|") ) { 181 String value = dbProperties.getProperty(s).trim(); 182 this.renamedDBs.put(s.replace("rename|", ""), value); 183 } 184 } 185 186 187 if (LOGGER.isDebugEnabled()) { 188 if (this.invalidDBContains != null) { 189 LOGGER.debug("skipping databases containing String: " + Arrays.toString(this.invalidDBContains)); 190 } 191 if (this.invalidDBMatches != null) { 192 LOGGER.debug("skipping databases matching String: " + Arrays.toString(this.invalidDBMatches)); 193 } 194 if (this.invalidDBStart != null) { 195 LOGGER.debug("skipping databases beginning with String: " + Arrays.toString(this.invalidDBStart)); 196 } 197 if (this.invalidDBEnd != null) { 198 LOGGER.debug("skipping databases ending with String: " + Arrays.toString(this.invalidDBEnd)); 199 } 200 201 LOGGER.debug("datasource: " + datasourceStyle); 202 LOGGER.debug("driver: " + driver); 203 LOGGER.debug("url: " + url); 204 LOGGER.debug("username: " + username); 205 LOGGER.debug("password: " + password); 206 for (Map.Entry<String, String> entry : this.renamedDBs.entrySet()) { 207 LOGGER.debug("renaming database: "+entry.getKey()+" : "+entry.getValue()); 208 } 209 } 210 } 211 212 public Boolean isDBNameValid(String s) { 213 if (this.configuredDatasource.equals(DataSource.ENSEMBLBACTERIA) && 214 !(s.contains("bacteria") || s.contains("collection") || s.contains("pan_homology")) ) { 215 return false; 216 } 217 if (!this.configuredDatasource.equals(DataSource.ENSEMBLBACTERIA) && 218 (s.contains("bacteria") || s.contains("collection"))) { 219 return false; 220 } 221 if (this.invalidDBContains != null && this.invalidDBContains.length > 0) { 222 for (int i = 0; i < this.invalidDBContains.length; i++) { 223 if (s.contains(this.invalidDBContains[i])) { 224 return false; 225 } 226 } 227 } 228 if (this.invalidDBStart != null && this.invalidDBStart.length > 0) { 229 for (int i = 0; i < this.invalidDBStart.length; i++) { 230 if (s.startsWith(this.invalidDBStart[i])) { 231 return false; 232 } 233 } 234 } 235 if (this.invalidDBEnd != null && this.invalidDBEnd.length > 0) { 236 for (int i = 0; i < this.invalidDBEnd.length; i++) { 237 if (s.endsWith(this.invalidDBEnd[i])) { 238 return false; 239 } 240 } 241 } 242 if (this.invalidDBMatches != null && this.invalidDBMatches.length > 0) { 243 for (int i = 0; i < this.invalidDBMatches.length; i++) { 244 if (s.equalsIgnoreCase(this.invalidDBMatches[i])) { 245 return false; 246 } 247 } 248 } 249 return true; 250 } 251 252 public String getDatasourceStyle() { 253 return datasourceStyle; 254 } 255 256 public String report() { 257 String out = newline + "DB CONNECTION REPORT" + newline +"--------------------"+newline+newline; 258 259 out = out + "Datasource Configured: " + configuredDatasource.toString() + newline; 260 out = out + "Datasource style: " + datasourceStyle + newline; 261 out = out + "Datasource URL: " + url + newline; 262 out = out + "Datasource user: " + username + newline; 263 264 if (this.invalidDBContains != null) { 265 out = out.concat("Skipping databases containing String: " + Arrays.toString(this.invalidDBContains)+newline); 266 } 267 if (this.invalidDBMatches != null) { 268 out = out.concat("Skipping databases matching String: " + Arrays.toString(this.invalidDBMatches)+newline); 269 } 270 if (this.invalidDBStart != null) { 271 out = out.concat("Skipping databases beginning with String: " + Arrays.toString(this.invalidDBStart)+newline); 272 } 273 if (this.invalidDBEnd != null) { 274 out = out.concat("Skipping databases ending with String: " + Arrays.toString(this.invalidDBEnd)+newline); 275 } 276 277 out = out+newline; 278 return out; 279 } 280 281 public String testConnection() { 282 String warning = ""; 283 284 try { 285 Class.forName("com.mysql.jdbc.Driver"); 286// if (LOGGER.isDebugEnabled()) { 287// PrintWriter w = new PrintWriter(System.err); 288// DriverManager.setLogWriter(w); 289// } 290 Connection conn = DriverManager.getConnection(url, username, password); 291 292 SQLWarning warn = conn.getWarnings(); 293 294 if (warn != null) { 295 warning = "WARNING:\n"; 296 } 297 298 while (warn != null) { 299 warning += "SQLState: " + warn.getSQLState() + "\n"; 300 warning += "Message: " + warn.getMessage() + "\n"; 301 warning += "Vendor: " + warn.getErrorCode() + "\n"; 302 warn = warn.getNextWarning(); 303 } 304 305 306 conn.close(); 307 308 } catch (ClassNotFoundException e) { 309 warning += "ERROR: Can't load driver\n" + e; 310 } catch (SQLException e) { 311 warning += "ERROR: Database access failed\n" + e; 312 } 313 if (warning.isEmpty()) { 314 return "OK"; 315 } else { 316 return warning; 317 } 318 319 } 320 321 public boolean isConnectionOK() { 322 323 try { 324 Class.forName("com.mysql.jdbc.Driver"); 325// if (LOGGER.isDebugEnabled()) { 326// PrintWriter w = new PrintWriter(System.err); 327// DriverManager.setLogWriter(w); 328// } 329 Connection conn = DriverManager.getConnection(url, username, password); 330 331 SQLWarning warn = conn.getWarnings(); 332 333 if (warn != null) { 334 return false; 335 } 336 conn.close(); 337 } catch (Exception e) { 338 return false; 339 } 340 341 return true; 342 343 } 344 345 public HashMap<String, String> getRenamedDBs() { 346 return renamedDBs; 347 } 348}