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 
OnTransforming(EventArgs e)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;
GetXmlDocument()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")]
LoadXmlDocument()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 
LoadFileOrData(string filename, string data)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 
GetXmlDocumentFromCache()142 		XmlDocument GetXmlDocumentFromCache ()
143 		{
144 			if (DataCache != null)
145 				return (XmlDocument) DataCache [GetDataKey ()];
146 
147 			return null;
148 		}
149 
GetDataKey()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 
UpdateCache()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.
UpdateXml()207 		void UpdateXml()
208 		{
209 			xmlDocument = LoadXmlDocument ();
210 			UpdateCache ();
211 			_documentNeedsUpdate = false;
212 		}
213 
Save()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 
GetHierarchicalView(string viewPath)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 
IListSource.GetList()247 		IList IListSource.GetList ()
248 		{
249 			return ListSourceHelper.GetList (this);
250 		}
251 
252 		bool IListSource.ContainsListCollection {
253 			get { return ListSourceHelper.ContainsListCollection (this); }
254 		}
255 
IDataSource.GetView(string viewName)256 		DataSourceView IDataSource.GetView (string viewName)
257 		{
258 			if (String.IsNullOrEmpty (viewName))
259 				viewName = "DefaultView";
260 
261 			return new XmlDataSourceView (this, viewName);
262 		}
263 
IDataSource.GetViewNames()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 
396