1 /* DatabaseLocationParser.java 2 * 3 * created: Jun 2013 4 * 5 * This file is part of Artemis 6 * 7 * Copyright (C) 2001 Genome Research Limited 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License 11 * as published by the Free Software Foundation; either version 2 12 * of the License, or (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 22 * 23 */ 24 package uk.ac.sanger.artemis.util; 25 26 import java.net.URI; 27 import java.net.URISyntaxException; 28 import java.util.HashMap; 29 import java.util.Map; 30 import java.util.Set; 31 32 /** 33 * 34 * @author Eric Rasche <rasche.eric@yandex.ru> 35 */ 36 public class DatabaseLocationParser { 37 38 private String host; 39 private String database; 40 private int port = 0; 41 private String db_engine = "postgresql"; 42 private String protocol = "jdbc"; 43 private static org.apache.log4j.Logger logger4j = 44 org.apache.log4j.Logger.getLogger(DatabaseLocationParser.class); 45 /** 46 * Desire use of Protocol in the final URL. i.e., "jdbc:" 47 */ 48 public static final int PROTOCOL = 1; 49 /** 50 * Desire use of scheme in final url. i.e., "postgres://" 51 */ 52 public static final int SCHEME = 2; 53 /** 54 * Desire use of database name in final url. 55 * 56 */ 57 public static final int DATABASE_NAME = 4; 58 /** 59 * Desire listing of query parameters in final url. e.g., 60 * "user=name&ssl=true" 61 */ 62 public static final int QUERY_PARAMS = 8; 63 private Map<String, String> params = new HashMap<String, String>(); 64 65 /** 66 * Empty initializer 67 */ DatabaseLocationParser()68 public DatabaseLocationParser() { 69 } 70 71 /** 72 * Create a new DLP object from a given URL 73 * 74 * @param url 75 */ DatabaseLocationParser(String url)76 public DatabaseLocationParser(String url) { 77 setFromURLString(url); 78 } 79 80 /** 81 * Set the URL internally and parse out important portions. 82 * 83 * @param url 84 */ setFromURLString(String url)85 public void setFromURLString(String url) { 86 logger4j.debug("DLP was called with a URL of [" + url + "]"); 87 try { 88 //"jdbc:postgres://localhost:5432/drupal6?user=drupal6&ssl=true"; 89 90 //If it's prefixed, remove that so URI parsing is correct 91 if (url.startsWith("jdbc:")) { 92 url = url.substring(5); 93 } 94 if (!url.startsWith(db_engine + "://")) { 95 url = db_engine + "://" + url; 96 } 97 98 99 URI db_loc = new URI(url); 100 101 logger4j.debug("URI " + db_loc.toString()); 102 logger4j.debug("Host: " + db_loc.getHost()); 103 logger4j.debug("Port: " + db_loc.getPort()); 104 logger4j.debug("Engine: " + db_loc.getScheme()); 105 logger4j.debug("DB: " + db_loc.getPath()); 106 107 host = db_loc.getHost(); 108 109 database = db_loc.getPath().substring(1); 110 111 port = db_loc.getPort(); 112 113 db_engine = db_loc.getScheme(); 114 115 //Split on '&' and parse each subunit 116 String[] query_params = db_loc.getQuery().split("&"); 117 for (int i = 0; i < query_params.length; i++) { 118 //Split based on the equals sign 119 logger4j.debug("Given a parameter:" + query_params[i]); 120 String[] parts = query_params[i].split("="); 121 122 123 //This will fail for input like user=chad=o&ssl=true 124 //As we'll only grab user=chad 125 // Then again, who has an equals sign in their username 126 if (parts.length > 1) { 127 params.put(parts[0], parts[1]); 128 logger4j.debug("[" + parts[0] + "," + parts[1] + "]"); 129 130 } else { 131 // This might fail strangely, but then again they're providing funky URLs 132 params.put("user", parts[0]); 133 logger4j.debug("[user," + parts[0] + "]"); 134 } 135 } 136 } catch (URISyntaxException ex) { 137 logger4j.warn("Error parsing URL [" + url + "]" + ex); 138 } 139 logger4j.debug("This has a complete_url of [" + getCompleteURL() + "]"); 140 } 141 142 /** 143 * Returns the complete URL 144 * 145 * @return complete url 146 */ getCompleteURL()147 public String getCompleteURL() { 148 return getURLWithFixes(PROTOCOL | SCHEME 149 | DATABASE_NAME | QUERY_PARAMS); 150 } 151 152 /** 153 * Returns the URL as required for a DriverManager.getConnection object 154 * 155 * @return url as required for a SQL connection 156 */ getConnectionString()157 public String getConnectionString() { 158 return getURLWithFixes(PROTOCOL | SCHEME 159 | DATABASE_NAME | QUERY_PARAMS); 160 } 161 162 /** 163 * Returns the unprefixed URL, for classes that automatically prepend 164 * 'jdbc:postgres://'. 165 * 166 * This is important for uk/ac/sanger/artemis/chado/DbSqlConfig.java 167 * 168 * @return unprefixed url with database and query parameters appended. 169 */ getUnprefixedURL()170 public String getUnprefixedURL() { 171 return getURLWithFixes(DATABASE_NAME | QUERY_PARAMS); 172 } 173 174 /** 175 * Returns a URL with a selection of modifications. 176 * 177 * Using a binary OR, one can select which modifications should be applied 178 * to create the final URL. These modifications consist of: 179 * 180 * - PROTOCOL: "jdbc:" - SCHEME: "postgresql://" - DATABASE_NAME: The 181 * supplied database name - QUERY_PARAMS: The supplied query parameters 182 * (user, ssl, etc) 183 * 184 * @param modifications, a binary OR'd selection of PROTOCOL, SCHEME, 185 * DATABASE_NAME, QUERY_PARAMS, all of which are available as public final 186 * static integers from this class 187 * @return String version of a URL, modified according to the rules 188 * supplied. 189 */ getURLWithFixes(int modifications)190 private String getURLWithFixes(int modifications) { 191 try { 192 String scheme = new String(db_engine); 193 String userInfo = null; 194 int db_port = new Integer(port); 195 String db_name = "/" + database; 196 String query_params = ""; 197 String fragment = null; 198 199 String result = ""; 200 if ((modifications & PROTOCOL) == PROTOCOL) { 201 result += protocol + ":"; 202 } 203 if ((modifications & SCHEME) != SCHEME) { 204 scheme = null; 205 } 206 if ((modifications & DATABASE_NAME) != DATABASE_NAME) { 207 db_name = null; 208 } 209 210 // Query Parameters 211 // "user=chado_user&ssl=true" 212 if ((modifications & QUERY_PARAMS) == QUERY_PARAMS) { 213 if (params.size() > 0) { 214 /** 215 * Handling of the query parameters. There are other ways to 216 * do this, but it's probably never going to be more than a 217 * "user" and an "ssl" parameter, which means that in the 218 * grand scheme of things, joining a couple strings together 219 * isn't a big issue 220 */ 221 Set<String> keys = params.keySet(); 222 java.util.Iterator<String> it = keys.iterator(); 223 while (it.hasNext()) { 224 String key = it.next(); 225 query_params += key + "=" + params.get(key) + "&"; 226 } 227 query_params = query_params.substring(0, query_params.length() - 1); 228 } 229 } 230 URI uri_result = new URI(scheme, userInfo, host, db_port, db_name, query_params, fragment); 231 logger4j.debug("Pre-final URL: " + uri_result.toString()); 232 233 result = result + uri_result.toString(); 234 //Bugfix. Even if SCHEME is null, // is still prepended. so we remove 235 if ((modifications & SCHEME) != SCHEME && (modifications & PROTOCOL) != PROTOCOL) { 236 result = result.substring(2); 237 } 238 return result; 239 } catch (URISyntaxException ex) { 240 logger4j.error("Could not construct URL. This will likely cause an " 241 + "SQL connection failure. "); 242 } 243 return null; 244 } 245 246 /** 247 * Checks whether SSL is enabled 248 * 249 * @return true if SSL is enabled 250 */ isSSLEnabled()251 public boolean isSSLEnabled() { 252 if (params.containsKey("ssl")) { 253 return params.get("ssl").equals("true"); 254 } else { 255 return false; 256 } 257 } 258 259 /** 260 * Returns the hostname 261 * 262 * @return the hostname 263 */ getHost()264 public String getHost() { 265 return host; 266 } 267 268 /** 269 * Returns the database 270 * 271 * @return the database name 272 */ getDatabase()273 public String getDatabase() { 274 return database; 275 } 276 277 /** 278 * Returns the port number 279 * 280 * @return port number 281 */ getPort()282 public int getPort() { 283 return port; 284 } 285 286 /** 287 * Returns the username of the user connecting to the database 288 * 289 * @return username 290 */ getUsername()291 public String getUsername() { 292 if (params.containsKey("user")) { 293 return params.get("user"); 294 } else { 295 return "chado"; //That's the default u/n afaik 296 } 297 } 298 299 /** 300 * Returns the database engine 301 * 302 * @return database engine (usu. postgresql) 303 */ getDBEngine()304 public String getDBEngine() { 305 return db_engine; 306 } 307 308 /** 309 * Sets the hostname 310 * 311 * @param hostname 312 */ setHost(String hostname)313 public void setHost(String hostname) { 314 host = hostname.trim(); 315 } 316 317 /** 318 * Sets the database name 319 * 320 * @param new_db_name 321 */ setDatabase(String new_db_name)322 public void setDatabase(String new_db_name) { 323 database = new_db_name.trim(); 324 } 325 326 /** 327 * Sets the port number 328 * 329 * @param new_port_number 330 */ setPort(String new_port_number)331 public void setPort(String new_port_number) { 332 port = Integer.parseInt(new_port_number.trim()); 333 } 334 335 /** 336 * Sets the port number 337 * 338 * @param new_port_number 339 */ setPort(int new_port_number)340 public void setPort(int new_port_number) { 341 port = new_port_number; 342 } 343 344 /** 345 * Sets the username to connect with 346 * 347 * @param new_username 348 */ setUsername(String new_username)349 public void setUsername(String new_username) { 350 params.put("user", new_username.trim()); 351 } 352 353 /** 354 * Enables or disables SSL in connection URL 355 * 356 * @param is_enabled 357 */ setSSL(boolean is_enabled)358 public void setSSL(boolean is_enabled) { 359 if (is_enabled) { 360 params.put("ssl", "true"); 361 } else { 362 params.remove("ssl"); 363 } 364 } 365 366 /** 367 * Sets the Database Engine 368 * 369 * @param new_db_engine 370 */ setDBEngine(String new_db_engine)371 public void setDBEngine(String new_db_engine) { 372 db_engine = new_db_engine.trim(); 373 } 374 } 375