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;
37 namespace System.Web.UI {
39 public abstract class TemplateControl : Control, INamingContainer
41 static readonly object abortTransaction = new object ();
42 static readonly object commitTransaction = new object ();
43 static readonly object error = new object ();
44 static readonly string [] methodNames = { "Page_Init",
49 "Page_PreRenderComplete",
50 "Page_SaveStateComplete",
59 "Page_AbortTransaction",
60 "Page_CommitTransaction" };
62 static readonly object [] EventKeys = {
67 Page.LoadCompleteEvent,
68 Page.PreRenderCompleteEvent,
69 Page.SaveStateCompleteEvent,
70 Page.InitCompleteEvent,
73 Control.DataBindingEvent,
74 Control.PreRenderEvent,
75 Control.DisposedEvent,
103 const BindingFlags bflags = BindingFlags.Public |
104 BindingFlags.NonPublic |
105 BindingFlags.Instance;
107 private byte [] GetResourceBytes (Type type)
109 Hashtable table = (Hashtable) AppDomain.CurrentDomain.GetData ("TemplateControl.RES_BYTES");
113 return (byte []) table [type];
115 private void SetResourceBytes (Type type, byte [] bytes)
117 Hashtable table = (Hashtable) AppDomain.CurrentDomain.GetData ("TemplateControl.RES_BYTES");
119 table = new Hashtable ();
120 AppDomain.CurrentDomain.SetData ("TemplateControl.RES_BYTES", table);
122 table [type] = bytes;
126 private Hashtable ResourceHash
130 Hashtable table = (Hashtable) AppDomain.CurrentDomain.GetData ("TemplateControl.RES_STRING");
132 table = new Hashtable ();
133 AppDomain.CurrentDomain.SetData ("TemplateControl.RES_STRING", table);
139 AppDomain.CurrentDomain.SetData ("TemplateControl.RES_STRING", value);
143 private string CachedString (Type type, int offset, int size)
145 CacheKey key = new CacheKey (type, offset, size);
147 string strObj = (string) ResourceHash [key];
148 if (strObj == null) {
149 char [] tmp = System.Text.Encoding.UTF8.GetChars (GetResourceBytes (this.GetType ()), offset, size);
150 strObj = new string (tmp);
152 Hashtable tmpResourceHash = (Hashtable) ResourceHash.Clone ();
153 tmpResourceHash.Add (key, strObj);
154 ResourceHash = tmpResourceHash;
158 public virtual string TemplateSourceDirectory_Private
164 protected TemplateControl ()
172 [EditorBrowsable (EditorBrowsableState.Never)]
173 protected virtual int AutoHandlers
179 [EditorBrowsable (EditorBrowsableState.Never)]
180 protected virtual bool SupportAutoEvents
189 protected virtual void Construct ()
194 protected LiteralControl CreateResourceBasedLiteralControl (int offset,
198 string str = CachedString (this.GetType (), offset, size);
199 return new LiteralControl (str);
202 sealed class EventMethodMap
204 public EventMethodMap (LifeCycleEvent EventKeyIndex, MethodInfo Method, bool NoParameters)
206 this.EventKeyIndex = EventKeyIndex;
207 this.Method = Method;
208 this.NoParameters = NoParameters;
211 public readonly LifeCycleEvent EventKeyIndex;
212 public readonly MethodInfo Method;
213 public readonly bool NoParameters;
216 // This hashtable cashes methods and events found in user code
217 const string eventMethodCacheKey = "eventMethodCacheKey";
218 static Hashtable EventMethodCache
220 get { return (Hashtable) AppDomain.CurrentDomain.GetData (eventMethodCacheKey); }
221 set { AppDomain.CurrentDomain.SetData (eventMethodCacheKey, value); }
224 internal void WireupAutomaticEvents ()
226 Type cacheKey = this.GetType ();
227 Hashtable eventMethodCache = EventMethodCache;
228 ArrayList eventMethodList = eventMethodCache == null ? null : (ArrayList) eventMethodCache [cacheKey];
230 if (eventMethodList == null) {
231 eventMethodList = new ArrayList ();
233 if (!SupportAutoEvents || !AutoEventWireup)
236 Type thisType = typeof (TemplateControl);
237 Type voidType = typeof (void);
238 Type [] DefaultParams = new Type [] {
240 typeof (EventArgs) };
242 for (int i = 0; i < methodNames.Length; i++) {
243 string methodName = methodNames [i];
245 bool noParams = false;
246 Type type = GetType ();
248 method = type.GetMethod (methodName, bflags, null, DefaultParams, null);
249 if (method != null) {
253 type = type.BaseType;
255 while (type != thisType);
257 if (method == null) {
260 method = type.GetMethod (methodName, bflags, null, Type.EmptyTypes, null);
261 if (method != null) {
266 type = type.BaseType;
268 while (type != thisType);
273 if (method.ReturnType != voidType)
276 eventMethodList.Add (new EventMethodMap ((LifeCycleEvent) i, method, noParams));
278 // We copy to not lock
280 Hashtable newEventMethodCache = eventMethodCache == null ? new Hashtable () : (Hashtable) eventMethodCache.Clone ();
281 newEventMethodCache [cacheKey] = eventMethodList;
282 EventMethodCache = newEventMethodCache;
285 foreach (EventMethodMap eventMethod in eventMethodList) {
286 EventHandler handler = eventMethod.NoParameters ?
287 new NoParamsInvoker (this, eventMethod.Method).FakeDelegate :
288 (EventHandler)Delegate.CreateDelegate (typeof (EventHandler), this, eventMethod.Method);
290 object eventKey = EventKeys [(int) eventMethod.EventKeyIndex];
292 Delegate existing = Events [eventKey];
293 if (existing != null && handler.Equals(existing))
296 switch (eventMethod.EventKeyIndex) {
297 case LifeCycleEvent.Init:
301 case LifeCycleEvent.PreInit:
302 ((Page)this).PreInit += handler;
304 case LifeCycleEvent.PreLoad:
305 ((Page) this).PreLoad += handler;
307 case LifeCycleEvent.LoadComplete:
308 ((Page) this).LoadComplete += handler;
310 case LifeCycleEvent.PreRenderComplete:
311 ((Page) this).PreRenderComplete += handler;
313 case LifeCycleEvent.SaveStateComplete:
314 ((Page) this).SaveStateComplete += handler;
316 case LifeCycleEvent.InitComplete:
317 ((Page) this).InitComplete += handler;
320 case LifeCycleEvent.Load:
323 case LifeCycleEvent.DataBinding:
324 DataBinding += handler;
326 case LifeCycleEvent.PreRender:
327 PreRender += handler;
329 case LifeCycleEvent.Disposed:
332 case LifeCycleEvent.Unload:
335 case LifeCycleEvent.Error:
338 case LifeCycleEvent.AbortTransaction:
339 AbortTransaction += handler;
341 case LifeCycleEvent.CommitTransaction:
342 CommitTransaction += handler;
348 [EditorBrowsable (EditorBrowsableState.Never)]
349 protected virtual void FrameworkInitialize ()
353 Type GetTypeFromControlPath (string virtualPath)
355 if (virtualPath == null)
356 throw new ArgumentNullException ("virtualPath");
358 string vpath = UrlUtils.Combine (TemplateSourceDirectory, virtualPath);
359 return PageMapper.GetObjectType (Context, vpath);
362 public Control LoadControl (string virtualPath)
365 if (virtualPath == null)
366 throw new ArgumentNullException ("virtualPath");
368 if (virtualPath == null)
369 throw new HttpException ("virtualPath is null");
371 Type type = GetTypeFromControlPath (virtualPath);
372 return LoadControl (type, null);
375 public Control LoadControl (Type type, object [] parameters)
377 object [] attrs = type.GetCustomAttributes (typeof (PartialCachingAttribute), true);
378 if (attrs != null && attrs.Length == 1) {
379 PartialCachingAttribute attr = (PartialCachingAttribute) attrs [0];
380 PartialCachingControl ctrl = new PartialCachingControl (type, parameters);
381 ctrl.VaryByParams = attr.VaryByParams;
382 ctrl.VaryByControls = attr.VaryByControls;
383 ctrl.VaryByCustom = attr.VaryByCustom;
387 object control = Activator.CreateInstance (type, parameters);
388 if (control is UserControl)
389 ((UserControl) control).InitializeAsUserControl (Page);
391 return (Control) control;
394 public ITemplate LoadTemplate (string virtualPath)
396 Type t = GetTypeFromControlPath (virtualPath);
397 return new SimpleTemplate (t);
400 protected virtual void OnAbortTransaction (EventArgs e)
402 EventHandler eh = Events [abortTransaction] as EventHandler;
407 protected virtual void OnCommitTransaction (EventArgs e)
409 EventHandler eh = Events [commitTransaction] as EventHandler;
414 protected virtual void OnError (EventArgs e)
416 EventHandler eh = Events [error] as EventHandler;
421 [MonoNotSupported ("Not supported")]
422 public Control ParseControl (string content)
424 throw new NotSupportedException ();
427 [MonoLimitation ("Always returns false")]
428 public virtual bool TestDeviceFilter (string filterName)
434 [EditorBrowsable (EditorBrowsableState.Never)]
435 public static object ReadStringResource (Type t)
440 [MonoTODO ("is this correct?")]
441 public Object ReadStringResource ()
443 return this.GetType ();
447 [EditorBrowsable (EditorBrowsableState.Never)]
448 protected void SetStringResourcePointer (object stringResourcePointer,
449 int maxResourceOffset)
451 if (GetResourceBytes (this.GetType ()) != null)
454 java.lang.Class c = vmw.common.TypeUtils.ToClass (stringResourcePointer);
455 java.lang.ClassLoader contextClassLoader = c.getClassLoader ();
457 //TODO:move this code to page mapper
458 string assemblyName = PageMapper.GetAssemblyResource (Context, VirtualPathUtility.ToAbsolute (AppRelativeVirtualPath));
459 if (assemblyName == null)
460 throw new HttpException (404, "The requested resource (" + this.AppRelativeVirtualPath + ") is not available.");
462 java.io.InputStream inputStream = contextClassLoader.getResourceAsStream (assemblyName);
464 System.IO.Stream strim = null;
465 if (inputStream == null) {
466 string descPath = String.Join ("/", new string [] { "assemblies", this.GetType ().Assembly.GetName ().Name, assemblyName });
468 strim = new StreamReader (HttpContext.Current.Request.MapPath ("/" + descPath)).BaseStream;
470 catch (Exception ex) {
471 throw new System.IO.IOException ("couldn't open resource file:" + assemblyName, ex);
474 throw new System.IO.IOException ("couldn't open resource file:" + assemblyName);
479 strim = (System.IO.Stream) vmw.common.IOUtils.getStream (inputStream);
480 int capacity = (int) strim.Length;
481 byte [] resourceBytes = new byte [capacity];
482 strim.Read (resourceBytes, 0, capacity);
483 SetResourceBytes (this.GetType (), resourceBytes);
485 catch (Exception e) {
486 throw new HttpException ("problem with dll.ghres file", e);
491 if (inputStream != null)
492 inputStream.close ();
497 [EditorBrowsable (EditorBrowsableState.Never)]
498 protected void WriteUTF8ResourceString (HtmlTextWriter output, int offset,
499 int size, bool fAsciiOnly)
501 string str = CachedString (this.GetType (), offset, size);
509 [WebSysDescription ("Raised when the user aborts a transaction.")]
510 public event EventHandler AbortTransaction
512 add { Events.AddHandler (abortTransaction, value); }
513 remove { Events.RemoveHandler (abortTransaction, value); }
516 [WebSysDescription ("Raised when the user initiates a transaction.")]
517 public event EventHandler CommitTransaction
519 add { Events.AddHandler (commitTransaction, value); }
520 remove { Events.RemoveHandler (commitTransaction, value); }
523 [WebSysDescription ("Raised when an exception occurs that cannot be handled.")]
524 public event EventHandler Error
526 add { Events.AddHandler (error, value); }
527 remove { Events.RemoveHandler (error, value); }
532 class SimpleTemplate : ITemplate
536 public SimpleTemplate (Type type)
541 public void InstantiateIn (Control control)
543 Control template = Activator.CreateInstance (type) as Control;
544 template.SetBindingContainer (false);
545 control.Controls.Add (template);
549 sealed private class CacheKey
552 readonly int _offset;
555 public CacheKey (Type type, int offset, int size)
562 public override int GetHashCode ()
564 return _type.GetHashCode () ^ _offset ^ _size;
567 public override bool Equals (object obj)
569 if (obj == null || !(obj is CacheKey))
572 CacheKey key = (CacheKey) obj;
573 return key._type == _type && key._offset == _offset && key._size == _size;
579 string _appRelativeVirtualPath = null;
581 public string AppRelativeVirtualPath
583 get { return _appRelativeVirtualPath; }
587 throw new ArgumentNullException ("value");
588 if (!UrlUtils.IsRooted (value) && !(value.Length > 0 && value [0] == '~'))
589 throw new ArgumentException ("The path that is set is not rooted");
590 _appRelativeVirtualPath = value;
592 int lastSlash = _appRelativeVirtualPath.LastIndexOf ('/');
593 AppRelativeTemplateSourceDirectory = (lastSlash > 0) ? _appRelativeVirtualPath.Substring (0, lastSlash + 1) : "~/";
597 internal override TemplateControl TemplateControlInternal {
601 protected internal object Eval (string expression)
603 return DataBinder.Eval (Page.GetDataItem (), expression);
606 protected internal string Eval (string expression, string format)
608 return DataBinder.Eval (Page.GetDataItem (), expression, format);
611 protected internal object XPath (string xpathexpression)
613 return XPathBinder.Eval (Page.GetDataItem (), xpathexpression);
616 protected internal object XPath (string xpathexpression, IXmlNamespaceResolver resolver)
618 return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, null, resolver);
621 protected internal string XPath (string xpathexpression, string format)
623 return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, format);
626 protected internal string XPath (string xpathexpression, string format, IXmlNamespaceResolver resolver)
628 return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, format, resolver);
631 protected internal IEnumerable XPathSelect (string xpathexpression)
633 return XPathBinder.Select (Page.GetDataItem (), xpathexpression);
636 protected internal IEnumerable XPathSelect (string xpathexpression, IXmlNamespaceResolver resolver)
638 return XPathBinder.Select (Page.GetDataItem (), xpathexpression, resolver);
641 protected object GetGlobalResourceObject (string className, string resourceKey)
643 return HttpContext.GetGlobalResourceObject (className, resourceKey);
646 protected object GetGlobalResourceObject (string className, string resourceKey, Type objType, string propName)
648 return ConvertResource (GetGlobalResourceObject (className, resourceKey), objType, propName);
651 protected Object GetLocalResourceObject (string resourceKey)
653 return HttpContext.GetLocalResourceObject (Context.Request.Path, resourceKey);
656 protected Object GetLocalResourceObject (string resourceKey, Type objType, string propName)
658 return ConvertResource (GetLocalResourceObject (resourceKey), objType, propName);
661 static Object ConvertResource (Object resource, Type objType, string propName) {
662 if (resource == null)
665 PropertyDescriptor pdesc = TypeDescriptor.GetProperties (objType) [propName];
669 TypeConverter converter = pdesc.Converter;
670 if (converter == null)
673 return resource is string ?
674 converter.ConvertFromInvariantString ((string) resource) :
675 converter.ConvertFrom (resource);