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

com.xiaoleilu.hutool.setting.dialect.BasicSetting Maven / Gradle / Ivy

package com.xiaoleilu.hutool.setting.dialect;

import java.io.File;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import com.xiaoleilu.hutool.convert.Convert;
import com.xiaoleilu.hutool.io.IoUtil;
import com.xiaoleilu.hutool.io.resource.ClassPathResource;
import com.xiaoleilu.hutool.io.resource.FileResource;
import com.xiaoleilu.hutool.io.resource.Resource;
import com.xiaoleilu.hutool.io.resource.ResourceUtil;
import com.xiaoleilu.hutool.io.resource.UrlResource;
import com.xiaoleilu.hutool.io.watch.SimpleWatcher;
import com.xiaoleilu.hutool.io.watch.WatchMonitor;
import com.xiaoleilu.hutool.lang.Assert;
import com.xiaoleilu.hutool.log.StaticLog;
import com.xiaoleilu.hutool.setting.AbsSetting;
import com.xiaoleilu.hutool.setting.Setting;
import com.xiaoleilu.hutool.setting.SettingLoader;
import com.xiaoleilu.hutool.setting.SettingRuntimeException;
import com.xiaoleilu.hutool.util.CharsetUtil;
import com.xiaoleilu.hutool.util.StrUtil;

/**
 * 分组设置工具类。 用于支持设置文件
* 1、支持变量,默认变量命名为 ${变量名},变量只能识别读入行的变量,例如第6行的变量在第三行无法读取 * 2、支持分组,分组为中括号括起来的内容,中括号以下的行都为此分组的内容,无分组相当于空字符分组
* 若某个key是name,加上分组后的键相当于group.name * 3、注释以#开头,但是空行和不带“=”的行也会被跳过,但是建议加# * 4、store方法不会保存注释内容,慎重使用 * @author xiaoleilu * */ public class BasicSetting extends AbsSetting implements Map{ private static final long serialVersionUID = 3618305164959883393L; /** 默认字符集 */ public final static Charset DEFAULT_CHARSET = CharsetUtil.CHARSET_UTF_8; /** 分组 */ private final LinkedList groups = new LinkedList(); /** 键值对存储 */ private final Map map = new ConcurrentHashMap<>(); /** 本设置对象的字符集 */ protected Charset charset; /** 是否使用变量 */ protected boolean isUseVariable; /** 设定文件的URL */ protected URL settingUrl; private SettingLoader settingLoader; private WatchMonitor watchMonitor; /** * 空构造 */ public BasicSetting() { } /** * 构造 * @param path 相对路径或绝对路径 */ public BasicSetting(String path) { this(path, DEFAULT_CHARSET, false); } /** * 构造,使用相对于Class文件根目录的相对路径 * * @param path 相对路径或绝对路径 * @param charset 字符集 * @param isUseVariable 是否使用变量 */ public BasicSetting(String path, Charset charset, boolean isUseVariable) { Assert.notBlank(path, "Blank setting path !"); this.init(ResourceUtil.getResourceObj(path), charset, isUseVariable); } /** * 构造 * * @param configFile 配置文件对象 * @param charset 字符集 * @param isUseVariable 是否使用变量 */ public BasicSetting(File configFile, Charset charset, boolean isUseVariable) { Assert.notNull(configFile, "Null setting file define!"); this.init(new FileResource(configFile), charset, isUseVariable); } /** * 构造,相对于classes读取文件 * * @param path 相对ClassPath路径或绝对路径 * @param clazz 基准类 * @param charset 字符集 * @param isUseVariable 是否使用变量 */ public BasicSetting(String path, Class clazz, Charset charset, boolean isUseVariable) { Assert.notBlank(path, "Blank setting path !"); this.init(new ClassPathResource(path, clazz), charset, isUseVariable); } /** * 构造 * * @param url 设定文件的URL * @param charset 字符集 * @param isUseVariable 是否使用变量 */ public BasicSetting(URL url, Charset charset, boolean isUseVariable) { Assert.notNull(url, "Null setting url define!"); this.init(new UrlResource(url), charset, isUseVariable); } /*--------------------------公有方法 start-------------------------------*/ /** * 初始化设定文件 * * @param resource {@link Resource} * @param charset 字符集 * @param isUseVariable 是否使用变量 * @return 成功初始化与否 */ public boolean init(Resource resource, Charset charset, boolean isUseVariable) { if (resource == null) { throw new NullPointerException("Null setting url define!"); } this.settingUrl = resource.getUrl(); this.charset = charset; this.isUseVariable = isUseVariable; return load(); } /** * 重新加载配置文件 * @return 是否加载成功 */ synchronized public boolean load() { if(null == this.settingLoader){ settingLoader = new SettingLoader(this, this.charset, this.isUseVariable); } return settingLoader.load(new UrlResource(this.settingUrl)); } /** * 在配置文件变更时自动加载 * @param autoReload 是否自动加载 */ public void autoLoad(boolean autoReload){ if(autoReload){ if(null != this.watchMonitor){ this.watchMonitor.close(); } try { watchMonitor = WatchMonitor.create(this.settingUrl, StandardWatchEventKinds.ENTRY_MODIFY); watchMonitor.setWatcher(new SimpleWatcher(){ @Override public void onModify(WatchEvent event, Path currentPath) { load(); } }).start(); } catch (Exception e) { throw new SettingRuntimeException(e, "Setting auto load not support url: [{}]", this.settingUrl); } StaticLog.debug("Auto load for [{}] listenning...", this.settingUrl); }else{ IoUtil.close(this.watchMonitor); this.watchMonitor = null; } } /** * @return 获得设定文件的路径 */ public String getSettingPath() { return (null == this.settingUrl) ? null : this.settingUrl.getPath(); } @Override public int size() { return map.size(); } @Override public Object getObj(String key, Object defaultValue) { final Object value = map.get(key); if(null == value) { return defaultValue; } return value; } /** * 获取并删除键值对,当指定键对应值非空时,返回并删除这个值,后边的键对应的值不再查找 * @param keys 键列表,常用于别名 * @return 值 * @since 3.1.2 */ public Object getAndRemove(String... keys) { Object value = null; for (String key : keys) { value = remove(key); if(null != value) { break; } } return value; } /** * 获取并删除键值对,当指定键对应值非空时,返回并删除这个值,后边的键对应的值不再查找 * @param keys 键列表,常用于别名 * @return 字符串值 * @since 3.1.2 */ public String getAndRemoveStr(String... keys) { Object value = null; for (String key : keys) { value = remove(key); if(null != value) { break; } } return (String)value; } /** * 获得指定分组的所有键值对 * @param group 分组 * @return map */ public Map getMap(String group){ if(StrUtil.isBlank(group)){ return this; } String groupDot = group.concat(StrUtil.DOT); Map map2 = new HashMap(); String keyStr; for (Object key : map.keySet()) { keyStr = Convert.toStr(key); if(StrUtil.isNotBlank(keyStr) && keyStr.startsWith(groupDot)){ map2.put(StrUtil.removePrefix(keyStr, groupDot), map.get(key)); } } return map2; } /** * 获得group对应的子Setting * @param group 分组 * @return {@link Setting} */ public BasicSetting getSetting(String group){ final BasicSetting setting = new BasicSetting(); setting.putAll(this.getMap(group)); return setting; } /** * 转换为Properties对象,原分组变为前缀 * @param group 分组 * @return Properties对象 */ public Properties getProperties(String group){ Properties properties = new Properties(); properties.putAll(getMap(group)); return properties; } //--------------------------------------------------------------------------------- Functions /** * 持久化当前设置,会覆盖掉之前的设置
* 持久化会不会保留之前的分组 * @param absolutePath 设置文件的绝对路径 */ public void store(String absolutePath) { if(null == this.settingLoader){ settingLoader = new SettingLoader(this, this.charset, this.isUseVariable); } settingLoader.store(absolutePath); } /** * 设置变量的正则
* 正则只能有一个group表示变量本身,剩余为字符 例如 \$\{(name)\}表示${name}变量名为name的一个变量表示 * * @param regex 正则 */ public void setVarRegex(String regex) { if(null == this.settingLoader){ throw new NullPointerException("SettingLoader is null !"); } this.settingLoader.setVarRegex(regex); } /** * 转换为Properties对象,原分组变为前缀 * @return Properties对象 */ public Properties toProperties(){ Properties properties = new Properties(); properties.putAll(map); return properties; } /** * @return 获得所有分组名 */ public LinkedList getGroups() { return this.groups; } //------------------------------------------------- Override Map interface /** * @return 所有键值对 */ @Override public Set> entrySet(){ return map.entrySet(); } @Override public boolean isEmpty() { return this.map.isEmpty(); } @Override public boolean containsKey(Object key) { return this.map.containsKey(key); } @Override public boolean containsValue(Object value) { return this.map.containsValue(value); } @Override public Object get(Object key) { return this.map.get(key); } @Override public Object put(Object key, Object value) { return this.map.put(key, value); } /** * 设置值
* 此方法设置值后会将key和group拼接为:[group].[key]的形式 * * @param key 键 * @param group 分组 * @param value 值 * @return this * @since 3.3.1 */ public BasicSetting set(String key, String group, Object value) { this.put(keyWithGroup(key, group), value); return this; } /** * 设置值 * * @param key 键 * @param value 值 * @return this * @since 3.3.1 */ public BasicSetting set(String key, Object value) { this.put(key, value); return this; } /** * 加入Map中的键值对 * @param map {@link Map} */ @Override public void putAll(Map map) { this.map.putAll(map); } @Override public Object remove(Object key) { return this.map.remove(key); } @Override public void clear() { this.map.clear(); } @Override public Set keySet() { return this.map.keySet(); } @Override public Collection values() { return this.map.values(); } @Override public String toString() { return map.toString(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((charset == null) ? 0 : charset.hashCode()); result = prime * result + ((groups == null) ? 0 : groups.hashCode()); result = prime * result + (isUseVariable ? 1231 : 1237); result = prime * result + ((map == null) ? 0 : map.hashCode()); result = prime * result + ((settingUrl == null) ? 0 : settingUrl.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj){ return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } BasicSetting other = (BasicSetting) obj; if (charset == null) { if (other.charset != null) { return false; } } else if (!charset.equals(other.charset)) { return false; } if (groups == null) { if (other.groups != null) { return false; } } else if (!groups.equals(other.groups)) { return false; } if (isUseVariable != other.isUseVariable) { return false; } if (map == null) { if (other.map != null) { return false; } } else if (!map.equals(other.map)) { return false; } if (settingUrl == null) { if (other.settingUrl != null) { return false; } } else if (!settingUrl.equals(other.settingUrl)) { return false; } return true; } }