001    /**
002     * Copyright (c) 2000-2011 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            @Override
145            public String put(String key, String value) {
146                    if (key == null) {
147                            return null;
148                    }
149                    else {
150                            if (value == null) {
151                                    return remove(key);
152                            }
153                            else {
154                                    _length += key.length() + value.length() + 2;
155    
156                                    return super.put(key, value);
157                            }
158                    }
159            }
160    
161            @Override
162            public String remove(Object key) {
163                    if ((key == null) || !containsKey(key)) {
164                            return null;
165                    }
166                    else {
167                            String keyString = (String)key;
168    
169                            String value = super.remove(key);
170    
171                            _length -= keyString.length() + value.length() + 2;
172    
173                            return value;
174                    }
175            }
176    
177            public String setProperty(String key, String value) {
178                    return put(key, value);
179            }
180    
181            @Override
182            public String toString() {
183                    StringBuilder sb = new StringBuilder(_length);
184    
185                    for (Map.Entry<String, String> entry : entrySet()) {
186                            String value = entry.getValue();
187    
188                            if (Validator.isNotNull(value)) {
189                                    if (_safe) {
190                                            value = _encode(value);
191                                    }
192    
193                                    sb.append(entry.getKey());
194                                    sb.append(StringPool.EQUAL);
195                                    sb.append(value);
196                                    sb.append(StringPool.NEW_LINE);
197                            }
198                    }
199    
200                    return sb.toString();
201            }
202    
203            protected int getToStringLength() {
204                    return _length;
205            }
206    
207            private static String _decode(String value) {
208                    return StringUtil.replace(
209                            value, _SAFE_NEWLINE_CHARACTER, StringPool.NEW_LINE);
210            }
211    
212            private static String _encode(String value) {
213                    return StringUtil.replace(
214                            value,
215                            new String[] {
216                                    StringPool.RETURN_NEW_LINE, StringPool.NEW_LINE,
217                                    StringPool.RETURN
218                            },
219                            new String[] {
220                                    _SAFE_NEWLINE_CHARACTER, _SAFE_NEWLINE_CHARACTER,
221                                    _SAFE_NEWLINE_CHARACTER
222                            });
223            }
224    
225            private boolean _isComment(String line) {
226                    return line.length() == 0 || line.startsWith(StringPool.POUND);
227            }
228    
229            private static final String _SAFE_NEWLINE_CHARACTER =
230                    "_SAFE_NEWLINE_CHARACTER_";
231    
232            private static Log _log = LogFactoryUtil.getLog(UnicodeProperties.class);
233    
234            private boolean _safe = false;
235            private int _length;
236    
237    }