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.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 }