1 11 12 package org.jivesoftware.util; 13 14 import org.dom4j.Document; 15 import org.dom4j.Element; 16 import org.dom4j.io.OutputFormat; 17 import org.dom4j.io.SAXReader; 18 19 import java.io.*; 20 import java.util.*; 21 22 40 public class XMLProperties { 41 42 private File file; 43 private Document document; 44 45 49 private Map propertyCache = new HashMap(); 50 51 58 public XMLProperties(String fileName) throws IOException { 59 this(new File(fileName)); 60 } 61 62 68 public XMLProperties(InputStream in) throws IOException { 69 Reader reader = new BufferedReader(new InputStreamReader(in)); 70 buildDoc(reader); 71 } 72 73 79 public XMLProperties(File file) throws IOException { 80 this.file = file; 81 if (!file.exists()) { 82 File tempFile; 87 tempFile = new File(file.getParentFile(), file.getName() + ".tmp"); 88 if (tempFile.exists()) { 89 Log.error("WARNING: " + file.getName() + " was not found, but temp file from " + 90 "previous write operation was. Attempting automatic recovery." + 91 " Please check file for data consistency."); 92 tempFile.renameTo(file); 93 } 94 else { 97 throw new FileNotFoundException("XML properties file does not exist: " 98 + file.getName()); 99 } 100 } 101 if (!file.canRead()) { 103 throw new IOException("XML properties file must be readable: " + file.getName()); 104 } 105 if (!file.canWrite()) { 106 throw new IOException("XML properties file must be writable: " + file.getName()); 107 } 108 109 FileReader reader = new FileReader(file); 110 buildDoc(reader); 111 } 112 113 119 public synchronized String getProperty(String name) { 120 String value = (String )propertyCache.get(name); 121 if (value != null) { 122 return value; 123 } 124 125 String [] propName = parsePropertyName(name); 126 Element element = document.getRootElement(); 128 for (int i = 0; i < propName.length; i++) { 129 element = element.element(propName[i]); 130 if (element == null) { 131 return null; 134 } 135 } 136 value = element.getTextTrim(); 139 if ("".equals(value)) { 140 return null; 141 } 142 else { 143 propertyCache.put(name, value); 145 return value; 146 } 147 } 148 149 170 public String [] getProperties(String name) { 171 String [] propName = parsePropertyName(name); 172 Element element = document.getRootElement(); 175 for (int i = 0; i < propName.length - 1; i++) { 176 element = element.element(propName[i]); 177 if (element == null) { 178 return new String []{}; 181 } 182 } 183 Iterator iter = element.elementIterator(propName[propName.length - 1]); 185 ArrayList props = new ArrayList(); 186 String value; 187 while (iter.hasNext()) { 188 value = ((Element)iter.next()).getTextTrim(); 190 if (!"".equals(value)) { 191 props.add(value); 192 } 193 } 194 String [] childrenNames = new String [props.size()]; 195 return (String [])props.toArray(childrenNames); 196 } 197 198 219 public Iterator getChildProperties(String name) { 220 String [] propName = parsePropertyName(name); 221 Element element = document.getRootElement(); 224 for (int i = 0; i < propName.length - 1; i++) { 225 element = element.element(propName[i]); 226 if (element == null) { 227 return Collections.EMPTY_LIST.iterator(); 230 } 231 } 232 Iterator iter = element.elementIterator(propName[propName.length - 1]); 234 ArrayList<String > props = new ArrayList<String >(); 235 while (iter.hasNext()) { 236 props.add(((Element)iter.next()).getName()); 237 } 238 return props.iterator(); 239 } 240 241 250 public String getAttribute(String name, String attribute) { 251 if (name == null || attribute == null) { 252 return null; 253 } 254 String [] propName = parsePropertyName(name); 255 Element element = document.getRootElement(); 257 for (int i = 0; i < propName.length; i++) { 258 String child = propName[i]; 259 element = element.element(child); 260 if (element == null) { 261 break; 264 } 265 } 266 if (element != null) { 267 return element.attributeValue(attribute); 269 } 270 return null; 271 } 272 273 291 public void setProperties(String name, List<String > values) { 292 String [] propName = parsePropertyName(name); 293 Element element = document.getRootElement(); 296 for (int i = 0; i < propName.length - 1; i++) { 297 if (element.element(propName[i]) == null) { 300 element.addElement(propName[i]); 301 } 302 element = element.element(propName[i]); 303 } 304 String childName = propName[propName.length - 1]; 305 List toRemove = new ArrayList(); 307 Iterator iter = element.elementIterator(childName); 308 while (iter.hasNext()) { 309 toRemove.add(iter.next()); 310 } 311 for (iter = toRemove.iterator(); iter.hasNext();) { 312 element.remove((Element)iter.next()); 313 } 314 for (String value : values) { 316 element.addElement(childName).setText(value); 317 } 318 saveProperties(); 319 320 Map params = new HashMap(); 322 params.put("value", values); 323 PropertyEventDispatcher.dispatchEvent((String )name, 324 PropertyEventDispatcher.EventType.xml_property_set, params); 325 } 326 327 337 public String [] getChildrenProperties(String parent) { 338 String [] propName = parsePropertyName(parent); 339 Element element = document.getRootElement(); 341 for (int i = 0; i < propName.length; i++) { 342 element = element.element(propName[i]); 343 if (element == null) { 344 return new String []{}; 347 } 348 } 349 List children = element.elements(); 351 int childCount = children.size(); 352 String [] childrenNames = new String [childCount]; 353 for (int i = 0; i < childCount; i++) { 354 childrenNames[i] = ((Element)children.get(i)).getName(); 355 } 356 return childrenNames; 357 } 358 359 366 public synchronized void setProperty(String name, String value) { 367 if (name == null) return; 368 if (value == null) value = ""; 369 370 propertyCache.put(name, value); 372 373 String [] propName = parsePropertyName(name); 374 Element element = document.getRootElement(); 376 for (int i = 0; i < propName.length; i++) { 377 if (element.element(propName[i]) == null) { 380 element.addElement(propName[i]); 381 } 382 element = element.element(propName[i]); 383 } 384 element.setText(value); 386 saveProperties(); 388 389 Map params = new HashMap(); 391 params.put("value", value); 392 PropertyEventDispatcher.dispatchEvent((String )name, 393 PropertyEventDispatcher.EventType.xml_property_set, params); 394 } 395 396 401 public synchronized void deleteProperty(String name) { 402 propertyCache.remove(name); 404 405 String [] propName = parsePropertyName(name); 406 Element element = document.getRootElement(); 408 for (int i = 0; i < propName.length - 1; i++) { 409 element = element.element(propName[i]); 410 if (element == null) { 412 return; 413 } 414 } 415 element.remove(element.element(propName[propName.length - 1])); 417 saveProperties(); 419 420 PropertyEventDispatcher.dispatchEvent((String )name, 422 PropertyEventDispatcher.EventType.xml_property_deleted, Collections.emptyMap()); 423 } 424 425 428 private void buildDoc(Reader in) throws IOException { 429 try { 430 SAXReader xmlReader = new SAXReader(); 431 document = xmlReader.read(in); 432 } 433 catch (Exception e) { 434 Log.error("Error reading XML properties", e); 435 throw new IOException(e.getMessage()); 436 } 437 finally { 438 if (in != null) { 439 in.close(); 440 } 441 } 442 } 443 444 448 private synchronized void saveProperties() { 449 boolean error = false; 450 File tempFile = null; 452 Writer writer = null; 453 try { 454 tempFile = new File(file.getParentFile(), file.getName() + ".tmp"); 455 writer = new FileWriter(tempFile); 456 OutputFormat prettyPrinter = OutputFormat.createPrettyPrint(); 457 XMLWriter xmlWriter = new XMLWriter(writer, prettyPrinter); 458 xmlWriter.write(document); 459 } 460 catch (Exception e) { 461 Log.error(e); 462 error = true; 464 } 465 finally { 466 if (writer != null) { 467 try { 468 writer.close(); 469 } 470 catch (IOException e1) { 471 Log.error(e1); 472 error = true; 473 } 474 } 475 } 476 477 if (!error) { 479 if (!file.delete()) { 481 Log.error("Error deleting property file: " + file.getAbsolutePath()); 482 return; 483 } 484 try { 486 copy(tempFile, file); 487 } 488 catch (Exception e) { 489 Log.error(e); 490 error = true; 492 } 493 if (!error) { 495 tempFile.delete(); 496 } 497 } 498 } 499 500 508 private String [] parsePropertyName(String name) { 509 List propName = new ArrayList(5); 510 StringTokenizer tokenizer = new StringTokenizer(name, "."); 512 while (tokenizer.hasMoreTokens()) { 513 propName.add(tokenizer.nextToken()); 514 } 515 return (String [])propName.toArray(new String [propName.size()]); 516 } 517 518 public void setProperties(Map propertyMap) { 519 Iterator iter = propertyMap.keySet().iterator(); 520 while (iter.hasNext()) { 521 String propertyName = (String ) iter.next(); 522 String propertyValue = (String ) propertyMap.get(propertyName); 523 setProperty(propertyName, propertyValue); 524 } 525 } 526 527 534 private static void copy(File inFile, File outFile) throws IOException { 535 FileInputStream fin = null; 536 FileOutputStream fout = null; 537 try { 538 fin = new FileInputStream(inFile); 539 fout = new FileOutputStream(outFile); 540 copy(fin, fout); 541 } 542 finally { 543 try { 544 if (fin != null) fin.close(); 545 } 546 catch (IOException e) { 547 } 549 try { 550 if (fout != null) fout.close(); 551 } 552 catch (IOException e) { 553 } 555 } 556 } 557 558 565 private static void copy(InputStream in, OutputStream out) throws IOException { 566 synchronized (in) { 568 synchronized (out) { 569 byte[] buffer = new byte[256]; 570 while (true) { 571 int bytesRead = in.read(buffer); 572 if (bytesRead == -1) break; 573 out.write(buffer, 0, bytesRead); 574 } 575 } 576 } 577 } 578 } 579 | Popular Tags |