karaf-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Guillaume Nodet <gno...@gmail.com>
Subject Re: svn commit: r1082775 - in /karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features: InstallKarsMojo.java OrderedProperties.java
Date Fri, 18 Mar 2011 07:36:00 GMT
Can we reuse the same Properties object we have throughout Karaf ?
It's the following:
  http://svn.apache.org/viewvc/felix/trunk/utils/src/main/java/org/apache/felix/utils/properties/Properties.java?revision=1076377&view=markup
This one is also ordered, but has the benefit (which would not be used
here) to be able to read / change properties file while preserving
comments, formatting and variable substitution.


On Fri, Mar 18, 2011 at 01:47,  <djencks@apache.org> wrote:
> Author: djencks
> Date: Fri Mar 18 00:47:16 2011
> New Revision: 1082775
>
> URL: http://svn.apache.org/viewvc?rev=1082775&view=rev
> Log:
> KARAF-424, KARAF-523 when constructing startup.properties, use maven-style ids and preserve
ordering
>
> Added:
>    karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/OrderedProperties.java
  (with props)
> Modified:
>    karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java
>
> Modified: karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java
> URL: http://svn.apache.org/viewvc/karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java?rev=1082775&r1=1082774&r2=1082775&view=diff
> ==============================================================================
> --- karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java
(original)
> +++ karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java
Fri Mar 18 00:47:16 2011
> @@ -28,6 +28,8 @@ import java.io.OutputStream;
>  import java.net.URI;
>  import java.util.Collection;
>  import java.util.EnumSet;
> +import java.util.LinkedHashMap;
> +import java.util.Map;
>  import java.util.Properties;
>  import java.util.Set;
>
> @@ -165,7 +167,7 @@ public class InstallKarsMojo extends Moj
>                 }
>             } else {
>                 getLog().info("Installing feature to system and startup.properties");
> -                Properties startupProperties = new Properties();
> +                OrderedProperties startupProperties = new OrderedProperties();
>                 if (startupPropertiesFile.exists()) {
>                     InputStream in = new FileInputStream(startupPropertiesFile);
>                     try {
> @@ -194,14 +196,14 @@ public class InstallKarsMojo extends Moj
>                     for (Bundle bundle: feature.getBundle()) {
>                         String location = bundle.getLocation();
>                         String startLevel = Integer.toString(bundle.getStartLevel());
> -                        bits = location.toString().split("[:/]");
> -                        if (bits.length < 4) {
> -                            getLog().warn("bad bundle: " + location);
> -                        } else {
> -                        Artifact bundleArtifact = factory.createArtifact(bits[1],
bits[2], bits[3], null, bits.length == 4? "jar": bits[4]);
> -                        String bundlePath = layout.pathOf(bundleArtifact);
> +//                        bits = location.toString().split("[:/]");
> +//                        if (bits.length < 4) {
> +//                            getLog().warn("bad bundle: " + location);
> +//                        } else {
> +//                        Artifact bundleArtifact = factory.createArtifact(bits[1],
bits[2], bits[3], null, bits.length == 4? "jar": bits[4]);
> +                        String bundlePath = location.startsWith("mvn:")?
location.substring("mvn:".length()).replaceAll("/", ":"): location;
> +                        //layout.pathOf(bundleArtifact);
>                         startupProperties.put(bundlePath, startLevel);
> -                        }
>                     }
>                 }
>
> @@ -266,4 +268,5 @@ public class InstallKarsMojo extends Moj
>             return null;
>         }
>     }
> +
>  }
>
> Added: karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/OrderedProperties.java
> URL: http://svn.apache.org/viewvc/karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/OrderedProperties.java?rev=1082775&view=auto
> ==============================================================================
> --- karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/OrderedProperties.java
(added)
> +++ karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/OrderedProperties.java
Fri Mar 18 00:47:16 2011
> @@ -0,0 +1,769 @@
> +/*
> + *  Licensed to the Apache Software Foundation (ASF) under one or more
> + *  contributor license agreements.  See the NOTICE file distributed with
> + *  this work for additional information regarding copyright ownership.
> + *  The ASF licenses this file to You under the Apache License, Version 2.0
> + *  (the "License"); you may not use this file except in compliance with
> + *  the License.  You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + *  Unless required by applicable law or agreed to in writing, software
> + *  distributed under the License is distributed on an "AS IS" BASIS,
> + *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + *  See the License for the specific language governing permissions and
> + *  limitations under the License.
> + */
> +
> +package org.apache.karaf.tooling.features;
> +
> +import java.io.IOException;
> +import java.io.InputStream;
> +import java.io.BufferedInputStream;
> +import java.io.OutputStream;
> +import java.io.OutputStreamWriter;
> +import java.io.PrintStream;
> +import java.io.PrintWriter;
> +import java.io.StringReader;
> +import java.nio.charset.Charset;
> +import java.nio.charset.IllegalCharsetNameException;
> +import java.nio.charset.UnsupportedCharsetException;
> +import java.security.AccessController;
> +import java.security.PrivilegedAction;
> +import java.util.Date;
> +import java.util.Enumeration;
> +import java.util.InvalidPropertiesFormatException;
> +import java.util.Iterator;
> +import java.util.LinkedHashMap;
> +import java.util.Map;
> +import java.util.Properties;
> +
> +import javax.xml.parsers.DocumentBuilder;
> +import javax.xml.parsers.DocumentBuilderFactory;
> +import javax.xml.parsers.ParserConfigurationException;
> +
> +import org.xml.sax.EntityResolver;
> +import org.xml.sax.ErrorHandler;
> +import org.xml.sax.InputSource;
> +import org.xml.sax.SAXException;
> +import org.xml.sax.SAXParseException;
> +
> +import org.w3c.dom.Document;
> +import org.w3c.dom.Element;
> +import org.w3c.dom.NodeList;
> +
> +//import org.apache.harmony.luni.internal.nls.Messages;
> +//import org.apache.harmony.luni.util.PriviAction;
> +
> +/**
> + * This is a copy of harmony's Properties implementation modified to extend LinkedHashMap
instead of Hashtable
> + * The default property stuff doesn't work.
> + *
> + * 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 LinkedHashMap
> + * @see java.lang.System#getProperties
> + */
> +public class OrderedProperties extends LinkedHashMap<Object, Object> {
> +
> +    private static final long serialVersionUID = 4112578634029874840L;
> +
> +    private transient DocumentBuilder builder = null;
> +
> +    private static final String PROP_DTD_NAME = "http://java.sun.com/dtd/properties.dtd";
> +
> +    private static final String PROP_DTD = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
> +            + "    <!ELEMENT properties (comment?, entry*) >"
> +            + "    <!ATTLIST properties version CDATA #FIXED \"1.0\" >"
> +            + "    <!ELEMENT comment (#PCDATA) >"
> +            + "    <!ELEMENT entry (#PCDATA) >"
> +            + "    <!ATTLIST entry key CDATA #REQUIRED >";
> +
> +    /**
> +     * The default values for keys not found in this {@code Properties}
> +     * instance.
> +     */
> +    protected Properties defaults;
> +
> +    private static final int NONE = 0, SLASH = 1, UNICODE = 2, CONTINUE = 3,
> +            KEY_DONE = 4, IGNORE = 5;
> +
> +    /**
> +     * Constructs a new {@code Properties} object.
> +     */
> +    public OrderedProperties() {
> +        super();
> +    }
> +
> +    /**
> +     * Constructs a new {@code Properties} object using the specified default
> +     * {@code Properties}.
> +     *
> +     * @param properties
> +     *            the default {@code Properties}.
> +     */
> +    public OrderedProperties(Properties properties) {
> +        defaults = properties;
> +    }
> +
> +    private void dumpString(StringBuilder buffer, 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);
> +                }
> +            }
> +        }
> +    }
> +
> +    /**
> +     * 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.
> +     */
> +    public String getProperty(String name) {
> +        Object result = super.get(name);
> +        String property = result instanceof String ? (String) result : null;
> +        if (property == null && defaults != null) {
> +            property = defaults.getProperty(name);
> +        }
> +        return property;
> +    }
> +
> +    /**
> +     * 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.
> +     */
> +    public String getProperty(String name, String defaultValue) {
> +        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;
> +    }
> +
> +    /**
> +     * 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.
> +     */
> +    public void list(PrintStream out) {
> +        if (out == null) {
> +            throw new NullPointerException();
> +        }
> +        StringBuilder buffer = new StringBuilder(80);
> +        Iterator<?> keys = keySet().iterator();
> +        while (keys.hasNext()) {
> +            String key = (String) keys.next();
> +            buffer.append(key);
> +            buffer.append('=');
> +            String property = (String) super.get(key);
> +            Properties def = defaults;
> +            if (property == null) {
> +                property = def.getProperty(key);
> +            }
> +            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);
> +        }
> +    }
> +
> +    /**
> +     * 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.
> +     */
> +    public void list(PrintWriter writer) {
> +        if (writer == null) {
> +            throw new NullPointerException();
> +        }
> +        StringBuilder buffer = new StringBuilder(80);
> +        Iterator<?> keys = keySet().iterator();
> +        while (keys.hasNext()) {
> +            String key = (String) keys.next();
> +            buffer.append(key);
> +            buffer.append('=');
> +            String property = (String) super.get(key);
> +            Properties def = defaults;
> +            if (property == null) {
> +                property = def.getProperty(key);
> +            }
> +            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);
> +        }
> +    }
> +
> +    /**
> +     * Loads properties from the specified {@code InputStream}. The encoding is
> +     * ISO8859-1. The {@code Properties} file is interpreted according to the
> +     * following rules:
> +     * <ul>
> +     * <li>Empty lines are ignored.</li>
> +     * <li>Lines starting with either a "#" or a "!" are comment lines and are
> +     * ignored.</li>
> +     * <li>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.</li>
> +     * <li>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.</li>
> +     * <li>Following escape sequences are recognized: "\ ", "\\", "\r", "\n",
> +     * "\!", "\#", "\t", "\b", "\f", and "&#92;uXXXX" (unicode character).</li>
> +     * </ul>
> +     *
> +     * @param in
> +     *            the {@code InputStream}.
> +     * @throws IOException
> +     *             if error occurs during reading from the {@code InputStream}.
> +     */
> +    @SuppressWarnings("fallthrough")
> +    public synchronized void load(InputStream in) throws IOException {
> +        if (in == null) {
> +            throw new NullPointerException();
> +        }
> +        int mode = NONE, unicode = 0, count = 0;
> +        char nextChar, buf[] = new char[40];
> +        int offset = 0, keyLength = -1, intVal;
> +        boolean firstChar = true;
> +        BufferedInputStream bis = new BufferedInputStream(in);
> +
> +        while (true) {
> +            intVal = bis.read();
> +            if (intVal == -1) {
> +                // if mode is UNICODE but has less than 4 hex digits, should
> +                // throw an IllegalArgumentException
> +                // luni.08=Invalid Unicode sequence: expected format \\uxxxx
> +                if (mode == UNICODE && count < 4) {
> +                    throw new IllegalArgumentException("Invalid Unicode sequence:
expected format \\\\uxxxx"); //$NON-NLS-1$
> +                }
> +                // if mode is SLASH and no data is read, should append '\u0000'
> +                // to buf
> +                if (mode == SLASH) {
> +                    buf[offset++] = '\u0000';
> +                }
> +                break;
> +            }
> +            nextChar = (char) (intVal & 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);
> +                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("Invalid Unicode sequence:
illegal character"); //$NON-NLS-1$
> +                }
> +                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) {
> +                            intVal = bis.read();
> +                            if (intVal == -1) {
> +                                break;
> +                            }
> +                            // & 0xff not required
> +                            nextChar = (char) intVal;
> +                            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 || (offset == 0 && keyLength
== 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;
> +        }
> +        if (keyLength == -1 && offset > 0) {
> +            keyLength = offset;
> +        }
> +        if (keyLength >= 0) {
> +            String temp = new String(buf, 0, offset);
> +            put(temp.substring(0, keyLength), temp.substring(keyLength));
> +        }
> +    }
> +
> +    /**
> +     * 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.
> +     */
> +//    public Enumeration<?> propertyNames() {
> +//        if (defaults == null) {
> +//            return keySet().;
> +//        }
> +//
> +//        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();
> +//    }
> +
> +    /**
> +     * 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.
> +     * @throws ClassCastException if 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.
> +     */
> +    @Deprecated
> +    public void save(OutputStream out, String comment) {
> +        try {
> +            store(out, comment);
> +        } catch (IOException e) {
> +        }
> +    }
> +
> +    /**
> +     * 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}.
> +     */
> +    public Object setProperty(String name, String value) {
> +        return put(name, value);
> +    }
> +
> +    private static String lineSeparator;
> +
> +    /**
> +     * 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}.
> +     * @throws ClassCastException if the key or value of a mapping is not a
> +     *                {@code String}.
> +     */
> +    public synchronized void store(OutputStream out, String comment)
> +            throws IOException {
> +        if (lineSeparator == null) {
> +            lineSeparator = AccessController
> +                    .doPrivileged(new PrivilegedAction<String>(){
> +
> +                        public String run() {
> +                            return System.getProperty("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();
> +    }
> +
> +    /**
> +     * Loads the properties from an {@code InputStream} containing the
> +     * properties in XML form. The XML document must begin with (and conform to)
> +     * following DOCTYPE:
> +     *
> +     * <pre>
> +     * &lt;!DOCTYPE properties SYSTEM &quot;http://java.sun.com/dtd/properties.dtd&quot;&gt;
> +     * </pre>
> +     *
> +     * 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.
> +     */
> +    public synchronized void loadFromXML(InputStream in) throws IOException,
> +            InvalidPropertiesFormatException {
> +        if (in == null) {
> +            throw new NullPointerException();
> +        }
> +
> +        if (builder == null) {
> +            DocumentBuilderFactory factory = DocumentBuilderFactory
> +                    .newInstance();
> +            factory.setValidating(true);
> +
> +            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");
> +                String value = entry.getTextContent();
> +
> +                /*
> +                 * 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);
> +        }
> +    }
> +
> +    /**
> +     * Writes all properties stored in this instance into the {@code
> +     * OutputStream} in XML representation. The DOCTYPE is
> +     *
> +     * <pre>
> +     * &lt;!DOCTYPE properties SYSTEM &quot;http://java.sun.com/dtd/properties.dtd&quot;&gt;
> +     * </pre>
> +     *
> +     * 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.
> +     */
> +    public void storeToXML(OutputStream os, String comment) throws IOException {
> +        storeToXML(os, comment, "UTF-8"); //$NON-NLS-1$
> +    }
> +
> +    /**
> +     * Writes all properties stored in this instance into the {@code
> +     * OutputStream} in XML representation. The DOCTYPE is
> +     *
> +     * <pre>
> +     * &lt;!DOCTYPE properties SYSTEM &quot;http://java.sun.com/dtd/properties.dtd&quot;&gt;
> +     * </pre>
> +     *
> +     * 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.
> +     */
> +    public synchronized void storeToXML(OutputStream os, String comment,
> +            String encoding) throws IOException {
> +
> +        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 String substitutePredefinedEntries(String s) {
> +
> +        /*
> +         * substitution for predefined character entities to use them safely in
> +         * XML
> +         */
> +        return s.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(
> +                ">", "&gt;").replaceAll("\u0027", "&apos;").replaceAll("\"",
> +                "&quot;");
> +    }
> +}
>
> Propchange: karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/OrderedProperties.java
> ------------------------------------------------------------------------------
>    svn:eol-style = native
>
> Propchange: karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/OrderedProperties.java
> ------------------------------------------------------------------------------
>    svn:keywords = Date Revision
>
> Propchange: karaf/trunk/tooling/features-maven-plugin/src/main/java/org/apache/karaf/tooling/features/OrderedProperties.java
> ------------------------------------------------------------------------------
>    svn:mime-type = text/plain
>
>
>



-- 
Cheers,
Guillaume Nodet
------------------------
Blog: http://gnodet.blogspot.com/
------------------------
Open Source SOA
http://fusesource.com

Mime
View raw message