View Javadoc

1   /*
2    * Copyright 2005,2009 Ivan SZKIBA
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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 }