001/* 002 * Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025package Torello.Java.ReadOnly; 026 027import java.nio.charset.Charset; 028import java.util.function.BiConsumer; 029import java.util.function.BiFunction; 030 031import Torello.Java.Additional.Ret2; 032import Torello.Java.Additional.Tuple2; 033import Torello.JavaDoc.LinkJavaSource; 034 035import java.io.*; 036import java.util.*; 037 038/** 039 * Immutable Wrapper for <CODE>java.util.Properties</CODE>, found in the "Java Collections 040 * Framework". 041 * 042 * <EMBED CLASS=globalDefs DATA-JDK=Properties> 043 * <EMBED CLASS='external-html' DATA-FILE-ID=DATA_CLASS> 044 */ 045@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="JDHBI_MAIN") 046public class ReadOnlyProperties extends ReadOnlyHashtable<Object, Object> 047{ 048 // ******************************************************************************************** 049 // ******************************************************************************************** 050 // Protected & Private Fields, Methods, Statics 051 // ******************************************************************************************** 052 // ******************************************************************************************** 053 054 055 /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */ 056 protected static final long serialVersionUID = 1; 057 058 // Minor Optimization where new Properties's that have no contents always re-use this static 059 // instance. 060 061 private static final Properties EMPTY_PROPERTIES = new Properties(0); 062 063 // Singleton & Empty ReadOnlyProperties, Uses the "Supplier Constructor" 064 private static final ReadOnlyProperties EMPTY_READONLY_PROPERTIES = 065 new ReadOnlyProperties(EMPTY_PROPERTIES); 066 067 // The actual Properties used by this instance. 068 private final Properties properties; 069 070 // TRUE => This was built using the class ROProperties 071 // FALSE => This was built using the clone() of a standard java.util.Properties constructor 072 073 private final boolean fromBuilderOrProperties; 074 075 // Mimics the C++ Keyword/Concept of "Friend Class". Is "Friends With" ROPropertiesBuilder 076 static class AccessBadge { private AccessBadge() { } } 077 private static final AccessBadge friendClassBadge = new AccessBadge(); 078 079 080 // ******************************************************************************************** 081 // ******************************************************************************************** 082 // Builder, Acess-Badge Constructor - and Static "Empty" getter (which is used by the builder) 083 // ******************************************************************************************** 084 // ******************************************************************************************** 085 086 087 /** 088 * Returns an empty singleton instance of this class. 089 * 090 * <EMBED CLASS='external-html' DATA-FILE-ID=EMPTY_SYNCHRONIZED> 091 */ 092 public static ReadOnlyProperties emptyROP() 093 { return EMPTY_READONLY_PROPERTIES; } 094 095 // To all the readers out there following along: The "AccessBadge" thing is just a slightly 096 // wimpier substitute for the C++ keyword / concept 'friend' or "Friend Class". It means this 097 // constructor is (for all intents and purposes) a private-constructor, except for the class 098 // ROPropertiesBuilder 099 // 100 // This is the Constructor used by the Builder. It has a "Zero-Size" Optimization 101 102 ReadOnlyProperties(ROPropertiesBuilder ropb, ROPropertiesBuilder.AccessBadge badge) 103 { 104 // This is a little bizarre, but necessary. Properties extends Hashtable 105 super(friendClassBadge); 106 107 Objects.requireNonNull(badge, "Access Badge is null. Requires Friend-Class Badge"); 108 109 this.fromBuilderOrProperties = true; 110 this.properties = ropb; 111 } 112 113 114 // ******************************************************************************************** 115 // ******************************************************************************************** 116 // Constructors 117 // ******************************************************************************************** 118 // ******************************************************************************************** 119 120 121 /** 122 * Clones parameter {@code 'properties'} (and saves it) in order to guarantee that 123 * {@code 'this'} instance is Read-Only and furthermore shielded from outside modification. 124 * 125 * @param properties The {@code Properties} to be cloned and saved into this instance internal 126 * and private {@code 'properties'} field. 127 */ 128 @SuppressWarnings("unchecked") 129 public ReadOnlyProperties(Properties properties) 130 { 131 // This is a little bizarre, but necessary. Properties extends Hashtable 132 super(friendClassBadge); 133 this.fromBuilderOrProperties = false; 134 135 // TO-DO: FIX-ME, CLONE IS NOT ACCEPTABLE IN READ-ONLY !!! IT IS A BACK-DOOR !!! 136 this.properties = (Properties) properties.clone(); 137 } 138 139 /** 140 * If only a small amount of processing needs to be done on the contents of some Java 141 * Map, and using an entire Builder-Class seems disproportionately complex - <I>this 142 * constructor can convert any Java {@code Map} into a {@code ReadOnlyProperties}, using 143 * a simple {@code 'mapTranslator'}</I>. 144 * 145 * @param <A> The Key-Type of the User-Provided {@code Map}. 146 * @param <B> The Value-Type of the User-Provided {@code Map}. 147 * 148 * @param map Any Java {@code Map}. 149 * 150 * @param mapTranslator A function for mapping the iterated elements of Map-Types {@code 'A'} 151 * and {@code 'B'}, into the actual {@code Properties's} Key and Value Type {@code 'String'}. 152 * 153 * <BR /><BR />If this parameter is passed null, this method will throw a 154 * {@code NullPointerException}. 155 * 156 * @throws NullPointerException if either parameter {@code 'i'} or parameter 157 * {@code 'mapTranslator'} is passed null. 158 */ 159 public <A, B> ReadOnlyProperties 160 (Map<A, B> map, BiFunction<A, B, Ret2<String, String>> mapTranslator) 161 { 162 super(friendClassBadge); 163 164 Objects.requireNonNull(mapTranslator, "You have passed null to parameter 'mapTranslator'"); 165 166 fromBuilderOrProperties = false; 167 168 Properties properties = new Properties(map.size()); 169 170 for (Map.Entry<A, B> entry : map.entrySet()) 171 { 172 Ret2<String, String> ret2 = mapTranslator.apply(entry.getKey(), entry.getValue()); 173 properties.put(ret2.a, ret2.b); 174 } 175 176 // Empty Optimization (throw away, completely, the reference, use static-constant) 177 this.properties = (properties.size() == 0) ? EMPTY_PROPERTIES : properties; 178 } 179 180 181 // ******************************************************************************************** 182 // ******************************************************************************************** 183 // More Constructors, March 2024 184 // ******************************************************************************************** 185 // ******************************************************************************************** 186 187 188 /** 189 * Reads a property list (key and element pairs) from the input byte stream. The input stream 190 * is in a simple line-oriented format as specified in {@code load(Reader)} and is assumed to 191 * use the ISO 8859-1 character encoding; that is each byte is one Latin1 character. Characters 192 * not in Latin1, and certain special characters, are represented in keys and elements using 193 * Unicode escapes as defined in section {@code 3.3} of <cite>The Java Language 194 * Specification</cite>. 195 * 196 * <BR /><BR />The specified stream remains open after this method returns. 197 * 198 * <BR /><BR /><SPAN CLASS=CopiedJDK>This Detail-Comment was copied from class: 199 * {@code java.util.Properties}, <B>JDK 21</B> 200 * 201 * <BR /><BR /><B>Method:</B> Properties.load(InputStream.inStream) 202 * </SPAN> 203 * 204 * @param inStream the input stream. 205 * @param sizeIfKnown <EMBED CLASS='external-html' DATA-FILE-ID=PROP_ICAPACITY> 206 * @throws IOException if an error occurred when reading from the input stream. 207 * 208 * @throws IllegalArgumentException if the input stream contains a malformed Unicode escape 209 * sequence. 210 * 211 * @throws NullPointerException if {@code inStream} is null. 212 */ 213 public ReadOnlyProperties(InputStream inStream, Integer sizeIfKnown) throws IOException 214 { 215 super(friendClassBadge); 216 217 this.fromBuilderOrProperties = false; 218 219 this.properties = (sizeIfKnown != null) ? new Properties(sizeIfKnown) : new Properties(); 220 221 this.properties.load(inStream); 222 } 223 224 /** 225 * Reads a property list (key and element pairs) from the input character stream in a simple 226 * line-oriented format. 227 * 228 * <EMBED CLASS='external-html' DATA-FILE-ID=LOAD_DESC_READER> 229 * 230 * <BR /><BR /><SPAN CLASS=CopiedJDK>This Detail-Comment was copied from class: 231 * {@code java.util.Properties}, <B>JDK 21</B> 232 * 233 * <BR /><BR /><B>Method:</B> Properties.load(InputStream.inStream) 234 * </SPAN> 235 * 236 * @param reader the input character stream. 237 * @param sizeIfKnown <EMBED CLASS='external-html' DATA-FILE-ID=PROP_ICAPACITY> 238 * @throws IOException if an error occurred when reading from the input stream. 239 * 240 * @throws IllegalArgumentException if a malformed Unicode escape appears in the input. 241 * @throws NullPointerException if {@code reader} is null. 242 */ 243 public ReadOnlyProperties(Reader reader, Integer sizeIfKnown) throws IOException 244 { 245 super(friendClassBadge); 246 247 this.fromBuilderOrProperties = false; 248 249 this.properties = (sizeIfKnown != null) ? new Properties(sizeIfKnown) : new Properties(); 250 251 this.properties.load(reader); 252 } 253 254 /** 255 * Loads all of the properties represented by the XML document on the specified input stream 256 * into this properties table. 257 * 258 * <EMBED CLASS='external-html' DATA-FILE-ID=LOADXML_DESC_INPUT_STRM> 259 * 260 * <BR /><BR /><SPAN CLASS=CopiedJDK>This Detail-Comment was copied from class: 261 * {@code java.util.Properties}, <B>JDK 21</B> 262 * 263 * <BR /><BR /><B>Method:</B> Properties.load(InputStream.inStream) 264 * </SPAN> 265 * 266 * @param sizeIfKnown <EMBED CLASS='external-html' DATA-FILE-ID=PROP_ICAPACITY> 267 * @param in the input stream from which to read the XML document. 268 * 269 * @throws IOException if reading from the specified input stream results in an 270 * {@code IOException}. 271 * 272 * @throws java.io.UnsupportedEncodingException if the document's encoding declaration can be 273 * read and it specifies an encoding that is not supported 274 * 275 * @throws InvalidPropertiesFormatException Data on input stream does not constitute a valid 276 * XML document with the mandated document type. 277 * 278 * @throws NullPointerException if {@code in} is null. 279 * 280 * @spec https://www.w3.org/TR/xml Extensible Markup Language (XML) 1.0 (Fifth Edition) 281 * @see #storeToXML(OutputStream, String, String) 282 * @see <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character Encoding in Entities</a> 283 */ 284 public ReadOnlyProperties(Integer sizeIfKnown, InputStream in) 285 throws IOException, UnsupportedEncodingException, InvalidPropertiesFormatException 286 { 287 super(friendClassBadge); 288 289 this.fromBuilderOrProperties = false; 290 291 this.properties = (sizeIfKnown != null) ? new Properties(sizeIfKnown) : new Properties(); 292 293 this.properties.loadFromXML(in); 294 } 295 296 297 // ******************************************************************************************** 298 // ******************************************************************************************** 299 // One More Constructor, for good luck - March 2024 300 // ******************************************************************************************** 301 // ******************************************************************************************** 302 303 304 /** 305 * Builds a {@code Properties} instance using the {@code 'refHolder'} & 306 * {@code 'computeNextEntry'} combination. 307 * 308 * @param refHolder <EMBED CLASS='external-html' DATA-FILE-ID=REF_HOLDER> 309 * @param computeNextEntry <EMBED CLASS='external-html' DATA-FILE-ID=COMPUTE_NEXT_RUN> 310 * @param sizeIfKnown <EMBED CLASS='external-html' DATA-FILE-ID=PROP_ICAPACITY> 311 */ 312 public ReadOnlyProperties( 313 Tuple2<Object, Object> refHolder, 314 Runnable computeNextEntry, 315 Integer sizeIfKnown 316 ) 317 { 318 super(friendClassBadge); 319 320 Objects.requireNonNull(refHolder, ROHelpers.NULL_MSG + "'refHolder'"); 321 Objects.requireNonNull(computeNextEntry, ROHelpers.NULL_MSG + "'computeNextEntry'"); 322 323 fromBuilderOrProperties = false; 324 325 Properties properties = new Properties(((sizeIfKnown == null) ? 16 : sizeIfKnown)); 326 327 do 328 { 329 computeNextEntry.run(); 330 if ((refHolder.a == null) && (refHolder.b == null)) break; 331 properties.put(refHolder.a, refHolder.b); 332 } 333 while (true); 334 335 // Empty Optimization (throw away, completely, the reference, use static-constant) 336 this.properties = (properties.size() == 0) ? EMPTY_PROPERTIES : properties; 337 } 338 339 340 // ******************************************************************************************** 341 // ******************************************************************************************** 342 // Original JDK Methods, java.util.Properties 343 // ******************************************************************************************** 344 // ******************************************************************************************** 345 346 347 /** 348 * Writes this property list (key and element pairs) from this instance' internal 349 * {@code Properties} table to the output character stream (in a format suitable for using the 350 * {@code Properties.load(Reader)} method. 351 * 352 * <EMBED CLASS='external-html' DATA-FILE-ID=STORE_DESC_WRITER> 353 * 354 * @param writer an output character stream writer. 355 * @param comments a description of the property list. 356 * 357 * @throws IOException if writing this property list to the specified output stream throws an 358 * {@code IOException}. 359 * 360 * @throws ClassCastException if this {@code Properties} object contains any keys or values 361 * that are not {@code Strings}. 362 * 363 * @throws NullPointerException if {@code writer} is null. 364 */ 365 public void store(Writer writer, String comments) 366 throws IOException 367 { this.properties.store(writer, comments); } 368 369 /** 370 * Writes this property list (key and element pairs) from this instance' internal 371 * {@code Properties} table to the output character stream in a format suitable for using the 372 * {@code Properties.load(InputStream)} method. 373 * 374 * <EMBED CLASS='external-html' DATA-FILE-ID=STORE_DESC_OUTPUTS> 375 * 376 * @param out an output stream. 377 * @param comments a description of the property list. 378 * 379 * @throws IOException if writing this property list to the specified output stream throws an 380 * {@code IOException}. 381 * 382 * @throws ClassCastException if this {@code Properties} object contains any keys or values 383 * that are not {@code Strings}. 384 * 385 * @throws NullPointerException if {@code out} is null. 386 */ 387 public void store(OutputStream out, String comments) 388 throws IOException 389 { this.properties.store(out, comments); } 390 391 /** 392 * Emits an XML document representing all of the properties contained in this table. 393 * 394 * <BR /><BR /> An invocation of this method of the form {@code props.storeToXML(os, comment)} 395 * behaves in exactly the same way as the invocation 396 * {@code props.storeToXML(os, comment, "UTF-8");}. 397 * 398 * @param os the output stream on which to emit the XML document. 399 * @param comment a description of the property list, or {@code null} if no comment is desired. 400 * 401 * @throws IOException if writing to the specified output stream results in an 402 * {@code IOException}. 403 * 404 * @throws NullPointerException if {@code os} is null. 405 * 406 * @throws ClassCastException if this {@code Properties} object contains any keys or values 407 * that are not {@code Strings}. 408 */ 409 public void storeToXML(OutputStream os, String comment) 410 throws IOException 411 { this.properties.storeToXML(os, comment); } 412 413 /** 414 * Emits an XML document representing all of the properties contained in this table, using the 415 * specified encoding. 416 * 417 * <EMBED CLASS='external-html' DATA-FILE-ID=STOREXML_DESC_OS_S_S> 418 * 419 * @param os the output stream on which to emit the XML document. 420 * @param comment a description of the property list, or {@code null} if no comment is desired. 421 * 422 * @param encoding the name of a supported 423 * <a href="../lang/package-summary.html#charenc">character encoding</a> 424 * 425 * @throws IOException if writing to the specified output stream results in an 426 * {@code IOException}. 427 * 428 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the 429 * implementation. 430 * 431 * @throws NullPointerException if {@code os} is {@code null}, or if {@code encoding} is 432 * {@code null}. 433 * 434 * @throws ClassCastException if this {@code Properties} object contains any keys or values 435 * that are not {@code Strings}. 436 * 437 * @spec https://www.w3.org/TR/xml Extensible Markup Language (XML) 1.0 (Fifth Edition) 438 * @see <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character Encoding in Entities</a> 439 */ 440 public void storeToXML(OutputStream os, String comment, String encoding) throws IOException 441 { this.properties.storeToXML(os, comment, encoding); } 442 443 /** 444 * Emits an XML document representing all of the properties contained in this table, using 445 * the specified encoding. 446 * 447 * <EMBED CLASS='external-html' DATA-FILE-ID=STOREXML_DESC_OS_S_CHRS> 448 * 449 * @param os the output stream on which to emit the XML document. 450 * @param comment a description of the property list, or {@code null} if no comment is desired. 451 * @param charset the charset 452 * 453 * @throws IOException if writing to the specified output stream results in an 454 * {@code IOException}. 455 * 456 * @throws NullPointerException if {@code os} or {@code charset} is {@code null}. 457 * 458 * @throws ClassCastException if this {@code Properties} object contains any keys or values 459 * that are not {@code Strings}. 460 * 461 * @spec https://www.w3.org/TR/xml Extensible Markup Language (XML) 1.0 (Fifth Edition) 462 * @see <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character Encoding in Entities</a> 463 */ 464 public void storeToXML(OutputStream os, String comment, Charset charset) throws IOException 465 { this.properties.storeToXML(os, comment, charset); } 466 467 /** 468 * Searches for the property with the specified key in this property list. If the key is not 469 * found in this property list, the default property list, and its defaults, recursively, are 470 * then checked. The method returns {@code null} if the property is not found. 471 * 472 * @param key the property key. 473 * @return the value in this property list with the specified key value. 474 */ 475 public String getProperty(String key) 476 { return this.properties.getProperty(key); } 477 478 /** 479 * Searches for the property with the specified key in this property list. If the key is not 480 * found in this property list, the default property list, and its defaults, recursively, are 481 * then checked. The method returns the default value argument if the property is not found. 482 * 483 * @param key the hashtable key. 484 * @param defaultValue a default value. 485 * 486 * @return the value in this property list with the specified key value. 487 */ 488 public String getProperty(String key, String defaultValue) 489 { return this.properties.getProperty(key, defaultValue); } 490 491 /** 492 * Returns an enumeration of all the keys in this property list, including distinct keys in 493 * the default property list if a key of the same name has not already been found from the main 494 * properties list. 495 * 496 * @return an enumeration of all the keys in this property list, including the keys in the 497 * default property list. 498 * 499 * @throws ClassCastException if any key in this property list is not a {@code String}. 500 * @see #stringPropertyNames 501 */ 502 public Enumeration<?> propertyNames() 503 { return this.properties.propertyNames(); } 504 505 /** 506 * Returns an unmodifiable set of keys from this property list where the key and its 507 * corresponding value are strings, including distinct keys in the default property list if a 508 * key of the same name has not already been found from the main properties list. Properties 509 * whose key or value is not of type {@code String} are omitted. 510 * 511 * <BR /><BR />The returned set is not backed by this {@code Properties} object. Changes to 512 * this {@code Properties} object are not reflected in the returned set. 513 * 514 * @return an unmodifiable set of keys in this property list where the key and its 515 * corresponding value are strings, including the keys in the default property list. 516 */ 517 @LinkJavaSource(handle="JavaHTMLReadOnlySet") 518 public ReadOnlySet<String> stringPropertyNames() 519 { return new JavaHTMLReadOnlySet<>(this.properties.stringPropertyNames()); } 520 521 /** 522 * Prints this property list out to the specified output stream. This method is useful for 523 * debugging. 524 * 525 * @param out an output stream. 526 * @throws ClassCastException if any key in this property list is not a {@code String}. 527 */ 528 public void list(PrintStream out) 529 { this.properties.list(out); } 530 531 /** 532 * Prints this property list out to the specified output stream. This method is useful for 533 * debugging. 534 * 535 * @param out an output stream. 536 * @throws ClassCastException if any key in this property list is not a {@code String}. 537 */ 538 public void list(PrintWriter out) 539 { this.properties.list(out); } 540 541 // 542 // Hashtable methods overridden and delegated to a ConcurrentHashMap instance 543 544 @Override 545 public int size() 546 { return this.properties.size(); } 547 548 @Override 549 public boolean isEmpty() 550 { return this.properties.isEmpty(); } 551 552 @Override 553 public Enumeration<Object> keys() 554 { return this.properties.keys(); } 555 556 @Override 557 public Enumeration<Object> elements() 558 { return this.properties.elements(); } 559 560 @Override 561 public boolean contains(Object value) 562 { return this.properties.contains(value); } 563 564 @Override 565 public boolean containsValue(Object value) 566 { return this.properties.containsValue(value); } 567 568 @Override 569 public boolean containsKey(Object key) 570 { return this.properties.containsKey(key); } 571 572 @Override 573 public Object get(Object key) 574 { return this.properties.get(key); } 575 576 @Override 577 @LinkJavaSource(handle="JavaHTMLReadOnlySet") 578 public ReadOnlySet<Object> keySet() 579 { 580 return new JavaHTMLReadOnlySet<>( 581 fromBuilderOrProperties 582 ? ((ROPropertiesBuilder) this.properties)._keySet(friendClassBadge) 583 : this.properties.keySet() 584 ); 585 } 586 587 @Override 588 @LinkJavaSource(handle="JavaHTMLReadOnlyCollection") 589 public ReadOnlyCollection<Object> values() 590 { 591 return new JavaHTMLReadOnlyCollection<>( 592 fromBuilderOrProperties 593 ? ((ROPropertiesBuilder) this.properties)._values(friendClassBadge) 594 : this.properties.values() 595 ); 596 } 597 598 @Override 599 @LinkJavaSource(handle="ROHelperEntrySet") 600 public ReadOnlySet<ReadOnlyMap.Entry<Object, Object>> entrySet() 601 { 602 return ROHelperEntrySet.toReadOnlyEntrySet( 603 fromBuilderOrProperties 604 ? ((ROPropertiesBuilder) this.properties)._entrySet(friendClassBadge) 605 : this.properties.entrySet() 606 ); 607 } 608 609 @Override 610 public Object getOrDefault(Object key, Object defaultValue) 611 { return this.properties.getOrDefault(key, defaultValue); } 612 613 @Override 614 public synchronized void forEach(BiConsumer<? super Object, ? super Object> action) 615 { this.properties.forEach(action); } 616 617 618 // ******************************************************************************************** 619 // ******************************************************************************************** 620 // Convert to java.util Types 621 // ******************************************************************************************** 622 // ******************************************************************************************** 623 624 625 /** 626 * Clone's {@code 'this'} instance internal {@code Properties} field, and returns it. 627 * <EMBED CLASS='external-html' DATA-TYPE=Properties DATA-FILE-ID=CLONE_TO> 628 * 629 * @return An independent, mutable copy of {@code 'this'} instance' internal 630 * {@code Properties} data-structure. 631 */ 632 public Properties cloneToProperties() 633 { 634 return fromBuilderOrProperties 635 ? new Properties(this.properties) 636 : (Properties) this.properties.clone(); 637 } 638 639 /** 640 * <BR>Same: Identical to the method {@link #cloneToProperties()}. 641 * <BR>Returns: Has Return-Type {@code Map<E>}, instead. 642 * <BR>Implements: Parent-Class {@link ReadOnlyMap#cloneToMap} 643 */ 644 @Torello.JavaDoc.IntoHTMLTable(title="Converts this ReadOnlyProperties to a java.util.Properties") 645 public Map<Object, Object> cloneToMap() { return cloneToProperties(); } 646 647 // Documented in the Implemented-Interface ReadOnlyMap 648 public Map<Object, Object> wrapToImmutableMap() 649 { return Collections.unmodifiableMap(this.properties); } 650 651 652 // ******************************************************************************************** 653 // ******************************************************************************************** 654 // java.lang.Object 655 // ******************************************************************************************** 656 // ******************************************************************************************** 657 658 659 /** 660 * Returns a {@code String} representation of this {@code Properties}. The {@code String} 661 * representation consists of a list of the collection's elements in the order they are 662 * returned by its iterator, enclosed in square brackets ({@code "[]"}). Adjacent elements are 663 * separated by the characters {@code ", "} (comma and space). Elements are converted to 664 * {@code String's} as by {@code String.valueOf(Object)}. 665 * 666 * @return a {@code String} representation of this {@code Properties} 667 */ 668 @Override 669 public String toString() 670 { return this.properties.toString(); } 671 672 /** 673 * Compares the specified Object with this List for equality, as per the definition in the 674 * class {@code java.util.Properties}. 675 * 676 * @param o object to be compared for equality with this {@code Properties} 677 * @return {@code TRUE} if the specified Object is equal to this map 678 */ 679 @Override 680 public boolean equals(Object o) 681 { 682 if (this == o) return true; 683 if (! (o instanceof ReadOnlyProperties)) return false; 684 return this.properties.equals(((ReadOnlyProperties) o).properties); 685 } 686 687 @Override 688 public synchronized int hashCode() 689 { return this.properties.hashCode(); } 690}