001    /**
002     * Copyright (c) 2000-2013 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    import java.util.TreeMap;
027    
028    /**
029     * <p>
030     * This is a rewrite of java.util.Properties that is not synchronized and
031     * natively supports non-ASCII encodings. It can also be configured to be
032     * "safe", allowing the values to have new line characters. When stored to a
033     * given BufferedWriter, "safe" properties will replace all new line characters
034     * with a _SAFE_NEWLINE_CHARACTER_.
035     * </p>
036     *
037     * <p>
038     * In its current form, this is not intended to replace java.util.Properties for
039     * reading properties flat files. This class is not thread-safe.
040     * </p>
041     *
042     * @author Alexander Chow
043     */
044    public class UnicodeProperties extends HashMap<String, String> {
045    
046            public UnicodeProperties() {
047                    super();
048            }
049    
050            public UnicodeProperties(boolean safe) {
051                    super();
052    
053                    _safe = safe;
054            }
055    
056            public void fastLoad(String props) {
057                    if (Validator.isNull(props)) {
058                            return;
059                    }
060    
061                    int x = props.indexOf(CharPool.NEW_LINE);
062                    int y = 0;
063    
064                    while (x != -1) {
065                            put(props.substring(y, x));
066    
067                            y = x;
068    
069                            x = props.indexOf(CharPool.NEW_LINE, y + 1);
070                    }
071    
072                    put(props.substring(y));
073            }
074    
075            public String getProperty(String key) {
076                    return get(key);
077            }
078    
079            public String getProperty(String key, String defaultValue) {
080                    String value = get(key);
081    
082                    if (value == null) {
083                            return defaultValue;
084                    }
085                    else {
086                            return value;
087                    }
088            }
089    
090            public boolean isSafe() {
091                    return _safe;
092            }
093    
094            public void load(String props) throws IOException {
095                    if (Validator.isNull(props)) {
096                            return;
097                    }
098    
099                    UnsyncBufferedReader unsyncBufferedReader = null;
100    
101                    try {
102                            unsyncBufferedReader = new UnsyncBufferedReader(
103                                    new UnsyncStringReader(props));
104    
105                            String line = unsyncBufferedReader.readLine();
106    
107                            while (line != null) {
108                                    put(line);
109                                    line = unsyncBufferedReader.readLine();
110                            }
111                    }
112                    finally {
113                            if (unsyncBufferedReader != null) {
114                                    try {
115                                            unsyncBufferedReader.close();
116                                    }
117                                    catch (Exception e) {
118                                    }
119                            }
120                    }
121            }
122    
123            public void put(String line) {
124                    line = line.trim();
125    
126                    if (_isComment(line)) {
127                            return;
128                    }
129    
130                    int pos = line.indexOf(CharPool.EQUAL);
131    
132                    if (pos == -1) {
133                            _log.error("Invalid property on line " + line);
134                    }
135                    else {
136                            String value = line.substring(pos + 1).trim();
137    
138                            if (_safe) {
139                                    value = _decode(value);
140                            }
141    
142                            setProperty(line.substring(0, pos).trim(), value);
143                    }
144            }
145    
146            @Override
147            public String put(String key, String value) {
148                    if (key == null) {
149                            return null;
150                    }
151    
152                    if (value == null) {
153                            return super.remove(key);
154                    }
155    
156                    return super.put(key, value);
157            }
158    
159            @Override
160            public void putAll(Map<? extends String, ? extends String> map) {
161                    for (Map.Entry<? extends String, ? extends String> entry :
162                                    map.entrySet()) {
163    
164                            put(entry.getKey(), entry.getValue());
165                    }
166            }
167    
168            @Override
169            public String remove(Object key) {
170                    if (key == null) {
171                            return null;
172                    }
173    
174                    return super.remove(key);
175            }
176    
177            public String setProperty(String key, String value) {
178                    return put(key, value);
179            }
180    
181            /**
182             * @deprecated As of 7.0.0, replaced by {@link #toString}
183             */
184            @Deprecated
185            public String toSortedString() {
186                    return toString();
187            }
188    
189            @Override
190            public String toString() {
191                    StringBundler sb = new StringBundler(4 * size());
192    
193                    Map<String, String> treeMap = new TreeMap<String, String>(this);
194    
195                    for (Map.Entry<String, String> entry : treeMap.entrySet()) {
196                            String value = entry.getValue();
197    
198                            if (Validator.isNull(value)) {
199                                    continue;
200                            }
201    
202                            if (_safe) {
203                                    value = _encode(value);
204                            }
205    
206                            sb.append(entry.getKey());
207                            sb.append(StringPool.EQUAL);
208                            sb.append(value);
209                            sb.append(StringPool.NEW_LINE);
210                    }
211    
212                    return sb.toString();
213            }
214    
215            /**
216             * @deprecated As of 7.0.0, with no direct replacement
217             */
218            @Deprecated
219            protected int getToStringLength() {
220                    return -1;
221            }
222    
223            private static String _decode(String value) {
224                    return StringUtil.replace(
225                            value, _SAFE_NEWLINE_CHARACTER, StringPool.NEW_LINE);
226            }
227    
228            private static String _encode(String value) {
229                    String encodedValue = StringUtil.replace(
230                            value, StringPool.RETURN_NEW_LINE, _SAFE_NEWLINE_CHARACTER);
231    
232                    return StringUtil.replace(
233                            encodedValue, new char[] {CharPool.NEW_LINE, CharPool.RETURN},
234                            new String[] {_SAFE_NEWLINE_CHARACTER, _SAFE_NEWLINE_CHARACTER});
235            }
236    
237            private boolean _isComment(String line) {
238                    if (line.isEmpty() || (line.charAt(0) == CharPool.POUND)) {
239                            return true;
240                    }
241    
242                    return false;
243            }
244    
245            private static final String _SAFE_NEWLINE_CHARACTER =
246                    "_SAFE_NEWLINE_CHARACTER_";
247    
248            private static Log _log = LogFactoryUtil.getLog(UnicodeProperties.class);
249    
250            private boolean _safe = false;
251    
252    }