Mark tests as not working under TARGET_JVM
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / ObjectDataSourceView.cs
1 //
2 // System.Web.UI.WebControls.ObjectDataSourceView
3 //
4 // Authors:
5 //  Lluis Sanchez Gual (lluis@novell.com)
6 //
7 // (C) 2005 Novell, Inc. (http://www.novell.com)
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 #if NET_2_0
32 using System;
33 using System.Reflection;
34 using System.Collections;
35 using System.Collections.Specialized;
36 using System.ComponentModel;
37 using System.IO;
38 using System.Data;
39 using System.Web.Compilation;
40
41 namespace System.Web.UI.WebControls
42 {
43
44         public class ObjectDataSourceView : DataSourceView, IStateManager
45         {
46                 ObjectDataSource owner;
47                 HttpContext context;
48                 Type objectType;
49                 Type dataObjectType;
50
51                 bool convertNullToDBNull = false;
52                 bool enablePaging = false;
53                 string dataObjectTypeName = null;
54                 string filterExpression = null;
55                 string maximumRowsParameterName = null;
56                 string oldValuesParameterFormatString = null;
57                 string deleteMethod = null;
58                 string insertMethod = null;
59                 string selectCountMethod = null;
60                 string selectMethod = null;
61                 string sortParameterName = null;
62                 string startRowIndexParameterName = null;
63                 string typeName = null;
64                 string updateMethod = null;
65                 private static string privateBinPath = null;
66
67                 bool isTrackingViewState = false;
68                 ParameterCollection selectParameters;
69                 ParameterCollection updateParameters;
70                 ParameterCollection deleteParameters;
71                 ParameterCollection insertParameters;
72                 ParameterCollection filterParameters;
73                 
74                 private static readonly object DeletedEvent = new object();
75                 private static readonly object DeletingEvent = new object();
76                 private static readonly object FilteringEvent = new object();
77                 private static readonly object InsertedEvent = new object();
78                 private static readonly object InsertingEvent = new object();
79                 private static readonly object ObjectCreatedEvent = new object();
80                 private static readonly object ObjectCreatingEvent = new object();
81                 private static readonly object ObjectDisposingEvent = new object();
82                 //              private static readonly object ResolvingMethodEvent = new object();
83                 private static readonly object SelectedEvent = new object();
84                 private static readonly object SelectingEvent = new object();
85                 private static readonly object UpdatedEvent = new object();
86                 private static readonly object UpdatingEvent = new object();
87                 
88                 public ObjectDataSourceView (ObjectDataSource owner, string name, HttpContext context): base (owner, name)
89                 {
90                         this.owner = owner;
91                         this.context = context;
92                 }
93                 
94                 public event ObjectDataSourceStatusEventHandler Deleted {
95                         add { Events.AddHandler (DeletedEvent, value); }
96                         remove { Events.RemoveHandler (DeletedEvent, value); }
97                 }
98                 
99                 public event ObjectDataSourceMethodEventHandler Deleting {
100                         add { Events.AddHandler (DeletingEvent, value); }
101                         remove { Events.RemoveHandler (DeletingEvent, value); }
102                 }
103                 
104                 public event ObjectDataSourceFilteringEventHandler Filtering {
105                         add { Events.AddHandler (FilteringEvent, value); }
106                         remove { Events.RemoveHandler (FilteringEvent, value); }
107                 }
108                 
109                 public event ObjectDataSourceStatusEventHandler Inserted {
110                         add { Events.AddHandler (InsertedEvent, value); }
111                         remove { Events.RemoveHandler (InsertedEvent, value); }
112                 }
113                 
114                 public event ObjectDataSourceMethodEventHandler Inserting {
115                         add { Events.AddHandler (InsertingEvent, value); }
116                         remove { Events.RemoveHandler (InsertingEvent, value); }
117                 }
118                 
119                 public event ObjectDataSourceObjectEventHandler ObjectCreated {
120                         add { Events.AddHandler (ObjectCreatedEvent, value); }
121                         remove { Events.RemoveHandler (ObjectCreatedEvent, value); }
122                 }
123                 
124                 public event ObjectDataSourceObjectEventHandler ObjectCreating {
125                         add { Events.AddHandler (ObjectCreatingEvent, value); }
126                         remove { Events.RemoveHandler (ObjectCreatingEvent, value); }
127                 }
128                 
129                 public event ObjectDataSourceDisposingEventHandler ObjectDisposing {
130                         add { Events.AddHandler (ObjectDisposingEvent, value); }
131                         remove { Events.RemoveHandler (ObjectDisposingEvent, value); }
132                 }
133                 
134                 /*              public event ObjectDataSourceResolvingMethodEventHandler ResolvingMethod {
135                                 add { Events.AddHandler (ResolvingMethodEvent, value); }
136                                 remove { Events.RemoveHandler (ResolvingMethodEvent, value); }
137                                 }
138                 */
139                 public event ObjectDataSourceStatusEventHandler Selected {
140                         add { Events.AddHandler (SelectedEvent, value); }
141                         remove { Events.RemoveHandler (SelectedEvent, value); }
142                 }
143                 
144                 public event ObjectDataSourceSelectingEventHandler Selecting {
145                         add { Events.AddHandler (SelectingEvent, value); }
146                         remove { Events.RemoveHandler (SelectingEvent, value); }
147                 }
148                 
149                 public event ObjectDataSourceStatusEventHandler Updated {
150                         add { Events.AddHandler (UpdatedEvent, value); }
151                         remove { Events.RemoveHandler (UpdatedEvent, value); }
152                 }
153                 
154                 public event ObjectDataSourceMethodEventHandler Updating {
155                         add { Events.AddHandler (UpdatingEvent, value); }
156                         remove { Events.RemoveHandler (UpdatingEvent, value); }
157                 }
158                 
159                 protected virtual void OnDeleted (ObjectDataSourceStatusEventArgs e)
160                 {
161                         if (Events != null) {
162                                 ObjectDataSourceStatusEventHandler eh = (ObjectDataSourceStatusEventHandler) Events [DeletedEvent];
163                                 if (eh != null) eh (this, e);
164                         }
165                 }
166                 
167                 protected virtual void OnDeleting (ObjectDataSourceMethodEventArgs e)
168                 {
169                         if (Events != null) {
170                                 ObjectDataSourceMethodEventHandler eh = (ObjectDataSourceMethodEventHandler) Events [DeletingEvent];
171                                 if (eh != null) eh (this, e);
172                         }
173                 }
174                 
175                 protected virtual void OnFiltering (ObjectDataSourceFilteringEventArgs e)
176                 {
177                         if (Events != null) {
178                                 ObjectDataSourceFilteringEventHandler eh = (ObjectDataSourceFilteringEventHandler) Events [FilteringEvent];
179                                 if (eh != null) eh (this, e);
180                         }
181                 }
182                 
183                 protected virtual void OnInserted (ObjectDataSourceStatusEventArgs e)
184                 {
185                         if (Events != null) {
186                                 ObjectDataSourceStatusEventHandler eh = (ObjectDataSourceStatusEventHandler) Events [InsertedEvent];
187                                 if (eh != null) eh (this, e);
188                         }
189                 }
190                 
191                 protected virtual void OnInserting (ObjectDataSourceMethodEventArgs e)
192                 {
193                         if (Events != null) {
194                                 ObjectDataSourceMethodEventHandler eh = (ObjectDataSourceMethodEventHandler) Events [InsertingEvent];
195                                 if (eh != null) eh (this, e);
196                         }
197                 }
198                 
199                 protected virtual void OnObjectCreated (ObjectDataSourceEventArgs e)
200                 {
201                         if (Events != null) {
202                                 ObjectDataSourceObjectEventHandler eh = (ObjectDataSourceObjectEventHandler) Events [ObjectCreatedEvent];
203                                 if (eh != null) eh (this, e);
204                         }
205                 }
206                 
207                 protected virtual void OnObjectCreating (ObjectDataSourceEventArgs e)
208                 {
209                         if (Events != null) {
210                                 ObjectDataSourceObjectEventHandler eh = (ObjectDataSourceObjectEventHandler) Events [ObjectCreatingEvent];
211                                 if (eh != null) eh (this, e);
212                         }
213                 }
214                 
215                 protected virtual void OnObjectDisposing (ObjectDataSourceDisposingEventArgs e)
216                 {
217                         if (Events != null) {
218                                 ObjectDataSourceDisposingEventHandler eh = (ObjectDataSourceDisposingEventHandler) Events [ObjectDisposingEvent];
219                                 if (eh != null) eh (this, e);
220                         }
221                 }
222                 
223                 /*              protected virtual void OnResolvingMethod (ObjectDataSourceResolvingMethodEventArgs e)
224                                 {
225                                 if (Events != null) {
226                                 ObjectDataSourceResolvingMethodEventHandler eh = (ObjectDataSourceResolvingMethodEventHandler) Events [ResolvingMethodEvent];
227                                 if (eh != null) eh (this, e);
228                                 }
229                                 }
230                 */
231                 
232                 protected virtual void OnSelected (ObjectDataSourceStatusEventArgs e)
233                 {
234                         if (Events != null) {
235                                 ObjectDataSourceStatusEventHandler eh = (ObjectDataSourceStatusEventHandler) Events [SelectedEvent];
236                                 if (eh != null) eh (this, e);
237                         }
238                 }
239                 
240                 protected virtual void OnSelecting (ObjectDataSourceSelectingEventArgs e)
241                 {
242                         if (Events != null) {
243                                 ObjectDataSourceSelectingEventHandler eh = (ObjectDataSourceSelectingEventHandler) Events [SelectingEvent];
244                                 if (eh != null) eh (this, e);
245                         }
246                 }
247                 
248                 protected virtual void OnUpdated (ObjectDataSourceStatusEventArgs e)
249                 {
250                         if (Events != null) {
251                                 ObjectDataSourceStatusEventHandler eh = (ObjectDataSourceStatusEventHandler) Events [UpdatedEvent];
252                                 if (eh != null) eh (this, e);
253                         }
254                 }
255                 
256                 protected virtual void OnUpdating (ObjectDataSourceMethodEventArgs e)
257                 {
258                         if (Events != null) {
259                                 ObjectDataSourceMethodEventHandler eh = (ObjectDataSourceMethodEventHandler) Events [UpdatingEvent];
260                                 if (eh != null) eh (this, e);
261                         }
262                 }
263                 
264                 public override bool CanDelete {
265                         get { return DeleteMethod.Length > 0; }
266                 }
267                 
268                 public override bool CanInsert {
269                         get { return InsertMethod.Length > 0; }
270                 }
271                 
272                 public override bool CanPage {
273                         get { return EnablePaging; }
274                 }
275                 
276                 public override bool CanRetrieveTotalRowCount {
277                         get {
278                                 if( SelectCountMethod.Length > 0)
279                                         return true;
280
281                                 return !EnablePaging;
282                         }
283                 }
284                 
285                 public override bool CanSort {
286                         get { return true; }
287                 }
288                 
289                 public override bool CanUpdate {
290                         get { return UpdateMethod.Length > 0; }
291                 }
292
293                 // LAME SPEC: MSDN says value should be stored in ViewState but tests show otherwise.
294                 private ConflictOptions conflictDetection = ConflictOptions.OverwriteChanges;
295                 public ConflictOptions ConflictDetection {
296                         get { return conflictDetection; }
297                         set { conflictDetection = value; }
298                 }
299
300                 public bool ConvertNullToDBNull {
301                         get { return convertNullToDBNull; }
302                         set { convertNullToDBNull = value; }
303                 }
304
305                 public string DataObjectTypeName {
306                         get {
307                                 return dataObjectTypeName != null ? dataObjectTypeName : string.Empty;
308                         }
309                         set {
310                                 dataObjectTypeName = value;
311                         }
312                 }
313
314                 public string DeleteMethod {
315                         get {
316                                 return deleteMethod != null ? deleteMethod : string.Empty;
317                         }
318                         set {
319                                 deleteMethod = value;
320                         }
321                 }
322                 
323                 public ParameterCollection DeleteParameters {
324                         get {
325                                 if (deleteParameters == null) {
326                                         deleteParameters = new ParameterCollection ();
327                                         deleteParameters.ParametersChanged += new EventHandler (OnParametersChanged); 
328                                 }
329                                 return deleteParameters;
330                         }
331                 }
332
333                 public bool EnablePaging {
334                         get {
335                                 return enablePaging;
336                         }
337                         set {
338                                 enablePaging = value;
339                         }
340                 }
341
342                 public string FilterExpression {
343                         get {
344                                 return filterExpression != null ? filterExpression : string.Empty;
345                         }
346                         set {
347                                 filterExpression = value;
348                         }
349                 }
350
351                 public ParameterCollection FilterParameters {
352                         get {
353                                 if (filterParameters == null) {
354                                         filterParameters = new ParameterCollection ();
355                                         filterParameters.ParametersChanged += new EventHandler (OnParametersChanged); 
356                                         if (IsTrackingViewState)
357                                                 ((IStateManager)filterParameters).TrackViewState ();
358                                 }
359                                 return filterParameters;
360                         }
361                 }
362
363                 public string InsertMethod {
364                         get {
365                                 return insertMethod != null ? insertMethod : string.Empty;
366                         }
367                         set {
368                                 insertMethod = value;
369                         }
370                 }
371
372                 public ParameterCollection InsertParameters {
373                         get {
374                                 if (insertParameters == null) {
375                                         insertParameters = new ParameterCollection ();
376                                         insertParameters.ParametersChanged += new EventHandler (OnParametersChanged); 
377                                 }
378                                 return insertParameters;
379                         }
380                 }
381
382                 public string MaximumRowsParameterName {
383                         get {
384                                 return maximumRowsParameterName != null ? maximumRowsParameterName : "maximumRows";
385                         }
386                         set {
387                                 maximumRowsParameterName = value;
388                         }
389                 }
390
391                 public string OldValuesParameterFormatString {
392                         get {
393                                 return oldValuesParameterFormatString != null ? oldValuesParameterFormatString : "{0}";
394                         }
395                         set {
396                                 oldValuesParameterFormatString = value;
397                         }
398                 }
399
400                 public string SelectCountMethod {
401                         get {
402                                 return selectCountMethod != null ? selectCountMethod : string.Empty;
403                         }
404                         set {
405                                 selectCountMethod = value;
406                         }
407                 }
408
409                 public string SelectMethod {
410                         get {
411                                 return selectMethod != null ? selectMethod : string.Empty;
412                         }
413                         set {
414                                 selectMethod = value;
415                         }
416                 }
417
418                 public ParameterCollection SelectParameters {
419                         get {
420                                 if (selectParameters == null) {
421                                         selectParameters = new ParameterCollection ();
422                                         selectParameters.ParametersChanged += new EventHandler (OnParametersChanged); 
423                                         if (IsTrackingViewState)
424                                                 ((IStateManager)selectParameters).TrackViewState ();
425                                 }
426                                 return selectParameters;
427                         }
428                 }
429
430                 public string SortParameterName {
431                         get {
432                                 return sortParameterName != null ? sortParameterName : string.Empty;
433                         }
434                         set {
435                                 sortParameterName = value;
436                         }
437                 }
438
439                 public string StartRowIndexParameterName {
440                         get {
441                                 return startRowIndexParameterName != null ? startRowIndexParameterName : "startRowIndex";
442                         }
443                         set {
444                                 startRowIndexParameterName = value;
445                         }
446                 }
447
448                 public string TypeName {
449                         get {
450                                 return typeName != null ? typeName : string.Empty;
451                         }
452                         set {
453                                 typeName = value;
454                                 objectType = null;
455                         }
456                 }
457
458                 public string UpdateMethod {
459                         get {
460                                 return updateMethod != null ? updateMethod : string.Empty;
461                         }
462                         set {
463                                 updateMethod = value;
464                         }
465                 }
466
467                 public ParameterCollection UpdateParameters {
468                         get {
469                                 if (updateParameters == null) {
470                                         updateParameters = new ParameterCollection ();
471                                         updateParameters.ParametersChanged += new EventHandler (OnParametersChanged); 
472                                 }
473                                 return updateParameters;
474                         }
475                 }
476
477                 private static string PrivateBinPath {
478                         get {
479                                 if (privateBinPath != null)
480                                         return privateBinPath;
481
482                                 AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
483                                 privateBinPath = Path.Combine (setup.ApplicationBase, setup.PrivateBinPath);
484
485                                 return privateBinPath;
486                         }
487                 }
488
489                 private Type LoadType (string typeName)
490                 {
491                         Type type = Type.GetType (typeName);
492                         if (type != null)
493                                 return type;
494
495                         IList tla;
496                         if ((tla = BuildManager.TopLevelAssemblies) != null) {
497                                 foreach (Assembly asm in tla) {
498                                         if (asm == null)
499                                                 continue;
500                                         type = asm.GetType (typeName);
501                                         if (type != null)
502                                                 return type;
503                                 }
504                         }
505
506                         if (!Directory.Exists (PrivateBinPath))
507                                 return null;
508
509                         string [] binDlls = Directory.GetFiles (PrivateBinPath, "*.dll");
510                         foreach (string s in binDlls) {
511                                 Assembly binA = Assembly.LoadFrom (s);
512                                 type = binA.GetType (typeName);
513                                 if (type == null)
514                                         continue;
515
516                                 return type;
517                         }
518
519                         return null;
520                 }
521     
522                 Type ObjectType {
523                         get {
524                                 if (objectType == null) {
525                                         objectType = LoadType (TypeName);
526                                         if (objectType == null)
527                                                 throw new InvalidOperationException ("Type not found: " + TypeName);
528                                 }
529                                 return objectType;
530                         }
531                 }
532                 
533                 Type DataObjectType {
534                         get {
535                                 if (dataObjectType == null) {
536                                         dataObjectType = LoadType (DataObjectTypeName);
537                                         if (objectType == null)
538                                                 throw new InvalidOperationException ("Type not found: " + DataObjectTypeName);
539                                 }
540                                 return dataObjectType;
541                         }
542                 }
543                 
544                 public IEnumerable Select (DataSourceSelectArguments arguments)
545                 {
546                         return ExecuteSelect (arguments);
547                 }
548                 
549                 public int Update (IDictionary keys, IDictionary values, IDictionary oldValues)
550                 {
551                         return ExecuteUpdate (keys, values, oldValues);
552                 }
553                 
554                 public int Delete (IDictionary keys, IDictionary oldValues)
555                 {
556                         return ExecuteDelete (keys, oldValues);
557                 }
558                 
559                 public int Insert (IDictionary values)
560                 {
561                         return ExecuteInsert (values);
562                 }
563                 
564                 protected override int ExecuteInsert (IDictionary values)
565                 {
566                         if (!CanInsert)
567                                 throw new NotSupportedException ("Insert operation not supported.");
568                                 
569                         IOrderedDictionary paramValues;
570                         MethodInfo method;
571                         
572                         if (DataObjectTypeName.Length == 0) {
573                                 paramValues = MergeParameterValues (InsertParameters, values, null, true);
574                                 method = GetObjectMethod (InsertMethod, paramValues, DataObjectMethodType.Insert);
575                         } else {
576                                 method = ResolveDataObjectMethod (InsertMethod, values, null, out paramValues);
577                         }
578                         
579                         ObjectDataSourceMethodEventArgs args = new ObjectDataSourceMethodEventArgs (paramValues);
580                         OnInserting (args);
581                         if (args.Cancel)
582                                 return -1;
583                         
584                         ObjectDataSourceStatusEventArgs rargs = InvokeMethod (method, paramValues);
585                         OnInserted (rargs);
586                         
587                         if (rargs.Exception != null && !rargs.ExceptionHandled)
588                                 throw rargs.Exception;
589
590                         if (owner.EnableCaching)
591                                 owner.Cache.Expire ();
592                         
593                         OnDataSourceViewChanged (EventArgs.Empty);
594
595                         return -1;
596                 }
597
598                 protected override int ExecuteDelete (IDictionary keys, IDictionary oldValues)
599                 {
600                         if (!CanDelete)
601                                 throw new NotSupportedException ("Delete operation not supported.");
602                                 
603                         if (ConflictDetection == ConflictOptions.CompareAllValues && (oldValues == null || oldValues.Count == 0))
604                                 throw new InvalidOperationException ("ConflictDetection is set to CompareAllValues and oldValues collection is null or empty.");
605
606                         IDictionary oldDataValues;
607                         oldDataValues = BuildOldValuesList (keys, oldValues, false);
608                                         
609                         IOrderedDictionary paramValues;
610                         MethodInfo method;
611                         
612                         if (DataObjectTypeName.Length == 0) {
613                                 paramValues = MergeParameterValues (DeleteParameters, null, oldDataValues, true);
614                                 method = GetObjectMethod (DeleteMethod, paramValues, DataObjectMethodType.Delete);
615                         } else {
616                                 method = ResolveDataObjectMethod (DeleteMethod, oldDataValues, null, out paramValues);
617                         }
618                         
619                         ObjectDataSourceMethodEventArgs args = new ObjectDataSourceMethodEventArgs (paramValues);
620                         OnDeleting (args);
621                         if (args.Cancel)
622                                 return -1;
623                         
624                         ObjectDataSourceStatusEventArgs rargs = InvokeMethod (method, paramValues);
625                         
626                         OnDeleted (rargs);
627                         
628                         if (rargs.Exception != null && !rargs.ExceptionHandled)
629                                 throw rargs.Exception;
630
631                         if (owner.EnableCaching)
632                                 owner.Cache.Expire ();
633                         
634                         OnDataSourceViewChanged (EventArgs.Empty);
635
636                         return -1;
637                 }
638
639                 protected override int ExecuteUpdate (IDictionary keys, IDictionary values, IDictionary oldValues)
640                 {
641                         IOrderedDictionary paramValues;
642                         MethodInfo method;
643
644                         IDictionary oldDataValues;
645                         oldDataValues = BuildOldValuesList (keys, oldValues, true);
646
647                         if (DataObjectTypeName.Length == 0)
648                         {
649                                 IDictionary dataValues;
650                                 dataValues = values;
651                                 paramValues = MergeParameterValues (UpdateParameters, dataValues, oldDataValues, false);
652                                 method = GetObjectMethod (UpdateMethod, paramValues, DataObjectMethodType.Update);
653                         }
654                         else
655                         {
656                                 if (ConflictDetection != ConflictOptions.CompareAllValues) {
657                                         oldDataValues = null;
658                                 }
659                                 IDictionary dataValues = new Hashtable ();
660                                 if (keys != null) {
661                                         foreach (DictionaryEntry de in keys)
662                                                 dataValues [de.Key] = de.Value;
663                                 }
664                                 if (values != null) {
665                                         foreach (DictionaryEntry de in values)
666                                                 dataValues [de.Key] = de.Value;
667                                 }
668
669                                 method = ResolveDataObjectMethod (UpdateMethod, dataValues, oldDataValues, out paramValues);
670                         }                       
671
672                         ObjectDataSourceMethodEventArgs args = new ObjectDataSourceMethodEventArgs (paramValues);
673                         OnUpdating (args);
674                         if (args.Cancel)
675                                 return -1;
676                         
677                         ObjectDataSourceStatusEventArgs rargs = InvokeMethod (method, paramValues);
678                         OnUpdated (rargs);
679                         
680                         if (rargs.Exception != null && !rargs.ExceptionHandled)
681                                 throw rargs.Exception;
682
683                         if (owner.EnableCaching)
684                                 owner.Cache.Expire ();
685                         
686                         OnDataSourceViewChanged (EventArgs.Empty);
687
688                         return -1;
689                 }
690
691                 private IDictionary BuildOldValuesList (IDictionary keys, IDictionary oldValues, bool keysWin) 
692                 {
693                         IDictionary oldDataValues;
694                         if (ConflictDetection == ConflictOptions.CompareAllValues) {
695                                 oldDataValues = new Hashtable ();
696                                 if (keys != null && !keysWin) {
697                                         foreach (DictionaryEntry de in keys)
698                                                 oldDataValues [de.Key] = de.Value;
699                                 }
700                                 if (oldValues != null) {
701                                         foreach (DictionaryEntry de in oldValues)
702                                                 oldDataValues [de.Key] = de.Value;
703                                 }
704                                 if (keys != null && keysWin) {
705                                         foreach (DictionaryEntry de in keys)
706                                                 oldDataValues [de.Key] = de.Value;
707                                 }
708                         }
709                         else {
710                                 oldDataValues = keys;
711                         }
712
713                         return oldDataValues;
714                 }
715
716                 protected internal override IEnumerable ExecuteSelect (DataSourceSelectArguments arguments)
717                 {
718                         arguments.RaiseUnsupportedCapabilitiesError (this);
719
720                         IOrderedDictionary paramValues = MergeParameterValues (SelectParameters, null, null, true);
721                         ObjectDataSourceSelectingEventArgs args = new ObjectDataSourceSelectingEventArgs (paramValues, arguments, false);
722
723                         object result = null;
724
725                         if (owner.EnableCaching)
726                                 result = owner.Cache.GetCachedObject (SelectMethod, SelectParameters);
727
728                         if (result == null) {
729                                 OnSelecting (args);
730                                 if (args.Cancel)
731                                         return new ArrayList ();
732
733                                 if (CanRetrieveTotalRowCount && arguments.RetrieveTotalRowCount)
734                                         arguments.TotalRowCount = QueryTotalRowCount (paramValues, arguments);
735
736                                 if (CanPage) {
737                                         if (StartRowIndexParameterName.Length == 0)
738                                                 throw new InvalidOperationException ("Paging is enabled, but the StartRowIndexParameterName property is not set.");
739                                         if (MaximumRowsParameterName.Length == 0)
740                                                 throw new InvalidOperationException ("Paging is enabled, but the MaximumRowsParameterName property is not set.");
741                                         paramValues [StartRowIndexParameterName] = arguments.StartRowIndex;
742                                         paramValues [MaximumRowsParameterName] = arguments.MaximumRows;
743                                 }
744
745                                 if (SortParameterName.Length > 0)
746                                         paramValues [SortParameterName] = arguments.SortExpression;
747
748                                 result = InvokeSelect (SelectMethod, paramValues);
749
750                                 if (owner.EnableCaching)
751                                         owner.Cache.SetCachedObject (SelectMethod, SelectParameters, result);
752                         }
753
754                         if (FilterExpression.Length > 0 && !(result is DataGrid || result is DataView || result is DataTable))
755                                 throw new NotSupportedException ("The FilterExpression property was set and the Select method does not return a DataSet, DataTable, or DataView.");
756
757                         if (owner.EnableCaching && result is IDataReader)
758                                 throw new NotSupportedException ("Data source does not support caching objects that implement IDataReader");
759                         
760                         if (result is DataSet) {
761                                 DataSet dset = (DataSet) result;
762                                 if (dset.Tables.Count == 0)
763                                         throw new InvalidOperationException ("The select method returnet a DataSet which doesn't contain any table.");
764                                 result = dset.Tables [0];
765                         }
766                         
767                         if (result is DataTable) {
768                                 DataView dview = new DataView ((DataTable)result);
769                                 if (arguments.SortExpression != null && arguments.SortExpression.Length > 0) {
770                                         dview.Sort = arguments.SortExpression;
771                                 }
772                                 if (FilterExpression.Length > 0) {
773                                         IOrderedDictionary fparams = FilterParameters.GetValues (context, owner);
774                                         ObjectDataSourceFilteringEventArgs fargs = new ObjectDataSourceFilteringEventArgs (fparams);
775                                         OnFiltering (fargs);
776                                         if (!fargs.Cancel) {
777                                                 object[] formatValues = new object [fparams.Count];
778                                                 for (int n=0; n<formatValues.Length; n++) {
779                                                         formatValues [n] = fparams [n];
780                                                         if (formatValues [n] == null) return dview;
781                                                 }
782                                                 dview.RowFilter = string.Format (FilterExpression, formatValues);
783                                         }
784                                 }
785                                 return dview;
786                         }
787                         
788                         if (result is IEnumerable)
789                                 return (IEnumerable) result;
790                         else
791                                 return new object[] { result };
792                 }
793                 
794                 int QueryTotalRowCount (IOrderedDictionary mergedParameters, DataSourceSelectArguments arguments)
795                 {
796                         ObjectDataSourceSelectingEventArgs countArgs = new ObjectDataSourceSelectingEventArgs (mergedParameters, arguments, true);
797                         OnSelecting (countArgs);
798                         if (countArgs.Cancel)
799                                 return 0;
800                         
801                         object count = InvokeSelect (SelectCountMethod, mergedParameters);
802                         return (int) Convert.ChangeType (count, typeof(int));
803                 }
804                 
805                 object InvokeSelect (string methodName, IOrderedDictionary paramValues)
806                 {
807                         MethodInfo method = GetObjectMethod (methodName, paramValues, DataObjectMethodType.Select);
808                         ObjectDataSourceStatusEventArgs rargs = InvokeMethod (method, paramValues);
809                         OnSelected (rargs);
810                         
811                         if (rargs.Exception != null && !rargs.ExceptionHandled)
812                                 throw rargs.Exception;
813
814                         return rargs.ReturnValue;
815                 }
816                 
817                 ObjectDataSourceStatusEventArgs InvokeMethod (MethodInfo method, IOrderedDictionary paramValues)
818                 {
819                         object instance = null;
820
821                         if (!method.IsStatic)
822                                 instance = CreateObjectInstance ();
823
824                         ParameterInfo[] pars = method.GetParameters ();
825                         
826                         ArrayList outParamInfos;
827                         object[] methodArgs = GetParameterArray (pars, paramValues, out outParamInfos); 
828                         
829                         if (methodArgs == null)
830                                 throw CreateMethodException (method.Name, paramValues);
831                                         
832                         object result = null;
833                         Hashtable outParams = null;
834                         
835                         try {
836                                 result = method.Invoke (instance, methodArgs);
837                                 if (outParamInfos != null) {
838                                         outParams = new Hashtable ();
839                                         foreach (ParameterInfo op in outParamInfos)
840                                                 outParams [op.Name] = methodArgs [op.Position];
841                                 }
842                                 return new ObjectDataSourceStatusEventArgs (result, outParams, null);
843                         }
844                         catch (Exception ex) {
845                                 return new ObjectDataSourceStatusEventArgs (result, outParams, ex);
846                         }
847                         finally {
848                                 if (instance != null)
849                                         DisposeObjectInstance (instance);
850                         }
851                 }
852                 
853                 MethodInfo GetObjectMethod (string methodName, IOrderedDictionary parameters, DataObjectMethodType methodType)
854                 {
855                         MemberInfo[] methods = ObjectType.GetMember (methodName, MemberTypes.Method, BindingFlags.Instance | 
856                                                                                  BindingFlags.Static | 
857                                                                                  BindingFlags.Public | 
858                                                                                  BindingFlags.IgnoreCase |
859                                                                                  BindingFlags.FlattenHierarchy);
860                         if (methods.Length > 1) {
861                                 // MSDN: The ObjectDataSource resolves method overloads by method name and number
862                                 // of parameters; the names and types of the parameters are not considered.
863                                 // LAMESPEC: the tests show otherwise
864                                 DataObjectMethodAttribute methodAttribute = null;
865                                 MethodInfo methodInfo = null;
866                                 bool hasConflict = false;
867                                 foreach (MethodInfo me in methods) { // we look for methods only
868                                         ParameterInfo [] pinfos = me.GetParameters ();
869                                         if (pinfos.Length == parameters.Count) {
870                                                 object [] attrs = me.GetCustomAttributes (typeof (DataObjectMethodAttribute), true);
871                                                 DataObjectMethodAttribute domAttr = (attrs != null && attrs.Length > 0) ? (DataObjectMethodAttribute) attrs [0] : null;
872                                                 if (domAttr != null && domAttr.MethodType != methodType)
873                                                         continue;
874
875                                                 bool paramsMatch = true;
876                                                 foreach (ParameterInfo pinfo in pinfos) {
877                                                         if (!parameters.Contains (pinfo.Name)) {
878                                                                 paramsMatch = false;
879                                                                 break;
880                                                         }
881                                                 }
882
883                                                 if (!paramsMatch)
884                                                         continue;
885
886                                                 if (domAttr != null) {
887                                                         if (methodAttribute != null) {
888                                                                 if (methodAttribute.IsDefault) {
889                                                                         if (domAttr.IsDefault) {
890                                                                                 methodInfo = null;
891                                                                                 break; //fail due to a conflict
892                                                                         }
893                                                                         else
894                                                                                 continue; //existing matches better
895                                                                 }
896                                                                 else {
897                                                                         methodInfo = null; //we override
898                                                                         hasConflict = !domAttr.IsDefault;
899                                                                 }
900                                                         }
901                                                         else
902                                                                 methodInfo = null; //we override
903                                                 }
904
905                                                 if (methodInfo == null) {
906                                                         methodAttribute = domAttr;
907                                                         methodInfo = me;
908                                                         continue;
909                                                 }
910
911                                                 hasConflict = true;
912                                         }
913                                 }
914
915                                 if (!hasConflict && methodInfo != null)
916                                         return methodInfo;
917                         }
918                         else if (methods.Length == 1) {
919                                 MethodInfo me = methods[0] as MethodInfo;
920                                 if (me != null && me.GetParameters().Length == parameters.Count)
921                                         return me;
922                         }
923                         
924                         throw CreateMethodException (methodName, parameters);
925                 }
926                 
927                 MethodInfo ResolveDataObjectMethod (string methodName, IDictionary values, IDictionary oldValues, out IOrderedDictionary paramValues)
928                 {
929                         MethodInfo method;
930                         if (oldValues != null)
931                                 method = ObjectType.GetMethod (methodName, new Type[] { DataObjectType, DataObjectType });
932                         else
933                                 method = ObjectType.GetMethod (methodName, new Type[] { DataObjectType });
934                         
935                         if (method == null)
936                                 throw new InvalidOperationException ("ObjectDataSource " + owner.ID + " could not find a method named '" + methodName + "' with parameters of type '" + DataObjectType + "' in '" + ObjectType + "'.");
937
938                         paramValues = new OrderedDictionary (StringComparer.InvariantCultureIgnoreCase);
939                         ParameterInfo[] ps = method.GetParameters ();
940                         
941                         if (oldValues != null) {
942                                 if (FormatOldParameter (ps[0].Name) == ps[1].Name) {
943                                         paramValues [ps[0].Name] = CreateDataObject (values);
944                                         paramValues [ps[1].Name] = CreateDataObject (oldValues);
945                                 } else if (FormatOldParameter (ps[1].Name) == ps[0].Name) {
946                                         paramValues [ps[0].Name] = CreateDataObject (oldValues);
947                                         paramValues [ps[1].Name] = CreateDataObject (values);
948                                 } else
949                                         throw new InvalidOperationException ("Method '" + methodName + "' does not have any parameter that fits the value of OldValuesParameterFormatString.");  
950                         } else {
951                                 paramValues [ps[0].Name] = CreateDataObject (values);
952                         }
953                         return method;
954                 }
955                 
956                 Exception CreateMethodException (string methodName, IOrderedDictionary parameters)
957                 {
958                         string s = "";
959                         foreach (string p in parameters.Keys) {
960                                 s += p + ", ";
961                         }
962                         return new InvalidOperationException ("ObjectDataSource " + owner.ID + " could not find a method named '" + methodName + "' with parameters " + s + "in type '" + ObjectType + "'.");
963                 }
964                 
965                 object CreateDataObject (IDictionary values)
966                 {
967                         object ob = Activator.CreateInstance (DataObjectType);
968                         foreach (DictionaryEntry de in values) {
969                                 PropertyInfo p = DataObjectType.GetProperty ((string)de.Key);
970                                 if (p == null) throw new InvalidOperationException ("Property " + de.Key + " not found in type '" +DataObjectType + "'.");
971                                 p.SetValue (ob, ConvertParameter (p.PropertyType, de.Value), null);
972                         }
973                         return ob;
974                 }
975                 
976                 object CreateObjectInstance ()
977                 {
978                         ObjectDataSourceEventArgs args = new ObjectDataSourceEventArgs (null);
979                         OnObjectCreating (args);
980                         
981                         if (args.ObjectInstance != null)
982                                 return args.ObjectInstance;
983                                 
984                         object ob = Activator.CreateInstance (ObjectType);
985                         
986                         args.ObjectInstance = ob;
987                         OnObjectCreated (args);
988                         
989                         return args.ObjectInstance;
990                 }
991                 
992                 void DisposeObjectInstance (object obj)
993                 {
994                         ObjectDataSourceDisposingEventArgs args = new ObjectDataSourceDisposingEventArgs (obj);
995                         OnObjectDisposing (args);
996                         
997                         if (!args.Cancel) {
998                                 IDisposable disp = obj as IDisposable;
999                                 if (disp != null) disp.Dispose ();
1000                         }
1001                 }
1002
1003                 object FindValueByName (string name, IDictionary values, bool format)
1004                 {
1005                         if (values == null)
1006                                 return null;
1007
1008                         foreach (DictionaryEntry de in values) {
1009                                 string valueName = format == true ? FormatOldParameter (de.Key.ToString ()) : de.Key.ToString ();
1010                                 if (name == valueName)
1011                                         return values [de.Key];
1012                         }
1013                         foreach (DictionaryEntry de in values) {
1014                                 string valueName = format == true ? FormatOldParameter (de.Key.ToString ()) : de.Key.ToString ();
1015                                 valueName = valueName.ToLower ();
1016                                 if (name.ToLower () == valueName)
1017                                         return values [de.Key];
1018                         }
1019                         return null;
1020                 }
1021
1022                 /// <summary>
1023                 /// Merge the current data item fields with view parameter default values
1024                 /// </summary>
1025                 /// <param name="viewParams">default parameters</param>
1026                 /// <param name="values">new parameters for update and insert</param>
1027                 /// <param name="oldValues">old parameters for update and delete</param>
1028                 /// <param name="allwaysAddNewValues">true for insert, as current item is
1029                 /// irrelevant for insert</param>
1030                 /// <returns>merged values</returns>
1031                 IOrderedDictionary MergeParameterValues (ParameterCollection viewParams, IDictionary values, IDictionary oldValues, bool allwaysAddNewValues)
1032                 {
1033                         OrderedDictionary mergedValues = new OrderedDictionary (StringComparer.InvariantCultureIgnoreCase);
1034                         foreach (Parameter p in viewParams) {
1035                                 bool oldAdded = false;
1036                                 if (oldValues != null) {
1037                                         object value = FindValueByName (p.Name, oldValues, true);
1038                                         if (value != null) {
1039                                                 object dataValue = p.ConvertValue (value);
1040                                                 mergedValues [p.Name] = dataValue;
1041                                                 oldAdded = true;
1042                                         }
1043                                 }
1044
1045                                 bool newAdded = false;
1046                                 if (values != null) {
1047                                         object value = FindValueByName (p.Name, values, false);
1048                                         if (value != null) {
1049                                                 object dataValue = p.ConvertValue (value);
1050                                                 mergedValues [p.Name] = dataValue;
1051                                                 newAdded = true;
1052                                         }
1053                                 }
1054                                 if ((!newAdded && !oldAdded) || allwaysAddNewValues) {
1055                                         object val = p.GetValue (context, owner);
1056                                         mergedValues [p.Name] = val;
1057                                 }
1058                         }
1059
1060                         if (values != null) {
1061                                 foreach (DictionaryEntry de in values)
1062                                         if (FindValueByName ((string) de.Key, mergedValues, false) == null)
1063                                                 mergedValues [de.Key] = de.Value;
1064                         }
1065
1066                         if (oldValues != null) {
1067                                 foreach (DictionaryEntry de in oldValues)
1068                                         if (FindValueByName ((string) de.Key, mergedValues, true) == null)
1069                                                 mergedValues [FormatOldParameter ((string) de.Key)] = de.Value;
1070                         }
1071
1072                         return mergedValues;
1073                 }
1074                 
1075                 object[] GetParameterArray (ParameterInfo[] methodParams, IOrderedDictionary viewParams, out ArrayList outParamInfos)
1076                 {
1077                         // FIXME: make this case insensitive
1078
1079                         outParamInfos = null;
1080                         object[] values = new object [methodParams.Length];
1081                         foreach (ParameterInfo mp in methodParams) {
1082                         
1083                                 // Parameter names must match
1084                                 if (!viewParams.Contains (mp.Name)) return null;
1085                                         
1086                                 values [mp.Position] = ConvertParameter (mp.ParameterType, viewParams [mp.Name]);
1087                                 if (mp.ParameterType.IsByRef) {
1088                                         if (outParamInfos == null) outParamInfos = new ArrayList ();
1089                                         outParamInfos.Add (mp);
1090                                 }
1091                         }
1092                         return values;
1093                 }
1094                 
1095                 object ConvertParameter (Type targetType, object value)
1096                 {
1097                         return ConvertParameter (Type.GetTypeCode (targetType), value);
1098                 }
1099                 
1100                 object ConvertParameter (TypeCode targetType, object value)
1101                 {
1102                         if (value == null) {
1103                                 if (targetType != TypeCode.Object && targetType != TypeCode.String)
1104                                         value = 0;
1105                                 else if (ConvertNullToDBNull)
1106                                         return DBNull.Value;
1107                         }
1108                         if (targetType == TypeCode.Object || targetType == TypeCode.Empty)
1109                                 return value;
1110                         else
1111                                 return Convert.ChangeType (value, targetType);
1112                 }
1113                 
1114                 string FormatOldParameter (string name)
1115                 {
1116                         string f = OldValuesParameterFormatString;
1117                         if (f.Length > 0)
1118                                 return String.Format (f, name);
1119                         else
1120                                 return name;
1121                 }
1122                 
1123                 void OnParametersChanged (object sender, EventArgs args)
1124                 {
1125                         OnDataSourceViewChanged (EventArgs.Empty);
1126                 }
1127                 
1128                 protected virtual void LoadViewState (object savedState)
1129                 {
1130                         object[] state = (savedState == null) ? new object [5] : (object[]) savedState;
1131                         ((IStateManager)SelectParameters).LoadViewState (state[0]); 
1132                         ((IStateManager)UpdateParameters).LoadViewState (state[1]); 
1133                         ((IStateManager)DeleteParameters).LoadViewState (state[2]); 
1134                         ((IStateManager)InsertParameters).LoadViewState (state[3]); 
1135                         ((IStateManager)FilterParameters).LoadViewState (state[4]); 
1136                 }
1137
1138                 protected virtual object SaveViewState()
1139                 {
1140                         object[] state = new object [5];
1141                         
1142                         if (selectParameters != null)
1143                                 state [0] = ((IStateManager)selectParameters).SaveViewState ();
1144                         if (updateParameters != null)
1145                                 state [1] = ((IStateManager)updateParameters).SaveViewState ();
1146                         if (deleteParameters != null)
1147                                 state [2] = ((IStateManager)deleteParameters).SaveViewState ();
1148                         if (insertParameters != null)
1149                                 state [3] = ((IStateManager)insertParameters).SaveViewState ();
1150                         if (filterParameters != null)
1151                                 state [4] = ((IStateManager)filterParameters).SaveViewState ();
1152                         
1153                         foreach (object ob in state)
1154                                 if (ob != null) return state;
1155                         
1156                         return null;
1157                 }
1158                 
1159                 protected virtual void TrackViewState()
1160                 {
1161                         isTrackingViewState = true;
1162
1163                         if (selectParameters != null) ((IStateManager)selectParameters).TrackViewState ();
1164                         if (filterParameters != null) ((IStateManager)filterParameters).TrackViewState ();
1165                 }
1166                 
1167                 protected bool IsTrackingViewState
1168                 {
1169                         get { return isTrackingViewState; }
1170                 }
1171                 
1172                 
1173                 bool IStateManager.IsTrackingViewState
1174                 {
1175                         get { return IsTrackingViewState; }
1176                 }
1177                 
1178                 void IStateManager.TrackViewState()
1179                 {
1180                         TrackViewState ();
1181                 }
1182                 
1183                 void IStateManager.LoadViewState (object savedState)
1184                 {
1185                         LoadViewState (savedState);
1186                 }
1187
1188                 object IStateManager.SaveViewState()
1189                 {
1190                         return SaveViewState ();
1191                 }
1192         }
1193 }
1194 #endif
1195
1196
1197
1198