1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    *
5    *
6    *
7    * The contents of this file are subject to the terms of the Liferay Enterprise
8    * Subscription License ("License"). You may not use this file except in
9    * compliance with the License. You can obtain a copy of the License by
10   * contacting Liferay, Inc. See the License for the specific language governing
11   * permissions and limitations under the License, including but not limited to
12   * distribution rights of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.kernel.util;
24  
25  import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader;
26  import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
27  import com.liferay.portal.kernel.log.Log;
28  import com.liferay.portal.kernel.log.LogFactoryUtil;
29  
30  import java.io.IOException;
31  
32  import java.util.HashMap;
33  
34  /**
35   * <a href="UnicodeProperties.java.html"><b><i>View Source</i></b></a>
36   *
37   * <p>
38   * This is a rewrite of java.util.Properties that is not synchronized and
39   * natively supports non-ASCII encodings. It can also be configured to be
40   * "safe", allowing the values to have new line characters. When stored to a
41   * given BufferedWriter, "safe" properties will replace all new line characters
42   * with a _SAFE_NEWLINE_CHARACTER_.
43   * </p>
44   *
45   * <p>
46   * In its current form, this is not intended to replace java.util.Properties for
47   * reading properties flat files. This class is not thread-safe.
48   * </p>
49   *
50   * @author Alexander Chow
51   */
52  public class UnicodeProperties extends HashMap<String, String> {
53  
54      public UnicodeProperties() {
55          super();
56      }
57  
58      public UnicodeProperties(boolean safe) {
59          super();
60  
61          _safe = safe;
62      }
63  
64      public String getProperty(String key) {
65          return get(key);
66      }
67  
68      public String getProperty(String key, String defaultValue) {
69          if (containsKey(key)) {
70              return getProperty(key);
71          }
72          else {
73              return defaultValue;
74          }
75      }
76  
77      public boolean isSafe() {
78          return _safe;
79      }
80  
81      public void load(String props) throws IOException {
82          if (Validator.isNull(props)) {
83              return;
84          }
85  
86          UnsyncBufferedReader unsyncBufferedReader = null;
87  
88          try {
89              unsyncBufferedReader = new UnsyncBufferedReader(
90                  new UnsyncStringReader(props));
91  
92              String line = unsyncBufferedReader.readLine();
93  
94              while (line != null) {
95                  line = line.trim();
96  
97                  if (_isComment(line)) {
98                      line = unsyncBufferedReader.readLine();
99  
100                     continue;
101                 }
102 
103                 int pos = line.indexOf(StringPool.EQUAL);
104 
105                 if (pos != -1) {
106                     String key = line.substring(0, pos).trim();
107                     String value = line.substring(pos + 1).trim();
108 
109                     if (_safe) {
110                         value = _decode(value);
111                     }
112 
113                     setProperty(key, value);
114                 }
115                 else {
116                     _log.error("Invalid property on line " + line);
117                 }
118 
119                 line = unsyncBufferedReader.readLine();
120             }
121         }
122         finally {
123             if (unsyncBufferedReader != null) {
124                 try {
125                     unsyncBufferedReader.close();
126                 }
127                 catch (Exception e) {
128                 }
129             }
130         }
131     }
132 
133     public String put(String key, String value) {
134         if (key == null) {
135             return null;
136         }
137         else {
138             if (value == null) {
139                 return remove(key);
140             }
141             else {
142                 _length += key.length() + value.length() + 2;
143 
144                 return super.put(key, value);
145             }
146         }
147     }
148 
149     public String remove(Object key) {
150         if ((key == null) || !containsKey(key)) {
151             return null;
152         }
153         else {
154             String keyString = (String)key;
155 
156             String value = super.remove(key);
157 
158             _length -= keyString.length() + value.length() + 2;
159 
160             return value;
161         }
162     }
163 
164     public String setProperty(String key, String value) {
165         return put(key, value);
166     }
167 
168     public String toString() {
169         StringBuilder sb = new StringBuilder(_length);
170 
171         for (String key : keySet()) {
172             String value = get(key);
173 
174             if (Validator.isNotNull(value)) {
175                 if (_safe) {
176                     value = _encode(value);
177                 }
178 
179                 sb.append(key);
180                 sb.append(StringPool.EQUAL);
181                 sb.append(value);
182                 sb.append(StringPool.NEW_LINE);
183             }
184         }
185 
186         return sb.toString();
187     }
188 
189     protected int getToStringLength() {
190         return _length;
191     }
192 
193     private static String _decode(String value) {
194         return StringUtil.replace(
195             value, _SAFE_NEWLINE_CHARACTER, StringPool.NEW_LINE);
196     }
197 
198     private static String _encode(String value) {
199         return StringUtil.replace(
200             value,
201             new String[] {
202                 StringPool.RETURN_NEW_LINE, StringPool.NEW_LINE,
203                 StringPool.RETURN
204             },
205             new String[] {
206                 _SAFE_NEWLINE_CHARACTER, _SAFE_NEWLINE_CHARACTER,
207                 _SAFE_NEWLINE_CHARACTER
208             });
209     }
210 
211     private boolean _isComment(String line) {
212         return line.length() == 0 || line.startsWith(StringPool.POUND);
213     }
214 
215     private static final String _SAFE_NEWLINE_CHARACTER =
216         "_SAFE_NEWLINE_CHARACTER_";
217 
218     private static Log _log = LogFactoryUtil.getLog(UnicodeProperties.class);
219 
220     private boolean _safe = false;
221     private int _length;
222 
223 }