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 object abortTransaction = new object ();
42 static object commitTransaction = new object ();
43 static object error = new object ();
44 static string [] methodNames = { "Page_Init",
49 "Page_PreRenderComplete",
50 "Page_SaveStateComplete",
59 "Page_AbortTransaction",
60 "Page_CommitTransaction" };
62 const BindingFlags bflags = BindingFlags.Public |
63 BindingFlags.NonPublic |
64 BindingFlags.Instance;
65 static readonly Type [] NoParams = new Type [0];
67 private static string hashTableMutex = "lock"; //used to sync access ResourceHash property
68 private byte [] GetResourceBytes (Type type)
70 Hashtable table = (Hashtable) AppDomain.CurrentDomain.GetData ("TemplateControl.RES_BYTES");
74 return (byte []) table [type];
76 private void SetResourceBytes (Type type, byte [] bytes)
78 Hashtable table = (Hashtable) AppDomain.CurrentDomain.GetData ("TemplateControl.RES_BYTES");
80 table = new Hashtable ();
81 AppDomain.CurrentDomain.SetData ("TemplateControl.RES_BYTES", table);
87 private Hashtable ResourceHash
91 Hashtable table = (Hashtable) AppDomain.CurrentDomain.GetData ("TemplateControl.RES_STRING");
93 table = new Hashtable ();
94 AppDomain.CurrentDomain.SetData ("TemplateControl.RES_STRING", table);
100 AppDomain.CurrentDomain.SetData ("TemplateControl.RES_STRING", value);
104 private string CachedString (Type type, int offset, int size)
106 CacheKey key = new CacheKey (type, offset, size);
108 string strObj = (string) ResourceHash [key];
109 if (strObj == null) {
110 char [] tmp = System.Text.Encoding.UTF8.GetChars (GetResourceBytes (this.GetType ()), offset, size);
111 strObj = new string (tmp);
113 Hashtable tmpResourceHash = (Hashtable) ResourceHash.Clone ();
114 tmpResourceHash.Add (key, strObj);
115 ResourceHash = tmpResourceHash;
119 public virtual string TemplateSourceDirectory_Private
125 protected TemplateControl ()
133 [EditorBrowsable (EditorBrowsableState.Never)]
134 protected virtual int AutoHandlers
140 [EditorBrowsable (EditorBrowsableState.Never)]
141 protected virtual bool SupportAutoEvents
150 protected virtual void Construct ()
155 protected LiteralControl CreateResourceBasedLiteralControl (int offset,
159 string str = CachedString (this.GetType (), offset, size);
160 return new LiteralControl (str);
163 sealed class EventMethodMap
165 public EventMethodMap (EventInfo Event, MethodInfo Method, bool NoParameters)
168 this.Method = Method;
169 this.NoParameters = NoParameters;
172 public readonly EventInfo Event;
173 public readonly MethodInfo Method;
174 public readonly bool NoParameters;
177 // This hashtable cashes methods and events found in user code
178 const string eventMethodCacheKey = "eventMethodCacheKey";
179 static Hashtable EventMethodCache
181 get { return (Hashtable) AppDomain.CurrentDomain.GetData (eventMethodCacheKey); }
182 set { AppDomain.CurrentDomain.SetData (eventMethodCacheKey, value); }
185 internal void WireupAutomaticEvents ()
187 Type cacheKey = this.GetType ();
188 Hashtable eventMethodCache = EventMethodCache;
189 ArrayList eventMethodList = eventMethodCache == null ? null : (ArrayList) eventMethodCache [cacheKey];
191 if (eventMethodList == null) {
192 eventMethodList = new ArrayList ();
194 if (!SupportAutoEvents || !AutoEventWireup)
197 Type thisType = typeof (TemplateControl);
198 Type voidType = typeof (void);
199 Type [] DefaultParams = new Type [] {
201 typeof (EventArgs) };
203 foreach (string methodName in methodNames) {
205 bool noParams = false;
206 Type type = GetType ();
208 method = type.GetMethod (methodName, bflags, null, DefaultParams, null);
209 if (method != null) {
213 type = type.BaseType;
215 while (type != thisType);
217 if (method == null) {
220 method = type.GetMethod (methodName, bflags, null, NoParams, null);
221 if (method != null) {
226 type = type.BaseType;
228 while (type != thisType);
233 if (method.ReturnType != voidType)
236 int pos = methodName.IndexOf ("_");
237 string eventName = methodName.Substring (pos + 1);
238 EventInfo evt = GetType ().GetEvent (eventName);
240 /* This should never happen */
244 eventMethodList.Add (new EventMethodMap (evt, method, noParams));
246 if (method.DeclaringType != type) {
247 if (!method.IsPublic && !method.IsFamilyOrAssembly &&
248 !method.IsFamilyAndAssembly && !method.IsFamily)
253 // We copy to not lock
255 Hashtable newEventMethodCache = eventMethodCache == null ? new Hashtable () : (Hashtable) eventMethodCache.Clone ();
256 newEventMethodCache [cacheKey] = eventMethodList;
257 EventMethodCache = newEventMethodCache;
260 foreach (EventMethodMap eventMethod in eventMethodList) {
261 if (eventMethod.NoParameters) {
262 NoParamsInvoker npi = new NoParamsInvoker (this, eventMethod.Method);
263 eventMethod.Event.AddEventHandler (this, npi.FakeDelegate);
266 eventMethod.Event.AddEventHandler (this, Delegate.CreateDelegate (typeof (EventHandler), this, eventMethod.Method));
271 [EditorBrowsable (EditorBrowsableState.Never)]
272 protected virtual void FrameworkInitialize ()
276 Type GetTypeFromControlPath (string virtualPath)
278 if (virtualPath == null)
279 throw new ArgumentNullException ("virtualPath");
281 string vpath = UrlUtils.Combine (TemplateSourceDirectory, virtualPath);
282 return PageMapper.GetObjectType (Context, vpath);
285 public Control LoadControl (string virtualPath)
288 if (virtualPath == null)
289 throw new ArgumentNullException ("virtualPath");
291 if (virtualPath == null)
292 throw new HttpException ("virtualPath is null");
294 Type type = GetTypeFromControlPath (virtualPath);
295 return LoadControl (type, null);
298 public Control LoadControl (Type type, object [] parameters)
300 object [] attrs = type.GetCustomAttributes (typeof (PartialCachingAttribute), true);
301 if (attrs != null && attrs.Length == 1) {
302 PartialCachingAttribute attr = (PartialCachingAttribute) attrs [0];
303 PartialCachingControl ctrl = new PartialCachingControl (type, parameters);
304 ctrl.VaryByParams = attr.VaryByParams;
305 ctrl.VaryByControls = attr.VaryByControls;
306 ctrl.VaryByCustom = attr.VaryByCustom;
310 object control = Activator.CreateInstance (type, parameters);
311 if (control is UserControl)
312 ((UserControl) control).InitializeAsUserControl (Page);
314 return (Control) control;
317 public ITemplate LoadTemplate (string virtualPath)
319 Type t = GetTypeFromControlPath (virtualPath);
320 return new SimpleTemplate (t);
323 protected virtual void OnAbortTransaction (EventArgs e)
325 EventHandler eh = Events [abortTransaction] as EventHandler;
330 protected virtual void OnCommitTransaction (EventArgs e)
332 EventHandler eh = Events [commitTransaction] as EventHandler;
337 protected virtual void OnError (EventArgs e)
339 EventHandler eh = Events [error] as EventHandler;
344 [MonoNotSupported ("Not supported")]
345 public Control ParseControl (string content)
347 throw new NotSupportedException ();
350 [MonoLimitation ("Always returns false")]
351 public virtual bool TestDeviceFilter (string filterName)
357 [EditorBrowsable (EditorBrowsableState.Never)]
358 public static object ReadStringResource (Type t)
363 [MonoTODO ("is this correct?")]
364 public Object ReadStringResource ()
366 return this.GetType ();
370 [EditorBrowsable (EditorBrowsableState.Never)]
371 protected void SetStringResourcePointer (object stringResourcePointer,
372 int maxResourceOffset)
374 if (GetResourceBytes (this.GetType ()) != null)
377 java.lang.Class c = vmw.common.TypeUtils.ToClass (stringResourcePointer);
378 java.lang.ClassLoader contextClassLoader = c.getClassLoader ();
380 //TODO:move this code to page mapper
381 string assemblyName = PageMapper.GetAssemblyResource (Context, VirtualPathUtility.ToAbsolute (AppRelativeVirtualPath));
382 if (assemblyName == null)
383 throw new HttpException (404, "The requested resource (" + this.AppRelativeVirtualPath + ") is not available.");
385 java.io.InputStream inputStream = contextClassLoader.getResourceAsStream (assemblyName);
387 System.IO.Stream strim = null;
388 if (inputStream == null) {
389 string descPath = String.Join ("/", new string [] { "assemblies", this.GetType ().Assembly.GetName ().Name, assemblyName });
391 strim = new StreamReader (HttpContext.Current.Request.MapPath ("/" + descPath)).BaseStream;
393 catch (Exception ex) {
394 throw new System.IO.IOException ("couldn't open resource file:" + assemblyName, ex);
397 throw new System.IO.IOException ("couldn't open resource file:" + assemblyName);
402 strim = (System.IO.Stream) vmw.common.IOUtils.getStream (inputStream);
403 int capacity = (int) strim.Length;
404 byte [] resourceBytes = new byte [capacity];
405 strim.Read (resourceBytes, 0, capacity);
406 SetResourceBytes (this.GetType (), resourceBytes);
408 catch (Exception e) {
409 throw new HttpException ("problem with dll.ghres file", e);
414 if (inputStream != null)
415 inputStream.close ();
420 [EditorBrowsable (EditorBrowsableState.Never)]
421 protected void WriteUTF8ResourceString (HtmlTextWriter output, int offset,
422 int size, bool fAsciiOnly)
424 string str = CachedString (this.GetType (), offset, size);
432 [WebSysDescription ("Raised when the user aborts a transaction.")]
433 public event EventHandler AbortTransaction
435 add { Events.AddHandler (abortTransaction, value); }
436 remove { Events.RemoveHandler (abortTransaction, value); }
439 [WebSysDescription ("Raised when the user initiates a transaction.")]
440 public event EventHandler CommitTransaction
442 add { Events.AddHandler (commitTransaction, value); }
443 remove { Events.RemoveHandler (commitTransaction, value); }
446 [WebSysDescription ("Raised when an exception occurs that cannot be handled.")]
447 public event EventHandler Error
449 add { Events.AddHandler (error, value); }
450 remove { Events.RemoveHandler (error, value); }
455 class SimpleTemplate : ITemplate
459 public SimpleTemplate (Type type)
464 public void InstantiateIn (Control control)
466 Control template = Activator.CreateInstance (type) as Control;
467 template.SetBindingContainer (false);
468 control.Controls.Add (template);
472 sealed private class CacheKey
475 readonly int _offset;
478 public CacheKey (Type type, int offset, int size)
485 public override int GetHashCode ()
487 return _type.GetHashCode () ^ _offset ^ _size;
490 public override bool Equals (object obj)
492 if (obj == null || !(obj is CacheKey))
495 CacheKey key = (CacheKey) obj;
496 return key._type == _type && key._offset == _offset && key._size == _size;
502 string _appRelativeVirtualPath = null;
504 public string AppRelativeVirtualPath
506 get { return _appRelativeVirtualPath; }
510 throw new ArgumentNullException ("value");
511 if (!UrlUtils.IsRooted (value) && !(value.Length > 0 && value [0] == '~'))
512 throw new ArgumentException ("The path that is set is not rooted");
513 _appRelativeVirtualPath = value;
515 int lastSlash = _appRelativeVirtualPath.LastIndexOf ('/');
516 AppRelativeTemplateSourceDirectory = (lastSlash > 0) ? _appRelativeVirtualPath.Substring (0, lastSlash + 1) : "~/";
520 internal override TemplateControl TemplateControlInternal {
524 protected internal object Eval (string expression)
526 return DataBinder.Eval (Page.GetDataItem (), expression);
529 protected internal string Eval (string expression, string format)
531 return DataBinder.Eval (Page.GetDataItem (), expression, format);
534 protected internal object XPath (string xpathexpression)
536 return XPathBinder.Eval (Page.GetDataItem (), xpathexpression);
539 protected internal object XPath (string xpathexpression, IXmlNamespaceResolver resolver)
541 return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, null, resolver);
544 protected internal string XPath (string xpathexpression, string format)
546 return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, format);
549 protected internal string XPath (string xpathexpression, string format, IXmlNamespaceResolver resolver)
551 return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, format, resolver);
554 protected internal IEnumerable XPathSelect (string xpathexpression)
556 return XPathBinder.Select (Page.GetDataItem (), xpathexpression);
559 protected internal IEnumerable XPathSelect (string xpathexpression, IXmlNamespaceResolver resolver)
561 return XPathBinder.Select (Page.GetDataItem (), xpathexpression, resolver);
564 protected object GetGlobalResourceObject (string className, string resourceKey)
566 return HttpContext.GetGlobalResourceObject (className, resourceKey);
569 protected object GetGlobalResourceObject (string className, string resourceKey, Type objType, string propName)
571 return ConvertResource (GetGlobalResourceObject (className, resourceKey), objType, propName);
574 protected Object GetLocalResourceObject (string resourceKey)
576 return HttpContext.GetLocalResourceObject (Context.Request.Path, resourceKey);
579 protected Object GetLocalResourceObject (string resourceKey, Type objType, string propName)
581 return ConvertResource (GetLocalResourceObject (resourceKey), objType, propName);
584 static Object ConvertResource (Object resource, Type objType, string propName) {
585 if (resource == null)
588 PropertyDescriptor pdesc = TypeDescriptor.GetProperties (objType) [propName];
592 TypeConverter converter = pdesc.Converter;
593 if (converter == null)
596 return resource is string ?
597 converter.ConvertFromInvariantString ((string) resource) :
598 converter.ConvertFrom (resource);