You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2010/09/21 13:38:05 UTC
svn commit: r999330 - in /karaf/branches/karaf-2.0.x:
assembly/src/main/filtered-resources/
shell/config/src/main/java/org/apache/karaf/shell/config/
shell/config/src/test/java/org/apache/karaf/shell/config/
Author: gnodet
Date: Tue Sep 21 11:38:05 2010
New Revision: 999330
URL: http://svn.apache.org/viewvc?rev=999330&view=rev
Log:
KARAF-140: Use a built-in Properties class to keep the comments
Added:
karaf/branches/karaf-2.0.x/shell/config/src/main/java/org/apache/karaf/shell/config/Properties.java
karaf/branches/karaf-2.0.x/shell/config/src/test/java/org/apache/karaf/shell/config/PropertiesTest.java
Modified:
karaf/branches/karaf-2.0.x/assembly/src/main/filtered-resources/features.xml
karaf/branches/karaf-2.0.x/shell/config/src/main/java/org/apache/karaf/shell/config/UpdateCommand.java
Modified: karaf/branches/karaf-2.0.x/assembly/src/main/filtered-resources/features.xml
URL: http://svn.apache.org/viewvc/karaf/branches/karaf-2.0.x/assembly/src/main/filtered-resources/features.xml?rev=999330&r1=999329&r2=999330&view=diff
==============================================================================
--- karaf/branches/karaf-2.0.x/assembly/src/main/filtered-resources/features.xml (original)
+++ karaf/branches/karaf-2.0.x/assembly/src/main/filtered-resources/features.xml Tue Sep 21 11:38:05 2010
@@ -45,14 +45,6 @@
<bundle>mvn:org.apache.karaf.features/org.apache.karaf.features.obr/${project.version}</bundle>
</feature>
<feature name="config" version="${project.version}">
- <bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.commons-configuration/${commons-configuration.version}</bundle>
- <bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.commons-beanutils/${commons-beanutils.version}</bundle>
- <bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.commons-codec/${commons-codec.version}</bundle>
- <bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.commons-jxpath/${commons-jxpath.version}</bundle>
- <bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.commons-digester/${commons-digester.version}</bundle>
- <bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.commons-lang/${commons-lang.version}</bundle>
- <bundle>mvn:commons-collections/commons-collections/${commons-collections.version}</bundle>
- <bundle>mvn:org.apache.geronimo.specs/geronimo-servlet_2.5_spec/${geronimo.servlet.version}</bundle>
<bundle>mvn:org.apache.karaf.shell/org.apache.karaf.shell.config/${project.version}</bundle>
</feature>
<feature name="http" version="${project.version}">
Added: karaf/branches/karaf-2.0.x/shell/config/src/main/java/org/apache/karaf/shell/config/Properties.java
URL: http://svn.apache.org/viewvc/karaf/branches/karaf-2.0.x/shell/config/src/main/java/org/apache/karaf/shell/config/Properties.java?rev=999330&view=auto
==============================================================================
--- karaf/branches/karaf-2.0.x/shell/config/src/main/java/org/apache/karaf/shell/config/Properties.java (added)
+++ karaf/branches/karaf-2.0.x/shell/config/src/main/java/org/apache/karaf/shell/config/Properties.java Tue Sep 21 11:38:05 2010
@@ -0,0 +1,904 @@
+/*
+ * 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.shell.config;
+
+import java.io.*;
+import java.net.URL;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+public class Properties extends AbstractMap<String, String> {
+
+ /** Constant for the supported comment characters.*/
+ private static final String COMMENT_CHARS = "#!";
+
+ /** The list of possible key/value separators */
+ private static final char[] SEPARATORS = new char[] {'=', ':'};
+
+ /** The white space characters used as key/value separators. */
+ private static final char[] WHITE_SPACE = new char[] {' ', '\t', '\f'};
+
+ /**
+ * The default encoding (ISO-8859-1 as specified by
+ * http://java.sun.com/j2se/1.5.0/docs/api/java/util/Properties.html)
+ */
+ private static final String DEFAULT_ENCODING = "ISO-8859-1";
+
+ /** Constant for the platform specific line separator.*/
+ private static final String LINE_SEPARATOR = System.getProperty("line.separator");
+
+ /** Constant for the radix of hex numbers.*/
+ private static final int HEX_RADIX = 16;
+
+ /** Constant for the length of a unicode literal.*/
+ private static final int UNICODE_LEN = 4;
+
+ private Map<String,String> storage = new LinkedHashMap<String,String>();
+ private Map<String,Layout> layout = new LinkedHashMap<String,Layout>();
+ private List<String> header;
+ private List<String> footer;
+ private File location;
+
+ public Properties() {
+ }
+
+ public Properties(File location) throws IOException {
+ this.location = location;
+ load(location);
+ }
+
+ public void load(File location) throws IOException {
+ InputStream is = new FileInputStream(location);
+ try {
+ load(is);
+ } finally {
+ is.close();
+ }
+ }
+
+ public void load(URL location) throws IOException {
+ InputStream is = location.openStream();
+ try {
+ load(is);
+ } finally {
+ is.close();
+ }
+ }
+
+ public void load(InputStream is) throws IOException {
+ load(new InputStreamReader(is, DEFAULT_ENCODING));
+ }
+
+ public void load(Reader reader) throws IOException {
+ loadLayout(reader);
+ }
+
+ public void save() throws IOException {
+ save(this.location);
+ }
+
+ public void save(File location) throws IOException {
+ OutputStream os = new FileOutputStream(location);
+ try {
+ save(os);
+ } finally {
+ os.close();
+ }
+ }
+
+ public void save(OutputStream os) throws IOException {
+ save(new OutputStreamWriter(os, DEFAULT_ENCODING));
+ }
+
+ public void save(Writer writer) throws IOException {
+ saveLayout(writer);
+ }
+
+ @Override
+ public Set<Entry<String, String>> entrySet() {
+ return storage.entrySet();
+ }
+
+ @Override
+ public String put(String key, String value) {
+ Layout l = layout.get(key);
+ if (l != null) {
+ l.clearValue();
+ }
+ return storage.put(key, value);
+ }
+
+ @Override
+ public String remove(Object key) {
+ Layout l = layout.get(key);
+ if (l != null) {
+ l.clearValue();
+ }
+ return storage.remove(key);
+ }
+
+ @Override
+ public void clear() {
+ for (Layout l : layout.values()) {
+ l.clearValue();
+ }
+ storage.clear();
+ }
+
+ /**
+ * Return the comment header.
+ *
+ * @return the comment header
+ */
+ public List<String> getHeader()
+ {
+ return header;
+ }
+
+ /**
+ * Set the comment header.
+ *
+ * @param header the header to use
+ */
+ public void setHeader(List<String> header)
+ {
+ this.header = header;
+ }
+
+ /**
+ * Return the comment footer.
+ *
+ * @return the comment footer
+ */
+ public List<String> getFooter()
+ {
+ return footer;
+ }
+
+ /**
+ * Set the comment footer.
+ *
+ * @param footer the footer to use
+ */
+ public void setFooter(List<String> footer)
+ {
+ this.footer = footer;
+ }
+
+ /**
+ * Reads a properties file and stores its internal structure. The found
+ * properties will be added to the associated configuration object.
+ *
+ * @param in the reader to the properties file
+ * @throws IOException if an error occurs
+ */
+ protected void loadLayout(Reader in) throws IOException
+ {
+ PropertiesReader reader = new PropertiesReader(in);
+ while (reader.nextProperty())
+ {
+ storage.put(reader.getPropertyName(), reader.getPropertyValue());
+ int idx = checkHeaderComment(reader.getCommentLines());
+ layout.put(reader.getPropertyName(),
+ new Layout(idx < reader.getCommentLines().size() ?
+ new ArrayList<String>(reader.getCommentLines().subList(idx, reader.getCommentLines().size())) :
+ null,
+ new ArrayList<String>(reader.getValueLines())));
+ }
+ footer = new ArrayList<String>(reader.getCommentLines());
+ }
+
+ /**
+ * Writes the properties file to the given writer, preserving as much of its
+ * structure as possible.
+ *
+ * @param out the writer
+ * @throws IOException if an error occurs
+ */
+ protected void saveLayout(Writer out) throws IOException
+ {
+ PropertiesWriter writer = new PropertiesWriter(out);
+ if (header != null)
+ {
+ for (String s : header)
+ {
+ writer.writeln(s);
+ }
+ }
+
+ for (String key : storage.keySet())
+ {
+ Layout l = layout.get(key);
+ if (l.getCommentLines() != null)
+ {
+ for (String s : l.getCommentLines())
+ {
+ writer.writeln(s);
+ }
+ }
+ if (l.getValueLines() != null)
+ {
+ for (String s : l.getValueLines())
+ {
+ writer.writeln(s);
+ }
+ }
+ else
+ {
+ writer.writeProperty(key, storage.get(key));
+ }
+ }
+ if (footer != null)
+ {
+ for (String s : footer)
+ {
+ writer.writeln(s);
+ }
+ }
+ writer.flush();
+ }
+
+ /**
+ * Checks if parts of the passed in comment can be used as header comment.
+ * This method checks whether a header comment can be defined (i.e. whether
+ * this is the first comment in the loaded file). If this is the case, it is
+ * searched for the lates blank line. This line will mark the end of the
+ * header comment. The return value is the index of the first line in the
+ * passed in list, which does not belong to the header comment.
+ *
+ * @param commentLines the comment lines
+ * @return the index of the next line after the header comment
+ */
+ private int checkHeaderComment(List<String> commentLines)
+ {
+ if (getHeader() == null && layout.isEmpty())
+ {
+ // This is the first comment. Search for blank lines.
+ int index = commentLines.size() - 1;
+ while (index >= 0 && commentLines.get(index).length() > 0)
+ {
+ index--;
+ }
+ setHeader(new ArrayList<String>(commentLines.subList(0, index + 1)));
+ return index + 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ /**
+ * Tests whether a line is a comment, i.e. whether it starts with a comment
+ * character.
+ *
+ * @param line the line
+ * @return a flag if this is a comment line
+ */
+ static boolean isCommentLine(String line) {
+ String s = line.trim();
+ // blank lines are also treated as comment lines
+ return s.length() < 1 || COMMENT_CHARS.indexOf(s.charAt(0)) >= 0;
+ }
+
+ /**
+ * <p>Unescapes any Java literals found in the <code>String</code> to a
+ * <code>Writer</code>.</p> This is a slightly modified version of the
+ * StringEscapeUtils.unescapeJava() function in commons-lang that doesn't
+ * drop escaped separators (i.e '\,').
+ *
+ * @param str the <code>String</code> to unescape, may be null
+ * @return the processed string
+ * @throws IllegalArgumentException if the Writer is <code>null</code>
+ */
+ protected static String unescapeJava(String str) {
+ if (str == null) {
+ return null;
+ }
+ int sz = str.length();
+ StringBuffer out = new StringBuffer(sz);
+ StringBuffer unicode = new StringBuffer(UNICODE_LEN);
+ boolean hadSlash = false;
+ boolean inUnicode = false;
+ for (int i = 0; i < sz; i++) {
+ char ch = str.charAt(i);
+ if (inUnicode) {
+ // if in unicode, then we're reading unicode
+ // values in somehow
+ unicode.append(ch);
+ if (unicode.length() == UNICODE_LEN) {
+ // unicode now contains the four hex digits
+ // which represents our unicode character
+ try {
+ int value = Integer.parseInt(unicode.toString(), HEX_RADIX);
+ out.append((char) value);
+ unicode.setLength(0);
+ inUnicode = false;
+ hadSlash = false;
+ } catch (NumberFormatException nfe) {
+ throw new IllegalArgumentException("Unable to parse unicode value: " + unicode, nfe);
+ }
+ }
+ continue;
+ }
+
+ if (hadSlash) {
+ // handle an escaped value
+ hadSlash = false;
+ switch (ch) {
+ case '\\' :
+ out.append('\\');
+ break;
+ case '\'' :
+ out.append('\'');
+ break;
+ case '\"' :
+ out.append('"');
+ break;
+ case 'r' :
+ out.append('\r');
+ break;
+ case 'f' :
+ out.append('\f');
+ break;
+ case 't' :
+ out.append('\t');
+ break;
+ case 'n' :
+ out.append('\n');
+ break;
+ case 'b' :
+ out.append('\b');
+ break;
+ case 'u' :
+ // uh-oh, we're in unicode country....
+ inUnicode = true;
+ break;
+ default :
+ out.append(ch);
+ break;
+ }
+ continue;
+ } else if (ch == '\\') {
+ hadSlash = true;
+ continue;
+ }
+ out.append(ch);
+ }
+
+ if (hadSlash) {
+ // then we're in the weird case of a \ at the end of the
+ // string, let's output it anyway.
+ out.append('\\');
+ }
+
+ return out.toString();
+ }
+
+ /**
+ * <p>Escapes the characters in a <code>String</code> using Java String rules.</p>
+ *
+ * <p>Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) </p>
+ *
+ * <p>So a tab becomes the characters <code>'\\'</code> and
+ * <code>'t'</code>.</p>
+ *
+ * <p>The only difference between Java strings and JavaScript strings
+ * is that in JavaScript, a single quote must be escaped.</p>
+ *
+ * <p>Example:
+ * <pre>
+ * input string: He didn't say, "Stop!"
+ * output string: He didn't say, \"Stop!\"
+ * </pre>
+ * </p>
+ *
+ * @param str String to escape values in, may be null
+ * @return String with escaped values, <code>null</code> if null string input
+ */
+ protected static String escapeJava(String str) {
+ if (str == null) {
+ return null;
+ }
+ int sz = str.length();
+ StringBuffer out = new StringBuffer(sz * 2);
+ for (int i = 0; i < sz; i++) {
+ char ch = str.charAt(i);
+ // handle unicode
+ if (ch > 0xfff) {
+ out.append("\\u").append(hex(ch));
+ } else if (ch > 0xff) {
+ out.append("\\u0").append(hex(ch));
+ } else if (ch > 0x7f) {
+ out.append("\\u00").append(hex(ch));
+ } else if (ch < 32) {
+ switch (ch) {
+ case '\b' :
+ out.append('\\');
+ out.append('b');
+ break;
+ case '\n' :
+ out.append('\\');
+ out.append('n');
+ break;
+ case '\t' :
+ out.append('\\');
+ out.append('t');
+ break;
+ case '\f' :
+ out.append('\\');
+ out.append('f');
+ break;
+ case '\r' :
+ out.append('\\');
+ out.append('r');
+ break;
+ default :
+ if (ch > 0xf) {
+ out.append("\\u00").append(hex(ch));
+ } else {
+ out.append("\\u000").append(hex(ch));
+ }
+ break;
+ }
+ } else {
+ switch (ch) {
+ case '"' :
+ out.append('\\');
+ out.append('"');
+ break;
+ case '\\' :
+ out.append('\\');
+ out.append('\\');
+ break;
+ default :
+ out.append(ch);
+ break;
+ }
+ }
+ }
+ return out.toString();
+ }
+
+ /**
+ * <p>Returns an upper case hexadecimal <code>String</code> for the given
+ * character.</p>
+ *
+ * @param ch The character to convert.
+ * @return An upper case hexadecimal <code>String</code>
+ */
+ protected static String hex(char ch) {
+ return Integer.toHexString(ch).toUpperCase(Locale.ENGLISH);
+ }
+
+ /**
+ * <p>Checks if the value is in the given array.</p>
+ *
+ * <p>The method returns <code>false</code> if a <code>null</code> array is passed in.</p>
+ *
+ * @param array the array to search through
+ * @param valueToFind the value to find
+ * @return <code>true</code> if the array contains the object
+ */
+ public static boolean contains(char[] array, char valueToFind) {
+ if (array == null) {
+ return false;
+ }
+ for (int i = 0; i < array.length; i++) {
+ if (valueToFind == array[i]) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * This class is used to read properties lines. These lines do
+ * not terminate with new-line chars but rather when there is no
+ * backslash sign a the end of the line. This is used to
+ * concatenate multiple lines for readability.
+ */
+ public static class PropertiesReader extends LineNumberReader
+ {
+ /** Stores the comment lines for the currently processed property.*/
+ private List<String> commentLines;
+
+ /** Stores the value lines for the currently processed property.*/
+ private List<String> valueLines;
+
+ /** Stores the name of the last read property.*/
+ private String propertyName;
+
+ /** Stores the value of the last read property.*/
+ private String propertyValue;
+
+ /**
+ * Creates a new instance of <code>PropertiesReader</code> and sets
+ * the underlaying reader and the list delimiter.
+ *
+ * @param reader the reader
+ */
+ public PropertiesReader(Reader reader)
+ {
+ super(reader);
+ commentLines = new ArrayList<String>();
+ valueLines = new ArrayList<String>();
+ }
+
+ /**
+ * Reads a property line. Returns null if Stream is
+ * at EOF. Concatenates lines ending with "\".
+ * Skips lines beginning with "#" or "!" and empty lines.
+ * The return value is a property definition (<code><name></code>
+ * = <code><value></code>)
+ *
+ * @return A string containing a property value or null
+ *
+ * @throws java.io.IOException in case of an I/O error
+ */
+ public String readProperty() throws java.io.IOException
+ {
+ commentLines.clear();
+ valueLines.clear();
+ StringBuffer buffer = new StringBuffer();
+
+ while (true)
+ {
+ String line = readLine();
+ if (line == null)
+ {
+ // EOF
+ return null;
+ }
+
+ if (isCommentLine(line))
+ {
+ commentLines.add(line);
+ continue;
+ }
+
+ valueLines.add(line);
+ line = line.trim();
+
+ if (checkCombineLines(line))
+ {
+ line = line.substring(0, line.length() - 1);
+ buffer.append(line);
+ }
+ else
+ {
+ buffer.append(line);
+ break;
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Parses the next property from the input stream and stores the found
+ * name and value in internal fields. These fields can be obtained using
+ * the provided getter methods. The return value indicates whether EOF
+ * was reached (<b>false</b>) or whether further properties are
+ * available (<b>true</b>).
+ *
+ * @return a flag if further properties are available
+ * @throws java.io.IOException if an error occurs
+ */
+ public boolean nextProperty() throws java.io.IOException
+ {
+ String line = readProperty();
+
+ if (line == null)
+ {
+ return false; // EOF
+ }
+
+ // parse the line
+ String[] property = parseProperty(line);
+ propertyName = unescapeJava(property[0]);
+ propertyValue = unescapeJava(property[1]);
+ return true;
+ }
+
+ /**
+ * Returns the comment lines that have been read for the last property.
+ *
+ * @return the comment lines for the last property returned by
+ * <code>readProperty()</code>
+ */
+ public List<String> getCommentLines()
+ {
+ return commentLines;
+ }
+
+ /**
+ * Returns the value lines that have been read for the last property.
+ *
+ * @return the raw value lines for the last property returned by
+ * <code>readProperty()</code>
+ */
+ public List<String> getValueLines()
+ {
+ return valueLines;
+ }
+
+ /**
+ * Returns the name of the last read property. This method can be called
+ * after <code>{@link #nextProperty()}</code> was invoked and its
+ * return value was <b>true</b>.
+ *
+ * @return the name of the last read property
+ */
+ public String getPropertyName()
+ {
+ return propertyName;
+ }
+
+ /**
+ * Returns the value of the last read property. This method can be
+ * called after <code>{@link #nextProperty()}</code> was invoked and
+ * its return value was <b>true</b>.
+ *
+ * @return the value of the last read property
+ */
+ public String getPropertyValue()
+ {
+ return propertyValue;
+ }
+
+ /**
+ * Checks if the passed in line should be combined with the following.
+ * This is true, if the line ends with an odd number of backslashes.
+ *
+ * @param line the line
+ * @return a flag if the lines should be combined
+ */
+ private static boolean checkCombineLines(String line)
+ {
+ int bsCount = 0;
+ for (int idx = line.length() - 1; idx >= 0 && line.charAt(idx) == '\\'; idx--)
+ {
+ bsCount++;
+ }
+
+ return bsCount % 2 != 0;
+ }
+
+ /**
+ * Parse a property line and return the key and the value in an array.
+ *
+ * @param line the line to parse
+ * @return an array with the property's key and value
+ */
+ private static String[] parseProperty(String line)
+ {
+ // sorry for this spaghetti code, please replace it as soon as
+ // possible with a regexp when the Java 1.3 requirement is dropped
+
+ String[] result = new String[2];
+ StringBuffer key = new StringBuffer();
+ StringBuffer value = new StringBuffer();
+
+ // state of the automaton:
+ // 0: key parsing
+ // 1: antislash found while parsing the key
+ // 2: separator crossing
+ // 3: value parsing
+ int state = 0;
+
+ for (int pos = 0; pos < line.length(); pos++)
+ {
+ char c = line.charAt(pos);
+
+ switch (state)
+ {
+ case 0:
+ if (c == '\\')
+ {
+ state = 1;
+ }
+ else if (contains(WHITE_SPACE, c))
+ {
+ // switch to the separator crossing state
+ state = 2;
+ }
+ else if (contains(SEPARATORS, c))
+ {
+ // switch to the value parsing state
+ state = 3;
+ }
+ else
+ {
+ key.append(c);
+ }
+
+ break;
+
+ case 1:
+ if (contains(SEPARATORS, c) || contains(WHITE_SPACE, c))
+ {
+ // this is an escaped separator or white space
+ key.append(c);
+ }
+ else
+ {
+ // another escaped character, the '\' is preserved
+ key.append('\\');
+ key.append(c);
+ }
+
+ // return to the key parsing state
+ state = 0;
+
+ break;
+
+ case 2:
+ if (contains(WHITE_SPACE, c))
+ {
+ // do nothing, eat all white spaces
+ state = 2;
+ }
+ else if (contains(SEPARATORS, c))
+ {
+ // switch to the value parsing state
+ state = 3;
+ }
+ else
+ {
+ // any other character indicates we encoutered the beginning of the value
+ value.append(c);
+
+ // switch to the value parsing state
+ state = 3;
+ }
+
+ break;
+
+ case 3:
+ value.append(c);
+ break;
+ }
+ }
+
+ result[0] = key.toString().trim();
+ result[1] = value.toString().trim();
+
+ return result;
+ }
+ } // class PropertiesReader
+
+ /**
+ * This class is used to write properties lines.
+ */
+ public static class PropertiesWriter extends FilterWriter
+ {
+ /**
+ * Constructor.
+ *
+ * @param writer a Writer object providing the underlying stream
+ */
+ public PropertiesWriter(Writer writer)
+ {
+ super(writer);
+ }
+
+ /**
+ * Writes the given property and its value.
+ *
+ * @param key the property key
+ * @param value the property value
+ * @throws java.io.IOException if an error occurs
+ */
+ public void writeProperty(String key, String value) throws IOException
+ {
+ write(escapeKey(key));
+ write(" = ");
+ write(escapeJava(value));
+ writeln(null);
+ }
+
+ /**
+ * Escape the separators in the key.
+ *
+ * @param key the key
+ * @return the escaped key
+ */
+ private String escapeKey(String key)
+ {
+ StringBuffer newkey = new StringBuffer();
+
+ for (int i = 0; i < key.length(); i++)
+ {
+ char c = key.charAt(i);
+
+ if (contains(SEPARATORS, c) || contains(WHITE_SPACE, c))
+ {
+ // escape the separator
+ newkey.append('\\');
+ newkey.append(c);
+ }
+ else
+ {
+ newkey.append(c);
+ }
+ }
+
+ return newkey.toString();
+ }
+
+ /**
+ * Helper method for writing a line with the platform specific line
+ * ending.
+ *
+ * @param s the content of the line (may be <b>null</b>)
+ * @throws java.io.IOException if an error occurs
+ */
+ public void writeln(String s) throws java.io.IOException
+ {
+ if (s != null)
+ {
+ write(s);
+ }
+ write(LINE_SEPARATOR);
+ }
+
+ } // class PropertiesWriter
+
+ /**
+ * TODO
+ */
+ protected static class Layout {
+
+ private List<String> commentLines;
+ private List<String> valueLines;
+
+ public Layout() {
+ }
+
+ public Layout(List<String> commentLines, List<String> valueLines) {
+ this.commentLines = commentLines;
+ this.valueLines = valueLines;
+ }
+
+ public List<String> getCommentLines() {
+ return commentLines;
+ }
+
+ public void setCommentLines(List<String> commentLines) {
+ this.commentLines = commentLines;
+ }
+
+ public List<String> getValueLines() {
+ return valueLines;
+ }
+
+ public void setValueLines(List<String> valueLines) {
+ this.valueLines = valueLines;
+ }
+
+ public void clearValue() {
+ this.valueLines = null;
+ }
+
+ } // class Layout
+
+}
Modified: karaf/branches/karaf-2.0.x/shell/config/src/main/java/org/apache/karaf/shell/config/UpdateCommand.java
URL: http://svn.apache.org/viewvc/karaf/branches/karaf-2.0.x/shell/config/src/main/java/org/apache/karaf/shell/config/UpdateCommand.java?rev=999330&r1=999329&r2=999330&view=diff
==============================================================================
--- karaf/branches/karaf-2.0.x/shell/config/src/main/java/org/apache/karaf/shell/config/UpdateCommand.java (original)
+++ karaf/branches/karaf-2.0.x/shell/config/src/main/java/org/apache/karaf/shell/config/UpdateCommand.java Tue Sep 21 11:38:05 2010
@@ -17,12 +17,9 @@
package org.apache.karaf.shell.config;
import java.io.File;
-import java.io.FileOutputStream;
import java.util.Dictionary;
import java.util.Enumeration;
-import java.util.Properties;
-import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.felix.gogo.commands.Option;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
@@ -51,11 +48,11 @@ public class UpdateCommand extends Confi
} else if (!bypassStorage && storage != null) {
String pid = (String) this.session.get(PROPERTY_CONFIG_PID);
File storageFile = new File(storage, pid + ".cfg");
- PropertiesConfiguration p = new PropertiesConfiguration(storageFile);
+ Properties p = new Properties(storageFile);
for (Enumeration keys = props.keys(); keys.hasMoreElements();) {
Object key = keys.nextElement();
if (!"service.pid".equals(key) && !"felix.fileinstall.filename".equals(key)) {
- p.setProperty((String) key, props.get(key));
+ p.put((String) key, (String) props.get(key));
}
}
storage.mkdirs();
Added: karaf/branches/karaf-2.0.x/shell/config/src/test/java/org/apache/karaf/shell/config/PropertiesTest.java
URL: http://svn.apache.org/viewvc/karaf/branches/karaf-2.0.x/shell/config/src/test/java/org/apache/karaf/shell/config/PropertiesTest.java?rev=999330&view=auto
==============================================================================
--- karaf/branches/karaf-2.0.x/shell/config/src/test/java/org/apache/karaf/shell/config/PropertiesTest.java (added)
+++ karaf/branches/karaf-2.0.x/shell/config/src/test/java/org/apache/karaf/shell/config/PropertiesTest.java Tue Sep 21 11:38:05 2010
@@ -0,0 +1,37 @@
+/*
+ * 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.shell.config;
+
+import java.io.IOException;
+import java.net.URL;
+
+import junit.framework.TestCase;
+
+public class PropertiesTest extends TestCase {
+
+ public void testLoadSave() throws IOException {
+ URL url = getClass().getClassLoader().getResource("OSGI-INF/metatype/metatype.properties");
+ Properties props = new Properties();
+ props.load(url);
+ props.save(System.err);
+ System.err.println("=====");
+
+ props.put("storage.name", "foo bar");
+ props.save(System.err);
+ System.err.println("=====");
+ }
+}