1 16 17 package org.apache.commons.configuration; 18 19 import java.io.Serializable ; 20 import java.util.Iterator ; 21 import java.util.NoSuchElementException ; 22 23 40 public class ConfigurationKey implements Serializable 41 { 42 43 public static final char PROPERTY_DELIMITER = '.'; 44 45 46 private static final String ATTRIBUTE_START = "[@"; 47 48 49 private static final String ATTRIBUTE_END = "]"; 50 51 52 private static final char INDEX_START = '('; 53 54 55 private static final char INDEX_END = ')'; 56 57 58 private static final int INITIAL_SIZE = 32; 59 60 61 private StringBuffer keyBuffer; 62 63 66 public ConfigurationKey() 67 { 68 keyBuffer = new StringBuffer (INITIAL_SIZE); 69 } 70 71 77 public ConfigurationKey(String key) 78 { 79 keyBuffer = new StringBuffer (key); 80 removeTrailingDelimiter(); 81 } 82 83 90 public ConfigurationKey append(String property) 91 { 92 if (keyBuffer.length() > 0 && !hasDelimiter() && !isAttributeKey(property)) 93 { 94 keyBuffer.append(PROPERTY_DELIMITER); 95 } 96 97 keyBuffer.append(property); 98 removeTrailingDelimiter(); 99 return this; 100 } 101 102 108 public ConfigurationKey appendIndex(int index) 109 { 110 keyBuffer.append(INDEX_START).append(index); 111 keyBuffer.append(INDEX_END); 112 return this; 113 } 114 115 121 public ConfigurationKey appendAttribute(String attr) 122 { 123 keyBuffer.append(constructAttributeKey(attr)); 124 return this; 125 } 126 127 132 public boolean isAttributeKey() 133 { 134 return isAttributeKey(keyBuffer.toString()); 135 } 136 137 145 public static boolean isAttributeKey(String key) 146 { 147 return key != null 148 && key.startsWith(ATTRIBUTE_START) 149 && key.endsWith(ATTRIBUTE_END); 150 } 151 152 159 public static String constructAttributeKey(String key) 160 { 161 StringBuffer buf = new StringBuffer (); 162 buf.append(ATTRIBUTE_START).append(key).append(ATTRIBUTE_END); 163 return buf.toString(); 164 } 165 166 174 public static String attributeName(String key) 175 { 176 return isAttributeKey(key) ? removeAttributeMarkers(key) : key; 177 } 178 179 185 static String removeAttributeMarkers(String key) 186 { 187 return key.substring(ATTRIBUTE_START.length(), key.length() - ATTRIBUTE_END.length()); 188 } 189 190 196 private boolean hasDelimiter() 197 { 198 return keyBuffer.length() > 0 199 && keyBuffer.charAt(keyBuffer.length() - 1) == PROPERTY_DELIMITER; 200 } 201 202 205 private void removeTrailingDelimiter() 206 { 207 while (hasDelimiter()) 208 { 209 keyBuffer.deleteCharAt(keyBuffer.length() - 1); 210 } 211 } 212 213 219 public String toString() 220 { 221 return keyBuffer.toString(); 222 } 223 224 230 public KeyIterator iterator() 231 { 232 return new KeyIterator(); 233 } 234 235 240 public int length() 241 { 242 return keyBuffer.length(); 243 } 244 245 253 public void setLength(int len) 254 { 255 keyBuffer.setLength(len); 256 } 257 258 265 public boolean equals(Object c) 266 { 267 if (c == null) 268 { 269 return false; 270 } 271 272 return keyBuffer.toString().equals(c.toString()); 273 } 274 275 280 public int hashCode() 281 { 282 return keyBuffer.hashCode(); 283 } 284 285 292 public ConfigurationKey commonKey(ConfigurationKey other) 293 { 294 if (other == null) 295 { 296 throw new IllegalArgumentException ("Other key must no be null!"); 297 } 298 299 ConfigurationKey result = new ConfigurationKey(); 300 KeyIterator it1 = iterator(); 301 KeyIterator it2 = other.iterator(); 302 303 while (it1.hasNext() && it2.hasNext() && partsEqual(it1, it2)) 304 { 305 if (it1.isAttribute()) 306 { 307 result.appendAttribute(it1.currentKey()); 308 } 309 else 310 { 311 result.append(it1.currentKey()); 312 if (it1.hasIndex) 313 { 314 result.appendIndex(it1.getIndex()); 315 } 316 } 317 } 318 319 return result; 320 } 321 322 332 public ConfigurationKey differenceKey(ConfigurationKey other) 333 { 334 ConfigurationKey common = commonKey(other); 335 ConfigurationKey result = new ConfigurationKey(); 336 337 if (common.length() < other.length()) 338 { 339 String k = other.toString().substring(common.length()); 340 int i = 0; 342 while (i < k.length() && k.charAt(i) == PROPERTY_DELIMITER) 343 { 344 i++; 345 } 346 347 if (i < k.length()) 348 { 349 result.append(k.substring(i)); 350 } 351 } 352 353 return result; 354 } 355 356 363 private static boolean partsEqual(KeyIterator it1, KeyIterator it2) 364 { 365 return it1.nextKey().equals(it2.nextKey()) 366 && it1.getIndex() == it2.getIndex() 367 && it1.isAttribute() == it2.isAttribute(); 368 } 369 370 375 public class KeyIterator implements Iterator , Cloneable 376 { 377 378 private String current; 379 380 381 private int startIndex; 382 383 384 private int endIndex; 385 386 387 private int indexValue; 388 389 390 private boolean hasIndex; 391 392 393 private boolean attribute; 394 395 398 private void findNextIndices() 399 { 400 startIndex = endIndex; 401 while (startIndex < keyBuffer.length() 403 && keyBuffer.charAt(startIndex) == PROPERTY_DELIMITER) 404 { 405 startIndex++; 406 } 407 408 if (startIndex >= keyBuffer.length()) 410 { 411 endIndex = keyBuffer.length(); 412 startIndex = endIndex - 1; 413 } 414 else 415 { 416 String s = keyBuffer.toString(); endIndex = s.indexOf(PROPERTY_DELIMITER, startIndex); 418 if (endIndex < 0) 419 { 420 endIndex = s.indexOf(ATTRIBUTE_START, startIndex); 421 if (endIndex < 0 || endIndex == startIndex) 422 { 423 endIndex = keyBuffer.length(); 424 } 425 } 426 } 427 } 428 429 435 public String nextKey() 436 { 437 return nextKey(false); 438 } 439 440 450 public String nextKey(boolean decorated) 451 { 452 if (!hasNext()) 453 { 454 throw new NoSuchElementException ("No more key parts!"); 455 } 456 457 hasIndex = false; 458 indexValue = -1; 459 findNextIndices(); 460 String key = keyBuffer.substring(startIndex, endIndex); 461 462 attribute = checkAttribute(key); 463 if (!attribute) 464 { 465 hasIndex = checkIndex(key); 466 if (!hasIndex) 467 { 468 current = key; 469 } 470 } 471 472 return currentKey(decorated); 473 } 474 475 482 private boolean checkAttribute(String key) 483 { 484 if (isAttributeKey(key)) 485 { 486 current = removeAttributeMarkers(key); 487 return true; 488 } 489 else 490 { 491 return false; 492 } 493 } 494 495 502 private boolean checkIndex(String key) 503 { 504 boolean result = false; 505 506 int idx = key.indexOf(INDEX_START); 507 if (idx > 0) 508 { 509 int endidx = key.indexOf(INDEX_END, idx); 510 511 if (endidx > idx + 1) 512 { 513 indexValue = Integer.parseInt(key.substring(idx + 1, endidx)); 514 current = key.substring(0, idx); 515 result = true; 516 } 517 } 518 519 return result; 520 } 521 522 527 public boolean hasNext() 528 { 529 return endIndex < keyBuffer.length(); 530 } 531 532 537 public Object next() 538 { 539 return nextKey(); 540 } 541 542 546 public void remove() 547 { 548 throw new UnsupportedOperationException ("Remove not supported!"); 549 } 550 551 558 public String currentKey() 559 { 560 return currentKey(false); 561 } 562 563 573 public String currentKey(boolean decorated) 574 { 575 return (decorated && isAttribute()) ? constructAttributeKey(current) : current; 576 } 577 578 584 public boolean isAttribute() 585 { 586 return attribute; 587 } 588 589 596 public int getIndex() 597 { 598 return indexValue; 599 } 600 601 607 public boolean hasIndex() 608 { 609 return hasIndex; 610 } 611 612 617 protected Object clone() 618 { 619 try 620 { 621 return super.clone(); 622 } 623 catch (CloneNotSupportedException cex) 624 { 625 return null; 627 } 628 } 629 } 630 } 631 | Popular Tags |