2 // System.Data.OleDb.OleDbConnection
5 // Konstantin Triger <kostat@mainsoft.com>
6 // Boris Kirzner <borisk@mainsoft.com>
8 // (C) 2006 Mainsoft Corporation (http://www.mainsoft.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System
.Data
.Common
;
35 using System
.Data
.Configuration
;
36 using System
.Collections
;
37 using System
.Collections
.Specialized
;
38 using System
.Reflection
;
39 using System
.Text
.RegularExpressions
;
40 using Mainsoft
.Data
.Configuration
;
42 using System
.Globalization
;
48 namespace Mainsoft
.Data
.Jdbc
.Providers
50 public class GenericProvider
: IConnectionProvider
52 #region JdbcUrlConnector
54 sealed class JdbcUrlConnector
{
57 private static readonly Regex JdbcUrlPatternRegex
= new Regex (@"\$\{(?<VALUE>[^$\{\}]*)\}", RegexOptions
.Compiled
| RegexOptions
.IgnoreCase
| RegexOptions
.ExplicitCapture
);
63 readonly IConnectionStringDictionary _keyMapper
;
64 readonly GenericProvider _provider
;
65 readonly ArrayList _excludedKeys
= new ArrayList();
71 internal JdbcUrlConnector (GenericProvider provider
, IConnectionStringDictionary keyMapper
) {
73 _keyMapper
= keyMapper
;
76 #endregion // Constructors
81 internal java
.sql
.Connection Connection
{
83 java
.util
.Properties properties
= new java
.util
.Properties ();
85 string url
= (string)_keyMapper
["JdbcURL"];
87 string jdbcUrlPattern
= (string)_provider
.ProviderInfo
[ConfigurationConsts
.JdbcUrlPattern
];
88 if (jdbcUrlPattern
== null || jdbcUrlPattern
.Length
== 0) {
89 //throw ExceptionHelper.JdbcUrlPatternNotFound ((string)_provider.ProviderInfo [ConfigurationConsts.Name]);
90 object [] args
= new object [] {_provider.ProviderInfo [ConfigurationConsts.Name]}
;
91 throw new ArgumentException (String
.Format("Provider '{0}' is not configured with valid JDBC URL pattern.",args
));
93 MatchEvaluator evaluator
= new MatchEvaluator (ReplaceEvaluator
);
94 url
= JdbcUrlPatternRegex
.Replace (jdbcUrlPattern
, evaluator
);
97 // hack for backward comatibility:
98 // if the connection string contains 'Provider',
99 // the following mapping will hold:
100 // 'User', 'User Id' --> 'user'
101 // 'Password' --> 'password'
102 if (_keyMapper
["Provider"] != null) {
104 const string USER
= "User";
105 const string USERID
= "User Id";
106 const string PASSWORD
= "Password";
108 string user
= (string)_keyMapper
[USER
];
110 properties
.put("user", user
);
111 _excludedKeys
.Add(USER
);
114 user
= (string)_keyMapper
[USERID
];
116 properties
.put("user", user
);
117 _excludedKeys
.Add(USERID
);
121 string password
= (string)_keyMapper
[PASSWORD
];
122 if (password
!= null) {
123 properties
.put("password", password
);
124 _excludedKeys
.Add(PASSWORD
);
129 if (_provider
._excludedKeys
!= null)
130 _excludedKeys
.AddRange(_provider
._excludedKeys
);
132 foreach(string key
in _provider
.KeyMapping
.Keys
) {
133 object value = _keyMapper
[key
];
136 bool contains
= false;
137 for (int i
= 0; i
< _excludedKeys
.Count
; i
++) {
138 if (String
.Compare((string)_excludedKeys
[i
], key
,
139 true, CultureInfo
.InvariantCulture
) == 0) {
145 properties
.put (key
, value);
146 _excludedKeys
.Add(key
);
150 for (int i
= 0; i
< _excludedKeys
.Count
; i
++) {
151 string value = _keyMapper
.GetConnectionStringKey((string)_excludedKeys
[i
]);
153 _excludedKeys
[i
] = value;
156 foreach(string key
in _keyMapper
.Keys
) {
157 object value = _keyMapper
[key
];
160 bool contains
= false;
161 for (int i
= 0; i
< _excludedKeys
.Count
; i
++) {
162 if (String
.Compare((string)_excludedKeys
[i
], key
,
163 true, CultureInfo
.InvariantCulture
) == 0) {
169 if (_provider
._unsupportedKeys
!= null)
170 for (int i
= 0; i
< _provider
._unsupportedKeys
.Length
; i
++)
171 if (String
.Compare ((string) _provider
._unsupportedKeys
[i
], key
,
172 true, CultureInfo
.InvariantCulture
) == 0)
173 throw new NotSupportedException (
174 String
.Format ("The parameter '{0}' is not supported.", key
));
176 properties
.put (key
, value);
180 Driver d
= ActivateJdbcDriver ();
181 // TBD : add DriverManager.setLoginTimeout
183 return d
.connect (url
, properties
);
185 return DriverManager
.getConnection (url
, properties
);
189 private string ReplaceEvaluator (Match m
) {
190 Group g
= m
.Groups
["VALUE"];
195 string usedKey
= g
.Value
.Trim();
197 string value = (string)_keyMapper
[usedKey
];
199 throw new ArgumentException(
200 String
.Format("Missing parameter {0}", g
.Value
),
203 _excludedKeys
.Add(usedKey
);
207 private Driver
ActivateJdbcDriver () {
208 string driver
= (string) _keyMapper
["JdbcDriverClassName"];
210 driver
= (string) _provider
.ProviderInfo
[ConfigurationConsts
.JdbcDriverClassName
];
212 if (driver
!= null && driver
.Length
!= 0) {
214 java
.lang
.ClassLoader contextLoader
= (java
.lang
.ClassLoader
) AppDomain
.CurrentDomain
.GetData ("GH_ContextClassLoader");
215 if (contextLoader
!= null)
216 return (Driver
) contextLoader
.loadClass (driver
).newInstance ();
217 return (Driver
) java
.lang
.Class
.forName (driver
).newInstance ();
219 catch (java
.lang
.ClassNotFoundException e
) {
220 throw new TypeLoadException (e
.Message
, e
);
222 catch (java
.lang
.InstantiationException e
) {
223 throw new MemberAccessException (e
.Message
, e
);
225 catch (java
.lang
.IllegalAccessException e
) {
226 throw new MissingMethodException (e
.Message
, e
);
233 #endregion // Methods
236 #endregion // JdbcUrlBuilder
238 #region DataSourceCache
240 private sealed class DataSourceCache
: AbstractDbMetaDataCache
{
241 internal DataSource
GetDataSource(string dataSourceName
,string namingProviderUrl
,string namingFactoryInitial
) {
242 Hashtable cache
= Cache
;
244 DataSource ds
= cache
[dataSourceName
] as DataSource
;
252 java
.util
.Properties properties
= new java
.util
.Properties();
254 if ((namingProviderUrl
!= null) && (namingProviderUrl
.Length
> 0)) {
255 properties
.put("java.naming.provider.url",namingProviderUrl
);
258 if ((namingFactoryInitial
!= null) && (namingFactoryInitial
.Length
> 0)) {
259 properties
.put("java.naming.factory.initial",namingFactoryInitial
);
262 ctx
= new InitialContext(properties
);
265 ds
= (DataSource
)ctx
.lookup(dataSourceName
);
267 catch(javax
.naming
.NameNotFoundException e
) {
268 // possible that is a Tomcat bug,
269 // so try to lookup for jndi datasource with "java:comp/env/" appended
270 ds
= (DataSource
)ctx
.lookup("java:comp/env/" + dataSourceName
);
273 cache
[dataSourceName
] = ds
;
278 #endregion // DatasourceCache
282 private static DataSourceCache _dataSourceCache
= new DataSourceCache();
284 private readonly IDictionary _providerInfo
;
285 private NameValueCollection _keyMapping
;
286 private string[] _excludedKeys
;
287 private string[] _unsupportedKeys
;
293 public GenericProvider(IDictionary providerInfo
)
295 _providerInfo
= providerInfo
;
299 #endregion // Constructors
303 protected IDictionary ProviderInfo
305 get { return _providerInfo; }
308 private NameValueCollection KeyMapping
312 if (_keyMapping
== null)
319 #endregion // Properties
323 public virtual java
.sql
.Connection
GetConnection (IConnectionStringDictionary conectionStringBuilder
)
325 string dataSourceJndi
= (string) conectionStringBuilder
.GetValue ("jndi-datasource-name");
327 if (dataSourceJndi
!= null && dataSourceJndi
.Length
> 0) {
329 string namingProviderUrl
= (string) conectionStringBuilder
.GetValue ("naming-provider-url");
330 string namingFactoryInitial
= (string) conectionStringBuilder
.GetValue ("naming-factory-initial");
331 DataSource ds
= _dataSourceCache
.GetDataSource(dataSourceJndi
,namingProviderUrl
,namingFactoryInitial
);
332 return ds
.getConnection();
335 JdbcUrlConnector connector
= new JdbcUrlConnector (this, conectionStringBuilder
);
336 return connector
.Connection
;
339 public virtual IConnectionStringDictionary
GetConnectionStringBuilder (string connectionString
)
341 return new ConnectionStringDictionary(connectionString
, KeyMapping
);
344 private void InitKeyMapping ()
347 if (_keyMapping
!= null)
350 _keyMapping
= new NameValueCollection (StringComparer
.OrdinalIgnoreCase
);
352 // create key mappings collection
353 string keyMappingsStr
= (string) _providerInfo
[ConfigurationConsts
.KeyMapping
];
354 if (keyMappingsStr
!= null) {
355 string [] keyMappings
= keyMappingsStr
.Split (ConfigurationConsts
.SemicolonArr
);
356 foreach (string keyMapping
in keyMappings
) {
357 if (keyMapping
.Length
== 0)
359 int equalsIndex
= keyMapping
.IndexOf ('=');
360 string key
= keyMapping
.Substring (0, equalsIndex
).Trim ();
361 string [] mappings
= keyMapping
.Substring (equalsIndex
+ 1).Trim ().Split (ConfigurationConsts
.CommaArr
);
362 foreach (string mapping
in mappings
)
363 _keyMapping
.Add (key
, mapping
.Trim ());
367 string keyMappingExcludesStr
= (string) _providerInfo
[ConfigurationConsts
.KeyMappingExcludes
];
368 if (keyMappingExcludesStr
!= null) {
369 _excludedKeys
= keyMappingExcludesStr
.Split (ConfigurationConsts
.CommaArr
);
370 for (int i
= 0; i
< _excludedKeys
.Length
; i
++)
371 _excludedKeys
[i
] = _excludedKeys
[i
].Trim ();
374 string keyMappingUnsupportedStr
= (string) _providerInfo
[ConfigurationConsts
.KeyMappingUnsupported
];
375 if (keyMappingUnsupportedStr
!= null) {
376 _unsupportedKeys
= keyMappingUnsupportedStr
.Split (ConfigurationConsts
.CommaArr
);
377 for (int i
= 0; i
< _unsupportedKeys
.Length
; i
++)
378 _unsupportedKeys
[i
] = _unsupportedKeys
[i
].Trim ();
383 #endregion // Methods