1 /* 2 * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.util; 27 28 import java.io.IOException; 29 import java.io.PrintStream; 30 import java.io.PrintWriter; 31 import java.io.InputStream; 32 import java.io.OutputStream; 33 import java.io.Reader; 34 import java.io.Writer; 35 import java.io.OutputStreamWriter; 36 import java.io.BufferedWriter; 37 import java.lang.reflect.*; 38 39 /** 40 * The <code>Properties</code> class represents a persistent set of 41 * properties. The <code>Properties</code> can be saved to a stream 42 * or loaded from a stream. Each key and its corresponding value in 43 * the property list is a string. 44 * <p> 45 * A property list can contain another property list as its 46 * "defaults"; this second property list is searched if 47 * the property key is not found in the original property list. 48 * <p> 49 * Because <code>Properties</code> inherits from <code>Hashtable</code>, the 50 * <code>put</code> and <code>putAll</code> methods can be applied to a 51 * <code>Properties</code> object. Their use is strongly discouraged as they 52 * allow the caller to insert entries whose keys or values are not 53 * <code>Strings</code>. The <code>setProperty</code> method should be used 54 * instead. If the <code>store</code> or <code>save</code> method is called 55 * on a "compromised" <code>Properties</code> object that contains a 56 * non-<code>String</code> key or value, the call will fail. Similarly, 57 * the call to the <code>propertyNames</code> or <code>list</code> method 58 * will fail if it is called on a "compromised" <code>Properties</code> 59 * object that contains a non-<code>String</code> key. 60 * 61 * <p> 62 * The {@link #load(java.io.Reader) load(Reader)} <tt>/</tt> 63 * {@link #store(java.io.Writer, java.lang.String) store(Writer, String)} 64 * methods load and store properties from and to a character based stream 65 * in a simple line-oriented format specified below. 66 * 67 * The {@link #load(java.io.InputStream) load(InputStream)} <tt>/</tt> 68 * {@link #store(java.io.OutputStream, java.lang.String) store(OutputStream, String)} 69 * methods work the same way as the load(Reader)/store(Writer, String) pair, except 70 * the input/output stream is encoded in ISO 8859-1 character encoding. 71 * Characters that cannot be directly represented in this encoding can be written using 72 * Unicode escapes as defined in section 3.3 of 73 * <cite>The Java™ Language Specification</cite>; 74 * only a single 'u' character is allowed in an escape 75 * sequence. The native2ascii tool can be used to convert property files to and 76 * from other character encodings. 77 * 78 * <p> The {@link #loadFromXML(InputStream)} and {@link 79 * #storeToXML(OutputStream, String, String)} methods load and store properties 129 */ 130 protected Properties defaults; 131 132 /** 133 * Creates an empty property list with no default values. 134 */ 135 public Properties() { 136 this(null); 137 } 138 139 /** 140 * Creates an empty property list with the specified defaults. 141 * 142 * @param defaults the defaults. 143 */ 144 public Properties(Properties defaults) { 145 this.defaults = defaults; 146 } 147 148 /** 149 * Calls the <tt>Hashtable</tt> method <code>put</code>. Provided for 150 * parallelism with the <tt>getProperty</tt> method. Enforces use of 151 * strings for property keys and values. The value returned is the 152 * result of the <tt>Hashtable</tt> call to <code>put</code>. 153 * 154 * @param key the key to be placed into this property list. 155 * @param value the value corresponding to <tt>key</tt>. 156 * @return the previous value of the specified key in this property 157 * list, or <code>null</code> if it did not have one. 158 * @see #getProperty 159 * @since 1.2 160 */ 161 public synchronized Object setProperty(String key, String value) { 162 return put(key, value); 163 } 164 165 166 /** 167 * Reads a property list (key and element pairs) from the input 168 * character stream in a simple line-oriented format. 169 * <p> 170 * Properties are processed in terms of lines. There are two 171 * kinds of line, <i>natural lines</i> and <i>logical lines</i>. 172 * A natural line is defined as a line of 173 * characters that is terminated either by a set of line terminator 174 * characters (<code>\n</code> or <code>\r</code> or <code>\r\n</code>) 175 * or by the end of the stream. A natural line may be either a blank line, 176 * a comment line, or hold all or some of a key-element pair. A logical 177 * line holds all the data of a key-element pair, which may be spread 178 * out across several adjacent natural lines by escaping 179 * the line terminator sequence with a backslash character 180 * <code>\</code>. Note that a comment line cannot be extended 181 * in this manner; every natural line that is a comment must have 182 * its own comment indicator, as described below. Lines are read from 183 * input until the end of the stream is reached. 184 * 185 * <p> 186 * A natural line that contains only white space characters is 187 * considered blank and is ignored. A comment line has an ASCII 188 * <code>'#'</code> or <code>'!'</code> as its first non-white 189 * space character; comment lines are also ignored and do not 190 * encode key-element information. In addition to line 191 * terminators, this format considers the characters space 192 * (<code>' '</code>, <code>'\u0020'</code>), tab 193 * (<code>'\t'</code>, <code>'\u0009'</code>), and form feed 194 * (<code>'\f'</code>, <code>'\u000C'</code>) to be white 195 * space. 196 * 197 * <p> 198 * If a logical line is spread across several natural lines, the 199 * backslash escaping the line terminator sequence, the line 200 * terminator sequence, and any white space at the start of the 201 * following line have no affect on the key or element values. 202 * The remainder of the discussion of key and element parsing 203 * (when loading) will assume all the characters constituting 204 * the key and element appear on a single natural line after 205 * line continuation characters have been removed. Note that 206 * it is <i>not</i> sufficient to only examine the character 207 * preceding a line terminator sequence to decide if the line 208 * terminator is escaped; there must be an odd number of 209 * contiguous backslashes for the line terminator to be escaped. 210 * Since the input is processed from left to right, a 211 * non-zero even number of 2<i>n</i> contiguous backslashes 212 * before a line terminator (or elsewhere) encodes <i>n</i> 213 * backslashes after escape processing. 214 * 215 * <p> 216 * The key contains all of the characters in the line starting 217 * with the first non-white space character and up to, but not 218 * including, the first unescaped <code>'='</code>, 219 * <code>':'</code>, or white space character other than a line 220 * terminator. All of these key termination characters may be 221 * included in the key by escaping them with a preceding backslash 222 * character; for example,<p> 223 * 224 * <code>\:\=</code><p> 225 * 226 * would be the two-character key <code>":="</code>. Line 227 * terminator characters can be included using <code>\r</code> and 228 * <code>\n</code> escape sequences. Any white space after the 229 * key is skipped; if the first non-white space character after 230 * the key is <code>'='</code> or <code>':'</code>, then it is 231 * ignored and any white space characters after it are also 232 * skipped. All remaining characters on the line become part of 233 * the associated element string; if there are no remaining 234 * characters, the element is the empty string 235 * <code>""</code>. Once the raw character sequences 236 * constituting the key and element are identified, escape 237 * processing is performed as described above. 238 * 239 * <p> 240 * As an example, each of the following three lines specifies the key 241 * <code>"Truth"</code> and the associated element value 242 * <code>"Beauty"</code>: 243 * <p> 244 * <pre> 245 * Truth = Beauty 246 * Truth:Beauty 247 * Truth :Beauty 248 * </pre> 249 * As another example, the following three lines specify a single 250 * property: 251 * <p> 252 * <pre> 253 * fruits apple, banana, pear, \ 254 * cantaloupe, watermelon, \ 255 * kiwi, mango 256 * </pre> 257 * The key is <code>"fruits"</code> and the associated element is: 258 * <p> 259 * <pre>"apple, banana, pear, cantaloupe, watermelon, kiwi, mango"</pre> 260 * Note that a space appears before each <code>\</code> so that a space 261 * will appear after each comma in the final result; the <code>\</code>, 262 * line terminator, and leading white space on the continuation line are 263 * merely discarded and are <i>not</i> replaced by one or more other 264 * characters. 265 * <p> 266 * As a third example, the line: 267 * <p> 268 * <pre>cheeses 269 * </pre> 270 * specifies that the key is <code>"cheeses"</code> and the associated 271 * element is the empty string <code>""</code>.<p> 272 * <p> 273 * 274 * <a name="unicodeescapes"></a> 275 * Characters in keys and elements can be represented in escape 276 * sequences similar to those used for character and string literals 277 * (see sections 3.3 and 3.10.6 of 278 * <cite>The Java™ Language Specification</cite>). 279 * 280 * The differences from the character escape sequences and Unicode 281 * escapes used for characters and strings are: 282 * 283 * <ul> 284 * <li> Octal escapes are not recognized. 285 * 286 * <li> The character sequence <code>\b</code> does <i>not</i> 287 * represent a backspace character. 288 * 289 * <li> The method does not treat a backslash character, 290 * <code>\</code>, before a non-valid escape character as an 291 * error; the backslash is silently dropped. For example, in a 292 * Java string the sequence <code>"\z"</code> would cause a 293 * compile time error. In contrast, this method silently drops 294 * the backslash. Therefore, this method treats the two character 295 * sequence <code>"\b"</code> as equivalent to the single 296 * character <code>'b'</code>. 297 * 298 * <li> Escapes are not necessary for single and double quotes; 299 * however, by the rule above, single and double quote characters 300 * preceded by a backslash still yield single and double quote 301 * characters, respectively. 302 * 303 * <li> Only a single 'u' character is allowed in a Uniocde escape 304 * sequence. 305 * 306 * </ul> 307 * <p> 308 * The specified stream remains open after this method returns. 309 * 310 * @param reader the input character stream. 311 * @throws IOException if an error occurred when reading from the 312 * input stream. 313 * @throws IllegalArgumentException if a malformed Unicode escape 314 * appears in the input. 315 * @since 1.6 316 */ 672 if (c == '\r' && 673 current != len - 1 && 674 comments.charAt(current + 1) == '\n') { 675 current++; 676 } 677 if (current == len - 1 || 678 (comments.charAt(current + 1) != '#' && 679 comments.charAt(current + 1) != '!')) 680 bw.write("#"); 681 } 682 last = current + 1; 683 } 684 current++; 685 } 686 if (last != current) 687 bw.write(comments.substring(last, current)); 688 bw.newLine(); 689 } 690 691 /** 692 * Calls the <code>store(OutputStream out, String comments)</code> method 693 * and suppresses IOExceptions that were thrown. 694 * 695 * @deprecated This method does not throw an IOException if an I/O error 696 * occurs while saving the property list. The preferred way to save a 697 * properties list is via the <code>store(OutputStream out, 698 * String comments)</code> method or the 699 * <code>storeToXML(OutputStream os, String comment)</code> method. 700 * 701 * @param out an output stream. 702 * @param comments a description of the property list. 703 * @exception ClassCastException if this <code>Properties</code> object 704 * contains any keys or values that are not 705 * <code>Strings</code>. 706 */ 707 @Deprecated 708 public void save(OutputStream out, String comments) { 709 try { 710 store(out, comments); 711 } catch (IOException e) { 712 } 713 } 714 715 /** 716 * Writes this property list (key and element pairs) in this 717 * <code>Properties</code> table to the output character stream in a 718 * format suitable for using the {@link #load(java.io.Reader) load(Reader)} 719 * method. 720 * <p> 721 * Properties from the defaults table of this <code>Properties</code> 722 * table (if any) are <i>not</i> written out by this method. 723 * <p> 724 * If the comments argument is not null, then an ASCII <code>#</code> 725 * character, the comments string, and a line separator are first written 726 * to the output stream. Thus, the <code>comments</code> can serve as an 727 * identifying comment. Any one of a line feed ('\n'), a carriage 728 * return ('\r'), or a carriage return followed immediately by a line feed 729 * in comments is replaced by a line separator generated by the <code>Writer</code> 730 * and if the next character in comments is not character <code>#</code> or 731 * character <code>!</code> then an ASCII <code>#</code> is written out 732 * after that line separator. 733 * <p> 734 * Next, a comment line is always written, consisting of an ASCII 735 * <code>#</code> character, the current date and time (as if produced 736 * by the <code>toString</code> method of <code>Date</code> for the 737 * current time), and a line separator as generated by the <code>Writer</code>. 738 * <p> 739 * Then every entry in this <code>Properties</code> table is 740 * written out, one per line. For each entry the key string is 741 * written, then an ASCII <code>=</code>, then the associated 742 * element string. For the key, all space characters are 743 * written with a preceding <code>\</code> character. For the 744 * element, leading space characters, but not embedded or trailing 745 * space characters, are written with a preceding <code>\</code> 746 * character. The key and element characters <code>#</code>, 747 * <code>!</code>, <code>=</code>, and <code>:</code> are written 748 * with a preceding backslash to ensure that they are properly loaded. 749 * <p> 750 * After the entries have been written, the output stream is flushed. 751 * The output stream remains open after this method returns. 752 * <p> 753 * 754 * @param writer an output character stream writer. 755 * @param comments a description of the property list. 756 * @exception IOException if writing this property list to the specified 757 * output stream throws an <tt>IOException</tt>. 758 * @exception ClassCastException if this <code>Properties</code> object 759 * contains any keys or values that are not <code>Strings</code>. 760 * @exception NullPointerException if <code>writer</code> is null. 761 * @since 1.6 762 */ 763 public void store(Writer writer, String comments) 764 throws IOException 765 { 766 store0((writer instanceof BufferedWriter)?(BufferedWriter)writer 767 : new BufferedWriter(writer), 768 comments, 769 false); 770 } 771 772 /** 773 * Writes this property list (key and element pairs) in this 774 * <code>Properties</code> table to the output stream in a format suitable 775 * for loading into a <code>Properties</code> table using the 776 * {@link #load(InputStream) load(InputStream)} method. 777 * <p> 778 * Properties from the defaults table of this <code>Properties</code> 779 * table (if any) are <i>not</i> written out by this method. 780 * <p> 781 * This method outputs the comments, properties keys and values in 782 * the same format as specified in 783 * {@link #store(java.io.Writer, java.lang.String) store(Writer)}, 784 * with the following differences: 785 * <ul> 786 * <li>The stream is written using the ISO 8859-1 character encoding. 787 * 788 * <li>Characters not in Latin-1 in the comments are written as 789 * <code>\u</code><i>xxxx</i> for their appropriate unicode 790 * hexadecimal value <i>xxxx</i>. 791 * 792 * <li>Characters less than <code>\u0020</code> and characters greater 793 * than <code>\u007E</code> in property keys or values are written 794 * as <code>\u</code><i>xxxx</i> for the appropriate hexadecimal 795 * value <i>xxxx</i>. 796 * </ul> 797 * <p> 798 * After the entries have been written, the output stream is flushed. 799 * The output stream remains open after this method returns. 800 * <p> 801 * @param out an output stream. 802 * @param comments a description of the property list. 803 * @exception IOException if writing this property list to the specified 804 * output stream throws an <tt>IOException</tt>. 805 * @exception ClassCastException if this <code>Properties</code> object 806 * contains any keys or values that are not <code>Strings</code>. 807 * @exception NullPointerException if <code>out</code> is null. 808 * @since 1.2 809 */ 810 public void store(OutputStream out, String comments) 811 throws IOException 812 { 813 store0(new BufferedWriter(new OutputStreamWriter(out, "8859_1")), 814 comments, 815 true); 816 } 817 818 private void store0(BufferedWriter bw, String comments, boolean escUnicode) 819 throws IOException 820 { 821 if (comments != null) { 822 writeComments(bw, comments); 823 } 824 bw.write("#" + new Date().toString()); 825 bw.newLine(); 826 synchronized (this) { 827 for (Enumeration e = keys(); e.hasMoreElements();) { 840 } 841 842 /** 843 * Loads all of the properties represented by the XML document on the 844 * specified input stream into this properties table. 845 * 846 * <p>The XML document must have the following DOCTYPE declaration: 847 * <pre> 848 * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> 849 * </pre> 850 * Furthermore, the document must satisfy the properties DTD described 851 * above. 852 * 853 * <p>The specified stream is closed after this method returns. 854 * 855 * @param in the input stream from which to read the XML document. 856 * @throws IOException if reading from the specified input stream 857 * results in an <tt>IOException</tt>. 858 * @throws InvalidPropertiesFormatException Data on input stream does not 859 * constitute a valid XML document with the mandated document type. 860 * @throws NullPointerException if <code>in</code> is null. 861 * @see #storeToXML(OutputStream, String, String) 862 * @since 1.5 863 */ 864 public synchronized void loadFromXML(InputStream in) 865 throws IOException, InvalidPropertiesFormatException 866 { 867 if (in == null) 868 throw new NullPointerException(); 869 XMLUtils.load(this, in); 870 in.close(); 871 } 872 873 /** 874 * Emits an XML document representing all of the properties contained 875 * in this table. 876 * 877 * <p> An invocation of this method of the form <tt>props.storeToXML(os, 878 * comment)</tt> behaves in exactly the same way as the invocation 879 * <tt>props.storeToXML(os, comment, "UTF-8");</tt>. 880 * 881 * @param os the output stream on which to emit the XML document. 882 * @param comment a description of the property list, or <code>null</code> 883 * if no comment is desired. 884 * @throws IOException if writing to the specified output stream 885 * results in an <tt>IOException</tt>. 886 * @throws NullPointerException if <code>os</code> is null. 887 * @throws ClassCastException if this <code>Properties</code> object 888 * contains any keys or values that are not 889 * <code>Strings</code>. 890 * @see #loadFromXML(InputStream) 891 * @since 1.5 892 */ 893 public void storeToXML(OutputStream os, String comment) 894 throws IOException 895 { 896 if (os == null) 897 throw new NullPointerException(); 898 storeToXML(os, comment, "UTF-8"); 899 } 900 901 /** 902 * Emits an XML document representing all of the properties contained 903 * in this table, using the specified encoding. 904 * 905 * <p>The XML document will have the following DOCTYPE declaration: 906 * <pre> 907 * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> 908 * </pre> 909 * 910 *<p>If the specified comment is <code>null</code> then no comment 911 * will be stored in the document. 912 * 913 * <p>The specified stream remains open after this method returns. 914 * 915 * @param os the output stream on which to emit the XML document. 916 * @param comment a description of the property list, or <code>null</code> 917 * if no comment is desired. 918 * @param encoding the name of a supported 919 * <a href="../lang/package-summary.html#charenc"> 920 * character encoding</a> 921 * 922 * @throws IOException if writing to the specified output stream 923 * results in an <tt>IOException</tt>. 924 * @throws NullPointerException if <code>os</code> is <code>null</code>, 925 * or if <code>encoding</code> is <code>null</code>. 926 * @throws ClassCastException if this <code>Properties</code> object 927 * contains any keys or values that are not 928 * <code>Strings</code>. 929 * @see #loadFromXML(InputStream) 930 * @since 1.5 931 */ 932 public void storeToXML(OutputStream os, String comment, String encoding) 933 throws IOException 934 { 935 if (os == null) 936 throw new NullPointerException(); 937 XMLUtils.save(this, os, comment, encoding); 938 } 939 940 /** 941 * Searches for the property with the specified key in this property list. 942 * If the key is not found in this property list, the default property list, 943 * and its defaults, recursively, are then checked. The method returns 944 * <code>null</code> if the property is not found. 945 * 946 * @param key the property key. 947 * @return the value in this property list with the specified key value. 948 * @see #setProperty 949 * @see #defaults 950 */ 951 public String getProperty(String key) { 952 Object oval = super.get(key); 953 String sval = (oval instanceof String) ? (String)oval : null; 954 return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval; 955 } 956 957 /** 958 * Searches for the property with the specified key in this property list. 959 * If the key is not found in this property list, the default property list, 960 * and its defaults, recursively, are then checked. The method returns the 961 * default value argument if the property is not found. 962 * 963 * @param key the hashtable key. 964 * @param defaultValue a default value. | 1 /* 2 * Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.util; 27 28 import java.io.IOException; 29 import java.io.PrintStream; 30 import java.io.PrintWriter; 31 import java.io.InputStream; 32 import java.io.OutputStream; 33 import java.io.Reader; 34 import java.io.Writer; 35 import java.io.OutputStreamWriter; 36 import java.io.BufferedWriter; 37 import java.lang.reflect.*; 38 39 /** 40 * The {@code Properties} class represents a persistent set of 41 * properties. The {@code Properties} can be saved to a stream 42 * or loaded from a stream. Each key and its corresponding value in 43 * the property list is a string. 44 * <p> 45 * A property list can contain another property list as its 46 * "defaults"; this second property list is searched if 47 * the property key is not found in the original property list. 48 * <p> 49 * Because {@code Properties} inherits from {@code Hashtable}, the 50 * {@code put} and {@code putAll} methods can be applied to a 51 * {@code Properties} object. Their use is strongly discouraged as they 52 * allow the caller to insert entries whose keys or values are not 53 * {@code Strings}. The {@code setProperty} method should be used 54 * instead. If the {@code store} or {@code save} method is called 55 * on a "compromised" {@code Properties} object that contains a 56 * non-{@code String} key or value, the call will fail. Similarly, 57 * the call to the {@code propertyNames} or {@code list} method 58 * will fail if it is called on a "compromised" {@code Properties} 59 * object that contains a non-{@code String} key. 60 * 61 * <p> 62 * The {@link #load(java.io.Reader) load(Reader)} <tt>/</tt> 63 * {@link #store(java.io.Writer, java.lang.String) store(Writer, String)} 64 * methods load and store properties from and to a character based stream 65 * in a simple line-oriented format specified below. 66 * 67 * The {@link #load(java.io.InputStream) load(InputStream)} <tt>/</tt> 68 * {@link #store(java.io.OutputStream, java.lang.String) store(OutputStream, String)} 69 * methods work the same way as the load(Reader)/store(Writer, String) pair, except 70 * the input/output stream is encoded in ISO 8859-1 character encoding. 71 * Characters that cannot be directly represented in this encoding can be written using 72 * Unicode escapes as defined in section 3.3 of 73 * <cite>The Java™ Language Specification</cite>; 74 * only a single 'u' character is allowed in an escape 75 * sequence. The native2ascii tool can be used to convert property files to and 76 * from other character encodings. 77 * 78 * <p> The {@link #loadFromXML(InputStream)} and {@link 79 * #storeToXML(OutputStream, String, String)} methods load and store properties 129 */ 130 protected Properties defaults; 131 132 /** 133 * Creates an empty property list with no default values. 134 */ 135 public Properties() { 136 this(null); 137 } 138 139 /** 140 * Creates an empty property list with the specified defaults. 141 * 142 * @param defaults the defaults. 143 */ 144 public Properties(Properties defaults) { 145 this.defaults = defaults; 146 } 147 148 /** 149 * Calls the <tt>Hashtable</tt> method {@code put}. Provided for 150 * parallelism with the <tt>getProperty</tt> method. Enforces use of 151 * strings for property keys and values. The value returned is the 152 * result of the <tt>Hashtable</tt> call to {@code put}. 153 * 154 * @param key the key to be placed into this property list. 155 * @param value the value corresponding to <tt>key</tt>. 156 * @return the previous value of the specified key in this property 157 * list, or {@code null} if it did not have one. 158 * @see #getProperty 159 * @since 1.2 160 */ 161 public synchronized Object setProperty(String key, String value) { 162 return put(key, value); 163 } 164 165 166 /** 167 * Reads a property list (key and element pairs) from the input 168 * character stream in a simple line-oriented format. 169 * <p> 170 * Properties are processed in terms of lines. There are two 171 * kinds of line, <i>natural lines</i> and <i>logical lines</i>. 172 * A natural line is defined as a line of 173 * characters that is terminated either by a set of line terminator 174 * characters ({@code \n} or {@code \r} or {@code \r\n}) 175 * or by the end of the stream. A natural line may be either a blank line, 176 * a comment line, or hold all or some of a key-element pair. A logical 177 * line holds all the data of a key-element pair, which may be spread 178 * out across several adjacent natural lines by escaping 179 * the line terminator sequence with a backslash character 180 * {@code \}. Note that a comment line cannot be extended 181 * in this manner; every natural line that is a comment must have 182 * its own comment indicator, as described below. Lines are read from 183 * input until the end of the stream is reached. 184 * 185 * <p> 186 * A natural line that contains only white space characters is 187 * considered blank and is ignored. A comment line has an ASCII 188 * {@code '#'} or {@code '!'} as its first non-white 189 * space character; comment lines are also ignored and do not 190 * encode key-element information. In addition to line 191 * terminators, this format considers the characters space 192 * ({@code ' '}, {@code '\u005Cu0020'}), tab 193 * ({@code '\t'}, {@code '\u005Cu0009'}), and form feed 194 * ({@code '\f'}, {@code '\u005Cu000C'}) to be white 195 * space. 196 * 197 * <p> 198 * If a logical line is spread across several natural lines, the 199 * backslash escaping the line terminator sequence, the line 200 * terminator sequence, and any white space at the start of the 201 * following line have no affect on the key or element values. 202 * The remainder of the discussion of key and element parsing 203 * (when loading) will assume all the characters constituting 204 * the key and element appear on a single natural line after 205 * line continuation characters have been removed. Note that 206 * it is <i>not</i> sufficient to only examine the character 207 * preceding a line terminator sequence to decide if the line 208 * terminator is escaped; there must be an odd number of 209 * contiguous backslashes for the line terminator to be escaped. 210 * Since the input is processed from left to right, a 211 * non-zero even number of 2<i>n</i> contiguous backslashes 212 * before a line terminator (or elsewhere) encodes <i>n</i> 213 * backslashes after escape processing. 214 * 215 * <p> 216 * The key contains all of the characters in the line starting 217 * with the first non-white space character and up to, but not 218 * including, the first unescaped {@code '='}, 219 * {@code ':'}, or white space character other than a line 220 * terminator. All of these key termination characters may be 221 * included in the key by escaping them with a preceding backslash 222 * character; for example,<p> 223 * 224 * {@code \:\=}<p> 225 * 226 * would be the two-character key {@code ":="}. Line 227 * terminator characters can be included using {@code \r} and 228 * {@code \n} escape sequences. Any white space after the 229 * key is skipped; if the first non-white space character after 230 * the key is {@code '='} or {@code ':'}, then it is 231 * ignored and any white space characters after it are also 232 * skipped. All remaining characters on the line become part of 233 * the associated element string; if there are no remaining 234 * characters, the element is the empty string 235 * {@code ""}. Once the raw character sequences 236 * constituting the key and element are identified, escape 237 * processing is performed as described above. 238 * 239 * <p> 240 * As an example, each of the following three lines specifies the key 241 * {@code "Truth"} and the associated element value 242 * {@code "Beauty"}: 243 * <p> 244 * <pre> 245 * Truth = Beauty 246 * Truth:Beauty 247 * Truth :Beauty 248 * </pre> 249 * As another example, the following three lines specify a single 250 * property: 251 * <p> 252 * <pre> 253 * fruits apple, banana, pear, \ 254 * cantaloupe, watermelon, \ 255 * kiwi, mango 256 * </pre> 257 * The key is {@code "fruits"} and the associated element is: 258 * <p> 259 * <pre>"apple, banana, pear, cantaloupe, watermelon, kiwi, mango"</pre> 260 * Note that a space appears before each {@code \} so that a space 261 * will appear after each comma in the final result; the {@code \}, 262 * line terminator, and leading white space on the continuation line are 263 * merely discarded and are <i>not</i> replaced by one or more other 264 * characters. 265 * <p> 266 * As a third example, the line: 267 * <p> 268 * <pre>cheeses 269 * </pre> 270 * specifies that the key is {@code "cheeses"} and the associated 271 * element is the empty string {@code ""}.<p> 272 * <p> 273 * 274 * <a name="unicodeescapes"></a> 275 * Characters in keys and elements can be represented in escape 276 * sequences similar to those used for character and string literals 277 * (see sections 3.3 and 3.10.6 of 278 * <cite>The Java™ Language Specification</cite>). 279 * 280 * The differences from the character escape sequences and Unicode 281 * escapes used for characters and strings are: 282 * 283 * <ul> 284 * <li> Octal escapes are not recognized. 285 * 286 * <li> The character sequence {@code \b} does <i>not</i> 287 * represent a backspace character. 288 * 289 * <li> The method does not treat a backslash character, 290 * {@code \}, before a non-valid escape character as an 291 * error; the backslash is silently dropped. For example, in a 292 * Java string the sequence {@code "\z"} would cause a 293 * compile time error. In contrast, this method silently drops 294 * the backslash. Therefore, this method treats the two character 295 * sequence {@code "\b"} as equivalent to the single 296 * character {@code 'b'}. 297 * 298 * <li> Escapes are not necessary for single and double quotes; 299 * however, by the rule above, single and double quote characters 300 * preceded by a backslash still yield single and double quote 301 * characters, respectively. 302 * 303 * <li> Only a single 'u' character is allowed in a Uniocde escape 304 * sequence. 305 * 306 * </ul> 307 * <p> 308 * The specified stream remains open after this method returns. 309 * 310 * @param reader the input character stream. 311 * @throws IOException if an error occurred when reading from the 312 * input stream. 313 * @throws IllegalArgumentException if a malformed Unicode escape 314 * appears in the input. 315 * @since 1.6 316 */ 672 if (c == '\r' && 673 current != len - 1 && 674 comments.charAt(current + 1) == '\n') { 675 current++; 676 } 677 if (current == len - 1 || 678 (comments.charAt(current + 1) != '#' && 679 comments.charAt(current + 1) != '!')) 680 bw.write("#"); 681 } 682 last = current + 1; 683 } 684 current++; 685 } 686 if (last != current) 687 bw.write(comments.substring(last, current)); 688 bw.newLine(); 689 } 690 691 /** 692 * Calls the {@code store(OutputStream out, String comments)} method 693 * and suppresses IOExceptions that were thrown. 694 * 695 * @deprecated This method does not throw an IOException if an I/O error 696 * occurs while saving the property list. The preferred way to save a 697 * properties list is via the {@code store(OutputStream out, 698 * String comments)} method or the 699 * {@code storeToXML(OutputStream os, String comment)} method. 700 * 701 * @param out an output stream. 702 * @param comments a description of the property list. 703 * @exception ClassCastException if this {@code Properties} object 704 * contains any keys or values that are not 705 * {@code Strings}. 706 */ 707 @Deprecated 708 public void save(OutputStream out, String comments) { 709 try { 710 store(out, comments); 711 } catch (IOException e) { 712 } 713 } 714 715 /** 716 * Writes this property list (key and element pairs) in this 717 * {@code Properties} table to the output character stream in a 718 * format suitable for using the {@link #load(java.io.Reader) load(Reader)} 719 * method. 720 * <p> 721 * Properties from the defaults table of this {@code Properties} 722 * table (if any) are <i>not</i> written out by this method. 723 * <p> 724 * If the comments argument is not null, then an ASCII {@code #} 725 * character, the comments string, and a line separator are first written 726 * to the output stream. Thus, the {@code comments} can serve as an 727 * identifying comment. Any one of a line feed ('\n'), a carriage 728 * return ('\r'), or a carriage return followed immediately by a line feed 729 * in comments is replaced by a line separator generated by the {@code Writer} 730 * and if the next character in comments is not character {@code #} or 731 * character {@code !} then an ASCII {@code #} is written out 732 * after that line separator. 733 * <p> 734 * Next, a comment line is always written, consisting of an ASCII 735 * {@code #} character, the current date and time (as if produced 736 * by the {@code toString} method of {@code Date} for the 737 * current time), and a line separator as generated by the {@code Writer}. 738 * <p> 739 * Then every entry in this {@code Properties} table is 740 * written out, one per line. For each entry the key string is 741 * written, then an ASCII {@code =}, then the associated 742 * element string. For the key, all space characters are 743 * written with a preceding {@code \} character. For the 744 * element, leading space characters, but not embedded or trailing 745 * space characters, are written with a preceding {@code \} 746 * character. The key and element characters {@code #}, 747 * {@code !}, {@code =}, and {@code :} are written 748 * with a preceding backslash to ensure that they are properly loaded. 749 * <p> 750 * After the entries have been written, the output stream is flushed. 751 * The output stream remains open after this method returns. 752 * <p> 753 * 754 * @param writer an output character stream writer. 755 * @param comments a description of the property list. 756 * @exception IOException if writing this property list to the specified 757 * output stream throws an <tt>IOException</tt>. 758 * @exception ClassCastException if this {@code Properties} object 759 * contains any keys or values that are not {@code Strings}. 760 * @exception NullPointerException if {@code writer} is null. 761 * @since 1.6 762 */ 763 public void store(Writer writer, String comments) 764 throws IOException 765 { 766 store0((writer instanceof BufferedWriter)?(BufferedWriter)writer 767 : new BufferedWriter(writer), 768 comments, 769 false); 770 } 771 772 /** 773 * Writes this property list (key and element pairs) in this 774 * {@code Properties} table to the output stream in a format suitable 775 * for loading into a {@code Properties} table using the 776 * {@link #load(InputStream) load(InputStream)} method. 777 * <p> 778 * Properties from the defaults table of this {@code Properties} 779 * table (if any) are <i>not</i> written out by this method. 780 * <p> 781 * This method outputs the comments, properties keys and values in 782 * the same format as specified in 783 * {@link #store(java.io.Writer, java.lang.String) store(Writer)}, 784 * with the following differences: 785 * <ul> 786 * <li>The stream is written using the ISO 8859-1 character encoding. 787 * 788 * <li>Characters not in Latin-1 in the comments are written as 789 * {@code \u005Cu}<i>xxxx</i> for their appropriate unicode 790 * hexadecimal value <i>xxxx</i>. 791 * 792 * <li>Characters less than {@code \u005Cu0020} and characters greater 793 * than {@code \u005Cu007E} in property keys or values are written 794 * as {@code \u005Cu}<i>xxxx</i> for the appropriate hexadecimal 795 * value <i>xxxx</i>. 796 * </ul> 797 * <p> 798 * After the entries have been written, the output stream is flushed. 799 * The output stream remains open after this method returns. 800 * <p> 801 * @param out an output stream. 802 * @param comments a description of the property list. 803 * @exception IOException if writing this property list to the specified 804 * output stream throws an <tt>IOException</tt>. 805 * @exception ClassCastException if this {@code Properties} object 806 * contains any keys or values that are not {@code Strings}. 807 * @exception NullPointerException if {@code out} is null. 808 * @since 1.2 809 */ 810 public void store(OutputStream out, String comments) 811 throws IOException 812 { 813 store0(new BufferedWriter(new OutputStreamWriter(out, "8859_1")), 814 comments, 815 true); 816 } 817 818 private void store0(BufferedWriter bw, String comments, boolean escUnicode) 819 throws IOException 820 { 821 if (comments != null) { 822 writeComments(bw, comments); 823 } 824 bw.write("#" + new Date().toString()); 825 bw.newLine(); 826 synchronized (this) { 827 for (Enumeration e = keys(); e.hasMoreElements();) { 840 } 841 842 /** 843 * Loads all of the properties represented by the XML document on the 844 * specified input stream into this properties table. 845 * 846 * <p>The XML document must have the following DOCTYPE declaration: 847 * <pre> 848 * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> 849 * </pre> 850 * Furthermore, the document must satisfy the properties DTD described 851 * above. 852 * 853 * <p>The specified stream is closed after this method returns. 854 * 855 * @param in the input stream from which to read the XML document. 856 * @throws IOException if reading from the specified input stream 857 * results in an <tt>IOException</tt>. 858 * @throws InvalidPropertiesFormatException Data on input stream does not 859 * constitute a valid XML document with the mandated document type. 860 * @throws NullPointerException if {@code in} is null. 861 * @see #storeToXML(OutputStream, String, String) 862 * @since 1.5 863 */ 864 public synchronized void loadFromXML(InputStream in) 865 throws IOException, InvalidPropertiesFormatException 866 { 867 if (in == null) 868 throw new NullPointerException(); 869 XMLUtils.load(this, in); 870 in.close(); 871 } 872 873 /** 874 * Emits an XML document representing all of the properties contained 875 * in this table. 876 * 877 * <p> An invocation of this method of the form <tt>props.storeToXML(os, 878 * comment)</tt> behaves in exactly the same way as the invocation 879 * <tt>props.storeToXML(os, comment, "UTF-8");</tt>. 880 * 881 * @param os the output stream on which to emit the XML document. 882 * @param comment a description of the property list, or {@code null} 883 * if no comment is desired. 884 * @throws IOException if writing to the specified output stream 885 * results in an <tt>IOException</tt>. 886 * @throws NullPointerException if {@code os} is null. 887 * @throws ClassCastException if this {@code Properties} object 888 * contains any keys or values that are not 889 * {@code Strings}. 890 * @see #loadFromXML(InputStream) 891 * @since 1.5 892 */ 893 public void storeToXML(OutputStream os, String comment) 894 throws IOException 895 { 896 if (os == null) 897 throw new NullPointerException(); 898 storeToXML(os, comment, "UTF-8"); 899 } 900 901 /** 902 * Emits an XML document representing all of the properties contained 903 * in this table, using the specified encoding. 904 * 905 * <p>The XML document will have the following DOCTYPE declaration: 906 * <pre> 907 * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> 908 * </pre> 909 * 910 *<p>If the specified comment is {@code null} then no comment 911 * will be stored in the document. 912 * 913 * <p>The specified stream remains open after this method returns. 914 * 915 * @param os the output stream on which to emit the XML document. 916 * @param comment a description of the property list, or {@code null} 917 * if no comment is desired. 918 * @param encoding the name of a supported 919 * <a href="../lang/package-summary.html#charenc"> 920 * character encoding</a> 921 * 922 * @throws IOException if writing to the specified output stream 923 * results in an <tt>IOException</tt>. 924 * @throws NullPointerException if {@code os} is {@code null}, 925 * or if {@code encoding} is {@code null}. 926 * @throws ClassCastException if this {@code Properties} object 927 * contains any keys or values that are not 928 * {@code Strings}. 929 * @see #loadFromXML(InputStream) 930 * @since 1.5 931 */ 932 public void storeToXML(OutputStream os, String comment, String encoding) 933 throws IOException 934 { 935 if (os == null) 936 throw new NullPointerException(); 937 XMLUtils.save(this, os, comment, encoding); 938 } 939 940 /** 941 * Searches for the property with the specified key in this property list. 942 * If the key is not found in this property list, the default property list, 943 * and its defaults, recursively, are then checked. The method returns 944 * {@code null} if the property is not found. 945 * 946 * @param key the property key. 947 * @return the value in this property list with the specified key value. 948 * @see #setProperty 949 * @see #defaults 950 */ 951 public String getProperty(String key) { 952 Object oval = super.get(key); 953 String sval = (oval instanceof String) ? (String)oval : null; 954 return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval; 955 } 956 957 /** 958 * Searches for the property with the specified key in this property list. 959 * If the key is not found in this property list, the default property list, 960 * and its defaults, recursively, are then checked. The method returns the 961 * default value argument if the property is not found. 962 * 963 * @param key the hashtable key. 964 * @param defaultValue a default value. |