001: /*
002: JSPWiki - a JSP-based WikiWiki clone.
003:
004: Copyright (C) 2001-2007 Janne Jalkanen (Janne.Jalkanen@iki.fi)
005:
006: This program is free software; you can redistribute it and/or modify
007: it under the terms of the GNU Lesser General Public License as published by
008: the Free Software Foundation; either version 2.1 of the License, or
009: (at your option) any later version.
010:
011: This program is distributed in the hope that it will be useful,
012: but WITHOUT ANY WARRANTY; without even the implied warranty of
013: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: GNU Lesser General Public License for more details.
015:
016: You should have received a copy of the GNU Lesser General Public License
017: along with this program; if not, write to the Free Software
018: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020: package com.ecyrd.jspwiki.util;
021:
022: import java.io.*;
023: import java.util.Iterator;
024: import java.util.Map;
025: import java.util.Properties;
026: import java.util.Map.Entry;
027:
028: import com.ecyrd.jspwiki.FileUtil;
029: import com.ecyrd.jspwiki.TextUtil;
030:
031: /**
032: * Extends {@link java.util.Properties} by providing support for comment
033: * preservation. When the properties are written to disk, previous
034: * comments present in the file are preserved.
035: * @author Andrew Jaquith
036: * @author Janne Jalkanen
037: * @since 2.4.22
038: */
039: public class CommentedProperties extends Properties {
040: private static final long serialVersionUID = 8057284636436329669L;
041:
042: private String m_propertyString;
043:
044: /**
045: * @see java.util.Properties#Properties()
046: */
047: public CommentedProperties() {
048: super ();
049: }
050:
051: /**
052: * Creates new properties.
053: *
054: * @param defaultValues A list of default values, which are used if in subsequent gets
055: * a key is not found.
056: */
057: public CommentedProperties(Properties defaultValues) {
058: super (defaultValues);
059: }
060:
061: /**
062: *{@inheritDoc}
063: */
064: public synchronized void load(InputStream inStream)
065: throws IOException {
066: // Load the file itself into a string
067: m_propertyString = FileUtil
068: .readContents(inStream, "ISO-8859-1");
069:
070: // Now load it into the properties object as normal
071: super .load(new ByteArrayInputStream(m_propertyString
072: .getBytes("ISO-8859-1")));
073: }
074:
075: /**
076: * {@inheritDoc}
077: */
078: public synchronized void load(Reader in) throws IOException {
079: m_propertyString = FileUtil.readContents(in);
080:
081: // Now load it into the properties object as normal
082: super .load(new ByteArrayInputStream(m_propertyString
083: .getBytes("ISO-8859-1")));
084: }
085:
086: /**
087: * {@inheritDoc}
088: */
089: public synchronized Object setProperty(String key, String value) {
090: return put(key, value);
091: }
092:
093: /**
094: * {@inheritDoc}
095: */
096: public synchronized void store(OutputStream out, String comments)
097: throws IOException {
098: byte[] bytes = m_propertyString.getBytes("ISO-8859-1");
099: FileUtil.copyContents(new ByteArrayInputStream(bytes), out);
100: out.flush();
101: }
102:
103: /**
104: * {@inheritDoc}
105: */
106: public synchronized Object put(Object arg0, Object arg1) {
107: // Write the property to the stored string
108: writeProperty(arg0, arg1);
109:
110: // Return the result of from the superclass properties object
111: return super .put(arg0, arg1);
112: }
113:
114: /**
115: * {@inheritDoc}
116: */
117: public synchronized void putAll(Map arg0) {
118: // Shove all of the entries into the property string
119: for (Iterator it = arg0.entrySet().iterator(); it.hasNext();) {
120: Entry entry = (Entry) it.next();
121: writeProperty(entry.getKey(), entry.getValue());
122: }
123:
124: // Call the superclass method
125: super .putAll(arg0);
126: }
127:
128: /**
129: * {@inheritDoc}
130: */
131: public synchronized Object remove(Object key) {
132: // Remove from the property string
133: deleteProperty(key);
134:
135: // Call the superclass method
136: return super .remove(key);
137: }
138:
139: /**
140: * {@inheritDoc}
141: */
142: public synchronized String toString() {
143: return m_propertyString;
144: }
145:
146: private void deleteProperty(Object arg0) {
147: // Get key and value
148: if (arg0 == null) {
149: throw new IllegalArgumentException("Key cannot be null.");
150: }
151: String key = arg0.toString();
152:
153: // Iterate through each line and replace anything matching our key
154: int idx = 0;
155: while ((idx < m_propertyString.length())
156: && ((idx = m_propertyString.indexOf(key, idx)) != -1)) {
157: int prevret = m_propertyString.lastIndexOf("\n", idx);
158: if (prevret != -1) {
159: // Commented lines are skipped
160: if (m_propertyString.charAt(prevret + 1) == '#') {
161: idx += key.length();
162: continue;
163: }
164: }
165:
166: // If "=" present, delete the entire line
167: int eqsign = m_propertyString.indexOf("=", idx);
168: if (eqsign != -1) {
169: int ret = m_propertyString.indexOf("\n", eqsign);
170: m_propertyString = TextUtil.replaceString(
171: m_propertyString, prevret, ret, "");
172: return;
173: }
174: }
175: }
176:
177: private void writeProperty(Object arg0, Object arg1) {
178: // Get key and value
179: if (arg0 == null) {
180: throw new IllegalArgumentException("Key cannot be null.");
181: }
182: if (arg1 == null) {
183: arg1 = "";
184: }
185: String key = arg0.toString();
186: String value = TextUtil.native2Ascii(arg1.toString());
187:
188: // Iterate through each line and replace anything matching our key
189: int idx = 0;
190: while ((idx < m_propertyString.length())
191: && ((idx = m_propertyString.indexOf(key, idx)) != -1)) {
192: int prevret = m_propertyString.lastIndexOf("\n", idx);
193: if (prevret != -1) {
194: // Commented lines are skipped
195: if (m_propertyString.charAt(prevret + 1) == '#') {
196: idx += key.length();
197: continue;
198: }
199: }
200:
201: // If "=" present, replace everything in line after it
202: int eqsign = m_propertyString.indexOf("=", idx);
203: if (eqsign != -1) {
204: int ret = m_propertyString.indexOf("\n", eqsign);
205: if (ret == -1) {
206: ret = m_propertyString.length();
207: }
208: m_propertyString = TextUtil.replaceString(
209: m_propertyString, eqsign + 1, ret, value);
210: return;
211: }
212: }
213:
214: // If it was not found, we'll add it to the end.
215: m_propertyString += "\n" + key + " = " + value + "\n";
216: }
217:
218: }
|