001    /**
002     * Copyright (c) 2000-present 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            }
048    
049            public UnicodeProperties(boolean safe) {
050                    _safe = safe;
051            }
052    
053            public void fastLoad(String props) {
054                    if (Validator.isNull(props)) {
055                            return;
056                    }
057    
058                    int x = props.indexOf(CharPool.NEW_LINE);
059                    int y = 0;
060    
061                    while (x != -1) {
062                            put(props.substring(y, x));
063    
064                            y = x;
065    
066                            x = props.indexOf(CharPool.NEW_LINE, y + 1);
067                    }
068    
069                    put(props.substring(y));
070            }
071    
072            public String getProperty(String key) {
073                    return get(key);
074            }
075    
076            public String getProperty(String key, String defaultValue) {
077                    String value = getProperty(key);
078    
079                    if (value == null) {
080                            return defaultValue;
081                    }
082                    else {
083                            return value;
084                    }
085            }
086    
087            public boolean isSafe() {
088                    return _safe;
089            }
090    
091            public void load(String props) throws IOException {
092                    if (Validator.isNull(props)) {
093                            return;
094                    }
095    
096                    UnsyncBufferedReader unsyncBufferedReader = null;
097    
098                    try {
099                            unsyncBufferedReader = new UnsyncBufferedReader(
100                                    new UnsyncStringReader(props));
101    
102                            String line = unsyncBufferedReader.readLine();
103    
104                            while (line != null) {
105                                    put(line);
106                                    line = unsyncBufferedReader.readLine();
107                            }
108                    }
109                    finally {
110                            if (unsyncBufferedReader != null) {
111                                    try {
112                                            unsyncBufferedReader.close();
113                                    }
114                                    catch (Exception e) {
115                                    }
116                            }
117                    }
118            }
119    
120            public void put(String line) {
121                    line = line.trim();
122    
123                    if (!_isComment(line)) {
124                            int pos = line.indexOf(CharPool.EQUAL);
125    
126                            if (pos != -1) {
127                                    String key = line.substring(0, pos).trim();
128                                    String value = line.substring(pos + 1).trim();
129    
130                                    if (_safe) {
131                                            value = _decode(value);
132                                    }
133    
134                                    setProperty(key, value);
135                            }
136                            else {
137                                    _log.error("Invalid property on line " + line);
138                            }
139                    }
140            }
141    
142            @Override
143            public String put(String key, String value) {
144                    if (key == null) {
145                            return null;
146                    }
147    
148                    if (value == null) {
149                            return remove(key);
150                    }
151    
152                    _length += key.length() + value.length() + 2;
153    
154                    return super.put(key, value);
155            }
156    
157            @Override
158            public String remove(Object key) {
159                    if ((key == null) || !containsKey(key)) {
160                            return null;
161                    }
162    
163                    String keyString = (String)key;
164    
165                    String value = super.remove(key);
166    
167                    _length -= keyString.length() + value.length() + 2;
168    
169                    return value;
170            }
171    
172            public String setProperty(String key, String value) {
173                    return put(key, value);
174            }
175    
176            /**
177             * @deprecated As of 7.0.0, replaced by {@link #toString}
178             */
179            @Deprecated
180            public String toSortedString() {
181                    return toString();
182            }
183    
184            @Override
185            public String toString() {
186                    StringBuilder sb = new StringBuilder(_length);
187    
188                    Set<String> keys = new TreeSet<String>(keySet());
189    
190                    for (String key : keys) {
191                            String value = get(key);
192    
193                            if (Validator.isNull(value)) {
194                                    continue;
195                            }
196    
197                            if (_safe) {
198                                    value = _encode(value);
199                            }
200    
201                            sb.append(key);
202                            sb.append(StringPool.EQUAL);
203                            sb.append(value);
204                            sb.append(StringPool.NEW_LINE);
205                    }
206    
207                    return sb.toString();
208            }
209    
210            protected int getToStringLength() {
211                    return _length;
212            }
213    
214            private static String _decode(String value) {
215                    return StringUtil.replace(
216                            value, _SAFE_NEWLINE_CHARACTER, StringPool.NEW_LINE);
217            }
218    
219            private static String _encode(String value) {
220                    return StringUtil.replace(
221                            value,
222                            new String[] {
223                                    StringPool.RETURN_NEW_LINE, StringPool.NEW_LINE,
224                                    StringPool.RETURN
225                            },
226                            new String[] {
227                                    _SAFE_NEWLINE_CHARACTER, _SAFE_NEWLINE_CHARACTER,
228                                    _SAFE_NEWLINE_CHARACTER
229                            });
230            }
231    
232            private boolean _isComment(String line) {
233                    return (line.length() == 0) || line.startsWith(StringPool.POUND);
234            }
235    
236            private static final String _SAFE_NEWLINE_CHARACTER =
237                    "_SAFE_NEWLINE_CHARACTER_";
238    
239            private static Log _log = LogFactoryUtil.getLog(UnicodeProperties.class);
240    
241            private int _length;
242            private boolean _safe = false;
243    
244    }