78c8754269b9c0b5591b2c8c88337700082b0eb8
[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                 }
99
100                 private string CachedString (string filename, int offset, int size)
101                 {
102                         string key = filename + offset + size;
103                         lock (hashTableMutex) {
104                                 string strObj = (string) ResourceHash [key];
105                                 if (strObj == null) {
106
107                                         char [] tmp = System.Text.Encoding.UTF8.GetChars (GetResourceBytes (this.GetType ()), offset, size);
108                                         strObj = new string (tmp);
109                                         ResourceHash.Add (key, strObj);
110                                 }
111
112                                 return strObj;
113                         }
114
115                 }
116                 public virtual string TemplateSourceDirectory_Private
117                 {
118                         get { return null; }
119                 }
120
121                 #region Constructor
122                 protected TemplateControl ()
123                 {
124                         Construct ();
125                 }
126
127                 #endregion
128
129                 #region Properties
130                 [EditorBrowsable (EditorBrowsableState.Never)]
131                 protected virtual int AutoHandlers
132                 {
133                         get { return 0; }
134                         set { }
135                 }
136
137                 [EditorBrowsable (EditorBrowsableState.Never)]
138                 protected virtual bool SupportAutoEvents
139                 {
140                         get { return true; }
141                 }
142
143                 #endregion
144
145                 #region Methods
146
147                 protected virtual void Construct ()
148                 {
149                 }
150
151                 [MonoTODO]
152                 protected LiteralControl CreateResourceBasedLiteralControl (int offset,
153                                                                                         int size,
154                                                                                         bool fAsciiOnly)
155                 {
156                         string str = CachedString (this.GetType ().FullName, offset, size);
157                         return new LiteralControl (str);
158                 }
159
160                 sealed class EventMethodMap
161                 {
162                         public EventMethodMap (EventInfo Event, MethodInfo Method, bool NoParameters)
163                         {
164                                 this.Event = Event;
165                                 this.Method = Method;
166                                 this.NoParameters = NoParameters;
167                         }
168
169                         public readonly EventInfo Event;
170                         public readonly MethodInfo Method;
171                         public readonly bool NoParameters;
172                 }
173
174                 // This hashtable cashes methods and events found in user code
175                 const string eventMethodCacheKey = "eventMethodCacheKey";
176                 static Hashtable EventMethodCache
177                 {
178                         get { return (Hashtable) AppDomain.CurrentDomain.GetData (eventMethodCacheKey); }
179                         set { AppDomain.CurrentDomain.SetData (eventMethodCacheKey, value); }
180                 }
181
182                 internal void WireupAutomaticEvents ()
183                 {
184                         Type cacheKey = this.GetType ();
185                         Hashtable eventMethodCache = EventMethodCache;
186                         ArrayList eventMethodList = eventMethodCache == null ? null : (ArrayList) eventMethodCache [cacheKey];
187
188                         if (eventMethodList == null) {
189                                 eventMethodList = new ArrayList ();
190
191                                 if (!SupportAutoEvents || !AutoEventWireup)
192                                         return;
193
194                                 Type thisType = typeof (TemplateControl);
195                                 Type voidType = typeof (void);
196                                 Type [] DefaultParams = new Type [] {
197                                 typeof (object),
198                                 typeof (EventArgs) };
199
200                                 foreach (string methodName in methodNames) {
201                                         MethodInfo method;
202                                         bool noParams = false;
203                                         Type type = GetType ();
204                                         do {
205                                                 method = type.GetMethod (methodName, bflags, null, DefaultParams, null);
206                                                 if (method != null) {
207                                                         break;
208                                                 }
209
210                                                 type = type.BaseType;
211                                         }
212                                         while (type != thisType);
213
214                                         if (method == null) {
215                                                 type = GetType ();
216                                                 do {
217                                                         method = type.GetMethod (methodName, bflags, null, NoParams, null);
218                                                         if (method != null) {
219                                                                 noParams = true;
220                                                                 break;
221                                                         }
222
223                                                         type = type.BaseType;
224                                                 }
225                                                 while (type != thisType);
226
227                                                 if (method == null)
228                                                         continue;
229                                         }
230                                         if (method.ReturnType != voidType)
231                                                 continue;
232
233                                         int pos = methodName.IndexOf ("_");
234                                         string eventName = methodName.Substring (pos + 1);
235                                         EventInfo evt = GetType ().GetEvent (eventName);
236                                         if (evt == null) {
237                                                 /* This should never happen */
238                                                 continue;
239                                         }
240
241                                         eventMethodList.Add (new EventMethodMap (evt, method, noParams));
242 #if ONLY_1_1
243                                 if (method.DeclaringType != type) {
244                                         if (!method.IsPublic && !method.IsFamilyOrAssembly &&
245                                             !method.IsFamilyAndAssembly && !method.IsFamily)
246                                                 continue;
247                                 }
248 #endif
249                                 }
250                                 // We copy to not lock
251
252                                 Hashtable newEventMethodCache = eventMethodCache == null ? new Hashtable () : (Hashtable) eventMethodCache.Clone ();
253                                 newEventMethodCache [cacheKey] = eventMethodList;
254                                 EventMethodCache = newEventMethodCache;
255                         }
256
257                         foreach (EventMethodMap eventMethod in eventMethodList) {
258                                 if (eventMethod.NoParameters) {
259                                         NoParamsInvoker npi = new NoParamsInvoker (this, eventMethod.Method);
260                                         eventMethod.Event.AddEventHandler (this, npi.FakeDelegate);
261                                 }
262                                 else {
263                                         eventMethod.Event.AddEventHandler (this, Delegate.CreateDelegate (typeof (EventHandler), this, eventMethod.Method));
264                                 }
265                         }
266                 }
267
268                 [EditorBrowsable (EditorBrowsableState.Never)]
269                 protected virtual void FrameworkInitialize ()
270                 {
271                 }
272
273                 Type GetTypeFromControlPath (string virtualPath)
274                 {
275                         if (virtualPath == null)
276                                 throw new ArgumentNullException ("virtualPath");
277
278                         string vpath = UrlUtils.Combine (TemplateSourceDirectory, virtualPath);
279                         return PageMapper.GetObjectType (Context, vpath);
280                 }
281
282                 public Control LoadControl (string virtualPath)
283                 {
284                         object control = Activator.CreateInstance (GetTypeFromControlPath (virtualPath));
285                         if (control is UserControl)
286                                 ((UserControl) control).InitializeAsUserControl (Page);
287
288                         return (Control) control;
289                 }
290
291                 public ITemplate LoadTemplate (string virtualPath)
292                 {
293                         Type t = GetTypeFromControlPath (virtualPath);
294                         return new SimpleTemplate (t);
295                 }
296
297                 protected virtual void OnAbortTransaction (EventArgs e)
298                 {
299                         EventHandler eh = Events [abortTransaction] as EventHandler;
300                         if (eh != null)
301                                 eh (this, e);
302                 }
303
304                 protected virtual void OnCommitTransaction (EventArgs e)
305                 {
306                         EventHandler eh = Events [commitTransaction] as EventHandler;
307                         if (eh != null)
308                                 eh (this, e);
309                 }
310
311                 protected virtual void OnError (EventArgs e)
312                 {
313                         EventHandler eh = Events [error] as EventHandler;
314                         if (eh != null)
315                                 eh (this, e);
316                 }
317
318                 [MonoNotSupported ("Not supported")]
319                 public Control ParseControl (string content)
320                 {
321                         throw new NotSupportedException ();
322                 }
323
324                 [MonoLimitation ("Always returns false")]
325                 public virtual bool TestDeviceFilter (string filterName)
326                 {
327                         return false;
328                 }
329
330                 [MonoTODO]
331                 [EditorBrowsable (EditorBrowsableState.Never)]
332                 public static object ReadStringResource (Type t)
333                 {
334                         return t;
335                 }
336 #if NET_2_0
337                 [MonoTODO ("is this correct?")]
338                 public Object ReadStringResource ()
339                 {
340                         return this.GetType ();
341                 }
342 #endif
343                 [MonoTODO]
344                 [EditorBrowsable (EditorBrowsableState.Never)]
345                 protected void SetStringResourcePointer (object stringResourcePointer,
346                                                          int maxResourceOffset)
347                 {
348                         if (GetResourceBytes (this.GetType ()) != null)
349                                 return;
350
351                         java.lang.Class c = vmw.common.TypeUtils.ToClass (stringResourcePointer);
352                         java.lang.ClassLoader contextClassLoader = c.getClassLoader ();
353
354                         //TODO:move this code to page mapper
355                         string assemblyName = PageMapper.GetAssemblyResource (HttpContext.Current, this.AppRelativeVirtualPath);
356                         if (assemblyName == null)
357                                 throw new HttpException (404, "The requested resource (" + this.AppRelativeVirtualPath + ") is not available.");
358
359                         java.io.InputStream inputStream = contextClassLoader.getResourceAsStream (assemblyName);
360
361                         System.IO.Stream strim = null;
362                         if (inputStream == null) {
363                                 string descPath = String.Join ("/", new string [] { "assemblies", this.GetType ().Assembly.GetName ().Name, assemblyName });
364                                 try {
365                                         strim = new StreamReader (HttpContext.Current.Request.MapPath ("/" + descPath)).BaseStream;
366                                 }
367                                 catch (Exception ex) {
368                                         throw new System.IO.IOException ("couldn't open resource file:" + assemblyName, ex);
369                                 }
370                                 if (strim == null)
371                                         throw new System.IO.IOException ("couldn't open resource file:" + assemblyName);
372                         }
373
374                         try {
375                                 if (strim == null)
376                                         strim = (System.IO.Stream) vmw.common.IOUtils.getStream (inputStream);
377                                 int capacity = (int) strim.Length;
378                                 byte [] resourceBytes = new byte [capacity];
379                                 strim.Read (resourceBytes, 0, capacity);
380                                 SetResourceBytes (this.GetType (), resourceBytes);
381                         }
382                         catch (Exception e) {
383                                 throw new HttpException ("problem with dll.ghres file", e);
384                         }
385                         finally {
386                                 if (strim != null)
387                                         strim.Close ();
388                                 if (inputStream != null)
389                                         inputStream.close ();
390                         }
391                 }
392
393                 [MonoTODO]
394                 [EditorBrowsable (EditorBrowsableState.Never)]
395                 protected void WriteUTF8ResourceString (HtmlTextWriter output, int offset,
396                                                         int size, bool fAsciiOnly)
397                 {
398                         string str = CachedString (this.GetType ().FullName, offset, size);
399                         output.Write (str);
400                 }
401
402                 #endregion
403
404                 #region Events
405
406                 [WebSysDescription ("Raised when the user aborts a transaction.")]
407                 public event EventHandler AbortTransaction
408                 {
409                         add { Events.AddHandler (abortTransaction, value); }
410                         remove { Events.RemoveHandler (abortTransaction, value); }
411                 }
412
413                 [WebSysDescription ("Raised when the user initiates a transaction.")]
414                 public event EventHandler CommitTransaction
415                 {
416                         add { Events.AddHandler (commitTransaction, value); }
417                         remove { Events.RemoveHandler (commitTransaction, value); }
418                 }
419
420                 [WebSysDescription ("Raised when an exception occurs that cannot be handled.")]
421                 public event EventHandler Error
422                 {
423                         add { Events.AddHandler (error, value); }
424                         remove { Events.RemoveHandler (error, value); }
425                 }
426
427                 #endregion
428
429                 class SimpleTemplate : ITemplate
430                 {
431                         Type type;
432
433                         public SimpleTemplate (Type type)
434                         {
435                                 this.type = type;
436                         }
437
438                         public void InstantiateIn (Control control)
439                         {
440                                 Control template = Activator.CreateInstance (type) as Control;
441                                 template.SetBindingContainer (false);
442                                 control.Controls.Add (template);
443                         }
444                 }
445
446 #if NET_2_0
447
448                 string _appRelativeVirtualPath = null;
449
450                 public string AppRelativeVirtualPath
451                 {
452                         get { return _appRelativeVirtualPath; }
453                         set
454                         {
455                                 if (value == null)
456                                         throw new ArgumentNullException ("value");
457                                 if (!UrlUtils.IsRooted (value) && !(value.Length > 0 && value [0] == '~'))
458                                         throw new ArgumentException ("The path that is set is not rooted");
459                                 _appRelativeVirtualPath = value;
460
461                                 int lastSlash = _appRelativeVirtualPath.LastIndexOf ('/');
462                                 AppRelativeTemplateSourceDirectory = (lastSlash > 0) ? _appRelativeVirtualPath.Substring (0, lastSlash + 1) : "~/";
463                         }
464                 }
465
466                 protected internal object Eval (string expression)
467                 {
468                         return DataBinder.Eval (Page.GetDataItem (), expression);
469                 }
470
471                 protected internal string Eval (string expression, string format)
472                 {
473                         return DataBinder.Eval (Page.GetDataItem (), expression, format);
474                 }
475
476                 protected internal object XPath (string xpathexpression)
477                 {
478                         return XPathBinder.Eval (Page.GetDataItem (), xpathexpression);
479                 }
480
481                 protected internal object XPath (string xpathexpression, IXmlNamespaceResolver resolver)
482                 {
483                         return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, null, resolver);
484                 }
485
486                 protected internal string XPath (string xpathexpression, string format)
487                 {
488                         return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, format);
489                 }
490
491                 protected internal string XPath (string xpathexpression, string format, IXmlNamespaceResolver resolver)
492                 {
493                         return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, format, resolver);
494                 }
495
496                 protected internal IEnumerable XPathSelect (string xpathexpression)
497                 {
498                         return XPathBinder.Select (Page.GetDataItem (), xpathexpression);
499                 }
500
501                 protected internal IEnumerable XPathSelect (string xpathexpression, IXmlNamespaceResolver resolver)
502                 {
503                         return XPathBinder.Select (Page.GetDataItem (), xpathexpression, resolver);
504                 }
505
506                 protected object GetGlobalResourceObject (string className, string resourceKey)
507                 {
508                         return HttpContext.GetGlobalResourceObject (className, resourceKey);
509                 }
510
511                 [MonoTODO ("Not implemented")]
512                 protected object GetGlobalResourceObject (string className, string resourceKey, Type objType, string propName)
513                 {
514                         // FIXME: not sure how to implement that one yet
515                         throw new NotSupportedException ();
516                 }
517
518                 protected Object GetLocalResourceObject (string resourceKey)
519                 {
520                         return HttpContext.GetLocalResourceObject (Context.Request.Path, resourceKey);
521                 }
522
523                 [MonoTODO ("Not implemented")]
524                 protected Object GetLocalResourceObject (string resourceKey, Type objType, string propName)
525                 {
526                         // FIXME: not sure how to implement that one yet
527                         throw new NotSupportedException ();
528                 }
529
530 #endif
531
532         }
533 }