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