FileDocCategorySizeDatePackage
Properties.javaAPI DocAndroid 1.5 API29583Wed May 06 22:41:04 BST 2009java.util

Properties

public class Properties extends Hashtable
A {@code Properties} object is a {@code Hashtable} where the keys and values must be {@code String}s. Each property can have a default {@code Properties} list which specifies the default values to be used when a given key is not found in this {@code Properties} instance.
see
Hashtable
see
java.lang.System#getProperties
since
Android 1.0

Fields Summary
private static final long
serialVersionUID
private transient DocumentBuilder
builder
private static final String
PROP_DTD_NAME
private static final String
PROP_DTD
protected Properties
defaults
The default values for keys not found in this {@code Properties} instance.
private static final int
NONE
private static final int
SLASH
private static final int
UNICODE
private static final int
CONTINUE
private static final int
KEY_DONE
private static final int
IGNORE
private static String
lineSeparator
Constructors Summary
public Properties()
Constructs a new {@code Properties} object.

since
Android 1.0


                   
      
        super();
    
public Properties(Properties properties)
Constructs a new {@code Properties} object using the specified default {@code Properties}.

param
properties the default {@code Properties}.
since
Android 1.0

        defaults = properties;
    
Methods Summary
private voiddumpString(java.lang.StringBuilder buffer, java.lang.String string, boolean key)

        int i = 0;
        if (!key && i < string.length() && string.charAt(i) == ' ") {
            buffer.append("\\ "); //$NON-NLS-1$
            i++;
        }

        for (; i < string.length(); i++) {
            char ch = string.charAt(i);
            switch (ch) {
            case '\t":
                buffer.append("\\t"); //$NON-NLS-1$
                break;
            case '\n":
                buffer.append("\\n"); //$NON-NLS-1$
                break;
            case '\f":
                buffer.append("\\f"); //$NON-NLS-1$
                break;
            case '\r":
                buffer.append("\\r"); //$NON-NLS-1$
                break;
            default:
                if ("\\#!=:".indexOf(ch) >= 0 || (key && ch == ' ")) {
                    buffer.append('\\");
                }
                if (ch >= ' " && ch <= '~") {
                    buffer.append(ch);
                } else {
                    String hex = Integer.toHexString(ch);
                    buffer.append("\\u"); //$NON-NLS-1$
                    for (int j = 0; j < 4 - hex.length(); j++) {
                        buffer.append("0"); //$NON-NLS-1$
                    }
                    buffer.append(hex);
                }
            }
        }
    
public java.lang.StringgetProperty(java.lang.String name)
Searches for the property with the specified name. If the property is not found, the default {@code Properties} are checked. If the property is not found in the default {@code Properties}, {@code null} is returned.

param
name the name of the property to find.
return
the named property value, or {@code null} if it can't be found.
since
Android 1.0

        Object result = super.get(name);
        String property = result instanceof String ? (String) result : null;
        if (property == null && defaults != null) {
            property = defaults.getProperty(name);
        }
        return property;
    
public java.lang.StringgetProperty(java.lang.String name, java.lang.String defaultValue)
Searches for the property with the specified name. If the property is not found, it looks in the default {@code Properties}. If the property is not found in the default {@code Properties}, it returns the specified default.

param
name the name of the property to find.
param
defaultValue the default value.
return
the named property value.
since
Android 1.0

        Object result = super.get(name);
        String property = result instanceof String ? (String) result : null;
        if (property == null && defaults != null) {
            property = defaults.getProperty(name);
        }
        if (property == null) {
            return defaultValue;
        }
        return property;
    
private java.lang.StringgetTextContent(org.w3c.dom.Node node)

        String result = (node instanceof Text ? ((Text) node).getData() : "");

        Node child = node.getFirstChild();
        while (child != null) {
            result = result + getTextContent(child);
            child = child.getNextSibling();
        }

        return result;
    
public voidlist(java.io.PrintStream out)
Lists the mappings in this {@code Properties} to the specified {@code PrintStream} in a human readable form.

param
out the {@code PrintStream} to write the content to in human readable form.
since
Android 1.0

        if (out == null) {
            throw new NullPointerException();
        }
        StringBuffer buffer = new StringBuffer(80);
        Enumeration<?> keys = propertyNames();
        while (keys.hasMoreElements()) {
            String key = (String) keys.nextElement();
            buffer.append(key);
            buffer.append('=");
            String property = (String) super.get(key);
            Properties def = defaults;
            while (property == null) {
                property = (String) def.get(key);
                def = def.defaults;
            }
            if (property.length() > 40) {
                buffer.append(property.substring(0, 37));
                buffer.append("..."); //$NON-NLS-1$
            } else {
                buffer.append(property);
            }
            out.println(buffer.toString());
            buffer.setLength(0);
        }
    
public voidlist(java.io.PrintWriter writer)
Lists the mappings in this {@code Properties} to the specified {@code PrintWriter} in a human readable form.

param
writer the {@code PrintWriter} to write the content to in human readable form.
since
Android 1.0

        if (writer == null) {
            throw new NullPointerException();
        }
        StringBuffer buffer = new StringBuffer(80);
        Enumeration<?> keys = propertyNames();
        while (keys.hasMoreElements()) {
            String key = (String) keys.nextElement();
            buffer.append(key);
            buffer.append('=");
            String property = (String) super.get(key);
            Properties def = defaults;
            while (property == null) {
                property = (String) def.get(key);
                def = def.defaults;
            }
            if (property.length() > 40) {
                buffer.append(property.substring(0, 37));
                buffer.append("..."); //$NON-NLS-1$
            } else {
                buffer.append(property);
            }
            writer.println(buffer.toString());
            buffer.setLength(0);
        }
    
public synchronized voidload(java.io.InputStream in)
Loads properties from the specified {@code InputStream}. The encoding is ISO8859-1. The {@code Properties} file is interpreted according to the following rules:
  • Empty lines are ignored.
  • Lines starting with either a "#" or a "!" are comment lines and are ignored.
  • A backslash at the end of the line escapes the following newline character ("\r", "\n", "\r\n"). If there's a whitespace after the backslash it will just escape that whitespace instead of concatenating the lines. This does not apply to comment lines.
  • A property line consists of the key, the space between the key and the value, and the value. The key goes up to the first whitespace, "=" or ":" that is not escaped. The space between the key and the value contains either one whitespace, one "=" or one ":" and any number of additional whitespaces before and after that character. The value starts with the first character after the space between the key and the value.
  • Following escape sequences are recognized: "\ ", "\\", "\r", "\n", "\!", "\#", "\t", "\b", "\f", and "\uXXXX" (unicode character).

param
in the {@code InputStream}.
throws
IOException if error occurs during reading from the {@code InputStream}.
since
Android 1.0

        int mode = NONE, unicode = 0, count = 0;
        char nextChar, buf[] = new char[40];
        int offset = 0, keyLength = -1;
        boolean firstChar = true;
        byte[] inbuf = new byte[256];
        int inbufCount = 0, inbufPos = 0;

        while (true) {
            if (inbufPos == inbufCount) {
                if ((inbufCount = in.read(inbuf)) == -1) {
                    break;
                }
                inbufPos = 0;
            }
            nextChar = (char) (inbuf[inbufPos++] & 0xff);

            if (offset == buf.length) {
                char[] newBuf = new char[buf.length * 2];
                System.arraycopy(buf, 0, newBuf, 0, offset);
                buf = newBuf;
            }
            if (mode == UNICODE) {
                int digit = Character.digit(nextChar, 16);
                // BEGIN android-changed
                // copied from newer version of Harmony
                if (digit >= 0) {
                    unicode = (unicode << 4) + digit;
                    if (++count < 4) {
                        continue;
                    }
                } else if (count <= 4) {
                    // luni.09=Invalid Unicode sequence: illegal character
                    throw new IllegalArgumentException(Messages.getString("luni.09"));
                }
                // END android-changed
                mode = NONE;
                buf[offset++] = (char) unicode;
                if (nextChar != '\n") {
                    continue;
                }
            }
            if (mode == SLASH) {
                mode = NONE;
                switch (nextChar) {
                case '\r":
                    mode = CONTINUE; // Look for a following \n
                    continue;
                case '\n":
                    mode = IGNORE; // Ignore whitespace on the next line
                    continue;
                case 'b":
                    nextChar = '\b";
                    break;
                case 'f":
                    nextChar = '\f";
                    break;
                case 'n":
                    nextChar = '\n";
                    break;
                case 'r":
                    nextChar = '\r";
                    break;
                case 't":
                    nextChar = '\t";
                    break;
                case 'u":
                    mode = UNICODE;
                    unicode = count = 0;
                    continue;
                }
            } else {
                switch (nextChar) {
                case '#":
                case '!":
                    if (firstChar) {
                        while (true) {
                            if (inbufPos == inbufCount) {
                                if ((inbufCount = in.read(inbuf)) == -1) {
                                    inbufPos = -1;
                                    break;
                                }
                                inbufPos = 0;
                            }
                            nextChar = (char) inbuf[inbufPos++]; // & 0xff
                                                                    // not
                                                                    // required
                            if (nextChar == '\r" || nextChar == '\n") {
                                break;
                            }
                        }
                        continue;
                    }
                    break;
                case '\n":
                    if (mode == CONTINUE) { // Part of a \r\n sequence
                        mode = IGNORE; // Ignore whitespace on the next line
                        continue;
                    }
                // fall into the next case
                case '\r":
                    mode = NONE;
                    firstChar = true;
                    if (offset > 0) {
                        if (keyLength == -1) {
                            keyLength = offset;
                        }
                        String temp = new String(buf, 0, offset);
                        put(temp.substring(0, keyLength), temp
                                .substring(keyLength));
                    }
                    keyLength = -1;
                    offset = 0;
                    continue;
                case '\\":
                    if (mode == KEY_DONE) {
                        keyLength = offset;
                    }
                    mode = SLASH;
                    continue;
                case ':":
                case '=":
                    if (keyLength == -1) { // if parsing the key
                        mode = NONE;
                        keyLength = offset;
                        continue;
                    }
                    break;
                }
                if (Character.isWhitespace(nextChar)) {
                    if (mode == CONTINUE) {
                        mode = IGNORE;
                    }
                    // if key length == 0 or value length == 0
                    if (offset == 0 || offset == keyLength || mode == IGNORE) {
                        continue;
                    }
                    if (keyLength == -1) { // if parsing the key
                        mode = KEY_DONE;
                        continue;
                    }
                }
                if (mode == IGNORE || mode == CONTINUE) {
                    mode = NONE;
                }
            }
            firstChar = false;
            if (mode == KEY_DONE) {
                keyLength = offset;
                mode = NONE;
            }
            buf[offset++] = nextChar;
        }
        // BEGIN android-added
        // copied from a newer version of Harmony
        if (mode == UNICODE && count <= 4) {
            // luni.08=Invalid Unicode sequence: expected format \\uxxxx
            throw new IllegalArgumentException(Messages.getString("luni.08"));
        }
        // END android-added
        if (keyLength >= 0) {
            String temp = new String(buf, 0, offset);
            put(temp.substring(0, keyLength), temp.substring(keyLength));
        }
    
public synchronized voidloadFromXML(java.io.InputStream in)
Loads the properties from an {@code InputStream} containing the properties in XML form. The XML document must begin with (and conform to) following DOCTYPE:
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
Also the content of the XML data must satisfy the DTD but the xml is not validated against it. The DTD is not loaded from the SYSTEM ID. After this method returns the InputStream is not closed.

param
in the InputStream containing the XML document.
throws
IOException in case an error occurs during a read operation.
throws
InvalidPropertiesFormatException if the XML data is not a valid properties file.
since
Android 1.0

        if (in == null) {
            throw new NullPointerException();
        }
        
        if (builder == null) {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            // BEGIN android-removed
            // factory.setValidating(true);
            // END android-removed
            
            try {
                builder = factory.newDocumentBuilder();
            } catch (ParserConfigurationException e) {
                throw new Error(e);
            }
            
            builder.setErrorHandler(new ErrorHandler() {
                public void warning(SAXParseException e) throws SAXException {
                    throw e;
                }

                public void error(SAXParseException e) throws SAXException {
                    throw e;
                }

                public void fatalError(SAXParseException e) throws SAXException {
                    throw e;
                }
            });
            
            builder.setEntityResolver(new EntityResolver() {
                public InputSource resolveEntity(String publicId, String systemId)
                        throws SAXException, IOException {
                    if (systemId.equals(PROP_DTD_NAME)) {
                        InputSource result = new InputSource(new StringReader(
                                PROP_DTD));
                        result.setSystemId(PROP_DTD_NAME);
                        return result;
                    }
                    throw new SAXException(
                            "Invalid DOCTYPE declaration: " + systemId);
                }
            });
        }
        
        try {
            Document doc = builder.parse(in);
            NodeList entries = doc.getElementsByTagName("entry"); 
            if (entries == null) {
                return;
            }
            int entriesListLength = entries.getLength();
            
            for (int i = 0; i < entriesListLength; i++) {
                Element entry = (Element) entries.item(i);
                String key = entry.getAttribute("key");
                // BEGIN android-removed
                // String value = entry.getTextContent();
                // END android-removed
                // BEGIN android-added
                String value = getTextContent(entry);
                // END android-added
                
                /*
                 * key != null & value != null
                 * but key or(and) value can be empty String
                 */
                put(key, value);
            }
        } catch (IOException e) {
            throw e;
        } catch (SAXException e) {
            throw new InvalidPropertiesFormatException(e);
        }
    
public java.util.EnumerationpropertyNames()
Returns all of the property names that this {@code Properties} object contains.

return
an {@code Enumeration} containing the names of all properties that this {@code Properties} object contains.
since
Android 1.0

        if (defaults == null) {
            return keys();
        }

        Hashtable<Object, Object> set = new Hashtable<Object, Object>(defaults.size() + size());
        Enumeration<?> keys = defaults.propertyNames();
        while (keys.hasMoreElements()) {
            set.put(keys.nextElement(), set);
        }
        keys = keys();
        while (keys.hasMoreElements()) {
            set.put(keys.nextElement(), set);
        }
        return set.keys();
    
public voidsave(java.io.OutputStream out, java.lang.String comment)
Saves the mappings in this {@code Properties} to the specified {@code OutputStream}, putting the specified comment at the beginning. The output from this method is suitable for being read by the {@link #load(InputStream)} method.

param
out the {@code OutputStream} to write to.
param
comment the comment to add at the beginning.
exception
ClassCastException when the key or value of a mapping is not a String.
deprecated
This method ignores any {@code IOException} thrown while writing -- use {@link #store} instead for better exception handling.
since
Android 1.0

        try {
            store(out, comment);
        } catch (IOException e) {
        }
    
public java.lang.ObjectsetProperty(java.lang.String name, java.lang.String value)
Maps the specified key to the specified value. If the key already exists, the old value is replaced. The key and value cannot be {@code null}.

param
name the key.
param
value the value.
return
the old value mapped to the key, or {@code null}.
since
Android 1.0

        return put(name, value);
    
public synchronized voidstore(java.io.OutputStream out, java.lang.String comment)
Stores the mappings in this {@code Properties} to the specified {@code OutputStream}, putting the specified comment at the beginning. The output from this method is suitable for being read by the {@link #load(InputStream)} method.

param
out the {@code OutputStream} to write to.
param
comment the comment to put at the beginning.
throws
IOException if an error occurs during the write to the {@code OutputStream}.
exception
ClassCastException when the key or value of a mapping is not a {@code String}.
since
Android 1.0

        if (lineSeparator == null) {
            lineSeparator = AccessController
                    .doPrivileged(new PriviAction<String>("line.separator")); //$NON-NLS-1$
        }

        StringBuilder buffer = new StringBuilder(200);
        OutputStreamWriter writer = new OutputStreamWriter(out, "ISO8859_1"); //$NON-NLS-1$
        if (comment != null) {
            writer.write("#"); //$NON-NLS-1$
            writer.write(comment);
            writer.write(lineSeparator); 
        }
        writer.write("#"); //$NON-NLS-1$
        writer.write(new Date().toString());
        writer.write(lineSeparator); 

        for (Map.Entry<Object, Object> entry : entrySet()) {
            String key = (String) entry.getKey();
            dumpString(buffer, key, true);
            buffer.append('=");
            dumpString(buffer, (String) entry.getValue(), false);
            buffer.append(lineSeparator);
            writer.write(buffer.toString());
            buffer.setLength(0);
        }
        writer.flush();
    
public voidstoreToXML(java.io.OutputStream os, java.lang.String comment)
Writes all properties stored in this instance into the {@code OutputStream} in XML representation. The DOCTYPE is
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
If the comment is null, no comment is added to the output. UTF-8 is used as the encoding. The {@code OutputStream} is not closed at the end. A call to this method is the same as a call to {@code storeToXML(os, comment, "UTF-8")}.

param
os the {@code OutputStream} to write to.
param
comment the comment to add. If null, no comment is added.
throws
IOException if an error occurs during writing to the output.
since
Android 1.0

        storeToXML(os, comment, "UTF-8");
    
public synchronized voidstoreToXML(java.io.OutputStream os, java.lang.String comment, java.lang.String encoding)
Writes all properties stored in this instance into the {@code OutputStream} in XML representation. The DOCTYPE is
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
If the comment is null, no comment is added to the output. The parameter {@code encoding} defines which encoding should be used. The {@code OutputStream} is not closed at the end.

param
os the {@code OutputStream} to write to.
param
comment the comment to add. If null, no comment is added.
param
encoding the code identifying the encoding that should be used to write into the {@code OutputStream}.
throws
IOException if an error occurs during writing to the output.
since
Android 1.0


        if (os == null || encoding == null) {
            throw new NullPointerException();
        }
        
        /*
         * We can write to XML file using encoding parameter but note that some
         * aliases for encodings are not supported by the XML parser. Thus we
         * have to know canonical name for encoding used to store data in XML
         * since the XML parser must recognize encoding name used to store data.
         */
        
        String encodingCanonicalName;
        try {
            encodingCanonicalName = Charset.forName(encoding).name();
        } catch (IllegalCharsetNameException e) {
            System.out.println("Warning: encoding name " + encoding
                    + " is illegal, using UTF-8 as default encoding");
            encodingCanonicalName = "UTF-8";
        } catch (UnsupportedCharsetException e) {
            System.out.println("Warning: encoding " + encoding
                    + " is not supported, using UTF-8 as default encoding");
            encodingCanonicalName = "UTF-8";
        }

        PrintStream printStream = new PrintStream(os, false, encodingCanonicalName);
        
        printStream.print("<?xml version=\"1.0\" encoding=\"");
        printStream.print(encodingCanonicalName);
        printStream.println("\"?>");
        
        printStream.print("<!DOCTYPE properties SYSTEM \"");
        printStream.print(PROP_DTD_NAME);
        printStream.println("\">");
        
        printStream.println("<properties>");
        
        if (comment != null) {
            printStream.print("<comment>");
            printStream.print(substitutePredefinedEntries(comment));
            printStream.println("</comment>");
        }

        for (Map.Entry<Object, Object> entry : entrySet()) {
            String keyValue = (String) entry.getKey();
            String entryValue = (String) entry.getValue();
            printStream.print("<entry key=\"");
            printStream.print(substitutePredefinedEntries(keyValue));
            printStream.print("\">");
            printStream.print(substitutePredefinedEntries(entryValue));
            printStream.println("</entry>");
        }
        printStream.println("</properties>");
        printStream.flush();
    
private java.lang.StringsubstitutePredefinedEntries(java.lang.String s)

        
        /*
         * substitution for predefined character entities
         * to use them safely in XML
         */
        return s.replaceAll("&", "&")
            .replaceAll("<", "<")
            .replaceAll(">", ">")
            .replaceAll("\u0027", "'")
            .replaceAll("\"", """);