001package net.gdface.utils;
002
003import java.io.File;
004import java.io.FileWriter;
005import java.io.IOException;
006import java.io.InputStream;
007import java.io.InputStreamReader;
008import java.net.URL;
009import java.util.HashSet;
010import java.util.Properties;
011import java.util.Set;
012
013/**
014 * 配置文件读取工具类
015 * @author guyadong
016 *
017 */
018public class ConfigUtils {
019        private static final String JAR_SUFFIX = ".jar";
020
021        /**
022         * 顺序加载不同位置的properties文件,加载顺序为:<br>
023         * 1.调用{@link ClassLoader#getResource(String)}方法在{@code clazz}所在位置查找,如果失败则抛出异常<br>
024         * 2.如果class在jar包中,则尝试读取在jar所在位置../confFolder/propFile,tomcat下即为WEB-INF/confFolder/propFile<br>
025         * 3.如果环境变量envVar定义,则从envVar指定的目录下读取propFile<br>
026         * 4.user.dir下查找confFolder/propFile加载配置<br>
027         * 后面的配置变量会覆盖前面的定义<br>
028         * @param propFile 要加载的properties文件名,为{@code null}或空时抛出异常 {@link IllegalArgumentException}
029         * @param confFolder popFile所在文件夹,{@code null}时使用默认值'conf'
030         * @param envVar 环境变量名 用于定义propFile位置,可为{@code null}
031         * @param clazz 用于获取 {@link ClassLoader}的类,为null时使用本类的class
032         * @param showProp 加载后是否显示所有值
033         * @return 返回加载后的{@link Properties}对象
034         */
035        public static Properties loadAllProperties(String propFile, String confFolder, String envVar, Class<?> clazz, boolean showProp) {
036                if(null==propFile||propFile.isEmpty()){
037                        throw new IllegalArgumentException("the argument 'propFile' must not be null or empty");
038                }
039                if (null == confFolder){
040                        confFolder = "conf";
041                }
042                if (null == clazz){
043                        clazz = ConfigUtils.class;
044                }
045                final String fileSeparator = System.getProperty("file.separator");
046                String propPath = confFolder.concat(System.getProperty("file.separator")).concat(propFile);
047                Properties props = new Properties();
048                Set<File> loadedFiles = new HashSet<File>();
049                try {
050                        // 在jar包中查找默认配置文件
051                        URL url = clazz.getClassLoader().getResource(propPath.replace(fileSeparator, "/"));
052                        if(null==url){
053                                throw new ExceptionInInitializerError(String.format("not found default properties %s", propPath));
054                        }
055                        loadProperties(url, props);
056                } catch (Exception e) {
057                        // 默认配置必须加载成功否则抛出异常
058                        throw new ExceptionInInitializerError(String.format("fail to load default properties(加载默认配置文件失败) %s cause by %s", propPath,
059                                        e.getMessage()));
060                }
061                try {
062                        // 加载 jar包所在位置 ../conf/cassdk.properties
063                        URL classLocation = clazz.getProtectionDomain().getCodeSource().getLocation();
064                        if (classLocation.toString().endsWith(JAR_SUFFIX)) {
065                                // jar包所在目录的父目录,tomcat下即为WEB-INF
066                                File jarParent = new File(classLocation.getPath()).getParentFile().getParentFile();
067                                if (null != jarParent) {
068                                        File confFile = new File(jarParent, propPath);
069                                        if (confFile.isFile()) {
070                                                loadProperties(confFile.toURI().toURL(), props);
071                                                loadedFiles.add(confFile);
072                                        }
073                                }
074                        }
075                } catch (Exception e) {
076                }
077                try {
078                        // 通过环境变量查找properties文件
079                        if (envVar != null && !envVar.isEmpty()) {
080                                String cf = System.getProperty(envVar);
081                                if (null != cf&&!cf.isEmpty()) {
082                                        File envFile = new File(cf, propFile);
083                                        if (!loadedFiles.contains(envFile)) {
084                                                loadProperties(envFile.toURI().toURL(), props);
085                                                loadedFiles.add(envFile);
086                                        }
087                                } else{
088                                        log("not defined environment variable '%s'", envVar);
089                                }
090                        }
091                } catch (Exception e) {
092                }
093                try {
094                        // 在当前路径下查找配置文件
095                        File propInUserDir = new File(System.getProperty("user.dir"), propPath);
096                        if (propInUserDir.isFile() && !loadedFiles.contains(propInUserDir)) {
097                                loadProperties(propInUserDir.toURI().toURL(), props);
098                                loadedFiles.add(propInUserDir);
099                        }
100                } catch (Exception e) {
101                }
102
103                // 输出所有参数值
104                if(showProp){
105                        props.list(System.out);
106                }
107                return props;
108        }
109        
110        /**
111         * 基于user.home,加载相对路径propPath指定的properties文件
112         * @param propPath
113         * @return
114         */
115        public static Properties loadPropertiesInUserHome(String propPath){
116                Properties props = new Properties();
117                try {
118                        // 在user.home路径下查找配置文件
119                        File propInUserHome = new File(System.getProperty("user.home"), propPath);
120                        if (propInUserHome.isFile() ) {
121                                loadProperties(propInUserHome.toURI().toURL(), props);
122                        }
123                } catch (Exception e) {
124                }
125                return props;
126        }
127        /**
128         * 基于user.home,保存指定的{@link Properties}
129         * @param properties
130         * @param propertiesFile properties文件名
131         * @throws IOException
132         * @see {@link Properties#store(java.io.Writer, String)}
133         * @see {@link System#getProperties()}
134         */
135        public static void storePropertiesInUserHome(Properties properties,String propertiesFile) throws IOException{
136                if(null==properties){
137                        throw new NullPointerException();
138                }
139                if(null==propertiesFile||propertiesFile.isEmpty()){
140                        throw new IllegalArgumentException("propertiesFile must not be empty or null");
141                }
142                File propInUserHome = new File(System.getProperty("user.home"), propertiesFile);
143                File parent=propInUserHome.getParentFile();
144                if(!parent.exists()){
145                        parent.mkdirs();
146                }
147                properties.store(new FileWriter(propInUserHome), null);
148
149        }
150        /**
151         * configure with the parameters given in the given url
152         * 
153         * @param url
154         *            the resource filename to be used
155         * @param props
156         *            dest properties to add
157         * @throws IOException
158         */
159        private static void loadProperties(URL url, Properties props) throws IOException {
160                if (null != url) {
161                        InputStream is = null;
162                        try {
163                                props.load(new InputStreamReader(is = url.openStream(),"UTF-8"));
164                                log("Load properties from %s", url.toString());
165                        } finally {
166                                if (is != null){
167                                        is.close();
168                                }
169                        }                       
170                }
171        }
172        private static void log(String format, Object ... args){
173                System.out.printf("[%s:%d]%s\n", 
174                                ConfigUtils.class.getSimpleName(),
175                                Thread.currentThread() .getStackTrace()[2].getLineNumber(),
176                                String.format(format, args));
177        }
178}