#region Apache Notice
/*****************************************************************************
* $Header: $
* $Revision$
* $Date$
*
* iBATIS.NET Data Mapper
* Copyright (C) 2004 - Gilles Bayon
*
*
* 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.
*
********************************************************************************/
#endregion
#region Using
using System;
using System.Collections;
using System.Collections.Specialized;
using System.IO;
using System.Text;
using System.Reflection;
using System.Threading;
using System.Xml;
using System.Xml.Schema;
using IBatisNet.Common;
using IBatisNet.Common.Exceptions;
using IBatisNet.Common.Logging;
using IBatisNet.Common.Utilities;
using IBatisNet.Common.Utilities.Objects;
using IBatisNet.Common.Utilities.Objects.Members;
using IBatisNet.Common.Xml;
using IBatisNet.DataMapper.Configuration.Alias;
using IBatisNet.DataMapper.Configuration.Cache;
using IBatisNet.DataMapper.Configuration.Cache.Fifo;
using IBatisNet.DataMapper.Configuration.Cache.Lru;
using IBatisNet.DataMapper.Configuration.Cache.Memory;
using IBatisNet.DataMapper.Configuration.ParameterMapping;
using IBatisNet.DataMapper.Configuration.ResultMapping;
using IBatisNet.DataMapper.Configuration.Serializers;
using IBatisNet.DataMapper.Configuration.Sql;
using IBatisNet.DataMapper.Configuration.Sql.Dynamic;
using IBatisNet.DataMapper.Configuration.Sql.Dynamic.Elements;
using IBatisNet.DataMapper.Configuration.Sql.SimpleDynamic;
using IBatisNet.DataMapper.Configuration.Sql.Static;
using IBatisNet.DataMapper.Configuration.Statements;
using IBatisNet.DataMapper.MappedStatements;
using IBatisNet.DataMapper.MappedStatements.ArgumentStrategy;
using IBatisNet.DataMapper.MappedStatements.PropertyStrategy;
using IBatisNet.DataMapper.Scope;
using IBatisNet.DataMapper.TypeHandlers;
#endregion
namespace IBatisNet.DataMapper.Configuration
{
///
/// Builds an ISqlMapper instance from the supplied resources (e.g. XML configuration files).
///
public class DomSqlMapBuilder
{
#region Embedded resource
// Which files must we allow to be used as Embedded Resources ?
// - slqMap.config [Yes]
// - providers.config [Yes]
// - sqlMap files [Yes]
// - properties file (like Database.config) [Yes]
// see contribution, NHibernate usage,
// see http://www.codeproject.com/csharp/EmbeddedResourceStrings.asp
// see http://www.devhood.com/tutorials/tutorial_details.aspx?tutorial_id=75
#endregion
#region Constant
private const string PROPERTY_ELEMENT_KEY_ATTRIB = "key";
private const string PROPERTY_ELEMENT_VALUE_ATTRIB = "value";
///
///
///
private const string DATAMAPPER_NAMESPACE_PREFIX = "mapper";
private const string PROVIDERS_NAMESPACE_PREFIX = "provider";
private const string MAPPING_NAMESPACE_PREFIX = "mapping";
private const string DATAMAPPER_XML_NAMESPACE = "http://ibatis.apache.org/dataMapper";
private const string PROVIDER_XML_NAMESPACE = "http://ibatis.apache.org/providers";
private const string MAPPING_XML_NAMESPACE = "http://ibatis.apache.org/mapping";
///
/// Default filename of main configuration file.
///
public const string DEFAULT_FILE_CONFIG_NAME = "SqlMap.config";
///
/// Default provider name
///
private const string DEFAULT_PROVIDER_NAME = "_DEFAULT_PROVIDER_NAME";
///
/// Dot representation.
///
public const string DOT = ".";
///
/// Token for SqlMapConfig xml root element.
///
private const string XML_DATAMAPPER_CONFIG_ROOT = "sqlMapConfig";
///
/// Token for xml path to SqlMapConfig settings element.
///
private const string XML_CONFIG_SETTINGS = "sqlMapConfig/settings/setting";
///
/// Token for default providers config file name.
///
private const string PROVIDERS_FILE_NAME = "providers.config";
///
/// Token for xml path to SqlMapConfig providers element.
///
private const string XML_CONFIG_PROVIDERS = "sqlMapConfig/providers";
///
/// Token for xml path to properties elements.
///
private const string XML_PROPERTIES = "properties";
///
/// Token for xml path to property elements.
///
private const string XML_PROPERTY = "property";
///
/// Token for xml path to settings add elements.
///
private const string XML_SETTINGS_ADD = "/*/add";
///
/// Token for xml path to global properties elements.
///
private const string XML_GLOBAL_PROPERTIES = "*/add";
///
/// Token for xml path to provider elements.
///
private const string XML_PROVIDER = "providers/provider";
///
/// Token for xml path to database provider elements.
///
private const string XML_DATABASE_PROVIDER = "sqlMapConfig/database/provider";
///
/// Token for xml path to database source elements.
///
private const string XML_DATABASE_DATASOURCE = "sqlMapConfig/database/dataSource";
///
/// Token for xml path to global type alias elements.
///
private const string XML_GLOBAL_TYPEALIAS = "sqlMapConfig/alias/typeAlias";
///
/// Token for xml path to global type alias elements.
///
private const string XML_GLOBAL_TYPEHANDLER = "sqlMapConfig/typeHandlers/typeHandler";
///
/// Token for xml path to sqlMap elements.
///
private const string XML_SQLMAP = "sqlMapConfig/sqlMaps/sqlMap";
///
/// Token for mapping xml root.
///
private const string XML_MAPPING_ROOT = "sqlMap";
///
/// Token for xml path to type alias elements.
///
private const string XML_TYPEALIAS = "sqlMap/alias/typeAlias";
///
/// Token for xml path to resultMap elements.
///
private const string XML_RESULTMAP = "sqlMap/resultMaps/resultMap";
///
/// Token for xml path to parameterMap elements.
///
private const string XML_PARAMETERMAP = "sqlMap/parameterMaps/parameterMap";
///
/// Token for xml path to sql elements.
///
private const string SQL_STATEMENT = "sqlMap/statements/sql";
///
/// Token for xml path to statement elements.
///
private const string XML_STATEMENT = "sqlMap/statements/statement";
///
/// Token for xml path to select elements.
///
private const string XML_SELECT = "sqlMap/statements/select";
///
/// Token for xml path to insert elements.
///
private const string XML_INSERT = "sqlMap/statements/insert";
///
/// Token for xml path to selectKey elements.
///
private const string XML_SELECTKEY= "selectKey";
///
/// Token for xml path to update elements.
///
private const string XML_UPDATE ="sqlMap/statements/update";
///
/// Token for xml path to delete elements.
///
private const string XML_DELETE ="sqlMap/statements/delete";
///
/// Token for xml path to procedure elements.
///
private const string XML_PROCEDURE ="sqlMap/statements/procedure";
///
/// Token for xml path to cacheModel elements.
///
private const string XML_CACHE_MODEL = "sqlMap/cacheModels/cacheModel";
///
/// Token for xml path to flushOnExecute elements.
///
private const string XML_FLUSH_ON_EXECUTE = "flushOnExecute";
///
/// Token for xml path to search statement elements.
///
private const string XML_SEARCH_STATEMENT ="sqlMap/statements";
///
/// Token for xml path to search parameterMap elements.
///
private const string XML_SEARCH_PARAMETER ="sqlMap/parameterMaps/parameterMap[@id='";
///
/// Token for xml path to search resultMap elements.
///
private const string XML_SEARCH_RESULTMAP ="sqlMap/resultMaps/resultMap[@id='";
///
/// Token for useStatementNamespaces attribute.
///
private const string ATR_USE_STATEMENT_NAMESPACES = "useStatementNamespaces";
///
/// Token for cacheModelsEnabled attribute.
///
private const string ATR_CACHE_MODELS_ENABLED = "cacheModelsEnabled";
///
/// Token for validateSqlMap attribute.
///
private const string ATR_VALIDATE_SQLMAP = "validateSqlMap";
///
/// Token for useReflectionOptimizer attribute.
///
private const string ATR_USE_REFLECTION_OPTIMIZER = "useReflectionOptimizer";
#endregion
#region Fields
private static readonly ILog _logger = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType );
private ConfigurationScope _configScope = null;
private DeSerializerFactory _deSerializerFactory = null;
private InlineParameterMapParser _paramParser = null;
private IObjectFactory _objectFactory = null;
private ISetAccessorFactory _setAccessorFactory = null;
private IGetAccessorFactory _getAccessorFactory = null;
private ISqlMapper _sqlMapper = null;
private bool _validateSqlMapConfig = true;
#endregion
#region Properties
///
/// Allow properties to be set before configuration.
///
public NameValueCollection Properties
{
set { _configScope.Properties.Add(value); }
}
///
/// Allow a custom to be set before configuration.
///
public ISetAccessorFactory SetAccessorFactory
{
set { _setAccessorFactory = value; }
}
///
/// Allow a custom to be set before configuration.
///
public IGetAccessorFactory GetAccessorFactory
{
set { _getAccessorFactory = value; }
}
///
/// Allow a custom to be set before configuration.
///
public IObjectFactory ObjectFactory
{
set { _objectFactory = value; }
}
///
/// Allow a custom to be set before configuration.
///
public ISqlMapper SqlMapper
{
set { _sqlMapper = value; }
}
///
/// Enable validation of SqlMap document. This property must be set before configuration.
///
public bool ValidateSqlMapConfig
{
set { _validateSqlMapConfig = value; }
}
#endregion
#region Constructor
///
/// Constructs a DomSqlMapBuilder.
///
public DomSqlMapBuilder()
{
_configScope = new ConfigurationScope();
_paramParser = new InlineParameterMapParser();
_deSerializerFactory = new DeSerializerFactory(_configScope);
}
#endregion
#region Configure
///
/// Configure a SqlMapper from default resource file named 'SqlMap.config'.
///
/// An ISqlMapper instance.
///
/// The file path is relative to the application root. For ASP.Net applications
/// this would be the same directory as the Web.config file. For other .Net
/// applications the SqlMap.config file should be placed in the same folder
/// as the executable.
///
public ISqlMapper Configure()
{
return Configure( Resources.GetConfigAsXmlDocument(DEFAULT_FILE_CONFIG_NAME) );
}
///
/// Configure and returns an ISqlMapper instance.
///
/// An xml sql map configuration document.
/// An ISqlMapper instance.
public ISqlMapper Configure(XmlDocument document)
{
return Build( document, false );
}
///
/// Configure an ISqlMapper object from a file path.
///
///
/// A relative ressource path from your Application root
/// or a absolue file path file:\\c:\dir\a.config
///
/// An ISqlMapper instance.
public ISqlMapper Configure(string resource)
{
XmlDocument document;
if (resource.StartsWith("file://"))
{
document = Resources.GetUrlAsXmlDocument( resource.Remove(0, 7) );
}
else
{
document = Resources.GetResourceAsXmlDocument( resource );
}
return Build( document, false);
}
///
/// Configure an ISqlMapper object from a stream.
///
/// A Stream resource.
/// An SqlMap
public ISqlMapper Configure(Stream resource)
{
XmlDocument document = Resources.GetStreamAsXmlDocument( resource );
return Build( document, false);
}
///
/// Configure an ISqlMapper object from a FileInfo.
///
/// A FileInfo resource.
/// An ISqlMapper instance.
public ISqlMapper Configure(FileInfo resource)
{
XmlDocument document = Resources.GetFileInfoAsXmlDocument( resource );
return Build( document, false);
}
///
/// Configure an ISqlMapper object from an Uri.
///
/// A Uri resource.
/// An ISqlMapper instance.
public ISqlMapper Configure(Uri resource)
{
XmlDocument document = Resources.GetUriAsXmlDocument( resource );
return Build( document, false);
}
///
/// Configure and monitor the default configuration file (SqlMap.config) for modifications
/// and automatically reconfigure SqlMap.
///
/// An ISqlMapper instance.
public ISqlMapper ConfigureAndWatch(ConfigureHandler configureDelegate)
{
return ConfigureAndWatch( DEFAULT_FILE_CONFIG_NAME, configureDelegate ) ;
}
///
/// Configure and monitor the configuration file for modifications
/// and automatically reconfigure the ISqlMapper instance.
///
///
/// A relative ressource path from your Application root
/// or an absolue file path file:\\c:\dir\a.config
///
///
/// Delegate called when the file has changed.
///
/// An ISqlMapper instance.
public ISqlMapper ConfigureAndWatch( string resource, ConfigureHandler configureDelegate )
{
XmlDocument document = null;
if (resource.StartsWith("file://"))
{
document = Resources.GetUrlAsXmlDocument( resource.Remove(0, 7) );
}
else
{
document = Resources.GetResourceAsXmlDocument( resource );
}
ConfigWatcherHandler.ClearFilesMonitored();
ConfigWatcherHandler.AddFileToWatch( Resources.GetFileInfo( resource ) );
TimerCallback callBakDelegate = new TimerCallback( OnConfigFileChange );
StateConfig state = new StateConfig();
state.FileName = resource;
state.ConfigureHandler = configureDelegate;
ISqlMapper sqlMapper = Build( document, true );
new ConfigWatcherHandler( callBakDelegate, state );
return sqlMapper;
}
///
/// Configure and monitor the configuration file for modifications
/// and automatically reconfigure the ISqlMapper instance.
///
///
/// A FileInfo to a SqlMap.config file.
///
///
/// Delegate called when the file has changed.
///
/// An ISqlMapper instance.
public ISqlMapper ConfigureAndWatch( FileInfo resource, ConfigureHandler configureDelegate )
{
XmlDocument document = Resources.GetFileInfoAsXmlDocument(resource);
ConfigWatcherHandler.ClearFilesMonitored();
ConfigWatcherHandler.AddFileToWatch( resource );
TimerCallback callBakDelegate = new TimerCallback( OnConfigFileChange );
StateConfig state = new StateConfig();
state.FileName = resource.FullName;
state.ConfigureHandler = configureDelegate;
ISqlMapper sqlMapper = Build( document, true );
new ConfigWatcherHandler(callBakDelegate, state);
return sqlMapper;
}
///
/// Callback called when the SqlMap.config file has changed.
///
/// The object.
public static void OnConfigFileChange(object obj)
{
StateConfig state = (StateConfig)obj;
state.ConfigureHandler( null );
}
#endregion
#region Methods
///
/// Build an ISqlMapper instance.
///
/// An xml configuration document.
/// A data source.
///
///
/// Returns an ISqlMapper instance.
private ISqlMapper Build(XmlDocument document,DataSource dataSource,
bool useConfigFileWatcher, bool isCallFromDao)
{
_configScope.SqlMapConfigDocument = document;
_configScope.DataSource = dataSource;
_configScope.IsCallFromDao = isCallFromDao;
_configScope.UseConfigFileWatcher = useConfigFileWatcher;
_configScope.XmlNamespaceManager = new XmlNamespaceManager(_configScope.SqlMapConfigDocument.NameTable);
_configScope.XmlNamespaceManager.AddNamespace(DATAMAPPER_NAMESPACE_PREFIX, DATAMAPPER_XML_NAMESPACE);
_configScope.XmlNamespaceManager.AddNamespace(PROVIDERS_NAMESPACE_PREFIX, PROVIDER_XML_NAMESPACE);
_configScope.XmlNamespaceManager.AddNamespace(MAPPING_NAMESPACE_PREFIX, MAPPING_XML_NAMESPACE);
try
{
if (_validateSqlMapConfig)
{
ValidateSchema( document.ChildNodes[1], "SqlMapConfig.xsd" );
}
Initialize();
return _configScope.SqlMapper;
}
catch(Exception e)
{
throw new ConfigurationException(_configScope.ErrorContext.ToString(), e);
}
}
///
/// Validates an XmlNode against a schema file.
///
/// The doc to validate.
/// Schema file name.
private void ValidateSchema( XmlNode section, string schemaFileName )
{
#if dotnet2
XmlReader validatingReader = null;
#else
XmlValidatingReader validatingReader = null;
#endif
Stream xsdFile = null;
_configScope.ErrorContext.Activity = "Validate SqlMap config";
try
{
//Validate the document using a schema
xsdFile = GetStream( schemaFileName );
if (xsdFile == null)
{
// TODO: avoid using hard-coded value "IBatisNet.DataMapper"
throw new ConfigurationException( "Unable to locate embedded resource [IBatisNet.DataMapper."+schemaFileName+"]. If you are building from source, verfiy the file is marked as an embedded resource.");
}
XmlSchema schema = XmlSchema.Read( xsdFile, new ValidationEventHandler(ValidationCallBack) );
#if dotnet2
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
// Create the XmlSchemaSet class.
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add(schema);
settings.Schemas = schemas;
validatingReader = XmlReader.Create( new XmlNodeReader(section) , settings);
// Wire up the call back. The ValidationEvent is fired when the
// XmlValidatingReader hits an issue validating a section of the xml
settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);
#else
validatingReader = new XmlValidatingReader(new XmlTextReader(new StringReader(section.OuterXml)));
validatingReader.ValidationType = ValidationType.Schema;
validatingReader.Schemas.Add(schema);
// Wire up the call back. The ValidationEvent is fired when the
// XmlValidatingReader hits an issue validating a section of the xml
validatingReader.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);
#endif
// Validate the document
while (validatingReader.Read()){}
if(! _configScope.IsXmlValid )
{
throw new ConfigurationException( "Invalid SqlMap.config document. cause :"+_configScope.ErrorContext.Resource);
}
}
finally
{
if( validatingReader != null ) validatingReader.Close();
if( xsdFile != null ) xsdFile.Close();
}
}
private void ValidationCallBack( object sender, ValidationEventArgs args )
{
_configScope.IsXmlValid = false;
_configScope.ErrorContext.Resource += args.Message + Environment.NewLine;
}
///
/// Load statements (select, insert, update, delete), parameters, and resultMaps.
///
///
///
///
///
///
/// Used by Dao
public ISqlMapper Build(XmlDocument document, DataSource dataSource, bool useConfigFileWatcher, NameValueCollection properties)
{
_configScope.Properties.Add(properties);
return Build(document, dataSource, useConfigFileWatcher, true);
}
///
/// Load SqlMap configuration from
/// from the XmlDocument passed in parameter.
///
/// The xml sql map configuration.
///
public ISqlMapper Build(XmlDocument document, bool useConfigFileWatcher)
{
return Build(document, null, useConfigFileWatcher, false);
}
///
/// Reset PreparedStatements cache
///
private void Reset()
{
}
///
/// Intialize the internal ISqlMapper instance.
///
private void Initialize()
{
Reset();
#region Load Global Properties
if (_configScope.IsCallFromDao == false)
{
_configScope.NodeContext = _configScope.SqlMapConfigDocument.SelectSingleNode( ApplyDataMapperNamespacePrefix(XML_DATAMAPPER_CONFIG_ROOT), _configScope.XmlNamespaceManager);
ParseGlobalProperties();
}
#endregion
#region Load settings
_configScope.ErrorContext.Activity = "loading global settings";
XmlNodeList settings = _configScope.SqlMapConfigDocument.SelectNodes( ApplyDataMapperNamespacePrefix(XML_CONFIG_SETTINGS), _configScope.XmlNamespaceManager);
if (settings!=null)
{
foreach (XmlNode setting in settings)
{
if (setting.Attributes[ATR_USE_STATEMENT_NAMESPACES] != null )
{
string value = NodeUtils.ParsePropertyTokens(setting.Attributes[ATR_USE_STATEMENT_NAMESPACES].Value, _configScope.Properties);
_configScope.UseStatementNamespaces = Convert.ToBoolean( value );
}
if (setting.Attributes[ATR_CACHE_MODELS_ENABLED] != null )
{
string value = NodeUtils.ParsePropertyTokens(setting.Attributes[ATR_CACHE_MODELS_ENABLED].Value, _configScope.Properties);
_configScope.IsCacheModelsEnabled = Convert.ToBoolean( value );
}
if (setting.Attributes[ATR_USE_REFLECTION_OPTIMIZER] != null )
{
string value = NodeUtils.ParsePropertyTokens(setting.Attributes[ATR_USE_REFLECTION_OPTIMIZER].Value, _configScope.Properties);
_configScope.UseReflectionOptimizer = Convert.ToBoolean( value );
}
if (setting.Attributes[ATR_VALIDATE_SQLMAP] != null )
{
string value = NodeUtils.ParsePropertyTokens(setting.Attributes[ATR_VALIDATE_SQLMAP].Value, _configScope.Properties);
_configScope.ValidateSqlMap = Convert.ToBoolean( value );
}
}
}
#endregion
if (_objectFactory == null)
{
_objectFactory = new ObjectFactory(_configScope.UseReflectionOptimizer);
}
if (_setAccessorFactory == null)
{
_setAccessorFactory = new SetAccessorFactory(_configScope.UseReflectionOptimizer);
}
if (_getAccessorFactory == null)
{
_getAccessorFactory = new GetAccessorFactory(_configScope.UseReflectionOptimizer);
}
if (_sqlMapper == null)
{
AccessorFactory accessorFactory = new AccessorFactory(_setAccessorFactory, _getAccessorFactory);
_configScope.SqlMapper = new SqlMapper(_objectFactory, accessorFactory);
}
else
{
_configScope.SqlMapper = _sqlMapper;
}
ParameterMap emptyParameterMap = new ParameterMap(_configScope.DataExchangeFactory);
emptyParameterMap.Id = ConfigurationScope.EMPTY_PARAMETER_MAP;
_configScope.SqlMapper.AddParameterMap( emptyParameterMap );
_configScope.SqlMapper.IsCacheModelsEnabled = _configScope.IsCacheModelsEnabled;
#region Cache Alias
TypeAlias cacheAlias = new TypeAlias(typeof(MemoryCacheControler));
cacheAlias.Name = "MEMORY";
_configScope.SqlMapper.TypeHandlerFactory.AddTypeAlias(cacheAlias.Name, cacheAlias);
cacheAlias = new TypeAlias(typeof(LruCacheController));
cacheAlias.Name = "LRU";
_configScope.SqlMapper.TypeHandlerFactory.AddTypeAlias(cacheAlias.Name, cacheAlias);
cacheAlias = new TypeAlias(typeof(FifoCacheController));
cacheAlias.Name = "FIFO";
_configScope.SqlMapper.TypeHandlerFactory.AddTypeAlias(cacheAlias.Name, cacheAlias);
cacheAlias = new TypeAlias(typeof(AnsiStringTypeHandler));
cacheAlias.Name = "AnsiStringTypeHandler";
_configScope.SqlMapper.TypeHandlerFactory.AddTypeAlias(cacheAlias.Name, cacheAlias);
#endregion
#region Load providers
if (_configScope.IsCallFromDao == false)
{
GetProviders();
}
#endregion
#region Load DataBase
#region Choose the provider
IDbProvider provider = null;
if ( _configScope.IsCallFromDao==false )
{
provider = ParseProvider();
_configScope.ErrorContext.Reset();
}
#endregion
#region Load the DataSources
_configScope.ErrorContext.Activity = "loading Database DataSource";
XmlNode nodeDataSource = _configScope.SqlMapConfigDocument.SelectSingleNode( ApplyDataMapperNamespacePrefix(XML_DATABASE_DATASOURCE), _configScope.XmlNamespaceManager );
if (nodeDataSource == null)
{
if (_configScope.IsCallFromDao == false)
{
throw new ConfigurationException("There's no dataSource tag in SqlMap.config.");
}
else // patch from Luke Yang
{
_configScope.SqlMapper.DataSource = _configScope.DataSource;
}
}
else
{
if (_configScope.IsCallFromDao == false)
{
_configScope.ErrorContext.Resource = nodeDataSource.OuterXml.ToString();
_configScope.ErrorContext.MoreInfo = "parse DataSource";
DataSource dataSource = DataSourceDeSerializer.Deserialize( nodeDataSource );
dataSource.DbProvider = provider;
dataSource.ConnectionString = NodeUtils.ParsePropertyTokens(dataSource.ConnectionString, _configScope.Properties);
_configScope.DataSource = dataSource;
_configScope.SqlMapper.DataSource = _configScope.DataSource;
}
else
{
_configScope.SqlMapper.DataSource = _configScope.DataSource;
}
_configScope.ErrorContext.Reset();
}
#endregion
#endregion
#region Load Global TypeAlias
foreach (XmlNode xmlNode in _configScope.SqlMapConfigDocument.SelectNodes( ApplyDataMapperNamespacePrefix(XML_GLOBAL_TYPEALIAS), _configScope.XmlNamespaceManager))
{
_configScope.ErrorContext.Activity = "loading global Type alias";
TypeAliasDeSerializer.Deserialize(xmlNode, _configScope);
}
_configScope.ErrorContext.Reset();
#endregion
#region Load TypeHandlers
foreach (XmlNode xmlNode in _configScope.SqlMapConfigDocument.SelectNodes( ApplyDataMapperNamespacePrefix(XML_GLOBAL_TYPEHANDLER), _configScope.XmlNamespaceManager))
{
try
{
_configScope.ErrorContext.Activity = "loading typeHandler";
TypeHandlerDeSerializer.Deserialize( xmlNode, _configScope );
}
catch (Exception e)
{
NameValueCollection prop = NodeUtils.ParseAttributes(xmlNode, _configScope.Properties);
throw new ConfigurationException(
String.Format("Error registering TypeHandler class \"{0}\" for handling .Net type \"{1}\" and dbType \"{2}\". Cause: {3}",
NodeUtils.GetStringAttribute(prop, "callback"),
NodeUtils.GetStringAttribute(prop, "type"),
NodeUtils.GetStringAttribute(prop, "dbType"),
e.Message), e);
}
}
_configScope.ErrorContext.Reset();
#endregion
#region Load sqlMap mapping files
foreach (XmlNode xmlNode in _configScope.SqlMapConfigDocument.SelectNodes( ApplyDataMapperNamespacePrefix(XML_SQLMAP), _configScope.XmlNamespaceManager))
{
_configScope.NodeContext = xmlNode;
ConfigureSqlMap();
}
#endregion
#region Attach CacheModel to statement
if (_configScope.IsCacheModelsEnabled)
{
foreach(DictionaryEntry entry in _configScope.SqlMapper.MappedStatements)
{
_configScope.ErrorContext.Activity = "Set CacheModel to statement";
IMappedStatement mappedStatement = (IMappedStatement)entry.Value;
if (mappedStatement.Statement.CacheModelName.Length >0)
{
_configScope.ErrorContext.MoreInfo = "statement : "+mappedStatement.Statement.Id;
_configScope.ErrorContext.Resource = "cacheModel : " +mappedStatement.Statement.CacheModelName;
mappedStatement.Statement.CacheModel = _configScope.SqlMapper.GetCache(mappedStatement.Statement.CacheModelName);
}
}
}
_configScope.ErrorContext.Reset();
#endregion
#region Register Trigger Statements for Cache Models
foreach (DictionaryEntry entry in _configScope.CacheModelFlushOnExecuteStatements)
{
string cacheModelId = (string)entry.Key;
IList statementsToRegister = (IList)entry.Value;
if (statementsToRegister != null && statementsToRegister.Count > 0)
{
foreach (string statementName in statementsToRegister)
{
IMappedStatement mappedStatement = _configScope.SqlMapper.MappedStatements[statementName] as IMappedStatement;
if (mappedStatement != null)
{
CacheModel cacheModel = _configScope.SqlMapper.GetCache(cacheModelId);
if (_logger.IsDebugEnabled)
{
_logger.Debug("Registering trigger statement [" + mappedStatement.Id + "] to cache model [" + cacheModel.Id + "]");
}
cacheModel.RegisterTriggerStatement(mappedStatement);
}
else
{
if (_logger.IsWarnEnabled)
{
_logger.Warn("Unable to register trigger statement [" + statementName + "] to cache model [" + cacheModelId + "]. Statement does not exist.");
}
}
}
}
}
#endregion
#region Resolve resultMap / Discriminator / PropertyStategy attributes on Result/Argument Property
foreach(DictionaryEntry entry in _configScope.SqlMapper.ResultMaps)
{
_configScope.ErrorContext.Activity = "Resolve 'resultMap' attribute on Result Property";
ResultMap resultMap = (ResultMap)entry.Value;
for(int index=0; index< resultMap.Properties.Count; index++)
{
ResultProperty result = resultMap.Properties[index];
if(result.NestedResultMapName.Length >0)
{
result.NestedResultMap = _configScope.SqlMapper.GetResultMap(result.NestedResultMapName);
}
result.PropertyStrategy = PropertyStrategyFactory.Get(result);
}
for(int index=0; index< resultMap.Parameters.Count; index++)
{
ResultProperty result = resultMap.Parameters[index];
if(result.NestedResultMapName.Length >0)
{
result.NestedResultMap = _configScope.SqlMapper.GetResultMap(result.NestedResultMapName);
}
result.ArgumentStrategy = ArgumentStrategyFactory.Get( (ArgumentProperty)result );
}
if (resultMap.Discriminator != null)
{
resultMap.Discriminator.Initialize(_configScope);
}
}
_configScope.ErrorContext.Reset();
#endregion
}
///
/// Load and initialize providers from specified file.
///
private void GetProviders()
{
IDbProvider provider;
XmlDocument xmlProviders;
_configScope.ErrorContext.Activity = "loading Providers";
XmlNode providersNode;
providersNode = _configScope.SqlMapConfigDocument.SelectSingleNode( ApplyDataMapperNamespacePrefix(XML_CONFIG_PROVIDERS), _configScope.XmlNamespaceManager);
if (providersNode != null )
{
xmlProviders = Resources.GetAsXmlDocument( providersNode, _configScope.Properties );
}
else
{
xmlProviders = Resources.GetConfigAsXmlDocument(PROVIDERS_FILE_NAME);
}
foreach (XmlNode node in xmlProviders.SelectNodes( ApplyProviderNamespacePrefix(XML_PROVIDER), _configScope.XmlNamespaceManager ) )
{
_configScope.ErrorContext.Resource = node.InnerXml.ToString();
provider = ProviderDeSerializer.Deserialize(node);
if (provider.IsEnabled)
{
_configScope.ErrorContext.ObjectId = provider.Name;
_configScope.ErrorContext.MoreInfo = "initialize provider";
provider.Initialize();
_configScope.Providers.Add(provider.Name, provider);
if (provider.IsDefault)
{
if (_configScope.Providers[DEFAULT_PROVIDER_NAME] == null)
{
_configScope.Providers.Add(DEFAULT_PROVIDER_NAME,provider);
}
else
{
throw new ConfigurationException(
string.Format("Error while configuring the Provider named \"{0}\" There can be only one default Provider.",provider.Name));
}
}
}
}
_configScope.ErrorContext.Reset();
}
///
/// Parse the provider tag.
///
/// A provider object.
private IDbProvider ParseProvider()
{
_configScope.ErrorContext.Activity = "load DataBase Provider";
XmlNode node = _configScope.SqlMapConfigDocument.SelectSingleNode( ApplyDataMapperNamespacePrefix(XML_DATABASE_PROVIDER), _configScope.XmlNamespaceManager );
if (node != null)
{
_configScope.ErrorContext.Resource = node.OuterXml.ToString();
string providerName = NodeUtils.ParsePropertyTokens(node.Attributes["name"].Value, _configScope.Properties);
_configScope.ErrorContext.ObjectId = providerName;
if (_configScope.Providers.Contains(providerName))
{
return (IDbProvider) _configScope.Providers[providerName];
}
else
{
throw new ConfigurationException(
string.Format("Error while configuring the Provider named \"{0}\". Cause : The provider is not in 'providers.config' or is not enabled.",
providerName));
}
}
else
{
if (_configScope.Providers.Contains(DEFAULT_PROVIDER_NAME))
{
return (IDbProvider) _configScope.Providers[DEFAULT_PROVIDER_NAME];
}
else
{
throw new ConfigurationException(
string.Format("Error while configuring the SqlMap. There is no provider marked default in 'providers.config' file."));
}
}
}
///
/// Load sqlMap statement.
///
private void ConfigureSqlMap( )
{
XmlNode sqlMapNode = _configScope.NodeContext;
_configScope.ErrorContext.Activity = "loading SqlMap";
_configScope.ErrorContext.Resource = sqlMapNode.OuterXml.ToString();
if (_configScope.UseConfigFileWatcher)
{
if (sqlMapNode.Attributes["resource"] != null || sqlMapNode.Attributes["url"] != null)
{
ConfigWatcherHandler.AddFileToWatch( Resources.GetFileInfo( Resources.GetValueOfNodeResourceUrl(sqlMapNode, _configScope.Properties) ) );
}
}
// Load the file
_configScope.SqlMapDocument = Resources.GetAsXmlDocument(sqlMapNode, _configScope.Properties);
if (_configScope.ValidateSqlMap)
{
ValidateSchema( _configScope.SqlMapDocument.ChildNodes[1], "SqlMap.xsd" );
}
_configScope.SqlMapNamespace = _configScope.SqlMapDocument.SelectSingleNode( ApplyMappingNamespacePrefix(XML_MAPPING_ROOT), _configScope.XmlNamespaceManager ).Attributes["namespace"].Value;
#region Load TypeAlias
foreach (XmlNode xmlNode in _configScope.SqlMapDocument.SelectNodes( ApplyMappingNamespacePrefix(XML_TYPEALIAS), _configScope.XmlNamespaceManager))
{
TypeAliasDeSerializer.Deserialize(xmlNode, _configScope);
}
_configScope.ErrorContext.MoreInfo = string.Empty;
_configScope.ErrorContext.ObjectId = string.Empty;
#endregion
#region Load resultMap
foreach (XmlNode xmlNode in _configScope.SqlMapDocument.SelectNodes( ApplyMappingNamespacePrefix(XML_RESULTMAP), _configScope.XmlNamespaceManager))
{
_configScope.ErrorContext.MoreInfo = "loading ResultMap tag";
_configScope.NodeContext = xmlNode; // A ResultMap node
BuildResultMap();
}
#endregion
#region Load parameterMaps
foreach (XmlNode xmlNode in _configScope.SqlMapDocument.SelectNodes( ApplyMappingNamespacePrefix(XML_PARAMETERMAP), _configScope.XmlNamespaceManager))
{
_configScope.ErrorContext.MoreInfo = "loading ParameterMap tag";
_configScope.NodeContext = xmlNode; // A ParameterMap node
BuildParameterMap();
}
#endregion
#region Load statements
#region Sql tag
foreach (XmlNode xmlNode in _configScope.SqlMapDocument.SelectNodes(ApplyMappingNamespacePrefix(SQL_STATEMENT), _configScope.XmlNamespaceManager))
{
_configScope.ErrorContext.MoreInfo = "loading sql tag";
_configScope.NodeContext = xmlNode; // A sql tag
SqlDeSerializer.Deserialize(xmlNode, _configScope);
}
#endregion
#region Statement tag
Statement statement;
foreach (XmlNode xmlNode in _configScope.SqlMapDocument.SelectNodes( ApplyMappingNamespacePrefix(XML_STATEMENT), _configScope.XmlNamespaceManager))
{
_configScope.ErrorContext.MoreInfo = "loading statement tag";
_configScope.NodeContext = xmlNode; // A statement tag
statement = StatementDeSerializer.Deserialize(xmlNode, _configScope);
statement.CacheModelName = _configScope.ApplyNamespace(statement.CacheModelName);
statement.ParameterMapName = _configScope.ApplyNamespace(statement.ParameterMapName);
//statement.ResultMapName = ApplyNamespace( statement.ResultMapName );
if (_configScope.UseStatementNamespaces)
{
statement.Id = _configScope.ApplyNamespace(statement.Id);
}
_configScope.ErrorContext.ObjectId = statement.Id;
statement.Initialize( _configScope );
// Build ISql (analyse sql statement)
ProcessSqlStatement( statement );
// Build MappedStatement
MappedStatement mappedStatement = new MappedStatement(_configScope.SqlMapper, statement);
IMappedStatement mapStatement = mappedStatement;
if (statement.CacheModelName != null && statement.CacheModelName.Length > 0 && _configScope.IsCacheModelsEnabled)
{
mapStatement = new CachingStatement(mappedStatement);
}
_configScope.SqlMapper.AddMappedStatement(mapStatement.Id, mapStatement);
}
#endregion
#region Select tag
Select select;
foreach (XmlNode xmlNode in _configScope.SqlMapDocument.SelectNodes( ApplyMappingNamespacePrefix(XML_SELECT), _configScope.XmlNamespaceManager))
{
_configScope.ErrorContext.MoreInfo = "loading select tag";
_configScope.NodeContext = xmlNode; // A select node
select = SelectDeSerializer.Deserialize(xmlNode, _configScope);
select.CacheModelName = _configScope.ApplyNamespace(select.CacheModelName);
select.ParameterMapName = _configScope.ApplyNamespace(select.ParameterMapName);
//select.ResultMapName = ApplyNamespace( select.ResultMapName );
if (_configScope.UseStatementNamespaces)
{
select.Id = _configScope.ApplyNamespace(select.Id);
}
_configScope.ErrorContext.ObjectId = select.Id;
select.Initialize( _configScope );
if (select.Generate != null)
{
GenerateCommandText(_configScope, select);
}
else
{
// Build ISql (analyse sql statement)
ProcessSqlStatement( select);
}
// Build MappedStatement
MappedStatement mappedStatement = new SelectMappedStatement(_configScope.SqlMapper, select);
IMappedStatement mapStatement = mappedStatement;
if (select.CacheModelName != null && select.CacheModelName.Length> 0 && _configScope.IsCacheModelsEnabled)
{
mapStatement = new CachingStatement(mappedStatement);
}
_configScope.SqlMapper.AddMappedStatement(mapStatement.Id, mapStatement);
}
#endregion
#region Insert tag
Insert insert;
foreach (XmlNode xmlNode in _configScope.SqlMapDocument.SelectNodes( ApplyMappingNamespacePrefix(XML_INSERT), _configScope.XmlNamespaceManager))
{
_configScope.ErrorContext.MoreInfo = "loading insert tag";
_configScope.NodeContext = xmlNode; // A insert tag
MappedStatement mappedStatement;
insert = InsertDeSerializer.Deserialize(xmlNode, _configScope);
insert.CacheModelName = _configScope.ApplyNamespace(insert.CacheModelName);
insert.ParameterMapName = _configScope.ApplyNamespace(insert.ParameterMapName);
//insert.ResultMapName = ApplyNamespace( insert.ResultMapName );
if (_configScope.UseStatementNamespaces)
{
insert.Id = _configScope.ApplyNamespace(insert.Id);
}
_configScope.ErrorContext.ObjectId = insert.Id;
insert.Initialize( _configScope );
// Build ISql (analyse sql command text)
if (insert.Generate != null)
{
GenerateCommandText(_configScope, insert);
}
else
{
ProcessSqlStatement( insert);
}
// Build MappedStatement
mappedStatement = new InsertMappedStatement( _configScope.SqlMapper, insert);
_configScope.SqlMapper.AddMappedStatement(mappedStatement.Id, mappedStatement);
#region statement SelectKey
// Set sql statement SelectKey
if (insert.SelectKey != null)
{
_configScope.ErrorContext.MoreInfo = "loading selectKey tag";
_configScope.NodeContext = xmlNode.SelectSingleNode( ApplyMappingNamespacePrefix(XML_SELECTKEY), _configScope.XmlNamespaceManager);
insert.SelectKey.Id = insert.Id;
insert.SelectKey.Initialize( _configScope );
insert.SelectKey.Id += DOT + "SelectKey";
// Initialize can also use _configScope.ErrorContext.ObjectId to get the id
// of the parent