Add license and copyright to all source files in System.Data
[mono.git] / mcs / class / System.Data / System.Data / XmlDiffLoader.cs
1 //
2 // mcs/class/System.Data/System.Data/XmlDiffLoader.cs
3 //
4 // Purpose: Loads XmlDiffGrams to DataSet 
5 //
6 // class: XmlDiffLoader
7 // assembly: System.Data.dll
8 // namespace: System.Data
9 //
10 // Author:
11 //     Ville Palo <vi64pa@koti.soon.fi>
12 //     Lluis Sanchez Gual (lluis@ximian.com)
13 //
14 // (c)copyright 2003 Ville Palo
15 //
16
17 //
18 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
19 //
20 // Permission is hereby granted, free of charge, to any person obtaining
21 // a copy of this software and associated documentation files (the
22 // "Software"), to deal in the Software without restriction, including
23 // without limitation the rights to use, copy, modify, merge, publish,
24 // distribute, sublicense, and/or sell copies of the Software, and to
25 // permit persons to whom the Software is furnished to do so, subject to
26 // the following conditions:
27 // 
28 // The above copyright notice and this permission notice shall be
29 // included in all copies or substantial portions of the Software.
30 // 
31 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 //
39 using System;
40 using System.Data;
41 using System.Xml;
42 using System.Xml.XPath;
43 using System.Collections;
44 using System.Globalization;
45
46 namespace System.Data {
47
48         internal class XmlDiffLoader 
49         {
50
51                 #region Fields
52                 private DataSet DSet;
53                 private DataTable table;
54                 private Hashtable DiffGrRows = new Hashtable ();
55                 private Hashtable ErrorRows = new Hashtable ();
56
57                 #endregion // Fields
58
59                 #region ctors
60
61                 public XmlDiffLoader (DataSet DSet) 
62                 {
63                         this.DSet = DSet;
64                 }
65
66                 public XmlDiffLoader (DataTable table) 
67                 {
68                         this.table = table;
69                 }
70
71                 #endregion //ctors
72
73                 #region Public methods
74
75                 public void Load (XmlReader reader) 
76                 {
77                         bool origEnforceConstraint = false;
78                         if (DSet != null) {
79                                 origEnforceConstraint = DSet.EnforceConstraints;
80                                 DSet.EnforceConstraints = false;
81                         }
82                         
83                         reader.MoveToContent ();
84                         if (reader.IsEmptyElement) {
85                                 reader.Skip ();
86                                 return;
87                         }
88                         
89                         reader.ReadStartElement ("diffgram", XmlConstants.DiffgrNamespace);
90                         reader.MoveToContent ();
91                         
92                         while (reader.NodeType != XmlNodeType.EndElement)
93                         {
94                                 if (reader.NodeType == XmlNodeType.Element)
95                                 {
96                                         if (reader.LocalName == "before" && reader.NamespaceURI == XmlConstants.DiffgrNamespace)
97                                                 LoadBefore (reader);
98                                         else if (reader.LocalName == "errors" && reader.NamespaceURI == XmlConstants.DiffgrNamespace)
99                                                 LoadErrors (reader);
100                                         else
101                                                 LoadCurrent (reader);
102                                 }
103                                 else
104                                         reader.Skip ();
105                         }
106                         
107                         reader.ReadEndElement ();
108                         
109                         if (DSet != null)
110                                 DSet.EnforceConstraints = origEnforceConstraint;
111                 }
112
113                 #endregion // Public methods
114
115                 #region Private methods
116
117                 private void LoadCurrent (XmlReader reader) 
118                 {
119                         if (reader.IsEmptyElement) {
120                                 reader.Skip ();
121                                 return;
122                         }
123                         reader.ReadStartElement ();             // Dataset root
124                         reader.MoveToContent ();
125
126                         while (reader.NodeType != XmlNodeType.EndElement)
127                         {
128                                 if (reader.NodeType == XmlNodeType.Element)
129                                 {
130                                         DataTable t = GetTable (reader.LocalName);
131                                         if (t != null)
132                                                 LoadCurrentTable (t, reader);
133 #if true
134                                         else
135                                                 reader.Skip ();
136 #else
137                                         else 
138                                                 throw new DataException (Locale.GetText ("Cannot load diffGram. Table '" + reader.LocalName + "' is missing in the destination dataset"));      
139 #endif
140                                 }
141                                 else
142                                         reader.Skip ();
143                         }
144                         
145                         reader.ReadEndElement ();
146                 }
147
148                 private void LoadBefore (XmlReader reader) 
149                 {
150                         if (reader.IsEmptyElement) {
151                                 reader.Skip ();
152                                 return;
153                         }
154                         reader.ReadStartElement ();
155                         reader.MoveToContent ();
156
157                         while (reader.NodeType != XmlNodeType.EndElement)
158                         {
159                                 if (reader.NodeType == XmlNodeType.Element)
160                                 {
161                                         DataTable t = GetTable (reader.LocalName);
162                                         if (t != null)
163                                                 LoadBeforeTable(t, reader);
164                                         else
165                                                 throw new DataException (Locale.GetText ("Cannot load diffGram. Table '" + reader.LocalName + "' is missing in the destination dataset"));
166                                 }
167                                 else
168                                         reader.Skip ();
169                         }
170                         
171                         reader.ReadEndElement ();
172                 }                                
173                                 
174                                            
175                 private void LoadErrors (XmlReader reader) 
176                 {
177                         if (reader.IsEmptyElement) {
178                                 reader.Skip ();
179                                 return;
180                         }
181                         reader.ReadStartElement ();
182                         reader.MoveToContent ();
183
184                         while (reader.NodeType != XmlNodeType.EndElement)
185                         {
186                                 if (reader.NodeType == XmlNodeType.Element)
187                                 {
188                                         DataRow Row = null;
189                 
190                                         // find the row in 'current' section
191                                         
192                                         string id = reader.GetAttribute ("id", XmlConstants.DiffgrNamespace);
193                                         
194                                         if (id != null)
195                                                 Row = (DataRow) ErrorRows [id];
196                 
197                                         if (reader.IsEmptyElement) continue;
198                                         reader.ReadStartElement ();
199                                         while (reader.NodeType != XmlNodeType.EndElement)
200                                         {
201                                                 if (reader.NodeType == XmlNodeType.Element) {
202                                                         string error = reader.GetAttribute ("Error", XmlConstants.DiffgrNamespace);
203                                                         Row.SetColumnError (reader.LocalName, error);
204                                                 }
205                                                 reader.Read ();
206                                         }
207                                 }
208                                 else
209                                         reader.Skip ();
210                         }
211                         reader.ReadEndElement ();
212                 }
213
214                 private void LoadColumns (DataTable Table, DataRow Row, XmlReader reader, DataRowVersion loadType) 
215                 {
216                         if (reader.IsEmptyElement) {
217                                 reader.Skip ();
218                                 return;
219                         }
220                         reader.ReadStartElement ();
221                         reader.MoveToContent ();
222                         
223                         while (reader.NodeType != XmlNodeType.EndElement)
224                         {
225                                 if (reader.NodeType != XmlNodeType.Element) { reader.Read (); continue; }
226                                 
227                                 if (Table.Columns.Contains (reader.LocalName)) 
228                                 {
229                                         string colName = reader.LocalName;
230                                         object data = XmlDataLoader.StringToObject (Table.Columns[colName].DataType, reader.ReadString ());
231                                         
232                                         if (loadType == DataRowVersion.Current) Row [colName] = data;
233                                         else Row.SetOriginalValue (colName, data);
234                                         reader.Read ();
235                                 }
236                                 else 
237                                 {
238                                         DataTable t = GetTable (reader.LocalName);
239                                         if (t != null) {
240                                                 if (loadType == DataRowVersion.Original)
241                                                         LoadBeforeTable (t, reader);
242                                                 else if (loadType == DataRowVersion.Current)
243                                                         LoadCurrentTable (t, reader);
244                                         }
245                                 }
246                         }
247                         
248                         reader.ReadEndElement ();
249                 }
250
251                 private void LoadBeforeTable (DataTable Table, XmlReader reader) 
252                 {
253                         string id = reader.GetAttribute ("id", XmlConstants.DiffgrNamespace);
254                         string rowOrder = reader.GetAttribute ("rowOrder", XmlConstants.MsdataNamespace);
255                         DataRow Row = (DataRow) DiffGrRows [id];
256                         
257                         if (Row == null)
258                         {
259                                 // Deleted row
260                                 Row = Table.NewRow ();
261                                 LoadColumns (Table, Row, reader, DataRowVersion.Current);
262                                 Table.Rows.InsertAt (Row, int.Parse (rowOrder));
263                                 Row.AcceptChanges ();
264                                 Row.Delete ();
265                         }
266                         else
267                         {
268                                 LoadColumns (Table, Row, reader, DataRowVersion.Original);
269                         }
270                 }
271
272                 private void LoadCurrentTable (DataTable Table, XmlReader reader) 
273                 {
274                         DataRowState state;
275                         DataRow Row = Table.NewRow ();
276
277                         string id = reader.GetAttribute  ("id", XmlConstants.DiffgrNamespace);
278                         string error = reader.GetAttribute ("hasErrors");
279                         string changes = reader.GetAttribute ("hasChanges", XmlConstants.DiffgrNamespace);
280                         
281                         if (changes != null)
282                         {
283                                 if (string.Compare (changes, "modified", true) == 0) {
284                                         DiffGrRows.Add (id, Row); // for later use
285                                         state = DataRowState.Modified;
286                                 }
287                                 else if (string.Compare (changes, "inserted", true) == 0) {
288                                         state = DataRowState.Added;
289                                 }
290                                 else
291                                         throw new InvalidOperationException ("Invalid row change state");
292                         }
293                         else
294                                 state = DataRowState.Unchanged;
295                         
296                         // If row had errors add row to hashtable for later use
297                         if (error != null && string.Compare (error, "true", true) == 0)
298                                 ErrorRows.Add (id, Row);
299                 
300                         LoadColumns (Table, Row, reader, DataRowVersion.Current);
301                         Table.Rows.Add (Row);
302                         
303                         if (state != DataRowState.Added)
304                                 Row.AcceptChanges ();
305                 }
306
307                 DataTable GetTable (string name)
308                 {
309                         if (DSet != null) 
310                                 return DSet.Tables [name];
311                         else if (name == table.TableName) 
312                                 return table;
313                         else
314                                 return null;
315                 }
316
317
318                 #endregion // Private methods
319         }
320 }