1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.ini4j;
17
18 import org.ini4j.spi.BeanAccess;
19 import org.ini4j.spi.BeanTool;
20 import org.ini4j.spi.Warnings;
21
22 import java.lang.reflect.Array;
23
24 import java.util.regex.Matcher;
25 import java.util.regex.Pattern;
26
27 public class BasicOptionMap extends CommonMultiMap<String, String> implements OptionMap
28 {
29 private static final char SUBST_CHAR = '$';
30 private static final String SYSTEM_PROPERTY_PREFIX = "@prop/";
31 private static final String ENVIRONMENT_PREFIX = "@env/";
32 private static final int SYSTEM_PROPERTY_PREFIX_LEN = SYSTEM_PROPERTY_PREFIX.length();
33 private static final int ENVIRONMENT_PREFIX_LEN = ENVIRONMENT_PREFIX.length();
34 private static final Pattern EXPRESSION = Pattern.compile("(?<!\\\\)\\$\\{(([^\\[\\}]+)(\\[([0-9]+)\\])?)\\}");
35 private static final int G_OPTION = 2;
36 private static final int G_INDEX = 4;
37 private static final long serialVersionUID = 325469712293707584L;
38 private BeanAccess _defaultBeanAccess;
39 private final boolean _propertyFirstUpper;
40
41 public BasicOptionMap()
42 {
43 this(false);
44 }
45
46 public BasicOptionMap(boolean propertyFirstUpper)
47 {
48 _propertyFirstUpper = propertyFirstUpper;
49 }
50
51 @Override
52 @SuppressWarnings(Warnings.UNCHECKED)
53 public <T> T getAll(Object key, Class<T> clazz)
54 {
55 requireArray(clazz);
56 T value;
57
58 value = (T) Array.newInstance(clazz.getComponentType(), length(key));
59 for (int i = 0; i < length(key); i++)
60 {
61 Array.set(value, i, BeanTool.getInstance().parse(get(key, i), clazz.getComponentType()));
62 }
63
64 return value;
65 }
66
67 @Override public void add(String key, Object value)
68 {
69 super.add(key, ((value == null) || (value instanceof String)) ? (String) value : String.valueOf(value));
70 }
71
72 @Override public void add(String key, Object value, int index)
73 {
74 super.add(key, ((value == null) || (value instanceof String)) ? (String) value : String.valueOf(value), index);
75 }
76
77 @Override public <T> T as(Class<T> clazz)
78 {
79 return BeanTool.getInstance().proxy(clazz, getDefaultBeanAccess());
80 }
81
82 @Override public <T> T as(Class<T> clazz, String keyPrefix)
83 {
84 return BeanTool.getInstance().proxy(clazz, newBeanAccess(keyPrefix));
85 }
86
87 @Override public String fetch(Object key)
88 {
89 int len = length(key);
90
91 return (len == 0) ? null : fetch(key, len - 1);
92 }
93
94 @Override public String fetch(Object key, String defaultValue)
95 {
96 String str = get(key);
97
98 return (str == null) ? defaultValue : str;
99 }
100
101 @Override public String fetch(Object key, int index)
102 {
103 String value = get(key, index);
104
105 if ((value != null) && (value.indexOf(SUBST_CHAR) >= 0))
106 {
107 StringBuilder buffer = new StringBuilder(value);
108
109 resolve(buffer);
110 value = buffer.toString();
111 }
112
113 return value;
114 }
115
116 @Override public <T> T fetch(Object key, Class<T> clazz)
117 {
118 return BeanTool.getInstance().parse(fetch(key), clazz);
119 }
120
121 @Override public <T> T fetch(Object key, Class<T> clazz, T defaultValue)
122 {
123 String str = fetch(key);
124
125 return (str == null) ? defaultValue : BeanTool.getInstance().parse(str, clazz);
126 }
127
128 @Override public <T> T fetch(Object key, int index, Class<T> clazz)
129 {
130 return BeanTool.getInstance().parse(fetch(key, index), clazz);
131 }
132
133 @Override
134 @SuppressWarnings(Warnings.UNCHECKED)
135 public <T> T fetchAll(Object key, Class<T> clazz)
136 {
137 requireArray(clazz);
138 T value;
139
140 value = (T) Array.newInstance(clazz.getComponentType(), length(key));
141 for (int i = 0; i < length(key); i++)
142 {
143 Array.set(value, i, BeanTool.getInstance().parse(fetch(key, i), clazz.getComponentType()));
144 }
145
146 return value;
147 }
148
149 @Override public void from(Object bean)
150 {
151 BeanTool.getInstance().inject(getDefaultBeanAccess(), bean);
152 }
153
154 @Override public void from(Object bean, String keyPrefix)
155 {
156 BeanTool.getInstance().inject(newBeanAccess(keyPrefix), bean);
157 }
158
159 @Override public <T> T get(Object key, Class<T> clazz)
160 {
161 return BeanTool.getInstance().parse(get(key), clazz);
162 }
163
164 @Override public String get(Object key, String defaultValue)
165 {
166 String str = get(key);
167
168 return (str == null) ? defaultValue : str;
169 }
170
171 @Override public <T> T get(Object key, Class<T> clazz, T defaultValue)
172 {
173 String str = get(key);
174
175 return (str == null) ? defaultValue : BeanTool.getInstance().parse(str, clazz);
176 }
177
178 @Override public <T> T get(Object key, int index, Class<T> clazz)
179 {
180 return BeanTool.getInstance().parse(get(key, index), clazz);
181 }
182
183 @Override public String put(String key, Object value)
184 {
185 return super.put(key, ((value == null) || (value instanceof String)) ? (String) value : String.valueOf(value));
186 }
187
188 @Override public String put(String key, Object value, int index)
189 {
190 return super.put(key, ((value == null) || (value instanceof String)) ? (String) value : String.valueOf(value), index);
191 }
192
193 @Override public void putAll(String key, Object value)
194 {
195 if (value != null)
196 {
197 requireArray(value.getClass());
198 }
199
200 remove(key);
201 if (value != null)
202 {
203 int n = Array.getLength(value);
204
205 for (int i = 0; i < n; i++)
206 {
207 add(key, Array.get(value, i));
208 }
209 }
210 }
211
212 @Override public void to(Object bean)
213 {
214 BeanTool.getInstance().inject(bean, getDefaultBeanAccess());
215 }
216
217 @Override public void to(Object bean, String keyPrefix)
218 {
219 BeanTool.getInstance().inject(bean, newBeanAccess(keyPrefix));
220 }
221
222 synchronized BeanAccess getDefaultBeanAccess()
223 {
224 if (_defaultBeanAccess == null)
225 {
226 _defaultBeanAccess = newBeanAccess();
227 }
228
229 return _defaultBeanAccess;
230 }
231
232 boolean isPropertyFirstUpper()
233 {
234 return _propertyFirstUpper;
235 }
236
237 BeanAccess newBeanAccess()
238 {
239 return new Access();
240 }
241
242 BeanAccess newBeanAccess(String propertyNamePrefix)
243 {
244 return new Access(propertyNamePrefix);
245 }
246
247 void resolve(StringBuilder buffer)
248 {
249 Matcher m = EXPRESSION.matcher(buffer);
250
251 while (m.find())
252 {
253 String name = m.group(G_OPTION);
254 int index = (m.group(G_INDEX) == null) ? -1 : Integer.parseInt(m.group(G_INDEX));
255 String value;
256
257 if (name.startsWith(ENVIRONMENT_PREFIX))
258 {
259 value = Config.getEnvironment(name.substring(ENVIRONMENT_PREFIX_LEN));
260 }
261 else if (name.startsWith(SYSTEM_PROPERTY_PREFIX))
262 {
263 value = Config.getSystemProperty(name.substring(SYSTEM_PROPERTY_PREFIX_LEN));
264 }
265 else
266 {
267 value = (index == -1) ? fetch(name) : fetch(name, index);
268 }
269
270 if (value != null)
271 {
272 buffer.replace(m.start(), m.end(), value);
273 m.reset(buffer);
274 }
275 }
276 }
277
278 private void requireArray(Class clazz)
279 {
280 if (!clazz.isArray())
281 {
282 throw new IllegalArgumentException("Array required");
283 }
284 }
285
286 class Access implements BeanAccess
287 {
288 private final String _prefix;
289
290 Access()
291 {
292 this(null);
293 }
294
295 Access(String prefix)
296 {
297 _prefix = prefix;
298 }
299
300 @Override public void propAdd(String propertyName, String value)
301 {
302 add(transform(propertyName), value);
303 }
304
305 @Override public String propDel(String propertyName)
306 {
307 return remove(transform(propertyName));
308 }
309
310 @Override public String propGet(String propertyName)
311 {
312 return fetch(transform(propertyName));
313 }
314
315 @Override public String propGet(String propertyName, int index)
316 {
317 return fetch(transform(propertyName), index);
318 }
319
320 @Override public int propLength(String propertyName)
321 {
322 return length(transform(propertyName));
323 }
324
325 @Override public String propSet(String propertyName, String value)
326 {
327 return put(transform(propertyName), value);
328 }
329
330 @Override public String propSet(String propertyName, String value, int index)
331 {
332 return put(transform(propertyName), value, index);
333 }
334
335 private String transform(String orig)
336 {
337 String ret = orig;
338
339 if (((_prefix != null) || isPropertyFirstUpper()) && (orig != null))
340 {
341 StringBuilder buff = new StringBuilder();
342
343 if (_prefix != null)
344 {
345 buff.append(_prefix);
346 }
347
348 if (isPropertyFirstUpper())
349 {
350 buff.append(Character.toUpperCase(orig.charAt(0)));
351 buff.append(orig.substring(1));
352 }
353 else
354 {
355 buff.append(orig);
356 }
357
358 ret = buff.toString();
359 }
360
361 return ret;
362 }
363 }
364 }