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.Threading;
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 private byte [] GetResourceBytes (Type type)
110 Hashtable table = (Hashtable) AppDomain.CurrentDomain.GetData ("TemplateControl.RES_BYTES");
114 return (byte []) table [type];
116 private 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 private 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 private 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 for (int i = 0; i < methodNames.Length; i++) {
244 string methodName = methodNames [i];
246 bool noParams = false;
247 Type type = GetType ();
249 method = type.GetMethod (methodName, bflags, null, DefaultParams, null);
250 if (method != null) {
254 type = type.BaseType;
256 while (type != thisType);
258 if (method == null) {
261 method = type.GetMethod (methodName, bflags, null, Type.EmptyTypes, null);
262 if (method != null) {
267 type = type.BaseType;
269 while (type != thisType);
274 if (method.ReturnType != voidType)
277 eventMethodList.Add (new EventMethodMap ((LifeCycleEvent) i, method, noParams));
279 // We copy to not lock
281 Hashtable newEventMethodCache = eventMethodCache == null ? new Hashtable () : (Hashtable) eventMethodCache.Clone ();
282 newEventMethodCache [cacheKey] = eventMethodList;
283 EventMethodCache = newEventMethodCache;
286 foreach (EventMethodMap eventMethod in eventMethodList) {
287 EventHandler handler = eventMethod.NoParameters ?
288 new NoParamsInvoker (this, eventMethod.Method).FakeDelegate :
289 (EventHandler)Delegate.CreateDelegate (typeof (EventHandler), this, eventMethod.Method);
291 object eventKey = EventKeys [(int) eventMethod.EventKeyIndex];
293 Delegate existing = Events [eventKey];
294 if (existing != null && handler.Equals(existing))
297 switch (eventMethod.EventKeyIndex) {
298 case LifeCycleEvent.Init:
302 case LifeCycleEvent.PreInit:
303 ((Page)this).PreInit += handler;
305 case LifeCycleEvent.PreLoad:
306 ((Page) this).PreLoad += handler;
308 case LifeCycleEvent.LoadComplete:
309 ((Page) this).LoadComplete += handler;
311 case LifeCycleEvent.PreRenderComplete:
312 ((Page) this).PreRenderComplete += handler;
314 case LifeCycleEvent.SaveStateComplete:
315 ((Page) this).SaveStateComplete += handler;
317 case LifeCycleEvent.InitComplete:
318 ((Page) this).InitComplete += handler;
321 case LifeCycleEvent.Load:
324 case LifeCycleEvent.DataBinding:
325 DataBinding += handler;
327 case LifeCycleEvent.PreRender:
328 PreRender += handler;
330 case LifeCycleEvent.Disposed:
333 case LifeCycleEvent.Unload:
336 case LifeCycleEvent.Error:
339 case LifeCycleEvent.AbortTransaction:
340 AbortTransaction += handler;
342 case LifeCycleEvent.CommitTransaction:
343 CommitTransaction += handler;
349 [EditorBrowsable (EditorBrowsableState.Never)]
350 protected virtual void FrameworkInitialize ()
354 Type GetTypeFromControlPath (string virtualPath)
356 if (virtualPath == null)
357 throw new ArgumentNullException ("virtualPath");
359 string vpath = UrlUtils.Combine (TemplateSourceDirectory, virtualPath);
360 return PageMapper.GetObjectType (Context, vpath);
363 public Control LoadControl (string virtualPath)
366 if (virtualPath == null)
367 throw new ArgumentNullException ("virtualPath");
369 if (virtualPath == null)
370 throw new HttpException ("virtualPath is null");
372 Type type = GetTypeFromControlPath (virtualPath);
373 return LoadControl (type, null);
376 public Control LoadControl (Type type, object [] parameters)
378 object [] attrs = type.GetCustomAttributes (typeof (PartialCachingAttribute), true);
379 if (attrs != null && attrs.Length == 1) {
380 PartialCachingAttribute attr = (PartialCachingAttribute) attrs [0];
381 PartialCachingControl ctrl = new PartialCachingControl (type, parameters);
382 ctrl.VaryByParams = attr.VaryByParams;
383 ctrl.VaryByControls = attr.VaryByControls;
384 ctrl.VaryByCustom = attr.VaryByCustom;
388 object control = Activator.CreateInstance (type, parameters);
389 if (control is UserControl)
390 ((UserControl) control).InitializeAsUserControl (Page);
392 return (Control) control;
395 public ITemplate LoadTemplate (string virtualPath)
397 Type t = GetTypeFromControlPath (virtualPath);
398 return new SimpleTemplate (t);
401 protected virtual void OnAbortTransaction (EventArgs e)
403 EventHandler eh = Events [abortTransaction] as EventHandler;
408 protected virtual void OnCommitTransaction (EventArgs e)
410 EventHandler eh = Events [commitTransaction] as EventHandler;
415 protected virtual void OnError (EventArgs e)
417 EventHandler eh = Events [error] as EventHandler;
422 [MonoNotSupported ("Not supported")]
423 public Control ParseControl (string content)
425 throw new NotSupportedException ();
428 [MonoLimitation ("Always returns false")]
429 public virtual bool TestDeviceFilter (string filterName)
435 [EditorBrowsable (EditorBrowsableState.Never)]
436 public static object ReadStringResource (Type t)
441 [MonoTODO ("is this correct?")]
442 public Object ReadStringResource ()
444 return this.GetType ();
448 [EditorBrowsable (EditorBrowsableState.Never)]
449 protected void SetStringResourcePointer (object stringResourcePointer,
450 int maxResourceOffset)
452 if (GetResourceBytes (this.GetType ()) != null)
455 java.lang.Class c = vmw.common.TypeUtils.ToClass (stringResourcePointer);
456 java.lang.ClassLoader contextClassLoader = c.getClassLoader ();
458 //TODO:move this code to page mapper
459 string assemblyName = PageMapper.GetAssemblyResource (Context, VirtualPathUtility.ToAbsolute (AppRelativeVirtualPath));
460 if (assemblyName == null)
461 throw new HttpException (404, "The requested resource (" + this.AppRelativeVirtualPath + ") is not available.");
463 java.io.InputStream inputStream = contextClassLoader.getResourceAsStream (assemblyName);
465 System.IO.Stream strim = null;
466 if (inputStream == null) {
467 string descPath = String.Join ("/", new string [] { "assemblies", this.GetType ().Assembly.GetName ().Name, assemblyName });
469 strim = new StreamReader (HttpContext.Current.Request.MapPath ("/" + descPath)).BaseStream;
471 catch (Exception ex) {
472 throw new System.IO.IOException ("couldn't open resource file:" + assemblyName, ex);
475 throw new System.IO.IOException ("couldn't open resource file:" + assemblyName);
480 strim = (System.IO.Stream) vmw.common.IOUtils.getStream (inputStream);
481 int capacity = (int) strim.Length;
482 byte [] resourceBytes = new byte [capacity];
483 strim.Read (resourceBytes, 0, capacity);
484 SetResourceBytes (this.GetType (), resourceBytes);
486 catch (Exception e) {
487 throw new HttpException ("problem with dll.ghres file", e);
492 if (inputStream != null)
493 inputStream.close ();
498 [EditorBrowsable (EditorBrowsableState.Never)]
499 protected void WriteUTF8ResourceString (HtmlTextWriter output, int offset,
500 int size, bool fAsciiOnly)
502 string str = CachedString (this.GetType (), offset, size);
510 [WebSysDescription ("Raised when the user aborts a transaction.")]
511 public event EventHandler AbortTransaction
513 add { Events.AddHandler (abortTransaction, value); }
514 remove { Events.RemoveHandler (abortTransaction, value); }
517 [WebSysDescription ("Raised when the user initiates a transaction.")]
518 public event EventHandler CommitTransaction
520 add { Events.AddHandler (commitTransaction, value); }
521 remove { Events.RemoveHandler (commitTransaction, value); }
524 [WebSysDescription ("Raised when an exception occurs that cannot be handled.")]
525 public event EventHandler Error
527 add { Events.AddHandler (error, value); }
528 remove { Events.RemoveHandler (error, value); }
533 class SimpleTemplate : ITemplate
537 public SimpleTemplate (Type type)
542 public void InstantiateIn (Control control)
544 Control template = Activator.CreateInstance (type) as Control;
545 template.SetBindingContainer (false);
546 control.Controls.Add (template);
550 sealed private class CacheKey
553 readonly int _offset;
556 public CacheKey (Type type, int offset, int size)
563 public override int GetHashCode ()
565 return _type.GetHashCode () ^ _offset ^ _size;
568 public override bool Equals (object obj)
570 if (obj == null || !(obj is CacheKey))
573 CacheKey key = (CacheKey) obj;
574 return key._type == _type && key._offset == _offset && key._size == _size;
580 Assembly _resourceAssembly = null;
581 string _appRelativeVirtualPath = null;
583 public string AppRelativeVirtualPath
585 get { return _appRelativeVirtualPath; }
589 throw new ArgumentNullException ("value");
590 if (!UrlUtils.IsRooted (value) && !(value.Length > 0 && value [0] == '~'))
591 throw new ArgumentException ("The path that is set is not rooted");
592 _appRelativeVirtualPath = value;
594 int lastSlash = _appRelativeVirtualPath.LastIndexOf ('/');
595 AppRelativeTemplateSourceDirectory = (lastSlash > 0) ? _appRelativeVirtualPath.Substring (0, lastSlash + 1) : "~/";
599 internal override TemplateControl TemplateControlInternal {
603 protected internal object Eval (string expression)
605 return DataBinder.Eval (Page.GetDataItem (), expression);
608 protected internal string Eval (string expression, string format)
610 return DataBinder.Eval (Page.GetDataItem (), expression, format);
613 protected internal object XPath (string xpathexpression)
615 return XPathBinder.Eval (Page.GetDataItem (), xpathexpression);
618 protected internal object XPath (string xpathexpression, IXmlNamespaceResolver resolver)
620 return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, null, resolver);
623 protected internal string XPath (string xpathexpression, string format)
625 return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, format);
628 protected internal string XPath (string xpathexpression, string format, IXmlNamespaceResolver resolver)
630 return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, format, resolver);
633 protected internal IEnumerable XPathSelect (string xpathexpression)
635 return XPathBinder.Select (Page.GetDataItem (), xpathexpression);
638 protected internal IEnumerable XPathSelect (string xpathexpression, IXmlNamespaceResolver resolver)
640 return XPathBinder.Select (Page.GetDataItem (), xpathexpression, resolver);
643 protected object GetGlobalResourceObject (string className, string resourceKey)
645 return HttpContext.GetGlobalResourceObject (className, resourceKey);
648 protected object GetGlobalResourceObject (string className, string resourceKey, Type objType, string propName)
650 return ConvertResource (GetGlobalResourceObject (className, resourceKey), objType, propName);
653 protected Object GetLocalResourceObject (string resourceKey)
655 if (_resourceAssembly == null)
656 _resourceAssembly = System.Web.Compilation.AppResourcesCompiler.GetCachedLocalResourcesAssembly (TemplateSourceDirectory);
658 string fileName = string.Empty;
659 int lastSlash = AppRelativeVirtualPath.LastIndexOf ('/');
661 if (lastSlash > 0 && AppRelativeVirtualPath.Length > lastSlash + 1)
662 fileName = AppRelativeVirtualPath.Substring (lastSlash + 1);
664 return HttpContext.GetResourceObject (fileName, resourceKey, Thread.CurrentThread.CurrentUICulture, _resourceAssembly);
667 protected Object GetLocalResourceObject (string resourceKey, Type objType, string propName)
669 return ConvertResource (GetLocalResourceObject (resourceKey), objType, propName);
672 static Object ConvertResource (Object resource, Type objType, string propName) {
673 if (resource == null)
676 PropertyDescriptor pdesc = TypeDescriptor.GetProperties (objType) [propName];
680 TypeConverter converter = pdesc.Converter;
681 if (converter == null)
684 return resource is string ?
685 converter.ConvertFromInvariantString ((string) resource) :
686 converter.ConvertFrom (resource);