All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.gdface.facelog.GlobalConfig Maven / Gradle / Ivy

There is a newer version: 5.3.0
Show newest version
package net.gdface.facelog;

import java.io.File;
import java.net.URI;
import java.net.URL;
import java.nio.file.Paths;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.Map.Entry;
import org.apache.commons.configuration2.CombinedConfiguration;
import org.apache.commons.configuration2.Configuration;
import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
import org.apache.commons.configuration2.builder.fluent.Configurations;
import org.apache.commons.configuration2.ex.ConfigurationException;
import org.apache.commons.configuration2.io.FileHandler;
import org.apache.commons.configuration2.sync.ReadWriteSynchronizer;
import org.apache.commons.configuration2.sync.Synchronizer;
import org.apache.commons.configuration2.tree.DefaultExpressionEngine;
import org.apache.commons.configuration2.tree.DefaultExpressionEngineSymbols;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.base.Function;
import com.google.common.base.MoreObjects;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Strings;

import gu.simplemq.redis.JedisPoolLazy.PropName;
import gu.sql2java.Constant.JdbcProperty;
import gu.simplemq.MessageQueueType;
import gu.simplemq.json.BaseJsonEncoder;
import gu.simplemq.redis.JedisUtils;

import static com.google.common.base.Preconditions.*;

import static net.gdface.utils.MiscellaneousUtils.elementsOf;
import redis.clients.jedis.JedisPoolConfig;

/**
 * 配置参数管理
 * @author guyadong
 *
 */
public class GlobalConfig implements ServiceConstant{
	/** 必须为public static final,{@value #ROOT_XML}会引用  */
	public static final String HOME_FOLDER = ".facelog";
	/** 必须为public static final,{@value #ROOT_XML}会引用  */
	public static final String USER_PROPERTIES= "config.properties";
	private static final String ENCODING = "UTF-8";
	private static final String ROOT_XML = "root.xml";
	private static final URL ROOT_URL = GlobalConfig.class.getClassLoader().getResource(ROOT_XML);
	private static final String ATTR_DESCRIPTION ="description"; 
	/** 用户自定义文件位置 ${user.home}/{@value #HOME_FOLDER}/{@value #USER_PROPERTIES} */
	private static final File USER_CONFIG_FILE = Paths.get(System.getProperty("user.home"),HOME_FOLDER,USER_PROPERTIES).toFile();
	/** 全局配置参数对象(immutable,修改无效) */
	private static final CombinedConfiguration CONFIG =readConfig();
	/** 用户定义配置对象(mutable),所有对参数的修改都基于此对象 */
	private static final PropertiesConfiguration USER_CONFIG = createUserConfig();
	private GlobalConfig() {
	}
	private static CombinedConfiguration readConfig(){
		try{
			// 指定文件编码方式,否则properties文件读取中文会是乱码,要求文件编码是UTF-8
		    FileBasedConfigurationBuilder.setDefaultEncoding(PropertiesConfiguration.class, ENCODING);
		    // 使用默认表达式引擎
			DefaultExpressionEngine engine = new DefaultExpressionEngine(DefaultExpressionEngineSymbols.DEFAULT_SYMBOLS);
			Configurations configs = new Configurations();
			CombinedConfiguration config = configs.combined(ROOT_URL);
			config.setExpressionEngine(engine);
			// 设置同步器
			config.setSynchronizer(new ReadWriteSynchronizer());
			config.setConversionHandler(ConversionHandlerWithURI.INSTANCE);
			return config;
		}catch(Exception e){
			throw new ExceptionInInitializerError(e);
		}
	}
	private static PropertiesConfiguration createUserConfig(){
		PropertiesConfiguration userConfig ;
		if(CONFIG.getNumberOfConfigurations()>1){
			// 有自定义配置文件
			userConfig = (PropertiesConfiguration) CONFIG.getConfiguration(0);	
		}else{
			// root.xml中对用户配置文件指定为 config-forceCreate 就不会抛出此异常
			throw new IllegalStateException("NOT FOUND user config file,please check " + ROOT_URL );
		}
		// 设置同步器
		userConfig.setSynchronizer(new ReadWriteSynchronizer());
		userConfig.setIOFactory(IoFactoryNoescape.INSTANCE);
		return userConfig;
	}
	/**
	 * 返回{@code key}的attribute的表达式
	 * @param key
	 * @param attr attribute name
	 * @return 返回{@code key}的attribute的表达式
	 * @throws IllegalArgumentException 输入参数为{@code null}或空
	 */
	public static final String expressionOfAttribute(String key,String attr){
		checkArgument(!Strings.isNullOrEmpty(key) && !Strings.isNullOrEmpty(attr),"input argument must not be null or empty");
		return String.format("%s[@%s]", key,attr);		
	}
	/**
	 * 返回{@code key}的描述({@code 'description'})
	 * @param key
	 * @return {@code key}的描述
	 * @see #expressionOfAttribute(String, String)
	 */
	public static final String descriptionOf(String key){
		return CONFIG.getString(expressionOfAttribute(key,ATTR_DESCRIPTION),"");
	}
	/** 全局配置参数对象 */
	public static CombinedConfiguration getConfig() {
		return CONFIG;
	}

	/** 从配置文件中读取REDIS参数 */
	static Map makeRedisParameters(){
		HashMap params = new HashMap(16);
		// 优先使用REDIS_URI
		if(CONFIG.containsKey(REDIS_URI)){
			params.put(PropName.uri, CONFIG.get(URI.class,REDIS_URI));
		}else{
			String host = CONFIG.getString(REDIS_HOST,null);
			if(!Strings.isNullOrEmpty(host)){
				params.put(PropName.host, host);
			}
			params.put(PropName.port, CONFIG.getInteger(REDIS_PORT,null));
			params.put(PropName.database, CONFIG.getInteger(REDIS_DATABASE,null));
			String pwd = CONFIG.getString(REDIS_PASSWORD,null);
			if(!Strings.isNullOrEmpty(pwd)){
				params.put(PropName.password, pwd);
			}
		}
		params.put(PropName.timeout, CONFIG.getInteger(REDIS_TIMEOUT,null));

		if(CONFIG.containsKey(REDIS_POOL_MAXTOTAL)){
			JedisPoolConfig poolConfig = new JedisPoolConfig();
			poolConfig.setMaxTotal(CONFIG.getInt(REDIS_POOL_MAXTOTAL));
			params.put(PropName.jedisPoolConfig, poolConfig);
		}
		// 过滤掉所有为null的参数
		return Maps.filterValues(params, Predicates.notNull());
	}
	/**
	 * 从配置文件中读取WEBREDIS参数
	 * @return 参数名vs参数值映射
	 */
	static Map makeWebredisParameters(){
		HashMap params = new HashMap(16);
		params.put(NODEJS_EXE, valueOf(String.class,NODEJS_EXE,null));
		params.put(WEBREDIS_FILE, valueOf(String.class,WEBREDIS_FILE,null));
		params.put(WEBREDIS_HOST, valueOf(String.class,WEBREDIS_HOST,DEFAULT_WEBREDIS_HOST));
		params.put(WEBREDIS_PORT, valueOf(Integer.class,WEBREDIS_PORT,DEFAULT_WEBREDIS_PORT));
	
		// 优先使用REDIS_URI
		if(defined(WEBREDIS_RURI)){
			params.put(WEBREDIS_RURI, valueOf(URI.class,WEBREDIS_RURI));
		}else{
			// 用redis host,port,database,password值创建redis uri
			URI uri = JedisUtils.createJedisURI(
					"redis",
					valueOf(String.class,WEBREDIS_RHOST,null), 
					valueOf(Integer.class,WEBREDIS_RPORT,null), 
					valueOf(String.class,WEBREDIS_RAUTH,null), 
					valueOf(Integer.class,WEBREDIS_RDB,null));
			params.put(WEBREDIS_RURI, uri);
		}
		// 过滤掉所有为null的参数
		return Maps.filterValues(params, Predicates.notNull());
	
	}
	private static MessageQueueType DEFAULT_MQ_IMPLTYPE = MessageQueueType.REDIS;
	static MessageQueueType getMessageQueueType(){
		return CONFIG.get(MessageQueueType.class, MQ_IMPLTYPE,DEFAULT_MQ_IMPLTYPE);
	}
	/**
	 * 从配置文件中读取消息系统参数
	 * @return 消息系统参数名-值映射
	 */
	static Map makeMessageQueueMqConfig(){
		Map map = Maps.newHashMap();
		map.put(MQParam.MQ_TYPE, getMessageQueueType().name());
		Map conn = 
				Maps.filterKeys(getProperties(PREFIX_MQ_CONNECT), new Predicate() {

				@Override
				public boolean apply(String input) {
					// 过滤掉类似 [@description] 的属性描述字段
					return ! input.matches(".*\\[@\\w+\\]");
				}
			});
		map.put(MQParam.MQ_CONNECT, BaseJsonEncoder.getEncoder().toJsonString(conn));
		return map;
	}
	private static boolean defined(String key){
		if(Strings.isNullOrEmpty(key)){
			return false;
		}
		return !CONFIG.getString(key,"").matches(".*\\$\\{.+\\}.*");
	}
	private static T valueOf(Class clazz,String key){
		return defined(key) ? CONFIG.get(clazz, key) : null;
	} 
	private static T valueOf(Class clazz,String key,T defaultValue){
		return defined(key)  ? CONFIG.get(clazz, key,defaultValue) : null;
	} 
	/** log 输出REDIS参数 */
	static final void logRedisParameters(Mapparams){
		logger.info("redis 服务器参数:");
		if(params.containsKey(PropName.uri)){
			logger.info("{}({}):{}", PropName.uri,descriptionOf(REDIS_URI),params.get(PropName.uri));
		}else{
			if(params.containsKey(PropName.host)){
				logger.info("{}({}):{}", PropName.host,descriptionOf(REDIS_HOST),params.get(PropName.host));
			}
			if(params.containsKey(PropName.port)){
				logger.info("{}({}):{}", PropName.port,descriptionOf(REDIS_PORT),params.get(PropName.port));
			}
			if(params.containsKey(PropName.database)){
				logger.info("{}({}):{}", PropName.database,descriptionOf(REDIS_DATABASE),params.get(PropName.database));
			}
			if(params.containsKey(PropName.password)){
				Object password = params.get(PropName.password); 
				logger.info("{}({}):{}", PropName.password,descriptionOf(REDIS_PASSWORD),
						null == password ? password :"*****");
			}
		}
		if(params.containsKey(PropName.timeout)){
			logger.info("{}({}):{}", PropName.timeout,descriptionOf(REDIS_TIMEOUT),params.get(PropName.timeout));
		}

		if(params.containsKey(PropName.jedisPoolConfig)){
			logger.info("{}({}):{}", "jedisPoolConfig.maxTotal",descriptionOf(REDIS_POOL_MAXTOTAL),
					((JedisPoolConfig)params.get(PropName.jedisPoolConfig)).getMaxTotal());
		}
		if(CONFIG.containsKey(REDIS_EXE)){
			logger.info("{}:{}",descriptionOf(REDIS_EXE),CONFIG.getString(REDIS_EXE));
		}
	}
	/** log 输出令牌管理参数 */
	static void logTokenParameters(){
		logger.info("令牌管理参数:");
		logger.info("{}:{}",
				descriptionOf(TOKEN_DEVICE_VALIDATE),
				CONFIG.getBoolean(TOKEN_DEVICE_VALIDATE));
		logger.info("{}:{}",
				descriptionOf(TOKEN_PERSON_VALIDATE),
				CONFIG.getBoolean(TOKEN_PERSON_VALIDATE));
		logger.info("{}:{}",
				descriptionOf(TOKEN_PERSON_EXPIRE),
				CONFIG.getInt(TOKEN_PERSON_EXPIRE));		
	}
	
	/**
	 * 从配置文件中读取数据库配置参数
	 * @return
	 */
	static EnumMap makeDatabaseConfig(){
		EnumMap params = new EnumMap(JdbcProperty.class);
		for(JdbcProperty prop: JdbcProperty.values()){
			String value = CONFIG.getString(prop.withPrefix(PREFIX_DATABASE), null);
			if(null !=value){
				params.put(prop, value);
			}
		}
		return params;		
	}
	static Map toStringKey(Map params){
		ImmutableMap> m1 = Maps.uniqueIndex(params.entrySet(), new Function,String>(){
			@Override
			public String apply(Entry input) {
				return input.getKey().key;
			}});
		return Maps.transformValues(m1, new Function,String>(){
			@Override
			public String apply(Entry input) {
				return input.getValue();
			}});
	}
	/** log 输出数据库配置参数 */
	static void logDatabaseProperties(Map params){
		for(Entry entry:params.entrySet()){
			String value = entry.getValue();
			if(null != value){
				logger.info("{}({}):{}",entry.getKey().key,descriptionOf(entry.getKey().withPrefix(PREFIX_DATABASE)),value);
			}
		}
	}
	/**
	 * 返回指定的参数,如果参数没有定义则返回{@code null}
	 */
	public static String getProperty(String key){
		return getConfig().getString(key,null);
	}
	
	/**
	 * 获取指定前缀的所有配置
	 * @param prefix 为{@code null}或空字符串时获取所有配置
	 * @return
	 */
	public static Map getProperties(String prefix){
		return toMap(getConfig().subset(MoreObjects.firstNonNull(prefix, "")));
	}
	
	/**
	 * 修改指定的配置参数
* {@link #CONFIG}是组合配置对象,是一组配置文件的镜像视图,不具备持久化能力,对其进行参数修改无效, * 只有这个方法设置参数才能被正确保存的用户自定义配置文件{@link #USER_CONFIG_FILE}
* @param key * @param value */ public static void setProperty(String key,Object value){ USER_CONFIG.setProperty(key, value); } /** * 修改一组配置参数 * @param config * @see #setProperty(String, Object) */ public static void setProperties(Map config){ Synchronizer sync = USER_CONFIG.getSynchronizer(); sync.beginWrite(); try{ for(Entry entry:config.entrySet()){ setProperty(entry.getKey(),entry.getValue()); } }finally{ sync.endWrite(); } } /** * 配置参数持久化
* 保存修改的配置到自定义配置文件({@link #USER_CONFIG_FILE}) */ public static void persistence() { try { // readConfig 方法中已经指定了文件默认编码方式为UTF-8,这里不需要再指定 FileHandler handler = new FileHandler(USER_CONFIG); handler.save(USER_CONFIG_FILE); } catch (ConfigurationException e) { throw new RuntimeException(e); } } /** * 将指定的{@link Configuration}转为{@code Map} * @param config * @return */ static Map toMap(final Configuration config){ return Maps.asMap(ImmutableSet.copyOf(config.getKeys()),new Function(){ @Override public String apply(String input) { return config.getString(input); }}); } /** * 将{@code value}用分隔符{@code ;,\t\r\f\n}切分为不含空格和分隔符的一组字符串 * @param value * @return {@code value}为{@code null}时返回空表 * @deprecated replace by {@link net.gdface.utils.MiscellaneousUtils#elementsOf(String)} */ public static ImmutableList getExplodedStringAsList(String value) { Builder builder = ImmutableList.builder(); if (value != null) { StringTokenizer st = new StringTokenizer(value, " ,;\t\n\r\f"); while (st.hasMoreTokens()) { builder = builder.add(st.nextToken()); } } return builder.build(); } /** * 将{@code key}指定的字符串分割转换为{@code enumType}枚举对象列表 * @param enumType * @param key * @return enum list */ public static final > ImmutableList getEnumList(final Class enumType,String key){ checkArgument(null != enumType,"enumType is null"); checkArgument(!Strings.isNullOrEmpty(key),"key is null or empty"); List strList = elementsOf(CONFIG.getString(key,"")); List enumList = Lists.transform(strList, new Function(){ @Override public E apply(String input) { try{ return Enum.valueOf(enumType, input); }catch(RuntimeException e){ return null; } }}); return ImmutableList.copyOf(Iterators.filter(enumList.iterator(), Predicates.notNull())); } /** * 将{@code key}指定的字符串分割转换为{@code enumType}枚举对象集 * @param enumType * @param key * @return enum list * @see #getEnumList(Class, String) */ public static final > ImmutableSet getEnumSet(final Class enumType,String key){ return ImmutableSet.copyOf(getEnumList(enumType, key)); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy