001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
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    
026    /**
027     * <p>
028     * This is a rewrite of java.util.Properties that is not synchronized and
029     * natively supports non-ASCII encodings. It can also be configured to be
030     * "safe", allowing the values to have new line characters. When stored to a
031     * given BufferedWriter, "safe" properties will replace all new line characters
032     * with a _SAFE_NEWLINE_CHARACTER_.
033     * </p>
034     *
035     * <p>
036     * In its current form, this is not intended to replace java.util.Properties for
037     * reading properties flat files. This class is not thread-safe.
038     * </p>
039     *
040     * @author Alexander Chow
041     */
042    public class UnicodeProperties extends HashMap<String, String> {
043    
044            public UnicodeProperties() {
045                    super();
046            }
047    
048            public UnicodeProperties(boolean safe) {
049                    super();
050    
051                    _safe = safe;
052            }
053    
054            public void fastLoad(String props) {
055                    if (Validator.isNull(props)) {
056                            return;
057                    }
058    
059                    int x = props.indexOf(CharPool.NEW_LINE);
060                    int y = 0;
061    
062                    while (x != -1) {
063                            put(props.substring(y, x));
064    
065                            y = x;
066    
067                            x = props.indexOf(CharPool.NEW_LINE, y + 1);
068                    }
069    
070                    put(props.substring(y));
071            }
072    
073            public String getProperty(String key) {
074                    return get(key);
075            }
076    
077            public String getProperty(String key, String defaultValue) {
078                    if (containsKey(key)) {
079                            return getProperty(key);
080                    }
081                    else {
082                            return defaultValue;
083                    }
084            }
085    
086            public boolean isSafe() {
087                    return _safe;
088            }
089    
090            public void load(String props) throws IOException {
091                    if (Validator.isNull(props)) {
092                            return;
093                    }
094    
095                    UnsyncBufferedReader unsyncBufferedReader = null;
096    
097                    try {
098                            unsyncBufferedReader = new UnsyncBufferedReader(
099                                    new UnsyncStringReader(props));
100    
101                            String line = unsyncBufferedReader.readLine();
102    
103                            while (line != null) {
104                                    put(line);
105                                    line = unsyncBufferedReader.readLine();
106                            }
107                    }
108                    finally {
109                            if (unsyncBufferedReader != null) {
110                                    try {
111                                            unsyncBufferedReader.close();
112                                    }
113                                    catch (Exception e) {
114                                    }
115                            }
116                    }
117            }
118    
119            private void put(String line) {
120                    line = line.trim();
121    
122                    if (!_isComment(line)) {
123                            int pos = line.indexOf(StringPool.EQUAL);
124    
125                            if (pos != -1) {
126                                    String key = line.substring(0, pos).trim();
127                                    String value = line.substring(pos + 1).trim();
128    
129                                    if (_safe) {
130                                            value = _decode(value);
131                                    }
132    
133                                    setProperty(key, value);
134                            }
135                            else {
136                                    _log.error("Invalid property on line " + line);
137                            }
138                    }
139            }
140    
141            public String put(String key, String value) {
142                    if (key == null) {
143                            return null;
144                    }
145                    else {
146                            if (value == null) {
147                                    return remove(key);
148                            }
149                            else {
150                                    _length += key.length() + value.length() + 2;
151    
152                                    return super.put(key, value);
153                            }
154                    }
155            }
156    
157            public String remove(Object key) {
158                    if ((key == null) || !containsKey(key)) {
159                            return null;
160                    }
161                    else {
162                            String keyString = (String)key;
163    
164                            String value = super.remove(key);
165    
166                            _length -= keyString.length() + value.length() + 2;
167    
168                            return value;
169                    }
170            }
171    
172            public String setProperty(String key, String value) {
173                    return put(key, value);
174            }
175    
176            public String toString() {
177                    StringBuilder sb = new StringBuilder(_length);
178    
179                    for (String key : keySet()) {
180                            String value = get(key);
181    
182                            if (Validator.isNotNull(value)) {
183                                    if (_safe) {
184                                            value = _encode(value);
185                                    }
186    
187                                    sb.append(key);
188                                    sb.append(StringPool.EQUAL);
189                                    sb.append(value);
190                                    sb.append(StringPool.NEW_LINE);
191                            }
192                    }
193    
194                    return sb.toString();
195            }
196    
197            protected int getToStringLength() {
198                    return _length;
199            }
200    
201            private static String _decode(String value) {
202                    return StringUtil.replace(
203                            value, _SAFE_NEWLINE_CHARACTER, StringPool.NEW_LINE);
204            }
205    
206            private static String _encode(String value) {
207                    return StringUtil.replace(
208                            value,
209                            new String[] {
210                                    StringPool.RETURN_NEW_LINE, StringPool.NEW_LINE,
211                                    StringPool.RETURN
212                            },
213                            new String[] {
214                                    _SAFE_NEWLINE_CHARACTER, _SAFE_NEWLINE_CHARACTER,
215                                    _SAFE_NEWLINE_CHARACTER
216                            });
217            }
218    
219            private boolean _isComment(String line) {
220                    return line.length() == 0 || line.startsWith(StringPool.POUND);
221            }
222    
223            private static final String _SAFE_NEWLINE_CHARACTER =
224                    "_SAFE_NEWLINE_CHARACTER_";
225    
226            private static Log _log = LogFactoryUtil.getLog(UnicodeProperties.class);
227    
228            private boolean _safe = false;
229            private int _length;
230    
231    }