* CssStyleCollection.cs: used ListDictionary instead of HybridDictionary as underlayi...
[mono.git] / mcs / class / System.Web / System.Web.UI / TemplateControl.jvm.cs
1 //
2 // (C) 2005 Mainsoft Corporation (http://www.mainsoft.com)
3 //
4
5 //
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:
13 //
14 // The above copyright notice and this permission notice shall be
15 // included in all copies or substantial portions of the Software.
16 //
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.
24 //
25
26 using System;
27 using System.Collections;
28 using System.ComponentModel;
29 using System.Reflection;
30 using System.Web;
31 using System.IO;
32 using System.Web.J2EE;
33 using System.Xml;
34 using vmw.common;
35 using System.Web.Util;
36
37 namespace System.Web.UI {
38
39         public abstract class TemplateControl : Control, INamingContainer
40         {
41                 static object abortTransaction = new object ();
42                 static object commitTransaction = new object ();
43                 static object error = new object ();
44                 static string [] methodNames = { "Page_Init",
45 #if NET_2_0
46                                                  "Page_PreInit",
47                                                  "Page_PreLoad",
48                                                  "Page_LoadComplete",
49                                                  "Page_PreRenderComplete",
50                                                  "Page_SaveStateComplete",
51                                                  "Page_InitComplete",
52 #endif
53                                                  "Page_Load",
54                                                  "Page_DataBind",
55                                                  "Page_PreRender",
56                                                  "Page_Disposed",
57                                                  "Page_Error",
58                                                  "Page_Unload",
59                                                  "Page_AbortTransaction",
60                                                  "Page_CommitTransaction" };
61
62                 const BindingFlags bflags = BindingFlags.Public |
63                                                 BindingFlags.NonPublic |
64                                                 BindingFlags.Instance;
65                 static readonly Type [] NoParams = new Type [0];
66
67                 private static string hashTableMutex = "lock"; //used to sync access ResourceHash property
68                 private byte [] GetResourceBytes (Type type)
69                 {
70                         Hashtable table = (Hashtable) AppDomain.CurrentDomain.GetData ("TemplateControl.RES_BYTES");
71                         if (table == null) {
72                                 return null;
73                         }
74                         return (byte []) table [type];
75                 }
76                 private void SetResourceBytes (Type type, byte [] bytes)
77                 {
78                         Hashtable table = (Hashtable) AppDomain.CurrentDomain.GetData ("TemplateControl.RES_BYTES");
79                         if (table == null) {
80                                 table = new Hashtable ();
81                                 AppDomain.CurrentDomain.SetData ("TemplateControl.RES_BYTES", table);
82                         }
83                         table [type] = bytes;
84                         return;
85                 }
86
87                 private Hashtable ResourceHash
88                 {
89                         get
90                         {
91                                 Hashtable table = (Hashtable) AppDomain.CurrentDomain.GetData ("TemplateControl.RES_STRING");
92                                 if (table == null) {
93                                         table = new Hashtable ();
94                                         AppDomain.CurrentDomain.SetData ("TemplateControl.RES_STRING", table);
95                                 }
96                                 return table;
97                         }
98                         set
99                         {
100                                 AppDomain.CurrentDomain.SetData ("TemplateControl.RES_STRING", value);
101                         }
102                 }
103
104                 private string CachedString (Type type, int offset, int size)
105                 {
106                         CacheKey key = new CacheKey (type, offset, size);
107
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);
112
113                                 Hashtable tmpResourceHash = (Hashtable) ResourceHash.Clone ();
114                                 tmpResourceHash.Add (key, strObj);
115                                 ResourceHash = tmpResourceHash;
116                         }
117                         return strObj;
118                 }
119                 public virtual string TemplateSourceDirectory_Private
120                 {
121                         get { return null; }
122                 }
123
124                 #region Constructor
125                 protected TemplateControl ()
126                 {
127                         Construct ();
128                 }
129
130                 #endregion
131
132                 #region Properties
133                 [EditorBrowsable (EditorBrowsableState.Never)]
134                 protected virtual int AutoHandlers
135                 {
136                         get { return 0; }
137                         set { }
138                 }
139
140                 [EditorBrowsable (EditorBrowsableState.Never)]
141                 protected virtual bool SupportAutoEvents
142                 {
143                         get { return true; }
144                 }
145
146                 #endregion
147
148                 #region Methods
149
150                 protected virtual void Construct ()
151                 {
152                 }
153
154                 [MonoTODO]
155                 protected LiteralControl CreateResourceBasedLiteralControl (int offset,
156                                                                                         int size,
157                                                                                         bool fAsciiOnly)
158                 {
159                         string str = CachedString (this.GetType (), offset, size);
160                         return new LiteralControl (str);
161                 }
162
163                 sealed class EventMethodMap
164                 {
165                         public EventMethodMap (EventInfo Event, MethodInfo Method, bool NoParameters)
166                         {
167                                 this.Event = Event;
168                                 this.Method = Method;
169                                 this.NoParameters = NoParameters;
170                         }
171
172                         public readonly EventInfo Event;
173                         public readonly MethodInfo Method;
174                         public readonly bool NoParameters;
175                 }
176
177                 // This hashtable cashes methods and events found in user code
178                 const string eventMethodCacheKey = "eventMethodCacheKey";
179                 static Hashtable EventMethodCache
180                 {
181                         get { return (Hashtable) AppDomain.CurrentDomain.GetData (eventMethodCacheKey); }
182                         set { AppDomain.CurrentDomain.SetData (eventMethodCacheKey, value); }
183                 }
184
185                 internal void WireupAutomaticEvents ()
186                 {
187                         Type cacheKey = this.GetType ();
188                         Hashtable eventMethodCache = EventMethodCache;
189                         ArrayList eventMethodList = eventMethodCache == null ? null : (ArrayList) eventMethodCache [cacheKey];
190
191                         if (eventMethodList == null) {
192                                 eventMethodList = new ArrayList ();
193
194                                 if (!SupportAutoEvents || !AutoEventWireup)
195                                         return;
196
197                                 Type thisType = typeof (TemplateControl);
198                                 Type voidType = typeof (void);
199                                 Type [] DefaultParams = new Type [] {
200                                 typeof (object),
201                                 typeof (EventArgs) };
202
203                                 foreach (string methodName in methodNames) {
204                                         MethodInfo method;
205                                         bool noParams = false;
206                                         Type type = GetType ();
207                                         do {
208                                                 method = type.GetMethod (methodName, bflags, null, DefaultParams, null);
209                                                 if (method != null) {
210                                                         break;
211                                                 }
212
213                                                 type = type.BaseType;
214                                         }
215                                         while (type != thisType);
216
217                                         if (method == null) {
218                                                 type = GetType ();
219                                                 do {
220                                                         method = type.GetMethod (methodName, bflags, null, NoParams, null);
221                                                         if (method != null) {
222                                                                 noParams = true;
223                                                                 break;
224                                                         }
225
226                                                         type = type.BaseType;
227                                                 }
228                                                 while (type != thisType);
229
230                                                 if (method == null)
231                                                         continue;
232                                         }
233                                         if (method.ReturnType != voidType)
234                                                 continue;
235
236                                         int pos = methodName.IndexOf ("_");
237                                         string eventName = methodName.Substring (pos + 1);
238                                         EventInfo evt = GetType ().GetEvent (eventName);
239                                         if (evt == null) {
240                                                 /* This should never happen */
241                                                 continue;
242                                         }
243
244                                         eventMethodList.Add (new EventMethodMap (evt, method, noParams));
245 #if ONLY_1_1
246                                 if (method.DeclaringType != type) {
247                                         if (!method.IsPublic && !method.IsFamilyOrAssembly &&
248                                             !method.IsFamilyAndAssembly && !method.IsFamily)
249                                                 continue;
250                                 }
251 #endif
252                                 }
253                                 // We copy to not lock
254
255                                 Hashtable newEventMethodCache = eventMethodCache == null ? new Hashtable () : (Hashtable) eventMethodCache.Clone ();
256                                 newEventMethodCache [cacheKey] = eventMethodList;
257                                 EventMethodCache = newEventMethodCache;
258                         }
259
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);
264                                 }
265                                 else {
266                                         eventMethod.Event.AddEventHandler (this, Delegate.CreateDelegate (typeof (EventHandler), this, eventMethod.Method));
267                                 }
268                         }
269                 }
270
271                 [EditorBrowsable (EditorBrowsableState.Never)]
272                 protected virtual void FrameworkInitialize ()
273                 {
274                 }
275
276                 Type GetTypeFromControlPath (string virtualPath)
277                 {
278                         if (virtualPath == null)
279                                 throw new ArgumentNullException ("virtualPath");
280
281                         string vpath = UrlUtils.Combine (TemplateSourceDirectory, virtualPath);
282                         return PageMapper.GetObjectType (Context, vpath);
283                 }
284
285                 public Control LoadControl (string virtualPath)
286                 {
287 #if NET_2_0
288                         if (virtualPath == null)
289                                 throw new ArgumentNullException ("virtualPath");
290 #else
291                         if (virtualPath == null)
292                                 throw new HttpException ("virtualPath is null");
293 #endif
294                         Type type = GetTypeFromControlPath (virtualPath);
295                         return LoadControl (type, null);
296                 }
297
298                 public Control LoadControl (Type type, object [] parameters)
299                 {
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;
307                                 return ctrl;
308                         }
309
310                         object control = Activator.CreateInstance (type, parameters);
311                         if (control is UserControl)
312                                 ((UserControl) control).InitializeAsUserControl (Page);
313
314                         return (Control) control;
315                 }
316
317                 public ITemplate LoadTemplate (string virtualPath)
318                 {
319                         Type t = GetTypeFromControlPath (virtualPath);
320                         return new SimpleTemplate (t);
321                 }
322
323                 protected virtual void OnAbortTransaction (EventArgs e)
324                 {
325                         EventHandler eh = Events [abortTransaction] as EventHandler;
326                         if (eh != null)
327                                 eh (this, e);
328                 }
329
330                 protected virtual void OnCommitTransaction (EventArgs e)
331                 {
332                         EventHandler eh = Events [commitTransaction] as EventHandler;
333                         if (eh != null)
334                                 eh (this, e);
335                 }
336
337                 protected virtual void OnError (EventArgs e)
338                 {
339                         EventHandler eh = Events [error] as EventHandler;
340                         if (eh != null)
341                                 eh (this, e);
342                 }
343
344                 [MonoNotSupported ("Not supported")]
345                 public Control ParseControl (string content)
346                 {
347                         throw new NotSupportedException ();
348                 }
349
350                 [MonoLimitation ("Always returns false")]
351                 public virtual bool TestDeviceFilter (string filterName)
352                 {
353                         return false;
354                 }
355
356                 [MonoTODO]
357                 [EditorBrowsable (EditorBrowsableState.Never)]
358                 public static object ReadStringResource (Type t)
359                 {
360                         return t;
361                 }
362 #if NET_2_0
363                 [MonoTODO ("is this correct?")]
364                 public Object ReadStringResource ()
365                 {
366                         return this.GetType ();
367                 }
368 #endif
369                 [MonoTODO]
370                 [EditorBrowsable (EditorBrowsableState.Never)]
371                 protected void SetStringResourcePointer (object stringResourcePointer,
372                                                          int maxResourceOffset)
373                 {
374                         if (GetResourceBytes (this.GetType ()) != null)
375                                 return;
376
377                         java.lang.Class c = vmw.common.TypeUtils.ToClass (stringResourcePointer);
378                         java.lang.ClassLoader contextClassLoader = c.getClassLoader ();
379
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.");
384
385                         java.io.InputStream inputStream = contextClassLoader.getResourceAsStream (assemblyName);
386
387                         System.IO.Stream strim = null;
388                         if (inputStream == null) {
389                                 string descPath = String.Join ("/", new string [] { "assemblies", this.GetType ().Assembly.GetName ().Name, assemblyName });
390                                 try {
391                                         strim = new StreamReader (HttpContext.Current.Request.MapPath ("/" + descPath)).BaseStream;
392                                 }
393                                 catch (Exception ex) {
394                                         throw new System.IO.IOException ("couldn't open resource file:" + assemblyName, ex);
395                                 }
396                                 if (strim == null)
397                                         throw new System.IO.IOException ("couldn't open resource file:" + assemblyName);
398                         }
399
400                         try {
401                                 if (strim == null)
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);
407                         }
408                         catch (Exception e) {
409                                 throw new HttpException ("problem with dll.ghres file", e);
410                         }
411                         finally {
412                                 if (strim != null)
413                                         strim.Close ();
414                                 if (inputStream != null)
415                                         inputStream.close ();
416                         }
417                 }
418
419                 [MonoTODO]
420                 [EditorBrowsable (EditorBrowsableState.Never)]
421                 protected void WriteUTF8ResourceString (HtmlTextWriter output, int offset,
422                                                         int size, bool fAsciiOnly)
423                 {
424                         string str = CachedString (this.GetType (), offset, size);
425                         output.Write (str);
426                 }
427
428                 #endregion
429
430                 #region Events
431
432                 [WebSysDescription ("Raised when the user aborts a transaction.")]
433                 public event EventHandler AbortTransaction
434                 {
435                         add { Events.AddHandler (abortTransaction, value); }
436                         remove { Events.RemoveHandler (abortTransaction, value); }
437                 }
438
439                 [WebSysDescription ("Raised when the user initiates a transaction.")]
440                 public event EventHandler CommitTransaction
441                 {
442                         add { Events.AddHandler (commitTransaction, value); }
443                         remove { Events.RemoveHandler (commitTransaction, value); }
444                 }
445
446                 [WebSysDescription ("Raised when an exception occurs that cannot be handled.")]
447                 public event EventHandler Error
448                 {
449                         add { Events.AddHandler (error, value); }
450                         remove { Events.RemoveHandler (error, value); }
451                 }
452
453                 #endregion
454
455                 class SimpleTemplate : ITemplate
456                 {
457                         Type type;
458
459                         public SimpleTemplate (Type type)
460                         {
461                                 this.type = type;
462                         }
463
464                         public void InstantiateIn (Control control)
465                         {
466                                 Control template = Activator.CreateInstance (type) as Control;
467                                 template.SetBindingContainer (false);
468                                 control.Controls.Add (template);
469                         }
470                 }
471
472                 sealed private class CacheKey
473                 {
474                         readonly Type _type;
475                         readonly int _offset;
476                         readonly int _size;
477
478                         public CacheKey (Type type, int offset, int size)
479                         {
480                                 _type = type;
481                                 _offset = offset;
482                                 _size = size;
483                         }
484
485                         public override int GetHashCode ()
486                         {
487                                 return _type.GetHashCode () ^ _offset ^ _size;
488                         }
489
490                         public override bool Equals (object obj)
491                         {
492                                 if (obj == null || !(obj is CacheKey))
493                                         return false;
494
495                                 CacheKey key = (CacheKey) obj;
496                                 return key._type == _type && key._offset == _offset && key._size == _size;
497                         }
498                 }
499
500 #if NET_2_0
501
502                 string _appRelativeVirtualPath = null;
503
504                 public string AppRelativeVirtualPath
505                 {
506                         get { return _appRelativeVirtualPath; }
507                         set
508                         {
509                                 if (value == null)
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;
514
515                                 int lastSlash = _appRelativeVirtualPath.LastIndexOf ('/');
516                                 AppRelativeTemplateSourceDirectory = (lastSlash > 0) ? _appRelativeVirtualPath.Substring (0, lastSlash + 1) : "~/";
517                         }
518                 }
519
520                 internal override TemplateControl TemplateControlInternal {
521                         get { return this; }
522                 }
523
524                 protected internal object Eval (string expression)
525                 {
526                         return DataBinder.Eval (Page.GetDataItem (), expression);
527                 }
528
529                 protected internal string Eval (string expression, string format)
530                 {
531                         return DataBinder.Eval (Page.GetDataItem (), expression, format);
532                 }
533
534                 protected internal object XPath (string xpathexpression)
535                 {
536                         return XPathBinder.Eval (Page.GetDataItem (), xpathexpression);
537                 }
538
539                 protected internal object XPath (string xpathexpression, IXmlNamespaceResolver resolver)
540                 {
541                         return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, null, resolver);
542                 }
543
544                 protected internal string XPath (string xpathexpression, string format)
545                 {
546                         return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, format);
547                 }
548
549                 protected internal string XPath (string xpathexpression, string format, IXmlNamespaceResolver resolver)
550                 {
551                         return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, format, resolver);
552                 }
553
554                 protected internal IEnumerable XPathSelect (string xpathexpression)
555                 {
556                         return XPathBinder.Select (Page.GetDataItem (), xpathexpression);
557                 }
558
559                 protected internal IEnumerable XPathSelect (string xpathexpression, IXmlNamespaceResolver resolver)
560                 {
561                         return XPathBinder.Select (Page.GetDataItem (), xpathexpression, resolver);
562                 }
563
564                 protected object GetGlobalResourceObject (string className, string resourceKey)
565                 {
566                         return HttpContext.GetGlobalResourceObject (className, resourceKey);
567                 }
568
569                 protected object GetGlobalResourceObject (string className, string resourceKey, Type objType, string propName)
570                 {
571                         return ConvertResource (GetGlobalResourceObject (className, resourceKey), objType, propName);
572                 }
573
574                 protected Object GetLocalResourceObject (string resourceKey)
575                 {
576                         return HttpContext.GetLocalResourceObject (Context.Request.Path, resourceKey);
577                 }
578
579                 protected Object GetLocalResourceObject (string resourceKey, Type objType, string propName)
580                 {
581                         return ConvertResource (GetLocalResourceObject (resourceKey), objType, propName);
582                 }
583
584                 static Object ConvertResource (Object resource, Type objType, string propName) {
585                         if (resource == null)
586                                 return resource;
587
588                         PropertyDescriptor pdesc = TypeDescriptor.GetProperties (objType) [propName];
589                         if (pdesc == null)
590                                 return resource;
591
592                         TypeConverter converter = pdesc.Converter;
593                         if (converter == null)
594                                 return resource;
595
596                         return resource is string ?
597                                 converter.ConvertFromInvariantString ((string) resource) :
598                                 converter.ConvertFrom (resource);
599                 }
600
601 #endif
602
603         }
604 }