Merge pull request #2832 from razzfazz/handle_eintr
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / XmlDataSource.cs
1 //
2 // System.Web.UI.WebControls.XmlDataSource
3 //
4 // Authors:
5 //      Ben Maurer (bmaurer@users.sourceforge.net)
6 //      Chris Toshok (toshok@ximian.com)
7 //
8 // (C) 2003 Ben Maurer
9 // (C) 2005 Novell, Inc (http://www.novell.com)
10 //
11
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System.Collections;
34 using System.Collections.Specialized;
35 using System.Drawing;
36 using System.Text;
37 using System.Xml;
38 using System.Xml.Xsl;
39 using System.ComponentModel;
40 using System.IO;
41 using System.Web.Caching;
42 using System.Security.Permissions;
43
44 namespace System.Web.UI.WebControls {
45
46         // CAS
47         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
48         [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
49         // attributes
50         [DesignerAttribute ("System.Web.UI.Design.WebControls.XmlDataSourceDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
51         [DefaultProperty ("DataFile")]
52         [DefaultEvent ("Transforming")]
53         [ParseChildren (true)]
54         [PersistChildren (false)]
55         [WebSysDescription ("Connect to an XML file.")]
56 //      [WebSysDisplayName ("XML file")]
57         [ToolboxBitmap ("")]
58         public class XmlDataSource : HierarchicalDataSourceControl, IDataSource, IListSource {
59
60                 string _data = string.Empty;
61                 string _transform = string.Empty;
62                 string _xpath = string.Empty;
63                 string _dataFile = string.Empty;
64                 string _transformFile = string.Empty;
65                 string _cacheKeyDependency = string.Empty;
66                 bool _enableCaching = true;
67                 int _cacheDuration = 0;
68                 bool _documentNeedsUpdate;
69                 
70                 DataSourceCacheExpiry _cacheExpirationPolicy = DataSourceCacheExpiry.Absolute;
71                 static readonly string [] emptyNames = new string [] { "DefaultView" };
72                 
73                 event EventHandler IDataSource.DataSourceChanged {
74                         add { ((IHierarchicalDataSource)this).DataSourceChanged += value; }
75                         remove { ((IHierarchicalDataSource)this).DataSourceChanged -= value; }
76                 }
77                 
78                 static object EventTransforming = new object ();
79                 public event EventHandler Transforming {
80                         add { Events.AddHandler (EventTransforming, value); }
81                         remove { Events.RemoveHandler (EventTransforming, value); }
82                 }
83
84                 protected virtual void OnTransforming (EventArgs e)
85                 {
86                         EventHandler eh = Events [EventTransforming] as EventHandler;
87                         if (eh != null)
88                                 eh (this, e);
89                 }
90                 
91                 XmlDocument xmlDocument;
92                 public XmlDocument GetXmlDocument ()
93                 {
94                         if (_documentNeedsUpdate)
95                                 UpdateXml ();
96                         
97                         if (xmlDocument == null && EnableCaching)
98                                 xmlDocument = GetXmlDocumentFromCache ();
99
100                         if (xmlDocument == null) {
101                                 xmlDocument = LoadXmlDocument ();
102                                 UpdateCache ();
103                         }
104
105                         return xmlDocument;
106                 }
107
108                 [MonoTODO ("schema")]
109                 XmlDocument LoadXmlDocument ()
110                 {
111                         XmlDocument document = LoadFileOrData (DataFile, Data);
112                         if (String.IsNullOrEmpty (TransformFile) && String.IsNullOrEmpty (Transform))
113                                 return document;
114
115                         XslTransform xslTransform = new XslTransform ();
116                         XmlDocument xsl = LoadFileOrData (TransformFile, Transform);
117                         xslTransform.Load (xsl);
118
119                         OnTransforming (EventArgs.Empty);
120
121                         XmlDocument transofrResult = new XmlDocument ();
122                         transofrResult.Load (xslTransform.Transform (document, TransformArgumentList));
123
124                         return transofrResult;
125                 }
126
127                 XmlDocument LoadFileOrData (string filename, string data)
128                 {
129                         XmlDocument document = new XmlDocument ();
130                         if (!String.IsNullOrEmpty (filename)) {
131                                 Uri uri;
132                                 if (Uri.TryCreate (filename, UriKind.Absolute, out uri))
133                                         document.Load (filename);
134                                 else
135                                         document.Load (MapPathSecure (filename));
136                         } else
137                                 if (!String.IsNullOrEmpty (data))
138                                         document.LoadXml (data);
139                         return document;
140                 }
141
142                 XmlDocument GetXmlDocumentFromCache ()
143                 {
144                         if (DataCache != null)
145                                 return (XmlDocument) DataCache [GetDataKey ()];
146
147                         return null;
148                 }
149
150                 string GetDataKey ()
151                 {
152                         if (String.IsNullOrEmpty (DataFile) && !String.IsNullOrEmpty (Data)) {
153                                 string key = CacheKeyContext;
154                                 if (!String.IsNullOrEmpty (key))
155                                         return key;
156                         }
157                         Page page = Page;
158                         string p = page != null ? page.ToString () : "NullPage";
159                         
160                         return TemplateSourceDirectory + "_" + p + "_" + ID;
161                 }
162
163                 Cache DataCache
164                 {
165                         get
166                         {
167                                 if (HttpContext.Current != null)
168                                         return HttpContext.Current.InternalCache;
169
170                                 return null;
171                         }
172                 }
173
174                 void UpdateCache ()
175                 {
176                         if (!EnableCaching)
177                                 return;
178
179                         if (DataCache == null)
180                                 return;
181
182                         string dataKey = GetDataKey ();
183                         if (DataCache [dataKey] != null)
184                                 DataCache.Remove (dataKey);
185
186                         DateTime absoluteExpiration = Cache.NoAbsoluteExpiration;
187                         TimeSpan slidindExpiraion = Cache.NoSlidingExpiration;
188
189                         if (CacheDuration > 0) {
190                                 if (CacheExpirationPolicy == DataSourceCacheExpiry.Absolute)
191                                         absoluteExpiration = DateTime.Now.AddSeconds (CacheDuration);
192                                 else
193                                         slidindExpiraion = new TimeSpan (CacheDuration * 10000L);
194                         }
195
196                         CacheDependency dependency = null;
197                         if (CacheKeyDependency.Length > 0)
198                                 dependency = new CacheDependency (new string [] { }, new string [] { CacheKeyDependency });
199                         else
200                                 dependency = new CacheDependency (new string [] { }, new string [] { });
201
202                         DataCache.Add (dataKey, xmlDocument, dependency,
203                                 absoluteExpiration, slidindExpiraion, CacheItemPriority.Default, null);
204                 }
205                 
206                 // If datafile changed, then DO NOT USE the cached data, but update it.
207                 void UpdateXml()
208                 {
209                         xmlDocument = LoadXmlDocument (); 
210                         UpdateCache ();
211                         _documentNeedsUpdate = false;
212                 }
213
214                 public void Save ()
215                 {
216                         if (!CanBeSaved)
217                                 throw new InvalidOperationException ();
218
219                         if (xmlDocument != null)
220                                 xmlDocument.Save (MapPathSecure (DataFile));
221                 }
222                 
223                 bool CanBeSaved {
224                         get {
225                                 return Transform == String.Empty && TransformFile == String.Empty && DataFile != String.Empty;
226                         }
227                 }
228                 
229                 protected override HierarchicalDataSourceView GetHierarchicalView (string viewPath)
230                 {
231                         XmlNode doc = this.GetXmlDocument ();
232                         XmlNodeList ret = null;
233                         
234                         if (!String.IsNullOrEmpty (viewPath)) {
235                                 XmlNode n = doc.SelectSingleNode (viewPath);
236                                 if (n != null)
237                                         ret = n.ChildNodes;
238                         } else if (!String.IsNullOrEmpty (XPath)) {
239                                 ret = doc.SelectNodes (XPath);
240                         } else {
241                                 ret = doc.ChildNodes;
242                         }
243                         
244                         return new XmlHierarchicalDataSourceView (ret);
245                 }
246                 
247                 IList IListSource.GetList ()
248                 {
249                         return ListSourceHelper.GetList (this);
250                 }
251                 
252                 bool IListSource.ContainsListCollection {
253                         get { return ListSourceHelper.ContainsListCollection (this); }
254                 }
255                 
256                 DataSourceView IDataSource.GetView (string viewName)
257                 {
258                         if (String.IsNullOrEmpty (viewName))
259                                 viewName = "DefaultView";
260                         
261                         return new XmlDataSourceView (this, viewName);
262                 }
263                 
264                 ICollection IDataSource.GetViewNames ()
265                 {
266                         return emptyNames;
267                 }
268                 
269                 [DefaultValue (0)]
270                 [TypeConverter (typeof(DataSourceCacheDurationConverter))]
271                 public virtual int CacheDuration {
272                         get {
273                                 return _cacheDuration;
274                         }
275                         set {
276                                 _cacheDuration = value;
277                         }
278                 }
279
280                 [DefaultValue (DataSourceCacheExpiry.Absolute)]
281                 public virtual DataSourceCacheExpiry CacheExpirationPolicy {
282                         get {
283                                 return _cacheExpirationPolicy;
284                         }
285                         set {
286                                 _cacheExpirationPolicy = value;
287                         }
288                 }
289
290                 [DefaultValue ("")]
291                 public virtual string CacheKeyDependency {
292                         get {
293                                 return _cacheKeyDependency;
294                         }
295                         set {
296                                 _cacheKeyDependency = value;
297                         }
298                 }
299
300                 [DefaultValue (true)]
301                 public virtual bool EnableCaching {
302                         get {
303                                 return _enableCaching;
304                         }
305                         set {
306                                 _enableCaching = value;
307                         }
308                 }
309
310                 [DefaultValue ("")]
311                 [PersistenceMode (PersistenceMode.InnerProperty)]
312                 [WebSysDescription ("Inline XML data.")]
313                 [WebCategory ("Data")]
314                 [EditorAttribute ("System.ComponentModel.Design.MultilineStringEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
315                 [TypeConverter (typeof(MultilineStringConverter))]
316                 public virtual string Data {
317                         get { return _data; }
318                         set {
319                                 if (_data != value) {
320                                         _data = value;
321                                         _documentNeedsUpdate = true;
322                                         OnDataSourceChanged(EventArgs.Empty);
323                                 }
324                         }
325                 }
326                 
327                 [DefaultValueAttribute ("")]
328                 [EditorAttribute ("System.Web.UI.Design.XmlDataFileEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
329                 [MonoLimitation ("Absolute path to the file system is not supported; use a relative URI instead.")]
330                 public virtual string DataFile {
331                         get { return _dataFile; }
332                         set {
333                                 if (_dataFile != value) {
334                                         _dataFile = value;
335                                         _documentNeedsUpdate = true;
336                                         OnDataSourceChanged(EventArgs.Empty);
337                                 }
338                         }
339                 }
340                 
341                 XsltArgumentList transformArgumentList;
342                 
343                 [BrowsableAttribute (false)]
344                 public virtual XsltArgumentList TransformArgumentList {
345                         get { return transformArgumentList; }
346                         set { transformArgumentList = value; }
347                 }
348                 
349                 [PersistenceModeAttribute (PersistenceMode.InnerProperty)]
350                 [EditorAttribute ("System.ComponentModel.Design.MultilineStringEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
351                 [DefaultValueAttribute ("")]
352                 [TypeConverterAttribute (typeof(MultilineStringConverter))]
353                 public virtual string Transform {
354                         get { return _transform; }
355                         set {
356                                 if (_transform != value) {
357                                         _transform = value; 
358                                         _documentNeedsUpdate = true;
359                                         OnDataSourceChanged(EventArgs.Empty);
360                                 }
361                         }
362                 }
363                 
364                 [EditorAttribute ("System.Web.UI.Design.XslTransformFileEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
365                 [DefaultValueAttribute ("")]
366                 [MonoLimitation ("Absolute path to the file system is not supported; use a relative URI instead.")]
367                 public virtual string TransformFile {
368                         get { return _transformFile; }
369                         set {
370                                 if (_transformFile != value) {
371                                         _transformFile = value;
372                                         _documentNeedsUpdate = true;
373                                         OnDataSourceChanged(EventArgs.Empty);
374                                 }
375                         }
376                 }
377                 
378                 [DefaultValueAttribute ("")]
379                 public virtual string XPath {
380                         get { return _xpath; }
381                         set {
382                                 if (_xpath != value) {
383                                         _xpath = value;
384                                         OnDataSourceChanged(EventArgs.Empty);
385                                 }
386                         }
387                 }
388                 [DefaultValue ("")]
389                 public virtual string CacheKeyContext {
390                         get { return ViewState.GetString ("CacheKeyContext", String.Empty); }
391                         set { ViewState ["CacheKeyContext"] = value; }
392                 }
393         }
394 }
395