/**
*
* Copyright 2014 The Darks ORM Project (Liu lihua)
*
* 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 darks.orm.core.config;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.Element;
import darks.orm.core.config.CacheConfiguration.CacheConfigType;
import darks.orm.exceptions.ClassReflectException;
import darks.orm.exceptions.ConfigException;
import darks.orm.log.Logger;
import darks.orm.log.LoggerFactory;
import darks.orm.util.FileHelper;
import darks.orm.util.ReflectHelper;
import darks.orm.util.XmlHelper;
/**
* Session config factory will build ORM config environment from config file.
* @author darks
*/
public final class SessionConfigFactory
{
private static final Logger logger = LoggerFactory.getLogger(SessionConfigFactory.class);
public static final String DEFAULT_CONFIG_PATH = "/darks.xml";
private static final String DTD_PUBLIC_ID = "-//darks//DTD darks 3.0//EN";
private static final String CONFIG_DTD_PATH = "/darks/orm/core/config/darks.dtd";
private static Map<String, Class<?>> configMap = new HashMap<String, Class<?>>(3);
static
{
configMap.put("jdbc", JdbcConfiguration.class);
configMap.put("bonecp", BoneCPConfiguration.class);
configMap.put("jndi", JndiConfiguration.class);
}
private SessionConfigFactory()
{
}
/**
* Get config file entity from file.
*
* @return Config file entity
* @throws ConfigException
*/
public static Configuration getConfiguration()
throws ConfigException
{
return getConfiguration(DEFAULT_CONFIG_PATH);
}
/**
* Get config file entity from file.
*
* @param configLocation Config file location
* @return Config file entity
* @throws ConfigException
*/
public static Configuration getConfiguration(String configLocation)
throws ConfigException
{
if (configLocation == null)
{
throw new ConfigException("ConfigLocation is null.");
}
InputStream cfgIns = SessionConfigFactory.class.getResourceAsStream(configLocation);
if (cfgIns == null)
{
throw new ConfigException("'" + configLocation + "' configuration file does not exists.");
}
return getConfiguration(cfgIns);
}
/**
* Get config file entity from file.
*
* @param configPath Config file path
* @return Config file entity
* @throws ConfigException
*/
public static Configuration getConfiguration(InputStream cfgIns)
throws ConfigException
{
Configuration cfg = new Configuration();
Document doc = XmlHelper.getXMLDocument(DTD_PUBLIC_ID, CONFIG_DTD_PATH, cfgIns);
if (doc == null)
{
throw new ConfigException("Fail to parse config file. Cause invalid config file.");
}
// Parse DataSource
parseDataSourceXpath(doc, cfg);
// Parse entity config
parseEntityXpath(doc, cfg);
// Parse SqlMap path config
parseSqlMapXpath(doc, cfg);
// Parse cache config
parseCacheXpath(doc, cfg);
return cfg;
}
/**
* Parse DataSource config
*
* @param doc Document
* @param cfg Configuration config
* @throws ConfigException
*/
private static void parseDataSourceXpath(Document doc, Configuration cfg)
throws ConfigException
{
String xpath = "/darks/dataSource[@type]";
List<?> nodes = doc.selectNodes(xpath);
Iterator<?> it = nodes.iterator();
while (it.hasNext())
{
Element node = (Element)it.next();
parseDataSourceNode(node, cfg);
}
cfg.ensureDataSourceChain();
cfg.ensureMainDataSourceConfig();
}
/**
* Parse DataSource single element
*
* @param node XML element node
* @param cfg Configuration config
* @throws ConfigException
*/
private static void parseDataSourceNode(Element node, Configuration cfg)
throws ConfigException
{
DataSourceConfiguration dsConfig = null;
Class<?> clazz = null;
if (node == null)
{
throw new ConfigException("document does not has 'dataSource' node.");
}
String type = node.attributeValue("type");
if (configMap.containsKey(type))
{
clazz = configMap.get(type);
}
if (clazz == null)
{
throw new ConfigException("DataSource type does not exists");
}
try
{
dsConfig = (DataSourceConfiguration)ReflectHelper.newFastInstance(clazz);
dsConfig.setType(type);
String id = node.attributeValue("id");
if (id == null)
{
id = type;
}
String main = node.attributeValue("main");
boolean isMain = false;
if (main != null)
{
isMain = Boolean.parseBoolean(main);
}
String chainref = node.attributeValue("chainref");
if (chainref != null)
{
dsConfig.setNextId(chainref);
}
List<?> nodes = node.selectNodes("property[@name][@value]");
Iterator<?> it = nodes.iterator();
Element el = null;
Field field = null;
while (it.hasNext())
{
el = (Element)it.next();
String name = el.attributeValue("name");
String value = el.attributeValue("value");
field = ReflectHelper.getField(clazz, name);
ReflectHelper.setFieldString(field, dsConfig, value);
}
el = (Element)node.selectSingleNode("resultSet");
if (el != null)
{
ResultSetConfig rsconfig = dsConfig.getResultSetConfig();
String rsType = el.attributeValue("type");
String rsSensitive = el.attributeValue("sensitive");
String rsConcurrency = el.attributeValue("concurrency");
rsconfig.setType(rsType);
rsconfig.setConcurrency(rsConcurrency);
rsconfig.setSensitive(rsSensitive);
}
cfg.addDataSourceConfig(id, dsConfig, isMain);
}
catch (NoSuchFieldException e)
{
throw new ConfigException(e.getMessage(), e);
}
catch (ClassReflectException e)
{
throw new ConfigException(e.getMessage(), e);
}
}
/**
* Parse entity config
*
* @param doc Document
* @param cfg Configuration config
* @throws ConfigException
*/
private static void parseEntityXpath(Document doc, Configuration cfg)
throws ConfigException
{
EntityConfiguration entityConfig = cfg.getEntityConfig();
String xpath = "/darks/entities";
Element node = (Element)doc.selectSingleNode(xpath);
if (node == null)
return;
List<?> nodes = node.selectNodes("entity[@class]");
Iterator<?> it = nodes.iterator();
while (it.hasNext())
{
Element el = (Element)it.next();
String alias = el.attributeValue("alias");
String className = el.attributeValue("class");
if (className == null || "".equals(className))
continue;
entityConfig.addEntityConfig(alias, className);
}
nodes = node.selectNodes("package[@name]");
it = nodes.iterator();
while (it.hasNext())
{
Element el = (Element)it.next();
String pkgName = el.attributeValue("name");
if (pkgName == null || "".equals(pkgName))
continue;
List<Class<?>> classList = ReflectHelper.scanPackageClasses(pkgName, true);
for (Class<?> clazz : classList)
{
entityConfig.addEntityConfig(clazz.getSimpleName(), clazz.getName());
}
}
}
/**
* Parse SqlMap config
*
* @param doc Document
* @param cfg Configuration config
* @throws ConfigException
*/
private static void parseSqlMapXpath(Document doc, Configuration cfg)
throws ConfigException
{
List<String> sqlMapsPath = cfg.getSqlMapsPath();
String xpath = "/darks/sqlMapGroup";
Element node = (Element)doc.selectSingleNode(xpath);
if (node == null)
return;
List<?> nodes = node.selectNodes("sqlMap");
Iterator<?> it = nodes.iterator();
while (it.hasNext())
{
Element el = (Element)it.next();
String path = el.getTextTrim();
if (path.indexOf("*") >= 0)
{
List<String> list = FileHelper.getRegexResourceFiles(path);
for (String fpath : list)
{
sqlMapsPath.add(fpath);
}
}
else
{
if (!"".equals(path))
{
sqlMapsPath.add(path);
}
}
}
}
/**
* Parse cache config
*
* @param doc Document
* @param cfg Configuration config
* @throws ConfigException
*/
private static void parseCacheXpath(Document doc, Configuration cfg)
throws ConfigException
{
CacheConfiguration cacheConfig = cfg.getCacheConfig();
String xpath = "/darks/cacheGroup";
Element node = (Element)doc.selectSingleNode(xpath);
if (node == null)
return;
String use = node.attributeValue("use");
String type = node.attributeValue("type");
String cacheId = node.attributeValue("cacheId");
String synchronous = node.attributeValue("synchronous");
// Whether to use cache
if (use != null)
{
if ("true".equalsIgnoreCase(use))
cacheConfig.setUseCache(true);
else if ("false".equalsIgnoreCase(use))
cacheConfig.setUseCache(false);
}
// Cache type
if (type != null)
{
if ("auto".equals(type))
cacheConfig.setCacheConfigType(CacheConfigType.Auto);
else if ("manual".equals(type))
cacheConfig.setCacheConfigType(CacheConfigType.Manual);
}
// Parse cache auto-id
if (cacheId != null)
{
cacheConfig.setAutoCacheId(cacheId);
}
// Whether synchronous cache
if (synchronous != null)
{
if ("true".equalsIgnoreCase(synchronous))
cacheConfig.setSynchronous(true);
else if ("false".equalsIgnoreCase(synchronous))
cacheConfig.setSynchronous(false);
}
cacheConfig.readCacheConfig(node);
}
}