2 // Mainsoft.Web.Profile.DerbyProfileProvider
5 // Vladimir Krasnov (vladimirk@mainsoft.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Data.OleDb;
\r
33 using System.Data.Common;
\r
34 using System.Collections;
35 using System.Configuration;
\r
36 using System.Globalization;
\r
37 using System.Web.Profile;
\r
38 using System.Web.Configuration;
39 using System.Collections.Specialized;
\r
43 using Mainsoft.Web.Security;
\r
44 using System.Configuration.Provider;
\r
46 namespace Mainsoft.Web.Profile
48 public class DerbyProfileProvider : ProfileProvider
50 ConnectionStringSettings _connectionString;
\r
51 string _applicationName = string.Empty;
52 bool _schemaChecked = false;
\r
53 DerbyUnloadManager.DerbyShutDownPolicy _shutDownPolicy = DerbyUnloadManager.DerbyShutDownPolicy.Default;
55 public DerbyProfileProvider ()
59 public override string ApplicationName
\r
61 get { return _applicationName; }
\r
62 set { _applicationName = value; }
\r
65 DbConnection CreateConnection ()
\r
67 if (!_schemaChecked) {
\r
68 DerbyDBSchema.CheckSchema (_connectionString.ConnectionString);
\r
69 _schemaChecked = true;
\r
71 DerbyUnloadManager.RegisterUnloadHandler (_connectionString.ConnectionString, _shutDownPolicy);
\r
74 OleDbConnection connection = new OleDbConnection (_connectionString.ConnectionString);
\r
79 public override int DeleteInactiveProfiles (ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate)
81 using (DbConnection connection = CreateConnection ()) {
\r
82 return DerbyProfileHelper.Profile_DeleteInactiveProfiles (connection, ApplicationName, (int) authenticationOption, userInactiveSinceDate);
\r
86 public override int DeleteProfiles (ProfileInfoCollection profiles)
\r
88 if (profiles == null)
\r
89 throw new ArgumentNullException ("profiles");
\r
90 if (profiles.Count == 0)
\r
91 throw new ArgumentException ("profiles");
\r
93 string [] usernames = new string [profiles.Count];
\r
96 foreach (ProfileInfo pi in profiles) {
\r
97 if (pi.UserName == null)
\r
98 throw new ArgumentNullException ("element in profiles collection is null");
\r
100 if (pi.UserName.Length == 0 || pi.UserName.Length > 256 || pi.UserName.IndexOf (",") != -1)
\r
101 throw new ArgumentException ("element in profiles collection in illegal format");
\r
103 usernames [i++] = pi.UserName;
\r
106 return DeleteProfilesInternal (usernames);
\r
109 public override int DeleteProfiles (string [] usernames)
\r
111 if (usernames == null)
\r
112 throw new ArgumentNullException ("usernames");
\r
114 Hashtable users = new Hashtable ();
\r
115 foreach (string username in usernames) {
\r
116 if (username == null)
\r
117 throw new ArgumentNullException ("element in usernames array is null");
\r
119 if (username.Length == 0 || username.Length > 256 || username.IndexOf (",") != -1)
\r
120 throw new ArgumentException ("element in usernames array in illegal format");
\r
122 if (users.ContainsKey (username))
\r
123 throw new ArgumentException ("duplicate element in usernames array");
\r
125 users.Add (username, username);
\r
128 return DeleteProfilesInternal (usernames);
\r
131 private int DeleteProfilesInternal (string[] usernames)
133 using (DbConnection connection = CreateConnection ()) {
\r
134 return DerbyProfileHelper.Profile_DeleteProfiles (connection, ApplicationName, usernames);
\r
138 public override ProfileInfoCollection FindInactiveProfilesByUserName (ProfileAuthenticationOption authenticationOption,
\r
139 string usernameToMatch,
\r
140 DateTime userInactiveSinceDate,
\r
143 out int totalRecords)
\r
145 CheckParam ("usernameToMatch", usernameToMatch, 256);
\r
147 throw new ArgumentException ("pageIndex is less than zero");
\r
149 throw new ArgumentException ("pageIndex is less than one");
\r
150 if (pageIndex * pageSize + pageSize - 1 > Int32.MaxValue)
\r
151 throw new ArgumentException ("pageIndex and pageSize are too large");
\r
153 DbDataReader reader = null;
\r
154 using (DbConnection connection = CreateConnection ()) {
\r
155 totalRecords = DerbyProfileHelper.Profile_GetInactiveProfiles (connection, ApplicationName, (int) authenticationOption, pageIndex, pageSize, usernameToMatch, userInactiveSinceDate, out reader);
\r
158 return BuildProfileInfoCollection (reader, pageIndex, pageSize, out totalRecords);
\r
163 public override ProfileInfoCollection FindProfilesByUserName (ProfileAuthenticationOption authenticationOption,
\r
164 string usernameToMatch,
\r
167 out int totalRecords)
\r
169 CheckParam ("usernameToMatch", usernameToMatch, 256);
\r
171 throw new ArgumentException ("pageIndex is less than zero");
\r
173 throw new ArgumentException ("pageIndex is less than one");
\r
174 if (pageIndex * pageSize + pageSize - 1 > Int32.MaxValue)
\r
175 throw new ArgumentException ("pageIndex and pageSize are too large");
\r
177 DbDataReader reader = null;
\r
178 using (DbConnection connection = CreateConnection ()) {
\r
179 totalRecords = DerbyProfileHelper.Profile_GetProfiles (connection, ApplicationName, (int) authenticationOption, pageIndex, pageSize, usernameToMatch, out reader);
\r
182 return BuildProfileInfoCollection (reader, pageIndex, pageSize, out totalRecords);
\r
187 public override ProfileInfoCollection GetAllInactiveProfiles (ProfileAuthenticationOption authenticationOption,
188 DateTime userInactiveSinceDate,
191 out int totalRecords)
194 throw new ArgumentException ("pageIndex is less than zero");
\r
196 throw new ArgumentException ("pageIndex is less than one");
\r
197 if (pageIndex * pageSize + pageSize - 1 > Int32.MaxValue)
\r
198 throw new ArgumentException ("pageIndex and pageSize are too large");
\r
200 DbDataReader reader = null;
\r
201 using (DbConnection connection = CreateConnection ()) {
\r
202 totalRecords = DerbyProfileHelper.Profile_GetInactiveProfiles (
\r
203 connection, ApplicationName, (int) authenticationOption,
\r
204 pageIndex, pageSize, null, userInactiveSinceDate, out reader);
\r
207 return BuildProfileInfoCollection (reader, pageIndex, pageSize, out totalRecords);
\r
212 public override ProfileInfoCollection GetAllProfiles (ProfileAuthenticationOption authenticationOption,
215 out int totalRecords)
218 throw new ArgumentException ("pageIndex is less than zero");
\r
220 throw new ArgumentException ("pageIndex is less than one");
\r
221 if (pageIndex * pageSize + pageSize - 1 > Int32.MaxValue)
\r
222 throw new ArgumentException ("pageIndex and pageSize are too large");
\r
224 DbDataReader reader = null;
\r
225 using (DbConnection connection = CreateConnection ()) {
\r
226 totalRecords = DerbyProfileHelper.Profile_GetProfiles (
\r
227 connection, ApplicationName, (int) authenticationOption,
\r
228 pageIndex, pageSize, null, out reader);
\r
231 return BuildProfileInfoCollection (reader, pageIndex, pageSize, out totalRecords);
\r
236 public override int GetNumberOfInactiveProfiles (ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate)
238 using (DbConnection connection = CreateConnection ()) {
\r
239 return DerbyProfileHelper.Profile_GetNumberOfInactiveProfiles (
\r
240 connection, ApplicationName, (int) authenticationOption, userInactiveSinceDate);
\r
244 public override SettingsPropertyValueCollection GetPropertyValues (SettingsContext sc, SettingsPropertyCollection properties)
246 SettingsPropertyValueCollection settings = new SettingsPropertyValueCollection ();
\r
248 if (properties.Count == 0)
\r
251 foreach (SettingsProperty property in properties) {
\r
252 if (property.SerializeAs == SettingsSerializeAs.ProviderSpecific)
\r
253 if (property.PropertyType.IsPrimitive || property.PropertyType == typeof (String))
\r
254 property.SerializeAs = SettingsSerializeAs.String;
\r
256 property.SerializeAs = SettingsSerializeAs.Xml;
\r
258 settings.Add (new SettingsPropertyValue (property));
\r
261 string username = (string) sc ["UserName"];
\r
263 DbDataReader reader;
\r
264 using (DbConnection connection = CreateConnection ()) {
\r
265 DerbyProfileHelper.Profile_GetProperties (connection, ApplicationName, username, DateTime.UtcNow, out reader);
\r
266 if (reader != null) {
\r
268 if (reader.Read ()) {
\r
269 string allnames = reader.GetString (0);
\r
270 string allvalues = reader.GetString (1);
\r
271 int binaryLen = (int) reader.GetBytes (2, 0, null, 0, 0);
\r
272 byte [] binaryvalues = new byte [binaryLen];
\r
273 reader.GetBytes (2, 0, binaryvalues, 0, binaryLen);
\r
275 DecodeProfileData (allnames, allvalues, binaryvalues, settings);
\r
283 public override void SetPropertyValues (SettingsContext sc, SettingsPropertyValueCollection properties)
\r
285 string username = (string) sc ["UserName"];
\r
286 bool authenticated = (bool) sc ["IsAuthenticated"];
\r
288 string names = String.Empty;
\r
289 string values = String.Empty;
\r
290 byte [] buf = null;
\r
292 EncodeProfileData (ref names, ref values, ref buf, properties, authenticated);
\r
294 using (DbConnection connection = CreateConnection ()) {
\r
295 DerbyProfileHelper.Profile_SetProperties (
\r
296 connection, _applicationName, names, values,
\r
297 buf, username, authenticated, DateTime.UtcNow);
\r
301 public override void Initialize (string name, NameValueCollection config)
303 if (config == null)
\r
304 throw new ArgumentNullException ("config");
\r
306 if (string.IsNullOrEmpty (name))
\r
307 name = "DerbyProfileProvider";
\r
309 if (string.IsNullOrEmpty (config ["description"])) {
\r
310 config.Remove ("description");
\r
311 config.Add ("description", "Derby profile provider");
\r
313 base.Initialize (name, config);
\r
315 _applicationName = GetStringConfigValue (config, "applicationName", "/");
\r
317 ProfileSection profileSection = (ProfileSection) WebConfigurationManager.GetSection ("system.web/profile");
\r
318 string connectionStringName = config ["connectionStringName"];
\r
319 _connectionString = WebConfigurationManager.ConnectionStrings [connectionStringName];
\r
320 if (_connectionString == null)
\r
321 throw new ProviderException (String.Format ("The connection name '{0}' was not found in the applications configuration or the connection string is empty.", connectionStringName));
\r
323 string shutdown = config ["shutdown"];
\r
324 if (!String.IsNullOrEmpty (shutdown))
\r
325 _shutDownPolicy = (DerbyUnloadManager.DerbyShutDownPolicy) Enum.Parse (typeof (DerbyUnloadManager.DerbyShutDownPolicy), shutdown, true);
\r
328 private ProfileInfoCollection BuildProfileInfoCollection (DbDataReader reader, int pageIndex, int pageSize, out int totalRecords)
\r
332 int num_to_skip = pageIndex * pageSize;
\r
333 ProfileInfoCollection pic = new ProfileInfoCollection ();
\r
335 while (reader.Read ()) {
\r
336 if (num_read >= num_to_skip && num_added < pageSize) {
\r
337 ProfileInfo pi = ReadProfileInfo (reader);
\r
345 totalRecords = num_read;
\r
349 private ProfileInfo ReadProfileInfo (DbDataReader reader)
\r
351 string username = reader.GetString (0);
\r
352 bool anonymous = reader.GetInt32 (1) > 0;
\r
353 DateTime lastUpdate = reader.GetDateTime (2);
\r
354 DateTime lastActivity = reader.GetDateTime (3);
\r
355 int size = reader.GetInt32 (4);
\r
357 return new ProfileInfo (username, anonymous, lastActivity, lastUpdate, size);
\r
361 private void DecodeProfileData (string allnames, string values, byte [] buf, SettingsPropertyValueCollection properties)
\r
363 if (allnames == null || values == null || buf == null || properties == null)
\r
366 string [] names = allnames.Split (':');
\r
367 for (int i = 0; i < names.Length; i += 4) {
\r
368 string name = names [i];
\r
369 SettingsPropertyValue pp = properties [name];
\r
374 int pos = Int32.Parse (names [i + 2], CultureInfo.InvariantCulture);
\r
375 int len = Int32.Parse (names [i + 3], CultureInfo.InvariantCulture);
\r
377 if (len == -1 && !pp.Property.PropertyType.IsValueType) {
\r
378 pp.PropertyValue = null;
\r
379 pp.IsDirty = false;
\r
380 pp.Deserialized = true;
\r
382 else if (names [i + 1] == "S" && pos >= 0 && len > 0 && values.Length >= pos + len) {
\r
383 pp.SerializedValue = values.Substring (pos, len);
\r
385 else if (names [i + 1] == "B" && pos >= 0 && len > 0 && buf.Length >= pos + len) {
\r
386 byte [] buf2 = new byte [len];
\r
387 Buffer.BlockCopy (buf, pos, buf2, 0, len);
\r
388 pp.SerializedValue = buf2;
\r
393 private void EncodeProfileData (ref string allNames, ref string allValues, ref byte [] buf, SettingsPropertyValueCollection properties, bool userIsAuthenticated)
\r
395 StringBuilder names = new StringBuilder ();
\r
396 StringBuilder values = new StringBuilder ();
\r
397 MemoryStream stream = new MemoryStream ();
\r
400 foreach (SettingsPropertyValue pp in properties) {
\r
401 if (!userIsAuthenticated && !(bool) pp.Property.Attributes ["AllowAnonymous"])
\r
404 if (!pp.IsDirty && pp.UsingDefaultValue)
\r
407 int len = 0, pos = 0;
\r
408 string propValue = null;
\r
410 if (pp.Deserialized && pp.PropertyValue == null)
\r
413 object sVal = pp.SerializedValue;
\r
417 else if (sVal is string) {
\r
418 propValue = (string) sVal;
\r
419 len = propValue.Length;
\r
420 pos = values.Length;
\r
423 byte [] b2 = (byte []) sVal;
\r
424 pos = (int) stream.Position;
\r
425 stream.Write (b2, 0, b2.Length);
\r
426 stream.Position = pos + b2.Length;
\r
431 names.Append (pp.Name + ":" + ((propValue != null) ? "S" : "B") + ":" + pos.ToString (CultureInfo.InvariantCulture) + ":" + len.ToString (CultureInfo.InvariantCulture) + ":");
\r
433 if (propValue != null)
\r
434 values.Append (propValue);
\r
437 buf = stream.ToArray ();
\r
440 if (stream != null)
\r
444 allNames = names.ToString ();
\r
445 allValues = values.ToString ();
\r
448 string GetStringConfigValue (NameValueCollection config, string name, string def)
\r
451 string val = config [name];
\r
457 void CheckParam (string pName, string p, int length)
\r
460 throw new ArgumentNullException (pName);
\r
461 if (p.Length == 0 || p.Length > length || p.IndexOf (",") != -1)
\r
462 throw new ArgumentException (String.Format ("invalid format for {0}", pName));
\r