001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portal.kernel.util;
016    
017    import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader;
018    import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
019    import com.liferay.portal.kernel.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    
022    import java.io.IOException;
023    
024    import java.util.HashMap;
025    import java.util.Map;
026    
027    /**
028     * <p>
029     * This is a rewrite of java.util.Properties that is not synchronized and
030     * natively supports non-ASCII encodings. It can also be configured to be
031     * "safe", allowing the values to have new line characters. When stored to a
032     * given BufferedWriter, "safe" properties will replace all new line characters
033     * with a _SAFE_NEWLINE_CHARACTER_.
034     * </p>
035     *
036     * <p>
037     * In its current form, this is not intended to replace java.util.Properties for
038     * reading properties flat files. This class is not thread-safe.
039     * </p>
040     *
041     * @author Alexander Chow
042     */
043    public class UnicodeProperties extends HashMap<String, String> {
044    
045            public UnicodeProperties() {
046                    super();
047            }
048    
049            public UnicodeProperties(boolean safe) {
050                    super();
051    
052                    _safe = safe;
053            }
054    
055            public void fastLoad(String props) {
056                    if (Validator.isNull(props)) {
057                            return;
058                    }
059    
060                    int x = props.indexOf(CharPool.NEW_LINE);
061                    int y = 0;
062    
063                    while (x != -1) {
064                            put(props.substring(y, x));
065    
066                            y = x;
067    
068                            x = props.indexOf(CharPool.NEW_LINE, y + 1);
069                    }
070    
071                    put(props.substring(y));
072            }
073    
074            public String getProperty(String key) {
075                    return get(key);
076            }
077    
078            public String getProperty(String key, String defaultValue) {
079                    String value = getProperty(key);
080    
081                    if (value == null) {
082                            return defaultValue;
083                    }
084                    else {
085                            return value;
086                    }
087            }
088    
089            public boolean isSafe() {
090                    return _safe;
091            }
092    
093            public void load(String props) throws IOException {
094                    if (Validator.isNull(props)) {
095                            return;
096                    }
097    
098                    UnsyncBufferedReader unsyncBufferedReader = null;
099    
100                    try {
101                            unsyncBufferedReader = new UnsyncBufferedReader(
102                                    new UnsyncStringReader(props));
103    
104                            String line = unsyncBufferedReader.readLine();
105    
106                            while (line != null) {
107                                    put(line);
108                                    line = unsyncBufferedReader.readLine();
109                            }
110                    }
111                    finally {
112                            if (unsyncBufferedReader != null) {
113                                    try {
114                                            unsyncBufferedReader.close();
115                                    }
116                                    catch (Exception e) {
117                                    }
118                            }
119                    }
120            }
121    
122            private void put(String line) {
123                    line = line.trim();
124    
125                    if (!_isComment(line)) {
126                            int pos = line.indexOf(CharPool.EQUAL);
127    
128                            if (pos != -1) {
129                                    String key = line.substring(0, pos).trim();
130                                    String value = line.substring(pos + 1).trim();
131    
132                                    if (_safe) {
133                                            value = _decode(value);
134                                    }
135    
136                                    setProperty(key, value);
137                            }
138                            else {
139                                    _log.error("Invalid property on line " + line);
140                            }
141                    }
142            }
143    
144            public String put(String key, String value) {
145                    if (key == null) {
146                            return null;
147                    }
148                    else {
149                            if (value == null) {
150                                    return remove(key);
151                            }
152                            else {
153                                    _length += key.length() + value.length() + 2;
154    
155                                    return super.put(key, value);
156                            }
157                    }
158            }
159    
160            public String remove(Object key) {
161                    if ((key == null) || !containsKey(key)) {
162                            return null;
163                    }
164                    else {
165                            String keyString = (String)key;
166    
167                            String value = super.remove(key);
168    
169                            _length -= keyString.length() + value.length() + 2;
170    
171                            return value;
172                    }
173            }
174    
175            public String setProperty(String key, String value) {
176                    return put(key, value);
177            }
178    
179            public String toString() {
180                    StringBuilder sb = new StringBuilder(_length);
181    
182                    for (Map.Entry<String, String> entry : entrySet()) {
183                            String value = entry.getValue();
184    
185                            if (Validator.isNotNull(value)) {
186                                    if (_safe) {
187                                            value = _encode(value);
188                                    }
189    
190                                    sb.append(entry.getKey());
191                                    sb.append(StringPool.EQUAL);
192                                    sb.append(value);
193                                    sb.append(StringPool.NEW_LINE);
194                            }
195                    }
196    
197                    return sb.toString();
198            }
199    
200            protected int getToStringLength() {
201                    return _length;
202            }
203    
204            private static String _decode(String value) {
205                    return StringUtil.replace(
206                            value, _SAFE_NEWLINE_CHARACTER, StringPool.NEW_LINE);
207            }
208    
209            private static String _encode(String value) {
210                    return StringUtil.replace(
211                            value,
212                            new String[] {
213                                    StringPool.RETURN_NEW_LINE, StringPool.NEW_LINE,
214                                    StringPool.RETURN
215                            },
216                            new String[] {
217                                    _SAFE_NEWLINE_CHARACTER, _SAFE_NEWLINE_CHARACTER,
218                                    _SAFE_NEWLINE_CHARACTER
219                            });
220            }
221    
222            private boolean _isComment(String line) {
223                    return line.length() == 0 || line.startsWith(StringPool.POUND);
224            }
225    
226            private static final String _SAFE_NEWLINE_CHARACTER =
227                    "_SAFE_NEWLINE_CHARACTER_";
228    
229            private static Log _log = LogFactoryUtil.getLog(UnicodeProperties.class);
230    
231            private boolean _safe = false;
232            private int _length;
233    
234    }