/*
* Copyright 2012 The Solmix Project
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.gnu.org/licenses/
* or see the FSF site: http://www.fsf.org.
*/
package org.solmix.runtime.cm.support;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.solmix.commons.util.DataUtils;
import org.solmix.runtime.cm.ConfigureUnit;
import org.solmix.runtime.cm.ConfigureUnitManager;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.util.DefaultPropertiesPersister;
import org.springframework.util.PropertiesPersister;
/**
*
* @author solmix.f@gmail.com
* @version $Id$ 2013-11-5
*/
public class SpringConfigureUnitManager implements ConfigureUnitManager
{
protected final Logger logger = LoggerFactory.getLogger(getClass());
public static final String DEFAULT_CFG_FILES = "classpath*:META-INF/solmix/*.cfg";
public static final String XML_FILE_EXTENSION = ".xml";
private Map<String, ConfigureUnit> configCache;
private final PropertiesPersister propertiesPersister = new DefaultPropertiesPersister();
private String fileEncoding;
@Override
public ConfigureUnit createFactoryConfigureUnit(String factoryPid) throws IOException {
throw new java.lang.RuntimeException("This method is not support by " + this.getClass().getName());
}
@Override
public synchronized ConfigureUnit getConfigureUnit(String pid) throws IOException {
if (configCache == null) {
configCache = buildConfig();
}
return configCache.get(pid);
}
private Map<String, ConfigureUnit> buildConfig() throws IOException {
Map<String, ConfigureUnit> configs = new java.util.concurrent.ConcurrentHashMap<String, ConfigureUnit>();
List<Resource> defaultResources = getConfigureResource(DEFAULT_CFG_FILES);
for (Resource re : defaultResources) {
String pid = getPidByFileName(re.getFilename());
configs.put(pid, new ConfigureUnitImpl(pid, loadProperties(re), this));
logTraceMessage("Loaded default configuration properties from file:",re);
}
String userParttern = System.getProperty(ConfigureUnit.USER_CONFIG_DIR_PROPERTY_NAME);
if (userParttern == null)
userParttern = ConfigureUnit.USER_CONFIG_DIR;
List<Resource> userConfigs = getConfigureResource(userParttern);
if (userConfigs != null && userConfigs.size() > 0) {
for (Resource re : userConfigs) {
String pid = getPidByFileName(re.getFilename());
if (configs.containsKey(pid)) {
ConfigureUnit cu = configs.get(pid);
Properties p = loadProperties(re);
cu.update(toDictionary(p));
logTraceMessage("merge user configured properties to merge system default:",re);
} else {
configs.put(pid, new ConfigureUnitImpl(pid, loadProperties(re), this));
logTraceMessage("Loaded user configuration properties from file:",re);
}
}
}
return configs;
}
private void logTraceMessage(String msg,Resource location){
if (logger.isTraceEnabled()) {
try {
logger.trace(msg + location.getURL().getPath());
} catch (IOException e) {
}
}
}
private Dictionary<String, ?> toDictionary(Properties properties) {
Dictionary<String, Object> dic = new Hashtable<String, Object>();
if (properties != null) {
Enumeration<Object> en = properties.keys();
while (en.hasMoreElements()) {
Object key = en.nextElement();
dic.put(key.toString(), properties.get(key));
}
}
return dic;
}
protected String getPidByFileName(String fileName) {
if (fileName.endsWith(".cfg")) {
return fileName.substring(0, fileName.length() - 4);
}
return fileName;
}
@Override
public ConfigureUnit[] listConfigureUnits(String filter) throws IOException {
ConfigureUnit[] fiter = null;
if (configCache == null) {
configCache = buildConfig();
}
if (filter == null) {
Collection<ConfigureUnit> conf = configCache.values();
fiter = conf.toArray(new ConfigureUnit[] {});
}
return fiter;
}
public List<Resource> getConfigureResource(String dir) {
List<Resource> resources = new ArrayList<Resource>();
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(Thread.currentThread().getContextClassLoader());
try {
Collections.addAll(resources, resolver.getResources(dir));
} catch (IOException e) {
logger.error("IOException", e);
}
return resources;
}
protected Properties loadProperties(Resource location) {
Properties props = new Properties();
InputStream is = null;
try {
is = location.getInputStream();
String filename = location.getFilename();
if (filename != null && filename.endsWith(XML_FILE_EXTENSION)) {
this.propertiesPersister.loadFromXml(props, is);
} else {
if (this.fileEncoding != null) {
this.propertiesPersister.load(props, new InputStreamReader(is, this.fileEncoding));
} else {
this.propertiesPersister.load(props, is);
}
}
} catch (IOException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Could not load properties from " + location + ": " + ex.getMessage());
}
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
}
}
}
checkSystemProperties(props);
return props;
}
/**
* @param props
*/
private void checkSystemProperties(Properties properties) {
if (properties != null) {
Enumeration<Object> en = properties.keys();
while (en.hasMoreElements()) {
Object key = en.nextElement();
Object value = properties.get(key);
if (value != null) {
value = DataUtils.getTemplateValue(value.toString());
}
properties.put(key, value);
}
}
}
}