package message.config.i18n;
import message.config.exception.ConfigException;
import message.utils.FileUtils;
import message.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.*;
/**
* 存放消息源的容器.
*
* @author sunhao(sunhao.java@gmail.com)
* @version V1.0, 13-4-15 下午11:11
*/
public class ResourceBundleHolder implements Serializable {
/**
* for logger
*/
private static final Logger logger = LoggerFactory.getLogger(ResourceBundleHolder.class);
private static final String SUFFIX_OF_PROPERTIES = ".properties";
private static final String SUFFIX_OF_TEXT = ".txt";
private static final String SUFFIX_OF_HTML = ".html";
private String fileEncoding = "UTF-8";
/**
* 存放资源名称与值,不包含locale信息.
*/
private Map defaultBundleMap = new HashMap();
/**
* 存放资源的当前顺序.
*/
private final Map defaultBundleOrderMap = new HashMap();
/**
* 存放每个locale对应的资源信息.
*/
private Map bundledMap = new HashMap();
/**
* 存放资源的当前顺序.
*/
private Map bundledOrderMap = new HashMap();
/**
* 根据baseName加资源文件.
* 本方法会遍历资源文件所在目录的所有以basename开头的文件,并加载该文件内的资源.
*
* @param baseFilePath Base file path.
* @param order 次序.
*/
public void loadMessageResource(String baseFilePath, int order) {
if (StringUtils.isEmpty(baseFilePath)) {
logger.debug("give baseFilePath is null!");
return;
}
File baseFile = new File(baseFilePath);
if (!baseFile.exists() || !baseFile.canRead()) {
logger.debug("give file '{}' not exist or can not read!", baseFilePath);
return;
}
//父级目录
File parentDir = baseFile.getParentFile();
//获取文件除去后缀的名称
//baseName.properties --> baseName
//baseName.txt --> baseName
//baseName.html --> baseName
String baseName = baseFile.getName();
baseName = StringUtils.substringBefore(baseName, ".");
if (logger.isDebugEnabled())
logger.debug("get baseName for give fileName '{}' is '{}'!", baseFile.getName(), baseName);
File[] fileChildren = parentDir.listFiles();
for (File file : fileChildren) {
String fileName = file.getName();
if (fileName.startsWith(baseName) && (fileName.endsWith(SUFFIX_OF_PROPERTIES) || fileName.endsWith(SUFFIX_OF_TEXT) || fileName.endsWith(SUFFIX_OF_HTML))) {
//匹配baseName的所有语言的properties文件
Locale locale = null;
try {
locale = this.getLocaleFromFileName(fileName, baseName);
} catch (Exception e) {
logger.warn("file '{}' can not get any locale, continue!", file.getAbsolutePath());
continue;
}
if (locale == null)
logger.warn("get locale is null!");
Properties properties = this.getProperties(baseName, file);
if (properties != null)
this.addProperties(properties, locale, order);
else
logger.warn("can not get any properties from given file '{}'!", file.getAbsolutePath());
}
}
}
/**
* 根据文件名取得文件所属的语言环境
*
* @param fileName 文件名(加后缀,并且可能是各种语言的properties),eg:message.properties or message_en_US.properties
* @param baseName 文件名(不加后缀),eg:message(上面两个文件对应的baseName都是message)
* @return 语言
*/
private Locale getLocaleFromFileName(String fileName, String baseName) {
//除去文件名
String localName = StringUtils.substring(fileName, 0, fileName.length() - (FileUtils.getFileExt(fileName).length()));
//只取local的信息(message.properties)
localName = StringUtils.substring(localName, baseName.length() + 1);
if (logger.isDebugEnabled())
logger.debug("get local name for file '{}' is '{}'!", fileName, baseName);
if (StringUtils.isEmpty(localName))
//message.properties(默认是中文环境)
return null;
String locals[] = localName.split("_");
Locale locale = null;
if (locals.length == 2) {
locale = new Locale(locals[0], locals[1]);
}
if (locals == null) {
throw new ConfigException(10007, "can not get locale!");
}
if (logger.isDebugEnabled())
logger.debug("get locale for file '{}' is '{}'!", fileName, locale);
return locale;
}
private Properties getProperties(String baseName, File file) {
Properties properties = new Properties();
String fileType = FileUtils.getFileExt(file);
try {
if (SUFFIX_OF_PROPERTIES.equals(fileType)) {
//1.properties
properties.load(new FileInputStream(file));
} else if (SUFFIX_OF_TEXT.equals(fileType) || SUFFIX_OF_HTML.equals(fileType)) {
//2.txt/html
properties.put(baseName, FileUtils.getFileText(file, this.fileEncoding));
} else {
//do nothing!
logger.debug("this file '{}' is not properties, txt, html!", file.getName());
}
} catch (IOException e) {
logger.error(e.getMessage(), e);
return null;
}
return properties;
}
/**
* 将文件中的资源放入map中
*
* @param src
* @param locale
* @param order
*/
private void addProperties(final Map src, Locale locale, final int order) {
if (locale == null) {
mergePropertiesToMap(defaultBundleMap, defaultBundleOrderMap, src, order);
locale = Locale.CHINA;
}
Map propertiesMap = (Map) this.bundledMap.get(locale);
Map orderMap = (Map) this.bundledOrderMap.get(locale);
//各种语言的property存储map
if (propertiesMap == null) {
propertiesMap = new HashMap();
this.bundledMap.put(locale, propertiesMap);
}
if (orderMap == null) {
orderMap = new HashMap();
this.bundledOrderMap.put(locale, orderMap);
}
//对各种语言的property进行处理
mergePropertiesToMap(propertiesMap, orderMap, src, order);
}
/**
* 将所给的资源Map融合到目标Map中.
*
* @param destMap 目标Map.
* @param orderMap 存放次序的Map.
* @param src 资源.
* @param order 次序.
*/
private void mergePropertiesToMap(final Map destMap, final Map orderMap, final Map src, final int order) {
for (Object keyObj : src.keySet()) {
String key = keyObj.toString();
if (!destMap.containsKey(key)) {
//不存在的话就直接添加
destMap.put(key, src.get(key)); //存储值信息
orderMap.put(key, order); //存储顺序的信息
} else {
//存在的话,则开始判断顺序
Integer oldOrder = (Integer) orderMap.get(key);
if (oldOrder == null)
//如果不存在order的值,则默认为最小的整数
oldOrder = Integer.MIN_VALUE;
//如果给定的order比已经存在的order大的话,则覆盖,否则跳过
if (order >= oldOrder) {
destMap.put(key, src.get(key));
orderMap.put(key, order);
}
}
}
}
public ResourceBundle getResourceBundle(Locale locale) {
return new DefaultResourceBundle(this.defaultBundleMap, this.bundledMap, locale);
}
public void setFileEncoding(String fileEncoding) {
this.fileEncoding = fileEncoding;
}
}