1 package net.suberic.util; 2 import java.util.*; 3 import java.io.*; 4 5 16 17 public class VariableBundle extends Object { 18 private Properties properties; 19 private Properties writableProperties; 20 private Properties temporaryProperties = new Properties(); 21 private ResourceBundle resources; 22 private VariableBundle parentProperties; 23 private File mSaveFile; 24 private Set removeSet = new HashSet(); 25 private Hashtable VCListeners = new Hashtable(); 26 private Hashtable VCGlobListeners = new Hashtable(); 27 28 public VariableBundle(InputStream propertiesFile, String resourceFile, VariableBundle newParentProperties) { 29 configure(propertiesFile, resourceFile, newParentProperties); 30 } 31 32 public VariableBundle(File propertiesFile, VariableBundle newParentProperties) throws java.io.FileNotFoundException { 33 FileInputStream fis = new FileInputStream(propertiesFile); 34 configure(fis, null, newParentProperties); 35 try { 36 fis.close(); 37 } catch (java.io.IOException ioe) { 38 } 39 mSaveFile = propertiesFile; 40 41 } 42 43 public VariableBundle(InputStream propertiesFile, String resourceFile) { 44 this(propertiesFile, resourceFile, null); 45 } 46 47 public VariableBundle(InputStream propertiesFile, VariableBundle newParentProperties) { 48 this(propertiesFile, null, newParentProperties); 49 } 50 51 public VariableBundle(Properties editableProperties, VariableBundle newParentProperties) { 52 writableProperties = editableProperties; 53 parentProperties = newParentProperties; 54 properties = new Properties(); 55 resources = null; 56 } 57 58 61 protected void configure(InputStream propertiesFile, String resourceFile, VariableBundle newParentProperties) { 62 63 writableProperties = new Properties(); 64 65 if (resourceFile != null) 66 try { 67 resources = ResourceBundle.getBundle(resourceFile, Locale.getDefault()); 68 } catch (MissingResourceException mre) { 69 System.err.println("Error loading resource " + mre.getClassName() + mre.getKey() + ": trying default locale."); 70 try { 71 resources = ResourceBundle.getBundle(resourceFile, Locale.US); 72 } catch (MissingResourceException mreTwo){ 73 System.err.println("Unable to load default (US) resource bundle; exiting."); 74 System.exit(1); 75 } 76 } 77 else 78 resources=null; 79 80 properties = new Properties(); 81 82 if (propertiesFile != null) 83 try { 84 properties.load(propertiesFile); 85 } catch (java.io.IOException ioe) { 86 System.err.println(ioe.getMessage() + ": " + propertiesFile); 87 } 88 89 List includeStreams = getPropertyAsList("VariableBundle.include", ""); 90 if (includeStreams != null && includeStreams.size() > 0) { 91 for (int i = 0; i < includeStreams.size(); i++) { 92 String current = (String ) includeStreams.get(i); 93 try { 94 if (current != null && ! current.equals("")) { 95 java.net.URL url = this.getClass().getResource(current); 96 97 java.io.InputStream is = url.openStream(); 98 99 properties.load(is); 100 } 101 } catch (java.io.IOException ioe) { 102 System.err.println("error including file " + current + ": " + ioe.getMessage()); 103 ioe.printStackTrace(); 104 } 105 } 106 } 107 108 parentProperties = newParentProperties; 109 110 111 } 112 113 public String getProperty(String key, String defaultValue) { 114 String returnValue = ""; 115 116 if (! propertyIsRemoved(key)) { 117 returnValue = temporaryProperties.getProperty(key, ""); 118 } 119 if (returnValue == "") { 120 if (! propertyIsRemoved(key)) { 121 returnValue = writableProperties.getProperty(key, ""); 122 } 123 if (returnValue == "") { 124 if (! propertyIsRemoved(key)) { 125 returnValue = properties.getProperty(key, ""); 126 } 127 if (returnValue == "") { 128 returnValue=getParentProperty(key, ""); 129 if (returnValue == "") { 130 if (resources != null) 131 try { 132 returnValue = resources.getString(key); 133 } catch (MissingResourceException mre) { 134 returnValue=defaultValue; 135 } 136 else 137 returnValue = defaultValue; 138 } 139 } 140 } 141 } 142 return returnValue; 143 } 144 145 public String getProperty(String key) throws MissingResourceException { 146 String returnValue; 147 148 returnValue = getProperty(key, ""); 149 if (returnValue == "") { 150 throw new MissingResourceException(key, "", key); 151 } 152 return returnValue; 153 } 154 155 156 157 private String getParentProperty(String key, String defaultValue) { 158 if (parentProperties==null) { 159 return defaultValue; 160 } else { 161 return parentProperties.getProperty(key, defaultValue); 162 } 163 } 164 165 166 public ResourceBundle getResources() { 167 return resources; 168 } 169 170 public void setResourceBundle (ResourceBundle newResources) { 171 resources = newResources; 172 } 173 174 public Properties getProperties() { 175 return properties; 176 } 177 178 181 public void setProperties(Properties newProperties) { 182 properties = newProperties; 183 } 184 185 public VariableBundle getParentProperties() { 186 return parentProperties; 187 } 188 189 public Properties getWritableProperties() { 190 return writableProperties; 191 } 192 193 public void setProperty(String propertyName, String propertyValue) { 194 internSetProperty(propertyName, propertyValue, true); 195 } 196 197 201 public void setAllProperties(Properties properties) { 202 for (String propertyName: properties.stringPropertyNames()) { 203 String propertyValue = properties.getProperty(propertyName); 204 internSetProperty(propertyName, propertyValue, false); 205 } 206 for (String propertyName: properties.stringPropertyNames()) { 207 fireValueChanged(propertyName); 208 } 209 } 210 211 private void internSetProperty(String propertyName, String propertyValue, boolean notify) { 212 213 temporaryProperties.remove(propertyName); 214 if (propertyValue == null || propertyValue.equalsIgnoreCase("")) { 215 removeProperty(propertyName); 216 writableProperties.remove(propertyName); 217 } else { 218 unRemoveProperty(propertyName); 219 writableProperties.setProperty(propertyName, propertyValue); 220 } 221 if (notify) { 222 fireValueChanged(propertyName); 223 } 224 } 225 226 229 public void setProperty(String propertyName, String propertyValue, boolean temporary) { 230 if (temporary) { 231 temporaryProperties.setProperty(propertyName, propertyValue); 232 fireValueChanged(propertyName); 233 } else { 234 setProperty(propertyName, propertyValue); 235 } 236 } 237 238 242 243 public Enumeration getPropertyAsEnumeration(String propertyName, String defaultValue) { 244 StringTokenizer tokens = new StringTokenizer(getProperty(propertyName, defaultValue), ":"); 245 return tokens; 246 } 247 248 252 public static Vector<String > convertToVector(String value) { 253 Vector<String > returnValue = new Vector<String >(); 254 StringTokenizer tokens = new StringTokenizer(value, ":"); 255 while (tokens.hasMoreElements()) 256 returnValue.add((String )tokens.nextElement()); 257 return returnValue; 258 } 259 260 264 public Vector<String > getPropertyAsVector(String propertyName, String defaultValue) { 265 return convertToVector(getProperty(propertyName, defaultValue)); 266 } 267 268 272 public static List<String > convertToList(String value) { 273 List<String > returnValue = new ArrayList<String >(); 274 StringTokenizer tokens = new StringTokenizer(value, ":"); 275 while (tokens.hasMoreElements()) 276 returnValue.add((String )tokens.nextElement()); 277 return returnValue; 278 } 279 280 284 public List<String > getPropertyAsList(String propertyName, String defaultValue) { 285 return convertToList(getProperty(propertyName, defaultValue)); 286 } 287 288 291 public static String convertToString(List pValue) { 292 if (pValue == null || pValue.size() == 0) 293 return ""; 294 else { 295 StringBuffer returnBuffer = new StringBuffer (); 296 Iterator it = pValue.iterator(); 297 while (it.hasNext()) { 298 returnBuffer.append((String ) it.next()); 299 if (it.hasNext()) { 300 returnBuffer.append(":"); 301 } 302 } 303 304 return returnBuffer.toString(); 305 } 306 } 307 308 311 public Set<String > getPropertyNames() { 312 HashSet<String > returnValue = new HashSet<String >(); 313 returnValue.addAll(temporaryProperties.stringPropertyNames()); 314 returnValue.addAll(writableProperties.stringPropertyNames()); 315 returnValue.addAll(properties.stringPropertyNames()); 316 if (parentProperties != null) 317 returnValue.addAll(parentProperties.getPropertyNames()); 318 if (resources != null) 319 returnValue.addAll(resources.keySet()); 320 321 return returnValue; 322 } 323 324 328 public Set<String > getPropertyNamesStartingWith(String startsWith) { 329 Set<String > returnValue = new HashSet<String >(); 330 Set<String > allProps = getPropertyNames(); 331 for (String prop: allProps) { 332 if (prop.startsWith(startsWith)) 333 returnValue.add(prop); 334 } 335 336 return returnValue; 337 } 338 339 344 public void saveProperties() { 345 if (mSaveFile != null) { 346 saveProperties(mSaveFile); 347 } 348 } 349 350 355 public void saveProperties(File pSaveFile) { 356 if (pSaveFile == null) 357 return; 358 359 synchronized(this) { 360 if (writableProperties.size() > 0) { 361 File outputFile; 362 String currentLine, key; 363 int equalsLoc; 364 365 try { 366 if (! pSaveFile.exists()) 367 pSaveFile.createNewFile(); 368 369 outputFile = pSaveFile.createTempFile(pSaveFile.getName(), ".tmp", pSaveFile.getParentFile()); 370 371 BufferedReader readSaveFile = new BufferedReader(new FileReader(pSaveFile)); 372 BufferedWriter writeSaveFile = new BufferedWriter(new FileWriter(outputFile)); 373 currentLine = readSaveFile.readLine(); 374 while (currentLine != null) { 375 equalsLoc = currentLine.indexOf('='); 376 if (equalsLoc != -1) { 377 String rawKey = currentLine.substring(0, equalsLoc); 378 key = unEscapeString(rawKey); 379 380 if (!propertyIsRemoved(key)) { 381 if (writableProperties.getProperty(key, "").equals("")) { 382 383 writeSaveFile.write(currentLine); 384 writeSaveFile.newLine(); 385 386 } else { 387 writeSaveFile.write(rawKey + "=" + escapeWhiteSpace(writableProperties.getProperty(key, ""))); 388 writeSaveFile.newLine(); 389 properties.setProperty(key, writableProperties.getProperty(key, "")); 390 writableProperties.remove(key); 391 } 392 } else { 393 properties.remove(key); 394 } 395 } else { 396 writeSaveFile.write(currentLine); 397 writeSaveFile.newLine(); 398 } 399 currentLine = readSaveFile.readLine(); 400 } 401 402 404 Set<String > propsLeft = writableProperties.stringPropertyNames(); 405 List<String > propsLeftList = new ArrayList<String >(propsLeft); 406 Collections.sort(propsLeftList); 407 for (String nextKey: propsLeftList) { 408 String nextKeyEscaped = escapeWhiteSpace(nextKey); 409 String nextValueEscaped = escapeWhiteSpace(writableProperties.getProperty(nextKey, "")); 410 writeSaveFile.write(nextKeyEscaped + "=" + nextValueEscaped); 411 writeSaveFile.newLine(); 412 413 properties.setProperty(nextKey, writableProperties.getProperty(nextKey, "")); 414 writableProperties.remove(nextKey); 415 } 416 417 clearRemoveList(); 418 419 readSaveFile.close(); 420 writeSaveFile.flush(); 421 writeSaveFile.close(); 422 423 String oldSaveName = pSaveFile.getAbsolutePath() + ".old"; 426 File oldSave = new File (oldSaveName); 427 if (oldSave.exists()) 428 oldSave.delete(); 429 430 String fileName = new String (pSaveFile.getAbsolutePath()); 431 pSaveFile.renameTo(oldSave); 432 outputFile.renameTo(new File(fileName)); 433 434 } catch (Exception e) { 435 System.out.println(getProperty("VariableBundle.saveError", "Error saving properties file: " + pSaveFile.getName() + ": " + e.getMessage())); 436 e.printStackTrace(System.err); 437 } 438 } 439 } 440 } 441 442 448 private String loadConvert (String theString) { 449 char aChar; 450 int len = theString.length(); 451 StringBuffer outBuffer = new StringBuffer (len); 452 453 for(int x=0; x<len; ) { 454 aChar = theString.charAt(x++); 455 if (aChar == '\\') { 456 aChar = theString.charAt(x++); 457 if(aChar == 'u') { 458 int value=0; 460 for (int i=0; i<4; i++) { 461 aChar = theString.charAt(x++); 462 switch (aChar) { 463 case '0': case '1': case '2': case '3': case '4': 464 case '5': case '6': case '7': case '8': case '9': 465 value = (value << 4) + aChar - '0'; 466 break; 467 case 'a': case 'b': case 'c': 468 case 'd': case 'e': case 'f': 469 value = (value << 4) + 10 + aChar - 'a'; 470 break; 471 case 'A': case 'B': case 'C': 472 case 'D': case 'E': case 'F': 473 value = (value << 4) + 10 + aChar - 'A'; 474 break; 475 default: 476 throw new IllegalArgumentException ( 477 "Malformed \\uxxxx encoding."); 478 } 479 } 480 outBuffer.append((char)value); 481 } else { 482 if (aChar == 't') aChar = '\t'; 483 else if (aChar == 'r') aChar = '\r'; 484 else if (aChar == 'n') aChar = '\n'; 485 else if (aChar == 'f') aChar = '\f'; 486 outBuffer.append(aChar); 487 } 488 } else 489 outBuffer.append(aChar); 490 } 491 return outBuffer.toString(); 492 } 493 494 501 private String saveConvert(String theString, boolean escapeSpace) { 502 int len = theString.length(); 503 StringBuffer outBuffer = new StringBuffer (len*2); 504 505 for(int x=0; x<len; x++) { 506 char aChar = theString.charAt(x); 507 switch(aChar) { 508 case ' ': 509 if (x == 0 || escapeSpace) 510 outBuffer.append('\\'); 511 512 outBuffer.append(' '); 513 break; 514 case '\\':outBuffer.append('\\'); outBuffer.append('\\'); 515 break; 516 case '\t':outBuffer.append('\\'); outBuffer.append('t'); 517 break; 518 case '\n':outBuffer.append('\\'); outBuffer.append('n'); 519 break; 520 case '\r':outBuffer.append('\\'); outBuffer.append('r'); 521 break; 522 case '\f':outBuffer.append('\\'); outBuffer.append('f'); 523 break; 524 default: 525 if ((aChar < 0x0020) || (aChar > 0x007e)) { 526 outBuffer.append('\\'); 527 outBuffer.append('u'); 528 outBuffer.append(toHex((aChar >> 12) & 0xF)); 529 outBuffer.append(toHex((aChar >> 8) & 0xF)); 530 outBuffer.append(toHex((aChar >> 4) & 0xF)); 531 outBuffer.append(toHex( aChar & 0xF)); 532 } else { 533 if (specialSaveChars.indexOf(aChar) != -1) 534 outBuffer.append('\\'); 535 outBuffer.append(aChar); 536 } 537 } 538 } 539 return outBuffer.toString(); 540 } 541 542 546 public String escapeWhiteSpace(String sourceString) { 547 560 return saveConvert(sourceString, true); 561 } 562 563 566 public String unEscapeString(String sourceString) { 567 return loadConvert(sourceString); 568 } 569 570 574 public void clearRemoveList() { 575 removeSet.clear(); 576 } 577 578 581 private void removeProperty(String remProp) { 582 if (remProp != null) { 583 removeSet.add(remProp.intern()); 584 } 585 } 586 587 593 private void unRemoveProperty(String unRemProp) { 594 if (unRemProp != null) { 595 removeSet.remove(unRemProp.intern()); 596 } 597 } 598 599 602 public boolean propertyIsRemoved(String prop) { 603 if (prop != null) { 604 return removeSet.contains(prop.intern()); 605 } 606 return false; 607 } 608 609 613 public void fireValueChanged(String changedValue) { 614 Set notified = new HashSet(); 616 617 Vector listeners = (Vector)VCListeners.get(changedValue); 618 if (listeners != null) { 619 Iterator iter = listeners.iterator(); 620 while (iter.hasNext()) { 621 ValueChangeListener vcl = (ValueChangeListener) iter.next(); 622 vcl.valueChanged(changedValue); 623 notified.add(vcl); 624 } 625 } 626 627 629 Enumeration keys = VCGlobListeners.keys(); 630 while (keys.hasMoreElements()) { 631 String currentPattern = (String ) keys.nextElement(); 632 if (changedValue.startsWith(currentPattern)) { 633 Vector globListeners = (Vector) VCGlobListeners.get(currentPattern); 634 if (globListeners != null && globListeners.size() > 0) { 635 for (int i = 0; i < globListeners.size(); i++) { 636 ValueChangeListener currentListener = ((ValueChangeListener)globListeners.elementAt(i)); 637 if (!notified.contains(currentListener)) { 638 currentListener.valueChanged(changedValue); 639 notified.add(currentListener); 640 } 641 } 642 } 643 } 644 } 645 646 } 647 648 652 public void addValueChangeListener(ValueChangeListener vcl, String property) { 653 if (property.endsWith("*")) { 654 String startProperty = property.substring(0, property.length() - 1); 655 Vector listeners = (Vector)VCGlobListeners.get(startProperty); 656 if (listeners == null) { 657 listeners = new Vector(); 658 listeners.add(vcl); 659 VCGlobListeners.put(startProperty, listeners); 660 } else { 661 if (!listeners.contains(vcl)) 662 listeners.add(vcl); 663 } 664 665 } else { 666 Vector listeners = (Vector)VCListeners.get(property); 667 if (listeners == null) { 668 listeners = new Vector(); 669 listeners.add(vcl); 670 VCListeners.put(property, listeners); 671 } else { 672 if (!listeners.contains(vcl)) 673 listeners.add(vcl); 674 } 675 } 676 } 677 678 682 public void removeValueChangeListener(ValueChangeListener vcl) { 683 Enumeration keys = VCListeners.keys(); 684 Vector currentListenerList; 685 while (keys.hasMoreElements()) { 686 currentListenerList = (Vector)VCListeners.get(keys.nextElement()); 687 while (currentListenerList != null && currentListenerList.contains(vcl)) 688 currentListenerList.remove(vcl); 689 } 690 691 keys = VCGlobListeners.keys(); 692 while (keys.hasMoreElements()) { 693 currentListenerList = (Vector)VCGlobListeners.get(keys.nextElement()); 694 while (currentListenerList != null && currentListenerList.contains(vcl)) 695 currentListenerList.remove(vcl); 696 } 697 } 698 699 703 public void removeValueChangeListener(ValueChangeListener vcl, String property) { 704 Vector currentListenerList; 705 currentListenerList = (Vector)VCListeners.get(property); 706 while (currentListenerList != null && currentListenerList.contains(vcl)) 707 currentListenerList.remove(vcl); 708 709 currentListenerList = (Vector)VCGlobListeners.get(property); 710 while (currentListenerList != null && currentListenerList.contains(vcl)) 711 currentListenerList.remove(vcl); 712 } 713 714 717 public Map getAllListeners() { 718 HashMap returnValue = new HashMap(VCListeners); 719 returnValue.putAll(VCGlobListeners); 720 return returnValue; 721 } 722 723 728 public String formatMessage(String key, Object ... arguments) { 729 String pattern = getProperty(key, key); 730 return java.text.MessageFormat.format(pattern, arguments); 731 } 732 733 737 private static char toHex(int nibble) { 738 return hexDigit[(nibble & 0xF)]; 739 } 740 741 742 private static final char[] hexDigit = { 743 '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' 744 }; 745 746 748 750 private static final String specialSaveChars = "=: \t\r\n\f#!"; 751 752 private static final String whiteSpaceChars = " \t\r\n\f"; 753 754 757 public File getSaveFile() { 758 return mSaveFile; 759 } 760 761 764 public void setSaveFile(File newFile) { 765 mSaveFile = newFile; 766 } 767 } 768 769 770 | Popular Tags |