1 21 22 package org.continuent.sequoia.driver; 23 24 import java.sql.SQLException ; 25 import java.util.HashMap ; 26 import java.util.Properties ; 27 import java.util.StringTokenizer ; 28 29 import org.continuent.sequoia.driver.connectpolicy.AbstractControllerConnectPolicy; 30 import org.continuent.sequoia.driver.connectpolicy.OrderedConnectPolicy; 31 import org.continuent.sequoia.driver.connectpolicy.PreferredListConnectPolicy; 32 import org.continuent.sequoia.driver.connectpolicy.RandomConnectPolicy; 33 import org.continuent.sequoia.driver.connectpolicy.RoundRobinConnectPolicy; 34 import org.continuent.sequoia.driver.connectpolicy.SingleConnectPolicy; 35 36 45 public class SequoiaUrl 46 { 47 private Driver driver; 48 private String url; 49 private String databaseName; 50 private ControllerInfo[] controllerList; 51 52 private final HashMap parameters; 53 private AbstractControllerConnectPolicy controllerConnectPolicy; 54 55 58 public static final int DEFAULT_CONTROLLER_PORT = 25322; 59 60 private int debugLevel; 62 63 public static final int DEBUG_LEVEL_DEBUG = 2; 64 65 public static final int DEBUG_LEVEL_INFO = 1; 66 67 public static final int DEBUG_LEVEL_OFF = 0; 68 69 78 public SequoiaUrl(Driver driver, String url, Properties props) 79 throws SQLException  80 { 81 this.driver = driver; 82 this.url = url; 83 84 parameters = new HashMap (); 85 parameters.putAll(props); 87 parseUrl(); 90 91 String debugProperty = (String ) parameters.get(Driver.DEBUG_PROPERTY); 92 debugLevel = DEBUG_LEVEL_OFF; 93 if (debugProperty != null) 94 { 95 if ("debug".equals(debugProperty)) 96 debugLevel = DEBUG_LEVEL_DEBUG; 97 else if ("info".equals(debugProperty)) 98 debugLevel = DEBUG_LEVEL_INFO; 99 } 100 controllerConnectPolicy = createConnectionPolicy(); 101 } 102 103 108 public int getDebugLevel() 109 { 110 return debugLevel; 111 } 112 113 118 public boolean isDebugEnabled() 119 { 120 return debugLevel == DEBUG_LEVEL_DEBUG; 121 } 122 123 128 public boolean isInfoEnabled() 129 { 130 return debugLevel >= DEBUG_LEVEL_INFO; 131 } 132 133 138 public AbstractControllerConnectPolicy getControllerConnectPolicy() 139 { 140 return controllerConnectPolicy; 141 } 142 143 148 public ControllerInfo[] getControllerList() 149 { 150 return controllerList; 151 } 152 153 158 public String getDatabaseName() 159 { 160 return databaseName; 161 } 162 163 172 public HashMap getParameters() 173 { 174 return parameters; 175 } 176 177 182 public String getUrl() 183 { 184 return url; 185 } 186 187 192 public void setUrl(String url) 193 { 194 this.url = url; 195 } 196 197 201 208 private AbstractControllerConnectPolicy createConnectionPolicy() 209 { 210 if (controllerList.length == 1) 211 return new SingleConnectPolicy(controllerList, debugLevel); 212 213 String policy = (String ) parameters 214 .get(Driver.PREFERRED_CONTROLLER_PROPERTY); 215 String retryInterval = (String ) parameters 216 .get(Driver.RETRY_INTERVAL_IN_MS_PROPERTY); 217 long retryIntervalInMs; 218 219 if (retryInterval == null) 221 retryIntervalInMs = Driver.DEFAULT_RETRY_INTERVAL_IN_MS; 222 else 223 retryIntervalInMs = Long.parseLong(retryInterval); 224 225 if ((policy == null) || policy.equals("roundRobin")) 231 return new RoundRobinConnectPolicy(controllerList, retryIntervalInMs, 232 debugLevel); 233 234 if (policy.equals("ordered")) 238 return new OrderedConnectPolicy(controllerList, retryIntervalInMs, 239 debugLevel); 240 241 if (policy.equals("random")) 244 return new RandomConnectPolicy(controllerList, retryIntervalInMs, 245 debugLevel); 246 247 return new PreferredListConnectPolicy(controllerList, retryIntervalInMs, 250 policy, debugLevel); 251 } 252 253 259 private void parseUrl() throws SQLException  260 { 261 if (url == null) 263 { 264 throw new IllegalArgumentException ( 265 "Illegal null URL in parseURL(String) method"); 266 } 267 268 if (!url.toLowerCase().startsWith(driver.sequoiaUrlHeader)) 269 throw new SQLException ("Malformed header from URL '" + url 270 + "' (expected '" + driver.sequoiaUrlHeader + "')"); 271 else 272 { 273 int nextSlash = url.indexOf('/', driver.sequoiaUrlHeaderLength); 275 if (nextSlash == -1) 276 throw new SQLException ("Malformed URL '" + url + "' (expected '" 278 + driver.sequoiaUrlHeader + "<hostname>/<database>')"); 279 280 int questionMark = url.indexOf('?', nextSlash); 282 questionMark = (questionMark == -1) 283 ? url.indexOf(';', nextSlash) 284 : questionMark; 285 286 String controllerURLs = url.substring(driver.sequoiaUrlHeaderLength, 287 nextSlash); 288 StringTokenizer controllers = new StringTokenizer (controllerURLs, ",", 291 false); 292 int tokenNumber = controllers.countTokens(); 293 if (tokenNumber == 0) 294 { 295 throw new SQLException ("Empty controller name in '" + controllerURLs 296 + "' in URL '" + url + "'"); 297 } 298 controllerList = new ControllerInfo[tokenNumber]; 299 int i = 0; 300 String token; 301 while (controllers.hasMoreTokens()) 304 { 305 token = controllers.nextToken().trim(); 306 if (token.equals("")) { 308 throw new SQLException ("Empty controller name in '" + controllerURLs 309 + "' in URL '" + url + "'"); 310 } 311 controllerList[i] = parseController(token); 312 i++; 313 } 314 315 databaseName = (questionMark == -1) ? url.substring(nextSlash + 1, url 317 .length()) : url.substring(nextSlash + 1, questionMark); 318 Character c = validDatabaseName(databaseName); 319 if (c != null) 320 throw new SQLException ( 321 "Unable to validate database name (unacceptable character '" + c 322 + "' in database '" + databaseName + "' from URL '" + url 323 + "')"); 324 325 parameters.putAll(parseUrlParams(url)); 327 } 328 } 329 330 338 private HashMap parseUrlParams(String urlString) throws SQLException  339 { 340 HashMap props = parseUrlParams(urlString, '?', "&", "="); 341 if (props == null) 342 props = parseUrlParams(urlString, ';', ";", "="); 343 if (props == null) 344 props = new HashMap (); 345 346 return props; 347 } 348 349 361 private HashMap parseUrlParams(String urlString, char beginMarker, 362 String parameterSeparator, String equal) throws SQLException  363 { 364 int questionMark = urlString.indexOf(beginMarker); 365 if (questionMark == -1) 366 return null; 367 else 368 { 369 HashMap props = new HashMap (); 370 String params = urlString.substring(questionMark + 1); 371 StringTokenizer st1 = new StringTokenizer (params, parameterSeparator); 372 while (st1.hasMoreTokens()) 373 { 374 String param = st1.nextToken(); 375 StringTokenizer st2 = new StringTokenizer (param, equal); 376 if (st2.hasMoreTokens()) 377 { 378 try 379 { 380 String paramName = st2.nextToken(); 381 String paramValue = (st2.hasMoreTokens()) ? st2.nextToken() : ""; 382 props.put(paramName, paramValue); 383 } 384 catch (Exception e) { 386 throw new SQLException ("Invalid parameter in URL: " + urlString); 387 } 388 } 389 } 390 return props; 391 } 392 } 393 394 402 public static ControllerInfo parseController(String controller) 403 throws SQLException  404 { 405 ControllerInfo controllerInfo = new ControllerInfo(); 406 407 StringTokenizer controllerURL = new StringTokenizer (controller, ":", true); 409 410 controllerInfo.setHostname(controllerURL.nextToken()); 412 Character c = validHostname(controllerInfo.getHostname()); 413 if (c != null) 414 throw new SQLException ( 415 "Unable to validate hostname (unacceptable character '" + c 416 + "' in hostname '" + controllerInfo.getHostname() 417 + "' from the URL part '" + controller + "')"); 418 419 if (!controllerURL.hasMoreTokens()) 420 controllerInfo.setPort(DEFAULT_CONTROLLER_PORT); 421 else 422 { 423 controllerURL.nextToken(); if (!controllerURL.hasMoreTokens()) 425 controllerInfo.setPort(DEFAULT_CONTROLLER_PORT); 426 else 427 { String port = controllerURL.nextToken(); 429 if (controllerURL.hasMoreTokens()) 430 throw new SQLException ( 431 "Invalid controller definition with more than one semicolon in URL part '" 432 + controller + "'"); 433 434 try 436 { 437 controllerInfo.setPort(Integer.parseInt(port)); 438 } 439 catch (NumberFormatException ne) 440 { 441 throw new SQLException ( 442 "Unable to validate port number (unacceptable port number '" 443 + port + "' in this URL part '" + controller + "')"); 444 } 445 } 446 } 447 return controllerInfo; 448 } 449 450 459 private static Character validHostname(String hostname) 460 { 461 char[] name = hostname.toCharArray(); 462 int size = hostname.length(); 463 char c; 464 char lastChar = ' '; 466 467 for (int i = 0; i < size; i++) 468 { 469 c = name[i]; 470 471 if (c == '.' || c == '-') 472 { 473 if (lastChar == '.' || lastChar == '-' || (i == size - 1) || (i == 0)) 474 { 475 return new Character (c); 478 } 479 } 480 else 481 { 482 if (((c < '0') || (c > 'z') || ((c > '9') && (c < 'A')) 483 || ((c > 'Z') && (c < '_')) || (c == '`'))) 484 { 485 return new Character (c); 486 } 487 } 488 lastChar = c; 489 } 490 return null; 491 } 492 493 502 private static Character validDatabaseName(String databaseName) 503 { 504 char[] name = databaseName.toCharArray(); 505 int size = databaseName.length(); 506 char c; 507 508 for (int i = 0; i < size; i++) 509 { 510 c = name[i]; 511 if ((c < '-') || (c > 'z') || (c == '/') || (c == '.') || (c == '`') 512 || ((c > '9') && (c < 'A')) || ((c > 'Z') && (c < '_'))) 513 return new Character (c); 514 } 515 return null; 516 } 517 518 521 public boolean equals(Object other) 522 { 523 if (!(other instanceof SequoiaUrl)) 524 return false; 525 SequoiaUrl castedOther = (SequoiaUrl) other; 526 return (url.equals(castedOther.url) && parameters 527 .equals(castedOther.parameters)); 528 } 529 530 533 public int hashCode() 534 { 535 return toString().hashCode(); 536 } 537 538 541 public String toString() 542 { 543 return (url + parameters); 544 } 545 } 546
| Popular Tags
|