2 // (C) 2005 Mainsoft Corporation (http://www.mainsoft.com)
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the
8 // "Software"), to deal in the Software without restriction, including
9 // without limitation the rights to use, copy, modify, merge, publish,
10 // distribute, sublicense, and/or sell copies of the Software, and to
11 // permit persons to whom the Software is furnished to do so, subject to
12 // the following conditions:
14 // The above copyright notice and this permission notice shall be
15 // included in all copies or substantial portions of the Software.
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 using System.Collections;
28 using System.ComponentModel;
29 using System.Reflection;
32 using System.Web.J2EE;
35 using System.Web.Util;
36 using System.Collections.Generic;
38 namespace System.Web.UI {
40 public abstract class TemplateControl : Control, INamingContainer
42 static readonly object abortTransaction = new object ();
43 static readonly object commitTransaction = new object ();
44 static readonly object error = new object ();
45 static readonly string [] methodNames = { "Page_Init",
50 "Page_PreRenderComplete",
51 "Page_SaveStateComplete",
60 "Page_AbortTransaction",
61 "Page_CommitTransaction" };
63 static readonly object [] EventKeys = {
68 Page.LoadCompleteEvent,
69 Page.PreRenderCompleteEvent,
70 Page.SaveStateCompleteEvent,
71 Page.InitCompleteEvent,
74 Control.DataBindingEvent,
75 Control.PreRenderEvent,
76 Control.DisposedEvent,
104 const BindingFlags bflags = BindingFlags.Public |
105 BindingFlags.NonPublic |
106 BindingFlags.Instance;
108 byte [] GetResourceBytes (Type type)
110 Hashtable table = (Hashtable) AppDomain.CurrentDomain.GetData ("TemplateControl.RES_BYTES");
114 return (byte []) table [type];
116 void SetResourceBytes (Type type, byte [] bytes)
118 Hashtable table = (Hashtable) AppDomain.CurrentDomain.GetData ("TemplateControl.RES_BYTES");
120 table = new Hashtable ();
121 AppDomain.CurrentDomain.SetData ("TemplateControl.RES_BYTES", table);
123 table [type] = bytes;
127 Hashtable ResourceHash
131 Hashtable table = (Hashtable) AppDomain.CurrentDomain.GetData ("TemplateControl.RES_STRING");
133 table = new Hashtable ();
134 AppDomain.CurrentDomain.SetData ("TemplateControl.RES_STRING", table);
140 AppDomain.CurrentDomain.SetData ("TemplateControl.RES_STRING", value);
144 string CachedString (Type type, int offset, int size)
146 CacheKey key = new CacheKey (type, offset, size);
148 string strObj = (string) ResourceHash [key];
149 if (strObj == null) {
150 char [] tmp = System.Text.Encoding.UTF8.GetChars (GetResourceBytes (this.GetType ()), offset, size);
151 strObj = new string (tmp);
153 Hashtable tmpResourceHash = (Hashtable) ResourceHash.Clone ();
154 tmpResourceHash.Add (key, strObj);
155 ResourceHash = tmpResourceHash;
159 public virtual string TemplateSourceDirectory_Private
165 protected TemplateControl ()
173 [EditorBrowsable (EditorBrowsableState.Never)]
174 protected virtual int AutoHandlers
180 [EditorBrowsable (EditorBrowsableState.Never)]
181 protected virtual bool SupportAutoEvents
190 protected virtual void Construct ()
195 protected LiteralControl CreateResourceBasedLiteralControl (int offset,
199 string str = CachedString (this.GetType (), offset, size);
200 return new LiteralControl (str);
203 sealed class EventMethodMap
205 public EventMethodMap (LifeCycleEvent EventKeyIndex, MethodInfo Method, bool NoParameters)
207 this.EventKeyIndex = EventKeyIndex;
208 this.Method = Method;
209 this.NoParameters = NoParameters;
212 public readonly LifeCycleEvent EventKeyIndex;
213 public readonly MethodInfo Method;
214 public readonly bool NoParameters;
217 // This hashtable cashes methods and events found in user code
218 const string eventMethodCacheKey = "eventMethodCacheKey";
219 static Hashtable EventMethodCache
221 get { return (Hashtable) AppDomain.CurrentDomain.GetData (eventMethodCacheKey); }
222 set { AppDomain.CurrentDomain.SetData (eventMethodCacheKey, value); }
225 internal void WireupAutomaticEvents ()
227 Type cacheKey = this.GetType ();
228 Hashtable eventMethodCache = EventMethodCache;
229 ArrayList eventMethodList = eventMethodCache == null ? null : (ArrayList) eventMethodCache [cacheKey];
231 if (eventMethodList == null) {
232 eventMethodList = new ArrayList ();
234 if (!SupportAutoEvents || !AutoEventWireup)
237 Type thisType = typeof (TemplateControl);
238 Type voidType = typeof (void);
239 Type [] DefaultParams = new Type [] {
241 typeof (EventArgs) };
243 LifeCycleEvent[] _pageEvents = new LifeCycleEvent[] {
244 LifeCycleEvent.PreInit,
245 LifeCycleEvent.PreLoad,
246 LifeCycleEvent.LoadComplete,
247 LifeCycleEvent.PreRenderComplete,
248 LifeCycleEvent.SaveStateComplete,
249 LifeCycleEvent.InitComplete
251 List<LifeCycleEvent> pageEvents = new List<LifeCycleEvent>(_pageEvents);
253 bool isPage = Page.GetType().IsAssignableFrom(GetType());
255 for (int i = 0; i < methodNames.Length; i++) {
257 // Don't look for page-only events in non-page controls.
258 if (!isPage && pageEvents.Contains((LifeCycleEvent)i))
261 string methodName = methodNames [i];
263 bool noParams = false;
264 Type type = GetType ();
266 method = type.GetMethod (methodName, bflags, null, DefaultParams, null);
267 if (method != null) {
271 type = type.BaseType;
273 while (type != thisType);
275 if (method == null) {
278 method = type.GetMethod (methodName, bflags, null, Type.EmptyTypes, null);
279 if (method != null) {
284 type = type.BaseType;
286 while (type != thisType);
291 if (method.ReturnType != voidType)
294 eventMethodList.Add (new EventMethodMap ((LifeCycleEvent) i, method, noParams));
296 // We copy to not lock
298 Hashtable newEventMethodCache = eventMethodCache == null ? new Hashtable () : (Hashtable) eventMethodCache.Clone ();
299 newEventMethodCache [cacheKey] = eventMethodList;
300 EventMethodCache = newEventMethodCache;
303 foreach (EventMethodMap eventMethod in eventMethodList) {
304 EventHandler handler = eventMethod.NoParameters ?
305 new NoParamsInvoker (this, eventMethod.Method).FakeDelegate :
306 (EventHandler)Delegate.CreateDelegate (typeof (EventHandler), this, eventMethod.Method);
308 object eventKey = EventKeys [(int) eventMethod.EventKeyIndex];
310 Delegate existing = Events [eventKey];
311 if (existing != null && handler.Equals(existing))
314 switch (eventMethod.EventKeyIndex) {
315 case LifeCycleEvent.Init:
319 case LifeCycleEvent.PreInit:
320 ((Page)this).PreInit += handler;
322 case LifeCycleEvent.PreLoad:
323 ((Page) this).PreLoad += handler;
325 case LifeCycleEvent.LoadComplete:
326 ((Page) this).LoadComplete += handler;
328 case LifeCycleEvent.PreRenderComplete:
329 ((Page) this).PreRenderComplete += handler;
331 case LifeCycleEvent.SaveStateComplete:
332 ((Page) this).SaveStateComplete += handler;
334 case LifeCycleEvent.InitComplete:
335 ((Page) this).InitComplete += handler;
338 case LifeCycleEvent.Load:
341 case LifeCycleEvent.DataBinding:
342 DataBinding += handler;
344 case LifeCycleEvent.PreRender:
345 PreRender += handler;
347 case LifeCycleEvent.Disposed:
350 case LifeCycleEvent.Unload:
353 case LifeCycleEvent.Error:
356 case LifeCycleEvent.AbortTransaction:
357 AbortTransaction += handler;
359 case LifeCycleEvent.CommitTransaction:
360 CommitTransaction += handler;
366 [EditorBrowsable (EditorBrowsableState.Never)]
367 protected virtual void FrameworkInitialize ()
371 Type GetTypeFromControlPath (string virtualPath)
373 if (virtualPath == null)
374 throw new ArgumentNullException ("virtualPath");
376 string vpath = UrlUtils.Combine (TemplateSourceDirectory, virtualPath);
377 return PageMapper.GetObjectType (Context, vpath);
380 public Control LoadControl (string virtualPath)
383 if (virtualPath == null)
384 throw new ArgumentNullException ("virtualPath");
386 if (virtualPath == null)
387 throw new HttpException ("virtualPath is null");
389 Type type = GetTypeFromControlPath (virtualPath);
390 return LoadControl (type, null);
393 public Control LoadControl (Type type, object [] parameters)
395 object [] attrs = type.GetCustomAttributes (typeof (PartialCachingAttribute), true);
396 if (attrs != null && attrs.Length == 1) {
397 PartialCachingAttribute attr = (PartialCachingAttribute) attrs [0];
398 PartialCachingControl ctrl = new PartialCachingControl (type, parameters);
399 ctrl.VaryByParams = attr.VaryByParams;
400 ctrl.VaryByControls = attr.VaryByControls;
401 ctrl.VaryByCustom = attr.VaryByCustom;
405 object control = Activator.CreateInstance (type, parameters);
406 if (control is UserControl)
407 ((UserControl) control).InitializeAsUserControl (Page);
409 return (Control) control;
412 public ITemplate LoadTemplate (string virtualPath)
414 Type t = GetTypeFromControlPath (virtualPath);
415 return new SimpleTemplate (t);
418 protected virtual void OnAbortTransaction (EventArgs e)
420 EventHandler eh = Events [abortTransaction] as EventHandler;
425 protected virtual void OnCommitTransaction (EventArgs e)
427 EventHandler eh = Events [commitTransaction] as EventHandler;
432 protected virtual void OnError (EventArgs e)
434 EventHandler eh = Events [error] as EventHandler;
439 [MonoNotSupported ("Not supported")]
440 public Control ParseControl (string content)
442 throw new NotSupportedException ();
445 [MonoLimitation ("Always returns false")]
446 public virtual bool TestDeviceFilter (string filterName)
452 [EditorBrowsable (EditorBrowsableState.Never)]
453 public static object ReadStringResource (Type t)
458 [MonoTODO ("is this correct?")]
459 public Object ReadStringResource ()
461 return this.GetType ();
465 [EditorBrowsable (EditorBrowsableState.Never)]
466 protected void SetStringResourcePointer (object stringResourcePointer,
467 int maxResourceOffset)
469 if (GetResourceBytes (this.GetType ()) != null)
472 java.lang.Class c = vmw.common.TypeUtils.ToClass (stringResourcePointer);
473 java.lang.ClassLoader contextClassLoader = c.getClassLoader ();
475 //TODO:move this code to page mapper
476 string assemblyName = PageMapper.GetAssemblyResource (Context, VirtualPathUtility.ToAbsolute (AppRelativeVirtualPath));
477 if (assemblyName == null)
478 throw new HttpException (404, "The requested resource (" + this.AppRelativeVirtualPath + ") is not available.");
480 java.io.InputStream inputStream = contextClassLoader.getResourceAsStream (assemblyName);
482 System.IO.Stream strim = null;
483 if (inputStream == null) {
484 string descPath = String.Join ("/", new string [] { "assemblies", this.GetType ().Assembly.GetName ().Name, assemblyName });
486 strim = new StreamReader (HttpContext.Current.Request.MapPath ("/" + descPath)).BaseStream;
488 catch (Exception ex) {
489 throw new System.IO.IOException ("couldn't open resource file:" + assemblyName, ex);
492 throw new System.IO.IOException ("couldn't open resource file:" + assemblyName);
497 strim = (System.IO.Stream) vmw.common.IOUtils.getStream (inputStream);
498 int capacity = (int) strim.Length;
499 byte [] resourceBytes = new byte [capacity];
500 strim.Read (resourceBytes, 0, capacity);
501 SetResourceBytes (this.GetType (), resourceBytes);
503 catch (Exception e) {
504 throw new HttpException ("problem with dll.ghres file", e);
509 if (inputStream != null)
510 inputStream.close ();
515 [EditorBrowsable (EditorBrowsableState.Never)]
516 protected void WriteUTF8ResourceString (HtmlTextWriter output, int offset,
517 int size, bool fAsciiOnly)
519 string str = CachedString (this.GetType (), offset, size);
527 [WebSysDescription ("Raised when the user aborts a transaction.")]
528 public event EventHandler AbortTransaction
530 add { Events.AddHandler (abortTransaction, value); }
531 remove { Events.RemoveHandler (abortTransaction, value); }
534 [WebSysDescription ("Raised when the user initiates a transaction.")]
535 public event EventHandler CommitTransaction
537 add { Events.AddHandler (commitTransaction, value); }
538 remove { Events.RemoveHandler (commitTransaction, value); }
541 [WebSysDescription ("Raised when an exception occurs that cannot be handled.")]
542 public event EventHandler Error
544 add { Events.AddHandler (error, value); }
545 remove { Events.RemoveHandler (error, value); }
550 class SimpleTemplate : ITemplate
554 public SimpleTemplate (Type type)
559 public void InstantiateIn (Control control)
561 Control template = Activator.CreateInstance (type) as Control;
562 template.SetBindingContainer (false);
563 control.Controls.Add (template);
567 sealed class CacheKey
570 readonly int _offset;
573 public CacheKey (Type type, int offset, int size)
580 public override int GetHashCode ()
582 return _type.GetHashCode () ^ _offset ^ _size;
585 public override bool Equals (object obj)
587 if (obj == null || !(obj is CacheKey))
590 CacheKey key = (CacheKey) obj;
591 return key._type == _type && key._offset == _offset && key._size == _size;
597 string _appRelativeVirtualPath = null;
599 public string AppRelativeVirtualPath
601 get { return _appRelativeVirtualPath; }
605 throw new ArgumentNullException ("value");
606 if (!UrlUtils.IsRooted (value) && !(value.Length > 0 && value [0] == '~'))
607 throw new ArgumentException ("The path that is set is not rooted");
608 _appRelativeVirtualPath = value;
610 int lastSlash = _appRelativeVirtualPath.LastIndexOf ('/');
611 AppRelativeTemplateSourceDirectory = (lastSlash > 0) ? _appRelativeVirtualPath.Substring (0, lastSlash + 1) : "~/";
615 internal override TemplateControl TemplateControlInternal {
619 protected internal object Eval (string expression)
621 return DataBinder.Eval (Page.GetDataItem (), expression);
624 protected internal string Eval (string expression, string format)
626 return DataBinder.Eval (Page.GetDataItem (), expression, format);
629 protected internal object XPath (string xpathexpression)
631 return XPathBinder.Eval (Page.GetDataItem (), xpathexpression);
634 protected internal object XPath (string xpathexpression, IXmlNamespaceResolver resolver)
636 return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, null, resolver);
639 protected internal string XPath (string xpathexpression, string format)
641 return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, format);
644 protected internal string XPath (string xpathexpression, string format, IXmlNamespaceResolver resolver)
646 return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, format, resolver);
649 protected internal IEnumerable XPathSelect (string xpathexpression)
651 return XPathBinder.Select (Page.GetDataItem (), xpathexpression);
654 protected internal IEnumerable XPathSelect (string xpathexpression, IXmlNamespaceResolver resolver)
656 return XPathBinder.Select (Page.GetDataItem (), xpathexpression, resolver);
659 protected object GetGlobalResourceObject (string className, string resourceKey)
661 return HttpContext.GetGlobalResourceObject (className, resourceKey);
664 protected object GetGlobalResourceObject (string className, string resourceKey, Type objType, string propName)
666 return ConvertResource (GetGlobalResourceObject (className, resourceKey), objType, propName);
669 protected Object GetLocalResourceObject (string resourceKey)
671 return HttpContext.GetLocalResourceObject (Context.Request.Path, resourceKey);
674 protected Object GetLocalResourceObject (string resourceKey, Type objType, string propName)
676 return ConvertResource (GetLocalResourceObject (resourceKey), objType, propName);
679 static Object ConvertResource (Object resource, Type objType, string propName) {
680 if (resource == null)
683 PropertyDescriptor pdesc = TypeDescriptor.GetProperties (objType) [propName];
687 TypeConverter converter = pdesc.Converter;
688 if (converter == null)
691 return resource is string ?
692 converter.ConvertFromInvariantString ((string) resource) :
693 converter.ConvertFrom (resource);