001/* 002 * Copyright (c) 2003-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2014-08-15 20:47:29 +0000 (Fri, 15 Aug 2014) $' 007 * '$Revision: 32892 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029 030package org.kepler.configuration; 031 032import java.util.ArrayList; 033import java.util.Iterator; 034import java.util.List; 035import java.util.StringTokenizer; 036import java.util.Vector; 037 038import org.kepler.build.modules.Module; 039 040/** 041 * Class that represents a configuration property within kepler 042 */ 043public class ConfigurationProperty 044{ 045 private Module module; 046 private String name; 047 private ConfigurationNamespace namespace; 048 private String value; 049 private List<ConfigurationProperty> propertiesList; 050 private ConfigurationProperty parent; 051 private boolean dirty; 052 private boolean mutable; 053 private Module originModule; 054 public static final ConfigurationNamespace namespaceDefault = new ConfigurationNamespace("configuration"); 055 056 /** 057 * constructor to build a configuration property for a module with a name and 058 * a list of properties to load 059 */ 060 public ConfigurationProperty(Module module, String name, List<ConfigurationProperty> propertiesList) 061 { 062 this(module, name, namespaceDefault, propertiesList); 063 } 064 065 /** 066 * constructor to build a configuration property for a module with a name, 067 * namespace and a list of properties to nest within it 068 */ 069 public ConfigurationProperty(Module module, String name, ConfigurationNamespace namespace, 070 List<ConfigurationProperty> propertiesList) 071 { 072 this(module, name, namespace, propertiesList, true); 073 } 074 075/** 076 * constructor to build a configuration property for a module with a name, 077 * namespace and a list of properties to nest within it 078 */ 079 public ConfigurationProperty(Module module, String name, ConfigurationNamespace namespace, 080 List<ConfigurationProperty> propertiesList, boolean notifyListeners) 081 { 082 init(module, name, namespace, null); 083 this.propertiesList = propertiesList; 084 Iterator<ConfigurationProperty>itr = propertiesList.iterator(); 085 while (itr.hasNext()) 086 { 087 ConfigurationProperty cp = itr.next(); 088 cp.setParent(this); 089 cp.setNamespace(notifyListeners, this.getNamespace()); 090 cp.setOriginModule(module); 091 } 092 } 093 094 /** 095 * constructor to build a configuration property for a module with a name 096 * and a single value 097 */ 098 public ConfigurationProperty(Module module, String name, String value) 099 { 100 this(module, name, namespaceDefault, value); 101 } 102 103 /** 104 * constructor to build a configuration property for a module with a name 105 * and a single value 106 */ 107 public ConfigurationProperty(Module module, String name, ConfigurationNamespace namespace, String value) 108 { 109 init(module, name, namespace, value); 110 } 111 112 /** 113 * constructor to build a configuration property for a module with a name 114 * but with no value or nested property list. 115 */ 116 public ConfigurationProperty(Module module, String name) 117 { 118 this(module, name, namespaceDefault, (String)null); 119 } 120 121 /** 122 * create a configuration property with one nested property 123 */ 124 public ConfigurationProperty(Module module, String name, ConfigurationProperty property) 125 throws NamespaceException, ConfigurationManagerException 126 { 127 this(module, name); 128 addProperty(property); 129 } 130 131 /** 132 * add a nested property to this configuration property 133 */ 134 public void addProperty(ConfigurationProperty property) 135 throws NamespaceException, ConfigurationManagerException 136 { 137 addProperty(property, false, true, true); 138 } 139 140 /** 141 * add a nested property to this configuration property 142 */ 143 public void addProperty(ConfigurationProperty property, boolean notifyListeners) 144 throws NamespaceException, ConfigurationManagerException 145 { 146 addProperty(property, false, notifyListeners, true); 147 } 148 149 /** 150 * add a nested property to this configuration property. if ignoreMutable 151 * is false, don't throw an exception if a property is mutable. this method 152 * is used by configuration readers to build the configuration and should 153 * not be used in normal api calls. 154 */ 155 protected void addProperty(ConfigurationProperty property, boolean ignoreMutable, 156 boolean notifyListeners, boolean setDirty) 157 throws NamespaceException, ConfigurationManagerException 158 { 159 if(!ignoreMutable && !mutable) 160 { //check to see if the property is not mutable. if it is not, throw 161 //an exception 162 throw new ConfigurationManagerException("The property " + getName() + 163 " is mutable and cannot be changed at runtime."); 164 } 165 166 checkNamespace(this, property); 167 propertiesList.add(property); 168 property.setParent(this); 169 if(setDirty) { 170 setDirty(true); 171 } 172 if (notifyListeners) { 173 notifyListeners(this); 174 } 175 } 176 177 /** 178 * add a new property for a given module with a given name that has the given 179 * property nested within it. 180 */ 181 public void addProperty(Module module, String name, ConfigurationProperty property) 182 throws NamespaceException, ConfigurationManagerException 183 { 184 addProperty(module, name, namespaceDefault, property); 185 } 186 187 /** 188 * add a new property for a given module with a given name that has the given 189 * property nested within it. 190 */ 191 public void addProperty(Module module, String name, ConfigurationNamespace namespace, 192 ConfigurationProperty property) 193 throws NamespaceException, ConfigurationManagerException 194 { 195 ConfigurationProperty cp = new ConfigurationProperty(module, name, namespace, (String)null); 196 checkNamespace(this, cp); 197 checkNamespace(this, property); 198 cp.addProperty(property); 199 addProperty(cp); 200 setDirty(true); 201 notifyListeners(this); 202 } 203 204 /** 205 * add propertyToAdd before the beforeProperty in the ordering of the list of 206 * properties for this property 207 * @param index index in this property's property list to add propertyToAdd 208 * @param propertyToAdd the property to add 209 */ 210 public void addPropertyAtIndex(int index, ConfigurationProperty propertyToAdd) 211 throws NamespaceException, ConfigurationManagerException 212 { 213 if(!mutable) 214 { //check to see if the property is not mutable. if it is not, throw 215 //an exception 216 throw new ConfigurationManagerException("The property " + getName() + 217 " is mutable and cannot be changed at runtime."); 218 } 219 checkNamespace(this, propertyToAdd); 220 propertiesList.add(index, propertyToAdd); 221 propertyToAdd.setParent(this); 222 setDirty(true); 223 notifyListeners(this); 224 } 225 226 /** 227 * add a nested property if the contents are not already present, 228 * ignoring: namespaces, modules, originmodules. NOTE: if the 229 * contents are the same, but in a different order, the property is 230 * added. 231 */ 232 public void addPropertyIfNotThere(ConfigurationProperty propertyToAdd) 233 throws NamespaceException, ConfigurationManagerException 234 { 235 addPropertyIfNotThere(propertyToAdd, true); 236 } 237 238 public void addPropertyIfNotThere(ConfigurationProperty propertyToAdd, boolean setDirty) 239 throws NamespaceException, ConfigurationManagerException 240 { 241 if(!containsProperty(propertyToAdd)) 242 { 243 addProperty(propertyToAdd, false, true, setDirty); 244 } 245 } 246 247 /** 248 * add a nested property at index if the contents are not already present, 249 * ignoring: namespaces, modules, originmodules. NOTE: if the 250 * contents are the same, but in a different order, the property is 251 * added. 252 */ 253 public void addPropertyIfNotThereAtIndex(int index, ConfigurationProperty propertyToAdd) 254 throws NamespaceException, ConfigurationManagerException 255 { 256 if(!containsProperty(propertyToAdd)) 257 { 258 addPropertyAtIndex(index, propertyToAdd); 259 } 260 } 261 262 /** 263 * remove the given property 264 * 265 * @param propertyToRemove the property to remove 266 * @return true if propertiesList contained this property 267 */ 268 public boolean removeProperty(ConfigurationProperty propertyToRemove) 269 { 270 boolean removed = propertiesList.remove(propertyToRemove); 271 setDirty(true); 272 notifyListeners(this); 273 return removed; 274 } 275 276 /** 277 * return a list of nested properties within this property 278 */ 279 public List<ConfigurationProperty> getProperties() 280 { 281 return propertiesList; 282 } 283 284 /** 285 * return a list of nested properties that have a specific name. Use 286 * dots to separate path names. For example "some.config.path.value" 287 */ 288 public List<ConfigurationProperty> getProperties(String name) 289 { 290 return getProperties(this, name, false); 291 } 292 293 /** 294 * do a recursive get through this ConfigurationProperty 295 * 296 * @param name the name to look for 297 * @param recursive 298 */ 299 public List<ConfigurationProperty> getProperties(String name, boolean recursive) 300 { 301 return getProperties(this, name, recursive); 302 } 303 304 /** 305 * get properties from a configurationProperty with a given name. If 306 * recursive is true, look through the entire structure of cp and return 307 * all properties with the given name. 308 * 309 * @param cp the ConfigurationProperty to get from 310 * @param name the name to look for 311 * @param recursive if true, look through the tree recursively. 312 */ 313 public static List<ConfigurationProperty> getProperties( 314 ConfigurationProperty cp, String name, boolean recursive) 315 { 316 //System.out.println("searching for " + name + " in " + cp.getName()); 317 List<ConfigurationProperty> propList = cp.getProperties(); 318 String[] s = processName(name); 319 if(s.length > 1) 320 { 321 return getPropertiesWithPath(cp, s, true); 322 } 323 324 Vector<ConfigurationProperty> props = new Vector<ConfigurationProperty>(); 325 326 for(ConfigurationProperty prop : propList) 327 { 328 if(prop.getName().equals(name)) 329 { 330 props.add(prop); 331 } 332 333 if(recursive) 334 { 335 List<ConfigurationProperty> recursiveProps = getProperties(prop, name, recursive); 336 if(recursiveProps.size() > 0) 337 { 338 for(int j=0; j<recursiveProps.size(); j++) 339 { 340 props.add(recursiveProps.get(j)); 341 } 342 } 343 } 344 } 345 return props; 346 } 347 348 /** 349 * if there are more than one property with the same name, just return 350 * the first one. Return null if the property is not found 351 */ 352 public ConfigurationProperty getProperty(String name) 353 { 354 return getProperty(name, 0); 355 } 356 357 /** 358 * return a property with a given name at the specified index. 359 * Example: 360 * prop1 361 * prop2=x 362 * prop2=y 363 * getProperty("prop2", 1).getValue() == y 364 * getProperty("prop2", 0).getValue() == x 365 * returns null if the property does not exist 366 */ 367 public ConfigurationProperty getProperty(String name, int index) 368 { 369 List propList = getProperties(name); 370 //prettyPrintList(propList); 371 if(propList.size() > index) 372 { 373 return (ConfigurationProperty)propList.get(index); 374 } 375 return null; 376 } 377 378 /** 379 * get the property with the given index in the current list of properties 380 */ 381 public ConfigurationProperty getProperty(int index) 382 { 383 return propertiesList.get(index); 384 } 385 386 /** 387 * override originalProperty with newProperty. 388 * 389 * @param originalProperty the property to override 390 * @param newProperty the property to take the place of originalProperty 391 * @param overrideNamespace true if you want to automatically set the namespace 392 * of newProperty (along with all of its subproperties) to that of 393 * originalProperty. 394 */ 395 public boolean overrideProperty(ConfigurationProperty originalProperty, 396 ConfigurationProperty newProperty, boolean overrideNamespace) 397 { 398 if(overrideNamespace) 399 { 400 newProperty.setNamespace(originalProperty.getNamespace(), true); 401 } 402 403 boolean replaced = replaceProperty(originalProperty, newProperty); 404 notifyListeners(this); 405 return replaced; 406 } 407 408 /** 409 * returns a list of properties within this property that have a specific 410 * name and value. This will return the parent property of any properties 411 * found. Example: 412 * 413 * <a> 414 * <name>jim</name> 415 * <otherprop>XXX</otherprop> 416 * </a> 417 * <b> 418 * <name>bob</name> 419 * <otherprop>XXX</otherprop> 420 * </b> 421 * <c> 422 * <name>jim</name> 423 * <otherprop>XXX</otherprop> 424 * </c> 425 * 426 * a call to findProperties("name", "jim") would return elements <a> and <c> 427 * in the list. 428 * Note: the name parameter can NOT use the shorthand "dot" notation. 429 * 430 * @param name the name of the property to find 431 * @param value the value of the property to find 432 * @param recursive true if you want a recursive (deep) search 433 */ 434 public List<ConfigurationProperty> findProperties(String name, String value, 435 boolean recursive) 436 { 437 return findProperties(this, name, value, recursive); 438 } 439 440 /** 441 * returns a list of properties within this property that have a specific 442 * name and value. This will return the parent property of any properties 443 * found. Example: 444 * 445 * <a> 446 * <name>jim</name> 447 * <otherprop>XXX</otherprop> 448 * </a> 449 * <b> 450 * <name>bob</name> 451 * <otherprop>XXX</otherprop> 452 * </b> 453 * <c> 454 * <name>jim</name> 455 * <otherprop>XXX</otherprop> 456 * </c> 457 * 458 * a call to findProperties("name", "jim") would return elements <a> and <c> 459 * in the list. 460 * Note: the name parameter can NOT use the shorthand "dot" notation. 461 * Note: this method is non-recursive. 462 * 463 * @param name the name of the property to find 464 * @param value the value of the property to find 465 */ 466 public List<ConfigurationProperty> findProperties(String name, String value) 467 { 468 return findProperties(name, value, false); 469 } 470 471 /** 472 * return the value of this property. if the value is not set this returns null 473 */ 474 public String getValue() 475 { 476 return value; 477 } 478 479 /** 480 * set the value of this property 481 */ 482 public void setValue(String value) 483 throws ConfigurationManagerException 484 { 485 if(!mutable) 486 { //check to see if the property is not mutable. if it is not, throw 487 //an exception 488 throw new ConfigurationManagerException("The property " + getName() + 489 " is mutable and cannot be changed at runtime."); 490 } 491 setDirty(true); 492 this.value = value; 493 notifyListeners(this); 494 } 495 496 /** 497 * return true if this property has a string value 498 */ 499 public boolean hasLeafValue() 500 { 501 if(value == null) 502 { 503 return false; 504 } 505 return true; 506 } 507 508 /** 509 * return true if this property has nested properties 510 */ 511 public boolean hasNestedProperties() 512 { 513 if(propertiesList.size() > 0) 514 { 515 return true; 516 } 517 return false; 518 } 519 520 /** 521 * return the name of this property 522 */ 523 public String getName() 524 { 525 return name; 526 } 527 528 /** 529 * return the module associated with this property 530 */ 531 public Module getModule() 532 { 533 return module; 534 } 535 536 /** 537 * return the namepace 538 */ 539 public ConfigurationNamespace getNamespace() 540 { 541 return this.namespace; 542 } 543 544 /** 545 * set dirty. generally other classes shouldn't call this 546 * but it's a good way to force serialization when nothing has 547 * actually changed. 548 */ 549 public void setDirty(boolean dirty){ 550 this.dirty = dirty; 551 } 552 553 /** 554 * set the namespace of this property 555 */ 556 public void setNamespace(boolean notifyListeners, ConfigurationNamespace namespace) 557 { 558 this.namespace = namespace; 559 if (notifyListeners){ 560 notifyListeners(this); 561 } 562 } 563 564 /** 565 * set the namespace of this property 566 */ 567 public void setNamespace(ConfigurationNamespace namespace) 568 { 569 this.namespace = namespace; 570 notifyListeners(this); 571 } 572 573 /** 574 * sets the namespace. If recursive is true, set all subproperties' namespaces 575 * as well. 576 */ 577 public void setNamespace(ConfigurationNamespace namespace, boolean recursive) 578 { 579 setNamespace(namespace, recursive, true); 580 } 581 582 /** 583 * sets the namespace. If recursive is true, set all subproperties' namespaces 584 * as well. 585 */ 586 public void setNamespace(ConfigurationNamespace namespace, boolean recursive, boolean notifyListeners) 587 { 588 setNamespace(this, namespace, recursive, notifyListeners); 589 if (notifyListeners){ 590 notifyListeners(this); 591 } 592 } 593 594 /** 595 * returns a fully qualified name including the module and namespace 596 */ 597 public String getFullName() 598 { 599 String modName = module.getName() + "."; 600 String ns = ""; 601 if(namespace != null) 602 { 603 ns = namespace + "."; 604 } 605 606 return modName + ns + name; 607 } 608 609 /** 610 * returns true if this propert is mutable. A mutable property is one that 611 * can be changed and realized without restarting the application. Only mutable 612 * properties can be overwritten at runtime. A property is assumed to be mutable 613 * unless it is set not to be. 614 */ 615 public boolean isMutable() 616 { 617 return mutable; 618 } 619 620 /** 621 * return true if this ConfigurationProperty contains a property with the given name.. 622 * Set recursive to true if you want to search this property's nested structure. 623 * @param property the property 624 */ 625 public boolean containsProperty(String name, boolean recursive) 626 { 627 if(!recursive) 628 { 629 ConfigurationProperty cp = getProperty(name); 630 if(cp == null) 631 { 632 return false; 633 } 634 return true; 635 } 636 else 637 { 638 for(ConfigurationProperty cp : propertiesList) 639 { 640 if(cp.getName().equals(name)) 641 { 642 return true; 643 } 644 if(cp.hasNestedProperties()) 645 { 646 if(cp.containsProperty(name, recursive)) 647 { 648 return true; 649 } 650 } 651 } 652 return false; 653 } 654 } 655 656 /** 657 * returns true if this property contains a nested property, 658 * ignoring: namespaces, modules, originmodules. NOTE: if the 659 * contents are the same, but in a different order, returns false. 660 */ 661 public boolean containsProperty(ConfigurationProperty nestedProperty) 662 { 663 for(ConfigurationProperty subProperty : getProperties()) 664 { 665 //System.out.println("checking"); 666 //System.out.println(subProperty.toString(true, false, false, false)); 667 //System.out.println(nestedProperty.toString(true, false, false, false)); 668 if(subProperty.equalsContents(nestedProperty)) 669 { 670 //System.out.println("found! not adding property."); 671 return true; 672 } 673 } 674 675 return false; 676 } 677 678 /** 679 * returns true if the property contents are identical to this one, 680 * ignoring: namespaces, modules, originmodules. NOTE: if the contents 681 * are the same, but in a different order, returns false. 682 */ 683 public boolean equalsContents(ConfigurationProperty property) 684 { 685 if(property == null) 686 { 687 return false; 688 } 689 else if(property == this) 690 { 691 return true; 692 } 693 else 694 { 695 return toStringContents().equals(property.toStringContents()); 696 } 697 698 } 699 700 /** 701 * return the xml version of this property 702 */ 703 public String getXML() 704 { 705 return getXML(this, ""); 706 } 707 708 public String toString(boolean recursive) 709 { 710 StringBuilder s = new StringBuilder("{name=" + 711 name + ", module=" + module.getName() + ", namespace=" + 712 namespace + ", value=" + value); 713 if(recursive && propertiesList.size() > 0) 714 { 715 s.append(", propertyList={"); 716 for(ConfigurationProperty cp : propertiesList) 717 { 718 s.append(cp.toString()); 719 } 720 s.append("}"); 721 } 722 723 s.append("}"); 724 return s.toString(); 725 } 726 727 /** 728 * return a string representation of this property 729 */ 730 public String toString() 731 { 732 return toString(true); 733 } 734 735 /** Returns the string contents of this property without the namespace, 736 * module name, and origin module name (if present). 737 */ 738 public String toStringContents() 739 { 740 return toString(true, false, false, false); 741 } 742 743 /** 744 * returns a string representation of this property 745 * @param recursive if true, string includes all sub-properties 746 * @param includeNamespace if true, string includes the namespace 747 * @param includeModule if true, string include module name 748 * @param includeOriginModule if true, string includes originModule name 749 */ 750 public String toString(boolean recursive, boolean includeNamespace, boolean includeModule, boolean includeOriginModule) 751 { 752 String s; 753 s = "{name=" + name; 754 755 if(includeModule) 756 { 757 s += ", module=" + module.getName(); 758 } 759 760 if(includeNamespace) 761 { 762 s += ", namespace=" + namespace; 763 } 764 765 s += ", value=" + value; 766 767 if(recursive && propertiesList.size() > 0) 768 { 769 s += ", propertyList={"; 770 for(ConfigurationProperty cp : propertiesList) 771 { 772 if(includeOriginModule || !cp.getName().equals("originModule")) 773 { 774 s += cp.toString(recursive, includeNamespace, includeModule, includeOriginModule); 775 } 776 } 777 s +="}"; 778 } 779 780 s += "}"; 781 return s; 782 } 783 784 /** 785 * print this configurationProperty nicely showing the hierarchy 786 */ 787 public void prettyPrint() 788 { 789 System.out.println(prettyPrint(this, "")); 790 } 791 792 /** 793 * returns true if this property has changed since it was last saved 794 * @param recursive true if the dirty flag should be searched for in any 795 * contained configuration property 796 */ 797 public boolean isDirty(boolean recursive) 798 { 799 if(!recursive) 800 { 801 return this.dirty; 802 } 803 804 return isDirty(this); 805 } 806 807 /** 808 * returns this congifuration property's dirty flag 809 */ 810 public boolean isDirty() 811 { 812 return isDirty(false); 813 } 814 815 /** 816 * returns the parent propert of this property. null if this property 817 * does not have a parent. 818 */ 819 public ConfigurationProperty getParent() 820 { 821 return this.parent; 822 } 823 824 /** 825 * set the namespace on a configurationProperty 826 */ 827 public static void setNamespace(ConfigurationProperty cp, ConfigurationNamespace namespace, 828 boolean recursive) 829 { 830 setNamespace(cp, namespace, recursive, true); 831 } 832 833 /** 834 * set the namespace on a configurationProperty 835 */ 836 public static void setNamespace(ConfigurationProperty cp, ConfigurationNamespace namespace, 837 boolean recursive, boolean notifyListeners) 838 { 839 cp.setNamespace(notifyListeners, namespace); 840 if(recursive) 841 { 842 List<ConfigurationProperty> propList = cp.getProperties(); 843 for(ConfigurationProperty prop : propList) 844 { 845 setNamespace(prop, namespace, recursive, notifyListeners); 846 } 847 } 848 } 849 850 /** 851 * Search a list of properties for properties that contain a name and a value 852 */ 853 public static List<ConfigurationProperty> findProperties( 854 List<ConfigurationProperty> properties, String name, String value, boolean recursive) 855 { 856 Vector<ConfigurationProperty> results = new Vector<ConfigurationProperty>(); 857 for(ConfigurationProperty cp : properties) 858 { 859 //System.out.println("searching " + cp.getName()); 860 List<ConfigurationProperty> subresults = findProperties(cp, name, value, recursive); 861 for(ConfigurationProperty p : subresults) 862 { 863 if(!checkForDuplicates(results, p)) 864 { 865 results.add(p); 866 } 867 } 868 } 869 return results; 870 } 871 872 /** 873 * return a list of properties that have a name that matches name and a value 874 * that matches value within property. If recursive is set to true, do a deep 875 * search of the property 876 */ 877 public static List<ConfigurationProperty> findProperties(ConfigurationProperty property, 878 String name, String value, boolean recursive) 879 { 880 Vector<ConfigurationProperty> found = new Vector<ConfigurationProperty>(); 881 List<ConfigurationProperty> propertiesList = property.getProperties(); 882 for(ConfigurationProperty cp : propertiesList) 883 { 884 //System.out.println("cp: " + cp.getName()); 885 if(cp.getName().equals(name) && cp.getValue().equals(value) && !checkForDuplicates(found, cp)) 886 { 887 found.add(cp.getParent()); 888 } 889 890 if(recursive) 891 { 892 List<ConfigurationProperty> l = findProperties(cp, name, value, recursive); 893 //simplePrintList(l); 894 for(int j=0; j<l.size(); j++) 895 { 896 if(!checkForDuplicates(found, l.get(j))) 897 { 898 found.add(l.get(j)); 899 } 900 } 901 } 902 } 903 904 return found; 905 } 906 907 /** 908 * pretty print a list of configuration properties 909 */ 910 public static void prettyPrintList(List<ConfigurationProperty> l) 911 { 912 System.out.println("["); 913 for(int i=0; i<l.size(); i++) 914 { 915 System.out.print(i + " = {\n"); 916 ConfigurationProperty cp = l.get(i); 917 System.out.println("module: " + cp.getModule().getName() + 918 " name: " + cp.getName() + 919 " namespace: " + cp.getNamespace().toString() + 920 " value: " + cp.getValue()); 921 cp.prettyPrint(); 922 System.out.print("}"); 923 if(i != l.size() - 1) 924 { 925 System.out.print(",\n"); 926 } 927 } 928 System.out.println("]"); 929 } 930 931 public static void simplePrintList(List<ConfigurationProperty> l) 932 { 933 System.out.print("\n["); 934 for(int i=0; i<l.size(); i++) 935 { 936 System.out.print(i + " = {"); 937 ConfigurationProperty cp = l.get(i); 938 System.out.print("module: " + cp.getModule().getName() + " namespace: " 939 + cp.getNamespace().toString() + " name: " + cp.getName()); 940 System.out.print("}"); 941 if(i != l.size() - 1) 942 { 943 System.out.print(",\n"); 944 } 945 } 946 System.out.println("]"); 947 } 948 949 /** 950 * return a list of strings of the values of a property with a given name in 951 * the list of properties 952 */ 953 public static List<String> getValueList(List<ConfigurationProperty> propList, 954 String propertyName, boolean recursive) 955 { 956 Vector<String> v = new Vector<String>(); 957 for(ConfigurationProperty cp : propList) 958 { 959 if(cp.getName().equals(propertyName)) 960 { 961 v.add(cp.getValue()); 962 } 963 964 if(recursive) 965 { 966 List<String> l = getValueList(cp.getProperties(), propertyName, recursive); 967 for(int j=0; j<l.size(); j++) 968 { 969 v.add(l.get(j)); 970 } 971 } 972 } 973 return v; 974 } 975 976 /** 977 * 978 */ 979 public void setOriginModule(Module m) 980 { 981 this.originModule = m; 982 } 983 984 /** 985 * 986 */ 987 public Module getOriginModule() 988 { 989 return this.originModule; 990 } 991 992 /** 993 * set the parent property of this property 994 */ 995 public void setParent(ConfigurationProperty property) 996 { 997 this.parent = property; 998 } 999 1000 /** 1001 * reset the dirty flag 1002 * @param recursive set to true if all properties that this property 1003 * contains should also be reset 1004 */ 1005 protected void resetDirty(boolean recursive) 1006 { 1007 setDirty(false); 1008 1009 if(!recursive) 1010 { 1011 return; 1012 } 1013 1014 Iterator it = getProperties().iterator(); 1015 while(it.hasNext()) 1016 { 1017 ConfigurationProperty cp = (ConfigurationProperty)it.next(); 1018 cp.resetDirty(true); 1019 } 1020 } 1021 1022 /** 1023 * recursively return all properties with a path denoted in s. If returnChildren 1024 * is true, return the found child nodes. If it is false, return the 1025 * found parent nodes. For example, if you are getting a/b/c, if returnChildren 1026 * is true, return a list of the c's. If returnChildren is false, 1027 * return a list of the a's. 1028 */ 1029 protected static List<ConfigurationProperty> getPropertiesWithPath(ConfigurationProperty property, 1030 String[] s, boolean returnChildren) 1031 { 1032 if(returnChildren) 1033 { //return the found children nodes 1034 List<ConfigurationProperty> properties = getProperties(property, s[0], true); 1035 for(int i=1; i<s.length; i++) 1036 { 1037 properties = getPropertiesFromList(properties, s[i]); 1038 } 1039 1040 return properties; 1041 } 1042 1043 //return the found parent nodes 1044 List<ConfigurationProperty> properties = getProperties(property, s[s.length - 1], true); 1045 for(int i=s.length - 2; i>=0; i--) 1046 { 1047 properties = getParentPropertiesFromList(properties, s[i]); 1048 } 1049 1050 return properties; 1051 } 1052 1053 /** 1054 * set whether this property is mutable. A mutable property is one that 1055 * can be changed and realized without restarting the application. Only mutable 1056 * properties can be overwritten at runtime. A property is assumed to be mutable 1057 * unless it is set not to be. 1058 */ 1059 protected void setMutable(boolean mutable) 1060 { 1061 this.mutable = mutable; 1062 } 1063 1064 /** 1065 * searches a list of properties for properties of a given name. This is 1066 * not recursive. 1067 * If returnChild is true, return the child elements instead of the parents 1068 */ 1069 private static List<ConfigurationProperty> getParentPropertiesFromList( 1070 List<ConfigurationProperty> propertyList, String name) 1071 { 1072 Vector<ConfigurationProperty> results = new Vector<ConfigurationProperty>(); 1073 for(ConfigurationProperty prop : propertyList) 1074 { 1075 //System.out.println("prop.parent: " + prop.getParent().getName()); 1076 if(prop.getParent().getName().equals(name)) 1077 { 1078 results.add(prop.getParent()); 1079 } 1080 } 1081 return results; 1082 } 1083 1084 /** 1085 * Note: callers should notifyListeners. 1086 * 1087 * replace a specific property within a property's subproperties and 1088 * return the index. This method is recursive. 1089 * 1090 * @param findProperty the property to look for 1091 * @param replaceProperty the property to replace findProperty with 1092 * @return boolean true if the property was found and replaced 1093 */ 1094 private boolean replaceProperty(ConfigurationProperty findProperty, 1095 ConfigurationProperty replaceProperty) 1096 { 1097 boolean found = false; 1098 for(int i=0; i<this.propertiesList.size(); i++) 1099 { 1100 ConfigurationProperty cp = this.propertiesList.get(i); 1101 if(cp == findProperty) 1102 { 1103 this.propertiesList.remove(i); 1104 this.propertiesList.add(i, replaceProperty); 1105 return true; 1106 } 1107 1108 List l = cp.getProperties(); 1109 if(l.size() > 0) 1110 { 1111 found = cp.replaceProperty(findProperty, replaceProperty); 1112 if(found) 1113 { 1114 break; 1115 } 1116 } 1117 } 1118 1119 return found; 1120 } 1121 1122 /** 1123 * return true if v contains cp 1124 */ 1125 private static boolean checkForDuplicates(Vector<ConfigurationProperty> v, ConfigurationProperty cp) 1126 { 1127 for(ConfigurationProperty p : v) 1128 { 1129 if(p == cp) 1130 { 1131 return true; 1132 } 1133 } 1134 return false; 1135 } 1136 1137 /** 1138 * return true of the property or any of its sub properties are dirty 1139 */ 1140 private boolean isDirty(ConfigurationProperty p) 1141 { 1142 if(p.isDirty()) 1143 { 1144 return true; 1145 } 1146 1147 List l = p.getProperties(); 1148 Iterator it = l.iterator(); 1149 while(it.hasNext()) 1150 { 1151 ConfigurationProperty cp = (ConfigurationProperty)it.next(); 1152 if(isDirty(cp)) 1153 { 1154 return true; 1155 } 1156 else 1157 { 1158 continue; 1159 } 1160 } 1161 1162 return false; 1163 } 1164 1165 /** 1166 * return an xml representation of this property 1167 */ 1168 private static String getXML(ConfigurationProperty cp, String spaces) 1169 { 1170 String s = ""; 1171 String name = cp.getName(); 1172 Iterator it = cp.getProperties().iterator(); 1173 String value = cp.getValue(); 1174 1175 s += spaces; 1176 s += "<" + name + ">\n"; 1177 1178 if(!cp.isMutable()) 1179 { 1180 s += spaces + " <mutable>false</mutable>\n"; 1181 } 1182 1183 Module originModule = cp.getOriginModule(); 1184 if (cp.getParent() == null) 1185 { 1186 System.out.println("ERROR ConfigurationProperty getXML(cp, spaces) cp.getParent() == null for cp:"); 1187 cp.prettyPrint(); 1188 } 1189 1190 if(originModule != null && !originModule.getName().equals(cp.getParent().getModule().getName())) 1191 { 1192 s += spaces + " <originModule>" + originModule.getName() + "</originModule>\n"; 1193 } 1194 1195 if(value != null && !value.equals("")) 1196 { 1197 s += spaces + " " + value + "\n"; 1198 } 1199 1200 while(it.hasNext()) 1201 { 1202 ConfigurationProperty c = (ConfigurationProperty)it.next(); 1203 // don't add originModule property more than once per property 1204 if (!c.getName().equals("originModule")){ 1205 s += getXML(c, spaces + " "); 1206 } 1207 } 1208 1209 s += spaces + "</" + name + ">\n"; 1210 1211 return s; 1212 } 1213 1214 /** 1215 * format the cp nicely 1216 */ 1217 private static String prettyPrint(ConfigurationProperty cp, String spaces) 1218 { 1219 String s = ""; 1220 String name = cp.getName(); 1221 Iterator it = cp.getProperties().iterator(); 1222 String value = cp.getValue(); 1223 String originModName = cp.getOriginModule().getName(); 1224 1225 boolean dirty = cp.isDirty(); 1226 s += spaces; 1227 s += name + "(" + originModName + ")"; 1228 if(dirty) 1229 { 1230 s += "(DIRTY)"; 1231 } 1232 1233 if(value != null && !value.equals("")) 1234 { 1235 s += " = " + value; 1236 } 1237 s += "\n"; 1238 1239 while(it.hasNext()) 1240 { 1241 ConfigurationProperty c = (ConfigurationProperty)it.next(); 1242 s += prettyPrint(c, spaces + " "); 1243 } 1244 return s; 1245 } 1246 1247 /** 1248 * process a name with . notations into a string array 1249 */ 1250 protected static String[] processName(String name) 1251 { 1252 String[] s; 1253 if(name.indexOf(".") != -1) 1254 { 1255 StringTokenizer st = new StringTokenizer(name, "."); 1256 int num = st.countTokens(); 1257 s = new String[num]; 1258 int i = 0; 1259 while(st.hasMoreTokens()) 1260 { 1261 String ss = st.nextToken(); 1262 s[i] = ss; 1263 i++; 1264 } 1265 return s; 1266 } 1267 else 1268 { 1269 s = new String[1]; 1270 s[0] = name; 1271 return s; 1272 } 1273 } 1274 1275 /** 1276 * recursively return the properties in the list that match name 1277 */ 1278 private static List<ConfigurationProperty> getPropertiesFromList( 1279 List<ConfigurationProperty> propertyList, String name) 1280 { 1281 if(propertyList == null) 1282 { 1283 return null; 1284 } 1285 Vector<ConfigurationProperty> results = new Vector<ConfigurationProperty>(); 1286 for(ConfigurationProperty cp : propertyList) 1287 { 1288 List<ConfigurationProperty> cpPropList = cp.getProperties(); 1289 for(ConfigurationProperty cpProp : cpPropList) 1290 { 1291 if(cpProp.getName().equals(name)) 1292 { 1293 results.add(cpProp); 1294 } 1295 } 1296 } 1297 return results; 1298 } 1299 1300 /** 1301 * initialize this property 1302 */ 1303 private void init(Module module, String name, ConfigurationNamespace namespace, String value) 1304 { 1305 this.propertiesList = new ArrayList<ConfigurationProperty>(); 1306 this.module = module; 1307 this.originModule = module; 1308 this.name = name; 1309 this.namespace = namespace; 1310 this.value = value; 1311 this.parent = null; 1312 this.mutable = true; 1313 } 1314 1315 /** 1316 * check to see if prop1 and prop2 are in the same namespace. If they aren't 1317 * throw a NamespaceException 1318 */ 1319 private void checkNamespace(ConfigurationProperty prop1, ConfigurationProperty prop2) 1320 throws NamespaceException 1321 { 1322 ConfigurationNamespace p1ns = prop1.getNamespace(); 1323 ConfigurationNamespace p2ns = prop2.getNamespace(); 1324 1325 if(p1ns == null && p2ns == null) 1326 { 1327 return; 1328 } 1329 else if(p1ns == null || p2ns == null) 1330 { 1331 throw new NamespaceException("The namespace of configuration property " + 1332 prop1.getFullName() + " is not in the same namespace as " + 1333 prop2.getFullName() + ". One namespace is null and the other is not."); 1334 } 1335 else if(!p1ns.equals(p2ns)) 1336 { 1337 throw new NamespaceException("The namespace of configuration property " + 1338 prop1.getFullName() + " is not in the same namespace as " + 1339 prop2.getFullName() + ". Properties must be in the same namespace " + 1340 "to be nested."); 1341 } 1342 } 1343 1344 /** 1345 * notify listeners that the property has changed. 1346 */ 1347 private void notifyListeners(ConfigurationProperty property) 1348 { 1349 try 1350 { 1351 ConfigurationManager.getInstance(false).notifyListeners(property); 1352 } 1353 catch(Exception e) 1354 { 1355 throw new RuntimeException("Could not notify listeners: " + e.getMessage()); 1356 } 1357 } 1358}