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