001/**   
002 * @Title: Configuratoin.java 
003 * @Package net.gdface.utils 
004 * @Description: 管理properties文件
005 * @author guyadong   
006 * @date 2014-10-14 下午3:20:09 
007 * @version V1.0   
008 */
009package net.gdface.utils;
010
011import java.io.File;
012import java.io.IOException;
013import java.io.InputStream;
014import java.lang.reflect.InvocationTargetException;
015import java.net.URL;
016import java.util.Properties;
017import java.util.Map.Entry;
018
019/**读取配置文件(properties)中的参数
020 * @author guyadong
021 * 
022 */
023public class Configuration extends Properties{
024        private static final long serialVersionUID = -3929851625670931787L;
025        /**
026         * property 属性名前缀,在调用{@link #getProperty(String)}或其他getProperty方法时参数会自动加上该前缀,默认为"",
027         * 如prefix为 net.gdface.facedbsdk.FaceDbSDKLocal
028         * 调用getProperty("minThread")时,其实是执行getProperty("net.gdface.facedbsdk.FaceDbSDKLocal.minThread")
029         */
030        private ThreadLocal<String> prefixs = new ThreadLocal<String>() {
031                @Override
032                protected String initialValue() {
033                        return "";//prefix初始值为""
034                }
035        };
036
037        /**使用指定的ClassLoader加载properties文件propFile
038         * @param classLoader
039         * @param propFile
040         * @throws IOException
041         * @see #configure(URL)
042         */
043        public Configuration(ClassLoader classLoader,String propFile) throws IOException {
044                URL url= classLoader.getResource(propFile);
045                if(null==url)
046                        throw new IOException(String.format("Cant found resource [%s] by %s",propFile,classLoader.getClass().getName()));
047                configure(url);
048        }
049        /**
050         * 从{@link File}构造对象
051         * @param propFile
052         * @throws IOException
053         */
054        public Configuration(File propFile) throws IOException {
055                this(propFile.toURI().toURL());
056        }       
057        public Configuration() {
058                super();
059        }
060        public Configuration(Properties defaults) {
061                super(defaults);
062        }
063        /**
064         * @param url
065         * @throws IOException
066         */
067        public Configuration(URL url) throws IOException {
068                configure(url);
069        }       
070        /**
071         * 根据{@link URL}加载配置文件
072         * @param url
073         * @throws IOException
074         * @see #configure(InputStream)
075         */
076        private void configure(URL url) throws IOException {
077                if(null==url)
078                        throw new NullPointerException("parameter [url] is null");
079                System.out.printf("Load properties from [%s]\n", url.toString());
080                InputStream is = url.openStream();
081                try {
082                        load(is);
083                } finally {
084                        is.close();
085                }
086        }
087        
088        /**
089         * 读取指定的key,用静态valueOf方法(如果有)将之转换成clazz指定的类型<br>
090         * 适用于{@link Number},{@link Boolean}类型,如果key不存在或为空或转换出错则返回null
091         * 
092         * @param key
093         * @param clazz
094         * @return
095         */
096        @SuppressWarnings("unchecked")
097        private <T> T _getPropertyBaseType(String key, Class<T> clazz) {
098                if (null == key||0==key.length())
099                        throw new IllegalArgumentException("the argument 'key' must not be null or empty");
100                if (null == clazz)
101                        throw new IllegalArgumentException("the argument 'clazz' must not be null");
102                String value = getProperty(key);
103                try {
104                        return null == value|| 0 == value.length() ? null : (T) clazz.getMethod("valueOf", String.class).invoke(null, value.trim());
105                } catch (NoSuchMethodException e) {
106                        new RuntimeException(
107                                        String.format("%s:not found static method 'valueOf' for %s", e.getClass().getSimpleName(),
108                                                        clazz.getName()), e);
109                } catch (IllegalAccessException e) {
110                        new RuntimeException(
111                                        String.format("%s:can't invoke method 'valueOf' for %s", e.getClass().getSimpleName(),
112                                                        clazz.getName()), e);
113                } catch (InvocationTargetException e) {
114                        try {
115                                throw e.getCause();
116                        } catch (NumberFormatException ie) {
117                                System.out.printf("%s: [%s=%s] can't be convert to %s\n", e.getClass().getSimpleName(), key, value,
118                                                clazz.getName());
119                        } catch (Throwable ie) {
120                                new RuntimeException(ie);
121                        }
122                }
123                return null;
124        }
125        
126        /**
127         * 设置指定的key为value
128         * 
129         * @param key
130         *            为{@link null}时抛出 {@link IllegalArgumentException}<br>
131         *            适用于{@link Number},{@link Boolean}类型
132         * @param value
133         *            为{@code null}时删除key并返回{@code null}
134         * @return 用静态valueOf方法返回key原来的值
135         */
136        @SuppressWarnings("unchecked")
137        private <T> T _setPropertyBaseType(String key, T value) {               
138                if (null == key||0==key.length())
139                        throw new IllegalArgumentException("the argument 'key' must not be null or empty");
140                // value为null时删除key,并返回null
141                if(null==value){remove(key);return null;}
142                try {
143                        String old = (String) setProperty(key,value.toString());
144                        return null == old|| 0 == old.length() ? null : (T) value.getClass().getMethod("valueOf", String.class).invoke(null, old.trim());
145                } catch (NoSuchMethodException e) {
146                        new RuntimeException(
147                                        String.format("%s:not found static method 'valueOf' for %s", e.getClass().getSimpleName(),
148                                                        value.getClass().getName()), e);
149                } catch (IllegalAccessException e) {
150                        new RuntimeException(
151                                        String.format("%s:can't invoke method 'valueOf' for %s", e.getClass().getSimpleName(),
152                                                        value.getClass().getName()), e);
153                } catch (InvocationTargetException e) {
154                        try {
155                                throw e.getCause();
156                        } catch (NumberFormatException ie) {
157                                System.out.printf("%s: [%s=%s] can't be convert to %s\n", e.getClass().getSimpleName(), key, value.toString(),
158                                                value.getClass().getName());
159                        } catch (Throwable ie) {
160                                new RuntimeException(ie);
161                        }
162                }
163                return null;
164        }
165        
166        @Override
167        public String getProperty(String key) {
168                return super.getProperty(this.getPrefix()+key);
169        }
170
171        @Override
172        public String getProperty(String key, String defaultValue) {
173                return super.getProperty(key, defaultValue);
174        }
175
176        @Override
177        public synchronized Object setProperty(String key, String value) {
178                return super.setProperty(this.getPrefix()+key, value);
179        }
180        /**读取指定的key,将之转换成与defaultValue类型相同的对象,如果key不存在或转换出错则返回defaultValue
181         * @param key
182         * @param defaultValue 缺省值
183         * @return
184         */
185        public <T> T getPropertyBaseType(String key, T defaultValue) {
186                if (null == defaultValue)
187                        throw new IllegalArgumentException("the argument 'defaultValue' must not be null");
188                @SuppressWarnings("unchecked")
189                T res = (T) _getPropertyBaseType(key,defaultValue.getClass());
190                return  ((null==res)?defaultValue:res);
191        }
192
193        public Boolean getPropertyBoolean(String key) {
194                return _getPropertyBaseType(key, Boolean.class);
195        }
196
197        public Boolean getPropertyBoolean(String key, Boolean defaultValue) {
198                return getPropertyBaseType(key, defaultValue);
199        }
200        
201        public Byte getPropertyByte(String key) {
202                return _getPropertyBaseType(key, Byte.class);
203        }
204        public Byte getPropertyByte(String key,Byte defaultValue) {
205                return getPropertyBaseType(key, defaultValue);
206        }
207        public Double getPropertyDouble(String key) {
208                return _getPropertyBaseType(key, Double.class);
209        }
210
211        public Double getPropertyDouble(String key,Double defaultValue) {
212                return getPropertyBaseType(key, defaultValue);
213        }
214
215        public Float getPropertyFloat(String key) {
216                return _getPropertyBaseType(key, Float.class);
217        }
218
219        public Float getPropertyFloat(String key,Float defaultValue) {
220                return getPropertyBaseType(key, defaultValue);
221        }
222
223        public Integer getPropertyInteger(String key) {
224                return _getPropertyBaseType(key, Integer.class);
225        }
226
227        public Integer getPropertyInteger(String key,Integer defaultValue) {
228                return getPropertyBaseType(key, defaultValue);
229        }
230
231        public Long getPropertyLong(String key) {
232                return _getPropertyBaseType(key, Long.class);
233        }
234        public Long getPropertyLong(String key,Long defaultValue) {
235                return getPropertyBaseType(key, defaultValue);
236        }
237        public Short getPropertyShort(String key) {
238                return _getPropertyBaseType(key, Short.class);
239        }
240        public Short getPropertyShort(String key,Short defaultValue) {
241                return getPropertyBaseType(key, defaultValue);
242        }
243        //////////////
244
245        public Boolean setPropertyBoolean(String key, Boolean value) {
246                return _setPropertyBaseType(key, value);
247        }
248        
249        public Byte setPropertyByte(String key,Byte value) {
250                return _setPropertyBaseType(key, value);
251        }
252
253        public Double setPropertyDouble(String key,Double value) {
254                return _setPropertyBaseType(key, value);
255        }
256
257        public Float setPropertyFloat(String key,Float value) {
258                return _setPropertyBaseType(key, value);
259        }
260
261        public Integer setPropertyInteger(String key,Integer value) {
262                return _setPropertyBaseType(key, value);
263        }
264
265        public Long setPropertyLong(String key,Long value) {
266                return _setPropertyBaseType(key, value);
267        }
268        public Short setPropertyShort(String key,Short value) {
269                return _setPropertyBaseType(key, value);
270        }
271        
272        public void setPropertyBooleanIfAbsent(String key, Boolean value) {
273                if(!containsKey(key)){
274                        setPropertyBoolean(key, value);
275                }
276        }
277        
278        public void setPropertyIfAbsent(String key, String value) {
279                if(!containsKey(key)){
280                        setProperty(key, value);
281                }
282        }
283        
284        public void setPropertyByteIfAbsent(String key,Byte value) {
285                if(!containsKey(key)){
286                        setPropertyByte(key, value);
287                }
288        }
289
290        public void setPropertyDoubleIfAbsent(String key,Double value) {
291                if(!containsKey(key)){
292                        setPropertyDouble(key, value);
293                }
294        }
295
296        public void setPropertyFloatIfAbsent(String key,Float value) {
297                if(!containsKey(key)){
298                        setPropertyFloat(key, value);
299                }
300        }
301
302        public void setPropertyIntegerIfAbsent(String key,Integer value) {
303                if(!containsKey(key)){
304                        setPropertyInteger(key, value);
305                }
306        }
307
308        public void setPropertyLongIfAbsent(String key,Long value) {
309                if(!containsKey(key)){
310                        setPropertyLong(key, value);
311                }
312        }
313        
314        public void setPropertyShortIfAbsent(String key,Short value) {
315                if(!containsKey(key)){
316                        setPropertyShort(key, value);
317                }
318        }       
319        /**如果参数为null,则prefix设置为""
320         * @param prefix 要设置的 prefix
321         * @return 
322         */
323        public Configuration setPrefix(String prefix) {
324                prefixs.set(null==prefix?"":prefix);
325                return this;
326        }
327        /**
328         * 设置 {@link #prefixs}空
329         * @return
330         */
331        public Configuration resetPrefix() {
332                return setPrefix(null);
333        }
334        /**
335         * @return prefix
336         */
337        public String getPrefix() {
338                return prefixs.get();
339        }
340        /**
341         * 返回如果指定了 {@link java.util.Properties#defaults},则返回所有相对增加或修改的值<br>
342         * 否则返回所有值
343         * @param out 输出对象,可为null
344         * @return
345         */
346        public Properties changedProperties(Properties out){
347                if(null==out)out=new Properties();
348                if(null==defaults)
349                        out.putAll(this);
350                else
351                        for(Entry<Object, Object> entry:entrySet()){
352                                String key=(String) entry.getKey();
353                                String value=(String)entry.getValue();
354                                if(!defaults.containsKey(key)||!value.equals(defaults.getProperty(key))){
355                                        out.setProperty(key, value);
356                                }
357                        }                       
358                return out;
359        }
360}