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.AbstractBeanInvocationHandler;
19 import org.ini4j.spi.BeanTool;
20 import org.ini4j.spi.IniHandler;
21
22 import java.lang.reflect.Array;
23 import java.lang.reflect.Proxy;
24
25 import java.util.regex.Matcher;
26 import java.util.regex.Pattern;
27
28 public class BasicProfile extends CommonMultiMap<String, Profile.Section> implements Profile
29 {
30 private static final String SECTION_SYSTEM_PROPERTIES = "@prop";
31 private static final String SECTION_ENVIRONMENT = "@env";
32 private static final Pattern EXPRESSION = Pattern.compile(
33 "(?<!\\\\)\\$\\{(([^\\[\\}]+)(\\[([0-9]+)\\])?/)?([^\\[^/\\}]+)(\\[(([0-9]+))\\])?\\}");
34 private static final int G_SECTION = 2;
35 private static final int G_SECTION_IDX = 4;
36 private static final int G_OPTION = 5;
37 private static final int G_OPTION_IDX = 7;
38 private static final long serialVersionUID = -1817521505004015256L;
39 private String _comment;
40 private final boolean _propertyFirstUpper;
41 private final boolean _treeMode;
42
43 public BasicProfile()
44 {
45 this(false, false);
46 }
47
48 public BasicProfile(boolean treeMode, boolean propertyFirstUpper)
49 {
50 _treeMode = treeMode;
51 _propertyFirstUpper = propertyFirstUpper;
52 }
53
54 @Override public String getComment()
55 {
56 return _comment;
57 }
58
59 @Override public void setComment(String value)
60 {
61 _comment = value;
62 }
63
64 @Override public Section add(String name)
65 {
66 if (isTreeMode())
67 {
68 int idx = name.lastIndexOf(getPathSeparator());
69
70 if (idx > 0)
71 {
72 String parent = name.substring(0, idx);
73
74 if (!containsKey(parent))
75 {
76 add(parent);
77 }
78 }
79 }
80
81 Section section = newSection(name);
82
83 add(name, section);
84
85 return section;
86 }
87
88 @Override public void add(String section, String option, Object value)
89 {
90 getOrAdd(section).add(option, value);
91 }
92
93 @Override public <T> T as(Class<T> clazz)
94 {
95 return as(clazz, null);
96 }
97
98 @Override public <T> T as(Class<T> clazz, String prefix)
99 {
100 return clazz.cast(Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[] { clazz },
101 new BeanInvocationHandler(prefix)));
102 }
103
104 @Override public String fetch(Object sectionName, Object optionName)
105 {
106 Section sec = get(sectionName);
107
108 return (sec == null) ? null : sec.fetch(optionName);
109 }
110
111 @Override public <T> T fetch(Object sectionName, Object optionName, Class<T> clazz)
112 {
113 Section sec = get(sectionName);
114
115 return (sec == null) ? BeanTool.getInstance().zero(clazz) : sec.fetch(optionName, clazz);
116 }
117
118 @Override public String get(Object sectionName, Object optionName)
119 {
120 Section sec = get(sectionName);
121
122 return (sec == null) ? null : sec.get(optionName);
123 }
124
125 @Override public <T> T get(Object sectionName, Object optionName, Class<T> clazz)
126 {
127 Section sec = get(sectionName);
128
129 return (sec == null) ? BeanTool.getInstance().zero(clazz) : sec.get(optionName, clazz);
130 }
131
132 @Override public String put(String sectionName, String optionName, Object value)
133 {
134 return getOrAdd(sectionName).put(optionName, value);
135 }
136
137 @Override public Section remove(Section section)
138 {
139 return remove((Object) section.getName());
140 }
141
142 @Override public String remove(Object sectionName, Object optionName)
143 {
144 Section sec = get(sectionName);
145
146 return (sec == null) ? null : sec.remove(optionName);
147 }
148
149 boolean isTreeMode()
150 {
151 return _treeMode;
152 }
153
154 char getPathSeparator()
155 {
156 return PATH_SEPARATOR;
157 }
158
159 boolean isPropertyFirstUpper()
160 {
161 return _propertyFirstUpper;
162 }
163
164 Section newSection(String name)
165 {
166 return new BasicProfileSection(this, name);
167 }
168
169 void resolve(StringBuilder buffer, Section owner)
170 {
171 Matcher m = EXPRESSION.matcher(buffer);
172
173 while (m.find())
174 {
175 String sectionName = m.group(G_SECTION);
176 String optionName = m.group(G_OPTION);
177 int optionIndex = parseOptionIndex(m);
178 Section section = parseSection(m, owner);
179 String value = null;
180
181 if (SECTION_ENVIRONMENT.equals(sectionName))
182 {
183 value = Config.getEnvironment(optionName);
184 }
185 else if (SECTION_SYSTEM_PROPERTIES.equals(sectionName))
186 {
187 value = Config.getSystemProperty(optionName);
188 }
189 else if (section != null)
190 {
191 value = (optionIndex == -1) ? section.fetch(optionName) : section.fetch(optionName, optionIndex);
192 }
193
194 if (value != null)
195 {
196 buffer.replace(m.start(), m.end(), value);
197 m.reset(buffer);
198 }
199 }
200 }
201
202 void store(IniHandler formatter)
203 {
204 formatter.startIni();
205 store(formatter, getComment());
206 for (Ini.Section s : values())
207 {
208 store(formatter, s);
209 }
210
211 formatter.endIni();
212 }
213
214 void store(IniHandler formatter, Section s)
215 {
216 store(formatter, getComment(s.getName()));
217 formatter.startSection(s.getName());
218 for (String name : s.keySet())
219 {
220 store(formatter, s, name);
221 }
222
223 formatter.endSection();
224 }
225
226 void store(IniHandler formatter, String comment)
227 {
228 formatter.handleComment(comment);
229 }
230
231 void store(IniHandler formatter, Section section, String option)
232 {
233 store(formatter, section.getComment(option));
234 int n = section.length(option);
235
236 for (int i = 0; i < n; i++)
237 {
238 store(formatter, section, option, i);
239 }
240 }
241
242 void store(IniHandler formatter, Section section, String option, int index)
243 {
244 formatter.handleOption(option, section.get(option, index));
245 }
246
247 private Section getOrAdd(String sectionName)
248 {
249 Section section = get(sectionName);
250
251 return ((section == null)) ? add(sectionName) : section;
252 }
253
254 private int parseOptionIndex(Matcher m)
255 {
256 return (m.group(G_OPTION_IDX) == null) ? -1 : Integer.parseInt(m.group(G_OPTION_IDX));
257 }
258
259 private Section parseSection(Matcher m, Section owner)
260 {
261 String sectionName = m.group(G_SECTION);
262 int sectionIndex = parseSectionIndex(m);
263
264 return (sectionName == null) ? owner : ((sectionIndex == -1) ? get(sectionName) : get(sectionName, sectionIndex));
265 }
266
267 private int parseSectionIndex(Matcher m)
268 {
269 return (m.group(G_SECTION_IDX) == null) ? -1 : Integer.parseInt(m.group(G_SECTION_IDX));
270 }
271
272 private final class BeanInvocationHandler extends AbstractBeanInvocationHandler
273 {
274 private final String _prefix;
275
276 private BeanInvocationHandler(String prefix)
277 {
278 _prefix = prefix;
279 }
280
281 @Override protected Object getPropertySpi(String property, Class<?> clazz)
282 {
283 String key = transform(property);
284 Object o = null;
285
286 if (containsKey(key))
287 {
288 if (clazz.isArray())
289 {
290 o = Array.newInstance(clazz.getComponentType(), length(key));
291 for (int i = 0; i < length(key); i++)
292 {
293 Array.set(o, i, get(key, i).as(clazz.getComponentType()));
294 }
295 }
296 else
297 {
298 o = get(key).as(clazz);
299 }
300 }
301
302 return o;
303 }
304
305 @Override protected void setPropertySpi(String property, Object value, Class<?> clazz)
306 {
307 String key = transform(property);
308
309 remove(key);
310 if (value != null)
311 {
312 if (clazz.isArray())
313 {
314 for (int i = 0; i < Array.getLength(value); i++)
315 {
316 Section sec = add(key);
317
318 sec.from(Array.get(value, i));
319 }
320 }
321 else
322 {
323 Section sec = add(key);
324
325 sec.from(value);
326 }
327 }
328 }
329
330 @Override protected boolean hasPropertySpi(String property)
331 {
332 return containsKey(transform(property));
333 }
334
335 String transform(String property)
336 {
337 String ret = (_prefix == null) ? property : (_prefix + property);
338
339 if (isPropertyFirstUpper())
340 {
341 StringBuilder buff = new StringBuilder();
342
343 buff.append(Character.toUpperCase(property.charAt(0)));
344 buff.append(property.substring(1));
345 ret = buff.toString();
346 }
347
348 return ret;
349 }
350 }
351 }