001    /**
002     * Copyright (c) 2000-2013 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    import java.util.Set;
026    import java.util.TreeSet;
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 = getProperty(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                            int pos = line.indexOf(CharPool.EQUAL);
128    
129                            if (pos != -1) {
130                                    String key = line.substring(0, pos).trim();
131                                    String value = line.substring(pos + 1).trim();
132    
133                                    if (_safe) {
134                                            value = _decode(value);
135                                    }
136    
137                                    setProperty(key, value);
138                            }
139                            else {
140                                    _log.error("Invalid property on line " + line);
141                            }
142                    }
143            }
144    
145            @Override
146            public String put(String key, String value) {
147                    if (key == null) {
148                            return null;
149                    }
150    
151                    if (value == null) {
152                            return remove(key);
153                    }
154    
155                    _length += key.length() + value.length() + 2;
156    
157                    return super.put(key, value);
158            }
159    
160            @Override
161            public String remove(Object key) {
162                    if ((key == null) || !containsKey(key)) {
163                            return null;
164                    }
165    
166                    String keyString = (String)key;
167    
168                    String value = super.remove(key);
169    
170                    _length -= keyString.length() + value.length() + 2;
171    
172                    return value;
173            }
174    
175            public String setProperty(String key, String value) {
176                    return put(key, value);
177            }
178    
179            /**
180             * @deprecated As of 7.0.0, replaced by {@link #toString}
181             */
182            @Deprecated
183            public String toSortedString() {
184                    return toString();
185            }
186    
187            @Override
188            public String toString() {
189                    StringBuilder sb = new StringBuilder(_length);
190    
191                    Set<String> keys = new TreeSet<String>(keySet());
192    
193                    for (String key : keys) {
194                            String value = get(key);
195    
196                            if (Validator.isNull(value)) {
197                                    continue;
198                            }
199    
200                            if (_safe) {
201                                    value = _encode(value);
202                            }
203    
204                            sb.append(key);
205                            sb.append(StringPool.EQUAL);
206                            sb.append(value);
207                            sb.append(StringPool.NEW_LINE);
208                    }
209    
210                    return sb.toString();
211            }
212    
213            protected int getToStringLength() {
214                    return _length;
215            }
216    
217            private static String _decode(String value) {
218                    return StringUtil.replace(
219                            value, _SAFE_NEWLINE_CHARACTER, StringPool.NEW_LINE);
220            }
221    
222            private static String _encode(String value) {
223                    return StringUtil.replace(
224                            value,
225                            new String[] {
226                                    StringPool.RETURN_NEW_LINE, StringPool.NEW_LINE,
227                                    StringPool.RETURN
228                            },
229                            new String[] {
230                                    _SAFE_NEWLINE_CHARACTER, _SAFE_NEWLINE_CHARACTER,
231                                    _SAFE_NEWLINE_CHARACTER
232                            });
233            }
234    
235            private boolean _isComment(String line) {
236                    return (line.length() == 0) || line.startsWith(StringPool.POUND);
237            }
238    
239            private static final String _SAFE_NEWLINE_CHARACTER =
240                    "_SAFE_NEWLINE_CHARACTER_";
241    
242            private static Log _log = LogFactoryUtil.getLog(UnicodeProperties.class);
243    
244            private int _length;
245            private boolean _safe = false;
246    
247    }