1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions 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.log.Log;
26  import com.liferay.portal.kernel.log.LogFactoryUtil;
27  
28  import java.io.BufferedReader;
29  import java.io.IOException;
30  import java.io.StringReader;
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   */
53  public class UnicodeProperties extends HashMap<String, String> {
54  
55      public UnicodeProperties() {
56          super();
57      }
58  
59      public UnicodeProperties(boolean safe) {
60          super();
61  
62          _safe = safe;
63      }
64  
65      public String getProperty(String key) {
66          return get(key);
67      }
68  
69      public String getProperty(String key, String defaultValue) {
70          if (containsKey(key)) {
71              return getProperty(key);
72          }
73          else {
74              return defaultValue;
75          }
76      }
77  
78      public boolean isSafe() {
79          return _safe;
80      }
81  
82      public void load(String props) throws IOException {
83          if (Validator.isNull(props)) {
84              return;
85          }
86  
87          BufferedReader br = null;
88  
89          try {
90              br = new BufferedReader(new StringReader(props));
91  
92              String line = br.readLine();
93  
94              while (line != null) {
95                  line = line.trim();
96  
97                  if (_isComment(line)) {
98                      line = br.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 = br.readLine();
120             }
121         }
122         finally {
123             if (br != null) {
124                 try {
125                     br.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 }