Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (C) 2015 HaiYang Li
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.landawn.abacus.util;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import com.landawn.abacus.annotation.SuppressFBWarnings;
import com.landawn.abacus.exception.ParseException;
import com.landawn.abacus.exception.UncheckedIOException;
import com.landawn.abacus.logging.Logger;
import com.landawn.abacus.logging.LoggerFactory;
import com.landawn.abacus.parser.Exclusion;
import com.landawn.abacus.parser.XMLSerializationConfig;
import com.landawn.abacus.parser.XMLSerializationConfig.XSC;
import com.landawn.abacus.type.Type;
/**
* @see Configuration
*/
@SuppressWarnings("java:S1192")
public final class PropertiesUtil {
private static final Logger logger = LoggerFactory.getLogger(PropertiesUtil.class);
private static final String TYPE = "type";
private static final XMLSerializationConfig xsc = XSC.create()
.tagByPropertyName(true)
.ignoreTypeInfo(true)
.setDateTimeFormat(DateTimeFormat.ISO_8601_DATE_TIME)
.setExclusion(Exclusion.NONE)
.setIgnoredPropNames((Map, Set>) null);
private static final ScheduledExecutorService scheduledExecutor;
static {
final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
executor.setRemoveOnCancelPolicy(true);
scheduledExecutor = MoreExecutors.getExitingScheduledExecutorService(executor);
}
private static final Map> registeredAutoRefreshProperties = new ConcurrentHashMap<>(256);
static {
final Runnable refreshTask = new TimerTask() {
@Override
public void run() {
synchronized (registeredAutoRefreshProperties) {
Properties properties = null;
Resource resource = null;
File file = null;
for (final Map.Entry> entry : registeredAutoRefreshProperties.entrySet()) {
resource = entry.getKey();
properties = entry.getValue();
file = resource.getFile();
if ((file != null) && (file.lastModified() > resource.getLastLoadTime())) {
final long lastLoadTime = file.lastModified();
Reader reader = null;
if (logger.isWarnEnabled()) {
logger.warn("Start to refresh properties with the updated file: " + file.getAbsolutePath());
logger.warn("[PROPERTIES]" + properties);
}
try {
reader = IOUtil.newFileReader(resource.getFile());
if (resource.getType() == ResourceType.PROPERTIES) {
merge(load(reader), (Properties) properties);
} else {
merge(loadFromXml(reader, (Class>) properties.getClass()),
(Properties) properties);
}
resource.setLastLoadTime(lastLoadTime);
} catch (final Exception e) {
logger.error("Failed to refresh properties: " + properties, e);
} finally {
IOUtil.close(reader);
}
if (logger.isWarnEnabled()) {
logger.warn("End to refresh properties with the updated file: " + file.getAbsolutePath());
logger.warn("[NEW PROPERTIES]" + properties);
}
}
}
}
}
};
scheduledExecutor.scheduleWithFixedDelay(refreshTask, 1000, 1000, TimeUnit.MICROSECONDS);
}
private PropertiesUtil() {
// singleton.
}
/**
* Finds the file with the specified configuration file name.
*
* @param configFileName the name of the configuration file to find
* @return the File object representing the found file
*/
public static File findFile(final String configFileName) {
return Configuration.findFile(configFileName);
}
/**
* Finds the directory with the specified configuration directory name.
*
* @param configDir the name of the configuration directory to find
* @return the File object representing the found directory
*/
public static File findDir(final String configDir) {
return Configuration.findDir(configDir);
}
/**
* Loads properties from the specified file.
*
* @param source The file from which to load the properties.
* @return A Properties object containing the loaded properties.
*/
public static Properties load(final File source) {
return load(source, false);
}
/**
* Loads properties from the specified file with an option for auto-refresh.
*
* @param source The file from which to load the properties.
* @param autoRefresh If {@code true}, the properties will be automatically refreshed when the file is modified.
* There is a background thread to check the file last modification time every second.
* @return A Properties object containing the loaded properties.
*/
public static Properties load(final File source, final boolean autoRefresh) {
Properties properties = null;
Reader reader = null;
try {
reader = IOUtil.newFileReader(source);
if (autoRefresh) {
final Resource resource = new Resource(Properties.class, source, ResourceType.PROPERTIES);
resource.setLastLoadTime(source.lastModified());
synchronized (registeredAutoRefreshProperties) {
properties = (Properties) registeredAutoRefreshProperties.get(resource);
if (properties == null) {
properties = load(reader);
registeredAutoRefreshProperties.put(resource, properties);
}
}
} else {
properties = load(reader);
}
return properties;
} finally {
IOUtil.close(reader);
}
}
/**
* Loads properties from the specified InputStream.
*
* @param source The InputStream from which to load the properties.
* @return A Properties object containing the loaded properties.
*/
public static Properties load(final InputStream source) {
final java.util.Properties tmp = new java.util.Properties();
try {
tmp.load(source);
} catch (final IOException e) {
throw new UncheckedIOException(e);
}
final Properties result = new Properties<>();
merge(tmp, result);
return result;
}
/**
* Loads properties from the specified Reader.
*
* @param source The Reader from which to load the properties.
* @return A Properties object containing the loaded properties.
*/
public static Properties load(final Reader source) {
final java.util.Properties tmp = new java.util.Properties();
try {
tmp.load(source);
} catch (final IOException e) {
throw new UncheckedIOException(e);
}
final Properties result = new Properties<>();
merge(tmp, result);
return result;
}
/**
* Merges the source properties into the target properties.
*
* @param srcProperties The source properties to merge from.
* @param targetProperties The target properties to merge into. If {@code null}, a new Properties object will be created.
* @return A Properties object containing the merged properties.
*/
@SuppressWarnings("rawtypes")
private static void merge(final java.util.Properties srcProperties, final Properties targetProperties) {
// final Map valueMap = new LinkedHashMap<>(targetProperties.values);
//
// final Set oldKeySet = N.newHashSet(valueMap.keySet());
// final Set srcPropNameSet = srcProperties.stringPropertyNames();
// final Set newKeySet = N.newHashSet();
//
// for (final String srcPropName : srcPropNameSet) {
// valueMap.put(srcPropName, srcProperties.getProperty(srcPropName));
// newKeySet.add(srcPropName);
// }
//
// for (final String key : oldKeySet) {
// if (!newKeySet.contains(key)) {
// valueMap.remove(key);
// }
// }
//
// targetProperties.reset(valueMap);
targetProperties.reset(new LinkedHashMap<>((Map) srcProperties));
}
private static void merge(final Properties extends K, ? extends V> srcProperties, final Properties targetProperties) {
// final Map valueMap = new LinkedHashMap<>(targetProperties.values);
//
// final Set oldKeySet = N.newHashSet(valueMap.keySet());
// final Set extends K> srcPropNameSet = srcProperties.keySet();
// final Set newKeySet = N.newHashSet();
// V srcPropValue = null;
// for (final K srcPropName : srcPropNameSet) {
// srcPropValue = srcProperties.get(srcPropName);
//
// // targetPropValue = valueMap.get(srcPropName);
// //
// // if (srcPropValue instanceof Properties && targetPropValue instanceof Properties) {
// // merge((Properties) srcPropValue, (Properties) targetPropValue);
// //
// // valueMap.put(srcPropName, targetPropValue);
// // } else {
// // valueMap.put(srcPropName, srcPropValue);
// // }
//
// valueMap.put(srcPropName, srcPropValue);
//
// newKeySet.add(srcPropName);
// }
//
// for (final K key : oldKeySet) {
// if (!newKeySet.contains(key)) {
// valueMap.remove(key);
// }
// }
//
// targetProperties.reset(valueMap);
targetProperties.reset(new LinkedHashMap<>(srcProperties.values));
}
/**
* Loads properties from the specified XML file.
*
* @param source The XML file from which to load the properties.
* @return A Properties object containing the loaded properties.
*/
public static Properties loadFromXml(final File source) {
return loadFromXml(source, false);
}
/**
* Loads properties from the specified XML file with an option for auto-refresh.
*
* @param source The XML file from which to load the properties.
* @param autoRefresh If {@code true}, the properties will be automatically refreshed when the file is modified.
* @return A Properties object containing the loaded properties.
*/
public static Properties loadFromXml(final File source, final boolean autoRefresh) {
return loadFromXml(source, autoRefresh, Properties.class);
}
/**
* Loads properties from the specified XML InputStream.
*
* @param source The InputStream from which to load the properties.
* @return A Properties object containing the loaded properties.
*/
public static Properties loadFromXml(final InputStream source) {
return loadFromXml(source, Properties.class);
}
/**
* Loads properties from the specified XML Reader.
*
* @param source The Reader from which to load the properties.
* @return A Properties object containing the loaded properties.
*/
public static Properties loadFromXml(final Reader source) {
return loadFromXml(source, Properties.class);
}
/**
* Loads properties from the specified XML file into the target properties class.
*
* @param The type of the target properties class.
* @param source The XML file from which to load the properties.
* @param targetClass The class of the target properties.
* @return An instance of the target properties class containing the loaded properties.
*/
public static > T loadFromXml(final File source, final Class extends T> targetClass) {
return loadFromXml(source, false, targetClass);
}
/**
* Loads properties from the specified XML file into the target properties class with an option for auto-refresh.
*
* @param The type of the target properties class.
* @param source The XML file from which to load the properties.
* @param autoRefresh If {@code true}, the properties will be automatically refreshed when the file is modified.
* There is a background thread to check the file last modification time every second.
* @param targetClass The class of the target properties.
* @return An instance of the target properties class containing the loaded properties.
*/
public static > T loadFromXml(final File source, final boolean autoRefresh, final Class extends T> targetClass) {
T properties = null;
Reader reader = null;
try {
reader = IOUtil.newFileReader(source);
if (autoRefresh) {
final Resource resource = new Resource(targetClass, source, ResourceType.XML);
resource.setLastLoadTime(source.lastModified());
synchronized (registeredAutoRefreshProperties) {
properties = (T) registeredAutoRefreshProperties.get(resource);
if (properties == null) {
properties = loadFromXml(reader, targetClass);
registeredAutoRefreshProperties.put(resource, properties);
}
}
} else {
properties = loadFromXml(reader, targetClass);
}
return properties;
} finally {
IOUtil.close(reader);
}
}
/**
* Loads properties from the specified XML InputStream into the target properties class.
*
* @param The type of the target properties class.
* @param source The InputStream from which to load the properties.
* @param targetClass The class of the target properties.
* @return An instance of the target properties class containing the loaded properties.
*/
public static > T loadFromXml(final InputStream source, final Class extends T> targetClass) {
final DocumentBuilder docBuilder = XmlUtil.createDOMParser(true, true);
Document doc;
try {
doc = docBuilder.parse(source);
} catch (final SAXException e) {
throw new ParseException(e);
} catch (final IOException e) {
throw new UncheckedIOException(e);
}
final Node node = doc.getFirstChild();
return loadFromXml(node, null, true, null, targetClass);
}
/**
* Loads properties from the specified XML Reader into the target properties class.
*
* @param The type of the target properties class.
* @param source The Reader from which to load the properties.
* @param targetClass The class of the target properties.
* @return An instance of the target properties class containing the loaded properties.
*/
public static > T loadFromXml(final Reader source, final Class extends T> targetClass) {
final DocumentBuilder docBuilder = XmlUtil.createDOMParser(true, true);
Document doc;
try {
doc = docBuilder.parse(new InputSource(source));
} catch (final SAXException e) {
throw new ParseException(e);
} catch (final IOException e) {
throw new UncheckedIOException(e);
}
final Node node = doc.getFirstChild();
return loadFromXml(node, null, true, null, targetClass);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private static > T loadFromXml(final Node source, Method propSetMethod, final boolean isFirstCall, final T output,
final Class inputClass) {
// TODO it's difficult to support duplicated property and may be misused.
if (hasDuplicatedPropName(source)) {
throw new RuntimeException("The source xml document contains duplicated properties which has same node tag name in the same root.");
}
Class> targetClass = null;
if (isFirstCall) {
targetClass = output == null ? (inputClass == null ? Properties.class : inputClass) : output.getClass();
} else {
targetClass = (propSetMethod == null) ? Properties.class : propSetMethod.getParameterTypes()[0];
}
final T properties = (T) (output == null ? N.newInstance(targetClass) : output);
final NodeList propNodes = source.getChildNodes();
@SuppressWarnings("ConstantValue")
final int propNodeLength = (propNodes == null) ? 0 : propNodes.getLength();
final Set newKeySet = N.newHashSet();
Node propNode = null;
String typeAttr = null;
String propName = null;
Object propValue = null;
for (int i = 0; i < propNodeLength; i++) {
propNode = propNodes.item(i);
if (propNode.getNodeType() != Document.ELEMENT_NODE) {
continue;
}
propName = ClassUtil.formalizePropName(propNode.getNodeName());
newKeySet.add(propName);
typeAttr = XmlUtil.getAttribute(propNode, TYPE);
propSetMethod = ClassUtil.getPropSetMethod(targetClass, propName);
if (XmlUtil.isTextElement(propNode)) {
if (Strings.isEmpty(typeAttr)) {
propValue = Strings.strip(XmlUtil.getTextContent(propNode));
} else {
propValue = N.typeOf(typeAttr).valueOf(Strings.strip(XmlUtil.getTextContent(propNode)));
}
} else {
// TODO it's difficult to support duplicated property and may be misused.
// How to get target property value for auto-refresh if it's list of Properties or entities.
final T targetPropValue = (T) properties.get(propName);
final Class propClass = (Class) (propSetMethod == null ? Properties.class : propSetMethod.getParameterTypes()[0]);
propValue = loadFromXml(propNode, propSetMethod, false, targetPropValue, propClass);
}
final Object oldPropValue = properties.get(propName);
if (oldPropValue != null && oldPropValue.getClass().equals(propValue.getClass())
&& (oldPropValue instanceof Collection || oldPropValue instanceof Map) && !(oldPropValue instanceof Properties)) {
if (oldPropValue instanceof Collection) {
((Collection) oldPropValue).clear();
((Collection) oldPropValue).addAll((Collection) propValue);
} else if (oldPropValue instanceof Map) {
((Map) oldPropValue).clear();
((Map) oldPropValue).putAll((Map) propValue);
}
} else {
if (propSetMethod == null) {
// TODO it's difficult to support duplicated property and may be misused.
// if (properties.containsKey(propName)) {
// String listPropName = propName + "List";
// List