1 package net.myvietnam.mvncore.configuration; 2 3 56 57 import java.io.Serializable ; 58 import java.util.Iterator ; 59 import java.util.NoSuchElementException ; 60 61 76 public class ConfigurationKey implements Serializable 77 { 78 79 private static final String ATTRIBUTE_START = "[@"; 80 81 82 private static final String ATTRIBUTE_END = "]"; 83 84 85 private static final char PROPERTY_DELIMITER = '.'; 86 87 88 private static final char INDEX_START = '('; 89 90 91 private static final char INDEX_END = ')'; 92 93 94 private static final int INITIAL_SIZE = 32; 95 96 97 private StringBuffer keyBuffer; 98 99 102 public ConfigurationKey() 103 { 104 keyBuffer = new StringBuffer (INITIAL_SIZE); 105 } 106 107 112 public ConfigurationKey(String key) 113 { 114 keyBuffer = new StringBuffer (key); 115 removeTrailingDelimiter(); 116 } 117 118 124 public ConfigurationKey append(String property) 125 { 126 if(keyBuffer.length() > 0 && !hasDelimiter() 127 && !isAttributeKey(property)) 128 { 129 keyBuffer.append(PROPERTY_DELIMITER); 130 } 131 132 keyBuffer.append(property); 133 removeTrailingDelimiter(); 134 return this; 135 } 136 137 142 public ConfigurationKey appendIndex(int index) 143 { 144 keyBuffer.append(INDEX_START).append(index); 145 keyBuffer.append(INDEX_END); 146 return this; 147 } 148 149 154 public ConfigurationKey appendAttribute(String attr) 155 { 156 keyBuffer.append(constructAttributeKey(attr)); 157 return this; 158 } 159 160 167 public static boolean isAttributeKey(String key) 168 { 169 return key != null 170 && key.startsWith(ATTRIBUTE_START) 171 && key.endsWith(ATTRIBUTE_END); 172 } 173 174 180 public static String constructAttributeKey(String key) 181 { 182 StringBuffer buf = new StringBuffer (); 183 buf.append(ATTRIBUTE_START).append(key).append(ATTRIBUTE_END); 184 return buf.toString(); 185 } 186 187 194 public static String attributeName(String key) 195 { 196 return (isAttributeKey(key)) ? 197 removeAttributeMarkers(key) : key; 198 } 199 200 205 private static String removeAttributeMarkers(String key) 206 { 207 return key.substring(ATTRIBUTE_START.length(), 208 key.length() - ATTRIBUTE_END.length()); 209 } 210 211 216 private boolean hasDelimiter() 217 { 218 return keyBuffer.length() > 0 219 && keyBuffer.charAt(keyBuffer.length()-1) == PROPERTY_DELIMITER; 220 } 221 222 225 private void removeTrailingDelimiter() 226 { 227 while(hasDelimiter()) 228 { 229 keyBuffer.deleteCharAt(keyBuffer.length()-1); 230 } 231 } 232 233 238 public String toString() 239 { 240 return keyBuffer.toString(); 241 } 242 243 248 public KeyIterator iterator() 249 { 250 return new KeyIterator(); 251 } 252 253 257 public int length() 258 { 259 return keyBuffer.length(); 260 } 261 262 269 public void setLength(int len) 270 { 271 keyBuffer.setLength(len); 272 } 273 274 280 public boolean equals(Object c) 281 { 282 if(c == null) 283 { 284 return false; 285 } 286 287 return keyBuffer.toString().equals(c.toString()); 288 } 289 290 294 public int hashCode() 295 { 296 return keyBuffer.hashCode(); 297 } 298 299 305 public ConfigurationKey commonKey(ConfigurationKey other) 306 { 307 if(other == null) 308 { 309 throw new IllegalArgumentException ("Other key must no be null!"); 310 } 311 312 ConfigurationKey result = new ConfigurationKey(); 313 KeyIterator it1 = iterator(); 314 KeyIterator it2 = other.iterator(); 315 316 while(it1.hasNext() && it2.hasNext() 317 && partsEqual(it1, it2)) 318 { 319 if(it1.isAttribute()) 320 { 321 result.appendAttribute(it1.currentKey()); 322 } 323 else 324 { 325 result.append(it1.currentKey()); 326 if(it1.hasIndex) 327 { 328 result.appendIndex(it1.getIndex()); 329 } 330 } 331 } 332 333 return result; 334 } 335 336 345 public ConfigurationKey differenceKey(ConfigurationKey other) 346 { 347 ConfigurationKey common = commonKey(other); 348 ConfigurationKey result = new ConfigurationKey(); 349 350 if(common.length() < other.length()) 351 { 352 String k = other.toString().substring(common.length()); 353 int i = 0; 355 while(i < k.length() && k.charAt(i) == PROPERTY_DELIMITER) 356 { 357 i++; 358 } 359 360 if(i < k.length()) 361 { 362 result.append(k.substring(i)); 363 } 364 } 365 366 return result; 367 } 368 369 375 private static boolean partsEqual(KeyIterator it1, KeyIterator it2) 376 { 377 return it1.nextKey().equals(it2.nextKey()) 378 && it1.getIndex() == it2.getIndex() 379 && it1.isAttribute() == it2.isAttribute(); 380 } 381 382 389 public class KeyIterator implements Iterator , Cloneable 390 { 391 392 private String current; 393 394 395 private int startIndex; 396 397 398 private int endIndex; 399 400 401 private int indexValue; 402 403 404 private boolean hasIndex; 405 406 407 private boolean attribute; 408 409 412 private void findNextIndices() 413 { 414 startIndex = endIndex; 415 while (startIndex < keyBuffer.length() 417 && keyBuffer.charAt(startIndex) == PROPERTY_DELIMITER) 418 { 419 startIndex++; 420 } 421 422 if (startIndex >= keyBuffer.length()) 424 { 425 endIndex = keyBuffer.length(); 426 startIndex = endIndex - 1; 427 } 428 else 429 { 430 String s = keyBuffer.toString(); endIndex = s.indexOf(PROPERTY_DELIMITER, startIndex); 432 if (endIndex < 0) 433 { 434 endIndex = s.indexOf(ATTRIBUTE_START, startIndex); 435 if (endIndex < 0 || endIndex == startIndex) 436 { 437 endIndex = keyBuffer.length(); 438 } 439 } 440 } 441 } 442 443 448 public String nextKey() 449 { 450 return nextKey(false); 451 } 452 453 462 public String nextKey(boolean decorated) 463 { 464 if(!hasNext()) 465 { 466 throw new NoSuchElementException ("No more key parts!"); 467 } 468 469 hasIndex = false; 470 indexValue = -1; 471 findNextIndices(); 472 String key = keyBuffer.substring(startIndex, endIndex).toString(); 473 474 attribute = checkAttribute(key); 475 if(!attribute) 476 { 477 hasIndex = checkIndex(key); 478 if(!hasIndex) 479 { 480 current = key; 481 } 482 } 483 484 return currentKey(decorated); 485 } 486 487 493 private boolean checkAttribute(String key) 494 { 495 if(isAttributeKey(key)) 496 { 497 current = removeAttributeMarkers(key); 498 return true; 499 } 500 else 501 { 502 return false; 503 } 504 } 505 506 512 private boolean checkIndex(String key) 513 { 514 boolean result = false; 515 516 int idx = key.indexOf(INDEX_START); 517 if(idx > 0) 518 { 519 int endidx = key.indexOf(INDEX_END, idx); 520 521 if(endidx > idx + 1) 522 { 523 indexValue = Integer.parseInt(key.substring(idx+1, endidx)); 524 current = key.substring(0, idx); 525 result = true; 526 } 527 } 528 529 return result; 530 } 531 532 536 public boolean hasNext() 537 { 538 return endIndex < keyBuffer.length(); 539 } 540 541 545 public Object next() 546 { 547 return nextKey(); 548 } 549 550 554 public void remove() 555 { 556 throw new UnsupportedOperationException ("Remove not supported!"); 557 } 558 559 565 public String currentKey() 566 { 567 return currentKey(false); 568 } 569 570 579 public String currentKey(boolean decorated) 580 { 581 return (decorated && isAttribute()) ? 582 constructAttributeKey(current) : current; 583 } 584 585 590 public boolean isAttribute() 591 { 592 return attribute; 593 } 594 595 601 public int getIndex() 602 { 603 return indexValue; 604 } 605 606 611 public boolean hasIndex() 612 { 613 return hasIndex; 614 } 615 616 620 protected Object clone() 621 { 622 try 623 { 624 return super.clone(); 625 } 626 catch(CloneNotSupportedException cex) 627 { 628 return null; 630 } 631 } 632 633 } 634 } 635 | Popular Tags |