#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