importing messaging-2008 branch to trunk.
[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 using System.Collections.Generic;
37
38 namespace System.Web.UI {
39
40         public abstract class TemplateControl : Control, INamingContainer
41         {
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",
46 #if NET_2_0
47                                                  "Page_PreInit",
48                                                  "Page_PreLoad",
49                                                  "Page_LoadComplete",
50                                                  "Page_PreRenderComplete",
51                                                  "Page_SaveStateComplete",
52                                                  "Page_InitComplete",
53 #endif
54                                                  "Page_Load",
55                                                  "Page_DataBind",
56                                                  "Page_PreRender",
57                                                  "Page_Disposed",
58                                                  "Page_Unload",
59                                                  "Page_Error",
60                                                  "Page_AbortTransaction",
61                                                  "Page_CommitTransaction" };
62
63                 static readonly object [] EventKeys = {
64                                                  Control.InitEvent,
65 #if NET_2_0
66                                                  Page.PreInitEvent,
67                                                  Page.PreLoadEvent,
68                                                  Page.LoadCompleteEvent,
69                                                  Page.PreRenderCompleteEvent,
70                                                  Page.SaveStateCompleteEvent,
71                                                  Page.InitCompleteEvent,
72 #endif
73                                                 Control.LoadEvent,
74                                                 Control.DataBindingEvent,
75                                                 Control.PreRenderEvent,
76                                                 Control.DisposedEvent,
77                                                 Control.UnloadEvent,
78                                                 error,
79                                                 abortTransaction,
80                                                 commitTransaction
81                 };
82
83                 enum LifeCycleEvent
84                 {
85                         Init,
86 #if NET_2_0
87                         PreInit,
88                         PreLoad,
89                         LoadComplete,
90                         PreRenderComplete,
91                         SaveStateComplete,
92                         InitComplete,
93 #endif
94                         Load,
95                         DataBinding,
96                         PreRender,
97                         Disposed,
98                         Unload,
99                         Error,
100                         AbortTransaction,
101                         CommitTransaction
102                 }
103
104                 const BindingFlags bflags = BindingFlags.Public |
105                                                 BindingFlags.NonPublic |
106                                                 BindingFlags.Instance;
107
108                 byte [] GetResourceBytes (Type type)
109                 {
110                         Hashtable table = (Hashtable) AppDomain.CurrentDomain.GetData ("TemplateControl.RES_BYTES");
111                         if (table == null) {
112                                 return null;
113                         }
114                         return (byte []) table [type];
115                 }
116                 void SetResourceBytes (Type type, byte [] bytes)
117                 {
118                         Hashtable table = (Hashtable) AppDomain.CurrentDomain.GetData ("TemplateControl.RES_BYTES");
119                         if (table == null) {
120                                 table = new Hashtable ();
121                                 AppDomain.CurrentDomain.SetData ("TemplateControl.RES_BYTES", table);
122                         }
123                         table [type] = bytes;
124                         return;
125                 }
126
127                 Hashtable ResourceHash
128                 {
129                         get
130                         {
131                                 Hashtable table = (Hashtable) AppDomain.CurrentDomain.GetData ("TemplateControl.RES_STRING");
132                                 if (table == null) {
133                                         table = new Hashtable ();
134                                         AppDomain.CurrentDomain.SetData ("TemplateControl.RES_STRING", table);
135                                 }
136                                 return table;
137                         }
138                         set
139                         {
140                                 AppDomain.CurrentDomain.SetData ("TemplateControl.RES_STRING", value);
141                         }
142                 }
143
144                 string CachedString (Type type, int offset, int size)
145                 {
146                         CacheKey key = new CacheKey (type, offset, size);
147
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);
152
153                                 Hashtable tmpResourceHash = (Hashtable) ResourceHash.Clone ();
154                                 tmpResourceHash.Add (key, strObj);
155                                 ResourceHash = tmpResourceHash;
156                         }
157                         return strObj;
158                 }
159                 public virtual string TemplateSourceDirectory_Private
160                 {
161                         get { return null; }
162                 }
163
164                 #region Constructor
165                 protected TemplateControl ()
166                 {
167                         Construct ();
168                 }
169
170                 #endregion
171
172                 #region Properties
173                 [EditorBrowsable (EditorBrowsableState.Never)]
174                 protected virtual int AutoHandlers
175                 {
176                         get { return 0; }
177                         set { }
178                 }
179
180                 [EditorBrowsable (EditorBrowsableState.Never)]
181                 protected virtual bool SupportAutoEvents
182                 {
183                         get { return true; }
184                 }
185
186                 #endregion
187
188                 #region Methods
189
190                 protected virtual void Construct ()
191                 {
192                 }
193
194                 [MonoTODO]
195                 protected LiteralControl CreateResourceBasedLiteralControl (int offset,
196                                                                                         int size,
197                                                                                         bool fAsciiOnly)
198                 {
199                         string str = CachedString (this.GetType (), offset, size);
200                         return new LiteralControl (str);
201                 }
202
203                 sealed class EventMethodMap
204                 {
205                         public EventMethodMap (LifeCycleEvent EventKeyIndex, MethodInfo Method, bool NoParameters)
206                         {
207                                 this.EventKeyIndex = EventKeyIndex;
208                                 this.Method = Method;
209                                 this.NoParameters = NoParameters;
210                         }
211
212                         public readonly LifeCycleEvent EventKeyIndex;
213                         public readonly MethodInfo Method;
214                         public readonly bool NoParameters;
215                 }
216
217                 // This hashtable cashes methods and events found in user code
218                 const string eventMethodCacheKey = "eventMethodCacheKey";
219                 static Hashtable EventMethodCache
220                 {
221                         get { return (Hashtable) AppDomain.CurrentDomain.GetData (eventMethodCacheKey); }
222                         set { AppDomain.CurrentDomain.SetData (eventMethodCacheKey, value); }
223                 }
224
225                 internal void WireupAutomaticEvents ()
226                 {
227                         Type cacheKey = this.GetType ();
228                         Hashtable eventMethodCache = EventMethodCache;
229                         ArrayList eventMethodList = eventMethodCache == null ? null : (ArrayList) eventMethodCache [cacheKey];
230
231                         if (eventMethodList == null) {
232                                 eventMethodList = new ArrayList ();
233
234                                 if (!SupportAutoEvents || !AutoEventWireup)
235                                         return;
236
237                                 Type thisType = typeof (TemplateControl);
238                                 Type voidType = typeof (void);
239                                 Type [] DefaultParams = new Type [] {
240                                 typeof (object),
241                                 typeof (EventArgs) };
242
243                 LifeCycleEvent[] _pageEvents = new LifeCycleEvent[] { 
244                     LifeCycleEvent.PreInit,
245                     LifeCycleEvent.PreLoad,
246                     LifeCycleEvent.LoadComplete,
247                     LifeCycleEvent.PreRenderComplete,
248                     LifeCycleEvent.SaveStateComplete,
249                     LifeCycleEvent.InitComplete
250                 };
251                 List<LifeCycleEvent> pageEvents = new List<LifeCycleEvent>(_pageEvents);
252
253                 bool isPage = Page.GetType().IsAssignableFrom(GetType());
254
255                                 for (int i = 0; i < methodNames.Length; i++) {
256                     
257                     // Don't look for page-only events in non-page controls.
258                     if (!isPage && pageEvents.Contains((LifeCycleEvent)i))
259                         continue;
260
261                                         string methodName = methodNames [i];
262                                         MethodInfo method;
263                                         bool noParams = false;
264                                         Type type = GetType ();
265                                         do {
266                                                 method = type.GetMethod (methodName, bflags, null, DefaultParams, null);
267                                                 if (method != null) {
268                                                         break;
269                                                 }
270
271                                                 type = type.BaseType;
272                                         }
273                                         while (type != thisType);
274
275                                         if (method == null) {
276                                                 type = GetType ();
277                                                 do {
278                                                         method = type.GetMethod (methodName, bflags, null, Type.EmptyTypes, null);
279                                                         if (method != null) {
280                                                                 noParams = true;
281                                                                 break;
282                                                         }
283
284                                                         type = type.BaseType;
285                                                 }
286                                                 while (type != thisType);
287
288                                                 if (method == null)
289                                                         continue;
290                                         }
291                                         if (method.ReturnType != voidType)
292                                                 continue;
293
294                                         eventMethodList.Add (new EventMethodMap ((LifeCycleEvent) i, method, noParams));
295                                 }
296                                 // We copy to not lock
297
298                                 Hashtable newEventMethodCache = eventMethodCache == null ? new Hashtable () : (Hashtable) eventMethodCache.Clone ();
299                                 newEventMethodCache [cacheKey] = eventMethodList;
300                                 EventMethodCache = newEventMethodCache;
301                         }
302
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);
307
308                                 object eventKey = EventKeys [(int) eventMethod.EventKeyIndex];
309
310                                 Delegate existing = Events [eventKey];
311                                 if (existing != null && handler.Equals(existing))
312                                         continue;
313
314                                 switch (eventMethod.EventKeyIndex) {
315                                 case LifeCycleEvent.Init:
316                                         Init += handler;
317                                         break;
318 #if NET_2_0
319                                 case LifeCycleEvent.PreInit:
320                                         ((Page)this).PreInit += handler;
321                                         break;
322                                 case LifeCycleEvent.PreLoad:
323                                         ((Page) this).PreLoad += handler;
324                                         break;
325                                 case LifeCycleEvent.LoadComplete:
326                                         ((Page) this).LoadComplete += handler;
327                                         break;
328                                 case LifeCycleEvent.PreRenderComplete:
329                                         ((Page) this).PreRenderComplete += handler;
330                                         break;
331                                 case LifeCycleEvent.SaveStateComplete:
332                                         ((Page) this).SaveStateComplete += handler;
333                                         break;
334                                 case LifeCycleEvent.InitComplete:
335                                         ((Page) this).InitComplete += handler;
336                                         break;
337 #endif
338                                 case LifeCycleEvent.Load:
339                                         Load += handler;
340                                         break;
341                                 case LifeCycleEvent.DataBinding:
342                                         DataBinding += handler;
343                                         break;
344                                 case LifeCycleEvent.PreRender:
345                                         PreRender += handler;
346                                         break;
347                                 case LifeCycleEvent.Disposed:
348                                         Disposed += handler;
349                                         break;
350                                 case LifeCycleEvent.Unload:
351                                         Unload += handler;
352                                         break;
353                                 case LifeCycleEvent.Error:
354                                         Error += handler;
355                                         break;
356                                 case LifeCycleEvent.AbortTransaction:
357                                         AbortTransaction += handler;
358                                         break;
359                                 case LifeCycleEvent.CommitTransaction:
360                                         CommitTransaction += handler;
361                                         break;
362                                 }
363                         }
364                 }
365
366                 [EditorBrowsable (EditorBrowsableState.Never)]
367                 protected virtual void FrameworkInitialize ()
368                 {
369                 }
370
371                 Type GetTypeFromControlPath (string virtualPath)
372                 {
373                         if (virtualPath == null)
374                                 throw new ArgumentNullException ("virtualPath");
375
376                         string vpath = UrlUtils.Combine (TemplateSourceDirectory, virtualPath);
377                         return PageMapper.GetObjectType (Context, vpath);
378                 }
379
380                 public Control LoadControl (string virtualPath)
381                 {
382 #if NET_2_0
383                         if (virtualPath == null)
384                                 throw new ArgumentNullException ("virtualPath");
385 #else
386                         if (virtualPath == null)
387                                 throw new HttpException ("virtualPath is null");
388 #endif
389                         Type type = GetTypeFromControlPath (virtualPath);
390                         return LoadControl (type, null);
391                 }
392
393                 public Control LoadControl (Type type, object [] parameters)
394                 {
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;
402                                 return ctrl;
403                         }
404
405                         object control = Activator.CreateInstance (type, parameters);
406                         if (control is UserControl)
407                                 ((UserControl) control).InitializeAsUserControl (Page);
408
409                         return (Control) control;
410                 }
411
412                 public ITemplate LoadTemplate (string virtualPath)
413                 {
414                         Type t = GetTypeFromControlPath (virtualPath);
415                         return new SimpleTemplate (t);
416                 }
417
418                 protected virtual void OnAbortTransaction (EventArgs e)
419                 {
420                         EventHandler eh = Events [abortTransaction] as EventHandler;
421                         if (eh != null)
422                                 eh (this, e);
423                 }
424
425                 protected virtual void OnCommitTransaction (EventArgs e)
426                 {
427                         EventHandler eh = Events [commitTransaction] as EventHandler;
428                         if (eh != null)
429                                 eh (this, e);
430                 }
431
432                 protected virtual void OnError (EventArgs e)
433                 {
434                         EventHandler eh = Events [error] as EventHandler;
435                         if (eh != null)
436                                 eh (this, e);
437                 }
438
439                 [MonoNotSupported ("Not supported")]
440                 public Control ParseControl (string content)
441                 {
442                         throw new NotSupportedException ();
443                 }
444
445                 [MonoLimitation ("Always returns false")]
446                 public virtual bool TestDeviceFilter (string filterName)
447                 {
448                         return false;
449                 }
450
451                 [MonoTODO]
452                 [EditorBrowsable (EditorBrowsableState.Never)]
453                 public static object ReadStringResource (Type t)
454                 {
455                         return t;
456                 }
457 #if NET_2_0
458                 [MonoTODO ("is this correct?")]
459                 public Object ReadStringResource ()
460                 {
461                         return this.GetType ();
462                 }
463 #endif
464                 [MonoTODO]
465                 [EditorBrowsable (EditorBrowsableState.Never)]
466                 protected void SetStringResourcePointer (object stringResourcePointer,
467                                                          int maxResourceOffset)
468                 {
469                         if (GetResourceBytes (this.GetType ()) != null)
470                                 return;
471
472                         java.lang.Class c = vmw.common.TypeUtils.ToClass (stringResourcePointer);
473                         java.lang.ClassLoader contextClassLoader = c.getClassLoader ();
474
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.");
479
480                         java.io.InputStream inputStream = contextClassLoader.getResourceAsStream (assemblyName);
481
482                         System.IO.Stream strim = null;
483                         if (inputStream == null) {
484                                 string descPath = String.Join ("/", new string [] { "assemblies", this.GetType ().Assembly.GetName ().Name, assemblyName });
485                                 try {
486                                         strim = new StreamReader (HttpContext.Current.Request.MapPath ("/" + descPath)).BaseStream;
487                                 }
488                                 catch (Exception ex) {
489                                         throw new System.IO.IOException ("couldn't open resource file:" + assemblyName, ex);
490                                 }
491                                 if (strim == null)
492                                         throw new System.IO.IOException ("couldn't open resource file:" + assemblyName);
493                         }
494
495                         try {
496                                 if (strim == null)
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);
502                         }
503                         catch (Exception e) {
504                                 throw new HttpException ("problem with dll.ghres file", e);
505                         }
506                         finally {
507                                 if (strim != null)
508                                         strim.Close ();
509                                 if (inputStream != null)
510                                         inputStream.close ();
511                         }
512                 }
513
514                 [MonoTODO]
515                 [EditorBrowsable (EditorBrowsableState.Never)]
516                 protected void WriteUTF8ResourceString (HtmlTextWriter output, int offset,
517                                                         int size, bool fAsciiOnly)
518                 {
519                         string str = CachedString (this.GetType (), offset, size);
520                         output.Write (str);
521                 }
522
523                 #endregion
524
525                 #region Events
526
527                 [WebSysDescription ("Raised when the user aborts a transaction.")]
528                 public event EventHandler AbortTransaction
529                 {
530                         add { Events.AddHandler (abortTransaction, value); }
531                         remove { Events.RemoveHandler (abortTransaction, value); }
532                 }
533
534                 [WebSysDescription ("Raised when the user initiates a transaction.")]
535                 public event EventHandler CommitTransaction
536                 {
537                         add { Events.AddHandler (commitTransaction, value); }
538                         remove { Events.RemoveHandler (commitTransaction, value); }
539                 }
540
541                 [WebSysDescription ("Raised when an exception occurs that cannot be handled.")]
542                 public event EventHandler Error
543                 {
544                         add { Events.AddHandler (error, value); }
545                         remove { Events.RemoveHandler (error, value); }
546                 }
547
548                 #endregion
549
550                 class SimpleTemplate : ITemplate
551                 {
552                         Type type;
553
554                         public SimpleTemplate (Type type)
555                         {
556                                 this.type = type;
557                         }
558
559                         public void InstantiateIn (Control control)
560                         {
561                                 Control template = Activator.CreateInstance (type) as Control;
562                                 template.SetBindingContainer (false);
563                                 control.Controls.Add (template);
564                         }
565                 }
566
567                 sealed class CacheKey
568                 {
569                         readonly Type _type;
570                         readonly int _offset;
571                         readonly int _size;
572
573                         public CacheKey (Type type, int offset, int size)
574                         {
575                                 _type = type;
576                                 _offset = offset;
577                                 _size = size;
578                         }
579
580                         public override int GetHashCode ()
581                         {
582                                 return _type.GetHashCode () ^ _offset ^ _size;
583                         }
584
585                         public override bool Equals (object obj)
586                         {
587                                 if (obj == null || !(obj is CacheKey))
588                                         return false;
589
590                                 CacheKey key = (CacheKey) obj;
591                                 return key._type == _type && key._offset == _offset && key._size == _size;
592                         }
593                 }
594
595 #if NET_2_0
596
597                 string _appRelativeVirtualPath = null;
598
599                 public string AppRelativeVirtualPath
600                 {
601                         get { return _appRelativeVirtualPath; }
602                         set
603                         {
604                                 if (value == null)
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;
609
610                                 int lastSlash = _appRelativeVirtualPath.LastIndexOf ('/');
611                                 AppRelativeTemplateSourceDirectory = (lastSlash > 0) ? _appRelativeVirtualPath.Substring (0, lastSlash + 1) : "~/";
612                         }
613                 }
614
615                 internal override TemplateControl TemplateControlInternal {
616                         get { return this; }
617                 }
618
619                 protected internal object Eval (string expression)
620                 {
621                         return DataBinder.Eval (Page.GetDataItem (), expression);
622                 }
623
624                 protected internal string Eval (string expression, string format)
625                 {
626                         return DataBinder.Eval (Page.GetDataItem (), expression, format);
627                 }
628
629                 protected internal object XPath (string xpathexpression)
630                 {
631                         return XPathBinder.Eval (Page.GetDataItem (), xpathexpression);
632                 }
633
634                 protected internal object XPath (string xpathexpression, IXmlNamespaceResolver resolver)
635                 {
636                         return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, null, resolver);
637                 }
638
639                 protected internal string XPath (string xpathexpression, string format)
640                 {
641                         return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, format);
642                 }
643
644                 protected internal string XPath (string xpathexpression, string format, IXmlNamespaceResolver resolver)
645                 {
646                         return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, format, resolver);
647                 }
648
649                 protected internal IEnumerable XPathSelect (string xpathexpression)
650                 {
651                         return XPathBinder.Select (Page.GetDataItem (), xpathexpression);
652                 }
653
654                 protected internal IEnumerable XPathSelect (string xpathexpression, IXmlNamespaceResolver resolver)
655                 {
656                         return XPathBinder.Select (Page.GetDataItem (), xpathexpression, resolver);
657                 }
658
659                 protected object GetGlobalResourceObject (string className, string resourceKey)
660                 {
661                         return HttpContext.GetGlobalResourceObject (className, resourceKey);
662                 }
663
664                 protected object GetGlobalResourceObject (string className, string resourceKey, Type objType, string propName)
665                 {
666                         return ConvertResource (GetGlobalResourceObject (className, resourceKey), objType, propName);
667                 }
668
669                 protected Object GetLocalResourceObject (string resourceKey)
670                 {
671                         return HttpContext.GetLocalResourceObject (Context.Request.Path, resourceKey);
672                 }
673
674                 protected Object GetLocalResourceObject (string resourceKey, Type objType, string propName)
675                 {
676                         return ConvertResource (GetLocalResourceObject (resourceKey), objType, propName);
677                 }
678
679                 static Object ConvertResource (Object resource, Type objType, string propName) {
680                         if (resource == null)
681                                 return resource;
682
683                         PropertyDescriptor pdesc = TypeDescriptor.GetProperties (objType) [propName];
684                         if (pdesc == null)
685                                 return resource;
686
687                         TypeConverter converter = pdesc.Converter;
688                         if (converter == null)
689                                 return resource;
690
691                         return resource is string ?
692                                 converter.ConvertFromInvariantString ((string) resource) :
693                                 converter.ConvertFrom (resource);
694                 }
695
696 #endif
697
698         }
699 }