2009-02-28 Gonzalo Paniagua Javier <gonzalo@novell.com>
[mono.git] / mcs / class / System.Web / System.Web.UI / Page.jvm.cs
1 //
2 // System.Web.UI.Page.jvm.cs
3 //
4 // Authors:
5 //   Eyal Alaluf (eyala@mainsoft.com)
6 //
7 // (C) 2006 Mainsoft Co. (http://www.mainsoft.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using javax.servlet.http;
30 using System.Collections.Specialized;
31 using System.Globalization;
32 using System.Web.Hosting;
33 using System.Web.J2EE;
34 using System.ComponentModel;
35 using System.IO;
36 using javax.faces.context;
37 using javax.faces.render;
38 using javax.servlet;
39 using javax.faces;
40 using javax.faces.application;
41 using javax.faces.@event;
42 using javax.faces.el;
43 using javax.faces.component;
44 using System.Threading;
45 using System.Web.Configuration;
46 using Mainsoft.Web.Hosting;
47
48 namespace System.Web.UI
49 {
50         public partial class Page
51         {
52                 string _namespace = null;
53                 StateManager.SerializedView _facesSerializedView;
54                 MethodBinding _action;
55                 MethodBinding _actionListener;
56                 bool _immediate;
57                 bool [] _validatorsState;
58                 ICallbackEventHandler _callbackTarget;
59                 string _callbackEventError = String.Empty;
60                 static readonly object CrossPagePostBack = new object ();
61                 FacesContext _facesContext;
62                 const string RenderBodyContentOnlyKey = "mainsoft.render.body.content.only";
63
64                 static readonly java.util.List emptyList = java.util.Collections.unmodifiableList (new java.util.ArrayList ());
65
66                 bool _isMultiForm = false;
67                 bool _isMultiFormInited = false;
68
69                 internal string Namespace
70                 {
71                         get {
72                                 if (_namespace == null) {
73
74                                         if (getFacesContext () != null) {
75                                                 _namespace = getFacesContext ().getExternalContext ().encodeNamespace (String.Empty);
76                                         }
77
78                                         _namespace = _namespace ?? String.Empty;
79                                 }
80                                 return _namespace;
81                         }
82                 }
83
84                 internal Pair PageState { get; set; }
85
86                 internal string theForm {
87                         get {
88                                 return "theForm" + Namespace;
89                         }
90                 }
91
92                 internal bool IsMultiForm {
93                         get {
94                                 if (!_isMultiFormInited) {
95                                         string isMultiForm = WebConfigurationManager.AppSettings ["mainsoft.use.portlet.namespace"];
96                                         _isMultiForm = isMultiForm != null ? Boolean.Parse(isMultiForm) : false;
97
98                                         _isMultiFormInited = true;
99                                 }
100                                 return _isMultiForm;
101                         }
102                 }
103
104                 IHttpHandler EnterThread () {
105
106                         IHttpHandler jsfHandler = _context.CurrentHandler;
107                         _context.PopHandler ();
108                         _context.PushHandler (this);
109                         if (jsfHandler == _context.Handler)
110                                 _context.Handler = this;
111                         
112                         _context.CurrentHandlerInternal = this;
113
114                         return jsfHandler;
115                 }
116
117                 void ExitThread (IHttpHandler jsfHandler) {
118                         // TODO
119                         //if (context.getResponseComplete ())
120                         //    Response.End ();
121
122                         _context.PopHandler ();
123                         _context.PushHandler (jsfHandler);
124                         if (this == _context.Handler)
125                                 _context.Handler = jsfHandler;
126
127                 }
128
129                 public override void encodeBegin (FacesContext context) {
130                         // do nothing
131                 }
132
133                 public override void encodeChildren (FacesContext context) {
134                         System.Diagnostics.Trace.WriteLine ("encodeChildren");
135
136                         // reset _facesContext if changed between action and render phases (such portal).
137                         _facesContext = null;
138
139                         IHttpHandler jsfHandler = EnterThread ();
140                         bool wasException = false;
141                         try {
142                                 if (!context.getResponseComplete ()) {
143
144                                         if (IsCallback) {
145                                                 string result = ProcessGetCallbackResult (_callbackTarget, _callbackEventError);
146                                                 HtmlTextWriter callbackOutput = new HtmlTextWriter (Response.Output);
147                                                 callbackOutput.Write (result);
148                                                 callbackOutput.Flush ();
149                                                 return;
150                                         }
151
152                                         // ensure lifecycle complete.
153                                         if (!IsLoaded) {
154                                                 ProcessLoad ();
155                                                 RestoreValidatorsState (_validatorsState);
156                                         }
157                                         if (!IsPrerendered)
158                                                 ProcessLoadComplete ();
159
160                                         RenderPage ();
161                                 }
162                         }
163                         catch (Exception ex) {
164                                 wasException = true;
165                                 HandleException (ex);
166                         }
167                         finally {
168                                 try {
169                                         if (!wasException)
170                                                 ProcessUnload ();
171                                 }
172                                 finally {
173                                         ExitThread (jsfHandler);
174                                 }
175                         }
176                 }
177
178                 public override void encodeEnd (FacesContext context) {
179                         // do nothing
180                 }
181
182                 // BUGBUG: must return correct value. Currently returns 0 as performance optimization.
183                 public override int getChildCount ()
184                 {
185                         return 0;
186                 }
187
188                 // BUGBUG: must return correct value. Currently returns empty list as performance optimization.
189                 public override java.util.List getChildren ()
190                 {
191                         return emptyList;
192                 }
193
194                 public override UIComponent getParent () {
195                         return null;
196                 }
197
198                 public override void setParent (UIComponent parent) {
199                         //ignore: parent is root
200                 }
201
202                 // TODO: consider validators state
203                 public override object processSaveState (FacesContext context) {
204                         System.Diagnostics.Trace.WriteLine ("processSaveState");
205
206                         object state = new Pair (PageState, GetValidatorsState ());
207                         return new StateSerializer (state);
208                 }
209
210                 public override void processRestoreState (FacesContext context, object state) {
211                         System.Diagnostics.Trace.WriteLine ("processRestoreState");
212
213                         if (state == null) {
214                                 Console.WriteLine ("WARNING: processRestoreState was called with null state.");
215                                 return; //throw new ArgumentNullException ("state");
216                         }
217                         IHttpHandler jsfHandler = EnterThread ();
218                         try {
219                                 state = ((StateSerializer) state).State;
220                                 PageState = (Pair) ((Pair) state).First;
221                                 _validatorsState = (bool []) ((Pair) state).Second;
222                                 RestorePageState ();
223                         }
224                         catch (Exception ex) {
225                                 HandleException (ex);
226                         }
227                         finally {
228                                 ExitThread (jsfHandler);
229                         }
230                 }
231
232                 public override void processDecodes (FacesContext context) {
233                         System.Diagnostics.Trace.WriteLine ("processDecodes");
234
235                         IHttpHandler jsfHandler = EnterThread ();
236                         try {
237                                 ProcessPostData ();
238
239                                 EventRaiserFacesEvent facesEvent = new EventRaiserFacesEvent (this);
240                                 facesEvent.setPhaseId (PhaseId.INVOKE_APPLICATION);
241                                 context.getViewRoot ().queueEvent (facesEvent);
242
243                                 base.processDecodes (context);
244                         }
245                         catch (Exception ex) {
246                                 HandleException (ex);
247                         }
248                         finally {
249                                 ExitThread (jsfHandler);
250                         }
251                 }
252
253                 public override void processValidators (FacesContext context) {
254                         System.Diagnostics.Trace.WriteLine ("processValidators");
255
256                         IHttpHandler jsfHandler = EnterThread ();
257                         try {
258                                 base.processValidators (context);
259                         }
260                         catch (Exception ex) {
261                                 HandleException (ex);
262                         }
263                         finally {
264                                 ExitThread (jsfHandler);
265                         }
266                 }
267
268                 public override void processUpdates (FacesContext context) {
269                         System.Diagnostics.Trace.WriteLine ("processUpdates");
270
271                         IHttpHandler jsfHandler = EnterThread ();
272                         try {
273                                 base.processUpdates (context);
274                         }
275                         catch (Exception ex) {
276                                 HandleException (ex);
277                         }
278                         finally {
279                                 ExitThread (jsfHandler);
280                         }
281                 }
282
283                 public override void broadcast (FacesEvent e) {
284                         System.Diagnostics.Trace.WriteLine ("broadcast");
285
286                         if (!(e is EventRaiserFacesEvent))
287                                 throw new NotSupportedException ("FacesEvent of class " + e.GetType ().Name + " not supported by Page");
288
289                         IHttpHandler jsfHandler = EnterThread ();
290                         bool doUnload = false;
291                         try {
292                                 ProcessRaiseEvents ();
293                                 doUnload = (ProcessLoadComplete () && IsCrossPagePostBack);
294                         }
295                         catch (Exception ex) {
296                                 doUnload = false;
297                                 HandleException (ex);
298                         }
299                         finally {
300                                 try {
301                                         if (doUnload) {
302                                                 getFacesContext ().responseComplete ();
303                                                 ProcessUnload ();
304                                         }
305                                 }
306                                 finally {
307                                         ExitThread (jsfHandler);
308                                 }
309                         }
310                 }
311
312                 void HandleException (Exception ex) {
313                         try {
314                                 if (ex is ThreadAbortException) {
315                                         if (FlagEnd.Value == ((ThreadAbortException) ex).ExceptionState) {
316                                                 Thread.ResetAbort ();
317                                                 return;
318                                         }
319                                         vmw.common.TypeUtils.Throw (ex);
320                                 }
321                                 else
322                                         ProcessException (ex);
323                         }
324                         finally {
325                                 if (getFacesContext () != null)
326                                         getFacesContext ().responseComplete ();
327                                 ProcessUnload ();
328                         }
329                 }
330
331                 bool [] GetValidatorsState () {
332                         if (is_validated && Validators.Count > 0) {
333                                 bool [] validatorsState = new bool [Validators.Count];
334                                 bool isValid = true;
335                                 for (int i = 0; i < Validators.Count; i++) {
336                                         IValidator val = Validators [i];
337                                         if (!val.IsValid)
338                                                 isValid = false;
339                                         else
340                                                 validatorsState [i] = true;
341                                 }
342                                 return validatorsState;
343                         }
344                         return null;
345                 }
346
347                 void RestoreValidatorsState (bool [] validatorsState) {
348                         if (validatorsState == null)
349                                 return;
350
351                         is_validated = true;
352                         for (int i = 0; i < Math.Min (validatorsState.Length, Validators.Count); i++) {
353                                 IValidator val = Validators [i];
354                                 val.IsValid = validatorsState [i];
355                         }
356                 }
357
358                 ResponseWriter SetupResponseWriter (TextWriter httpWriter) { //TODO
359                         FacesContext facesContext = getFacesContext ();
360
361                         ResponseWriter oldWriter = facesContext.getResponseWriter ();
362                         if (oldWriter == null)
363                                 throw new InvalidOperationException ();
364
365                         ResponseWriter writer = oldWriter.cloneWithWriter (new AspNetResponseWriter (httpWriter));
366                         
367                         facesContext.setResponseWriter (writer);
368                         return oldWriter;
369                 }
370
371                 string DecodeNamespace (string id) {
372                         if (Namespace.Length > 0 && id.Length > Namespace.Length && id.StartsWith (Namespace, StringComparison.Ordinal))
373                                 id = id.Substring (Namespace.Length);
374                         return id;
375                 }
376
377                 protected override FacesContext getFacesContext () {
378                         return _facesContext ?? (_facesContext = FacesContext.getCurrentInstance ());
379                 }
380
381                 internal FacesContext FacesContext {
382                         get { return getFacesContext (); }
383                 }
384
385                 #region EventRaiserFacesEvent
386                 sealed class EventRaiserFacesEvent : FacesEvent
387                 {
388                         public EventRaiserFacesEvent (Page page)
389                                 : base (page) {
390                         }
391
392                         public override bool isAppropriateListener (FacesListener __p1) {
393                                 throw new NotSupportedException ();
394                         }
395
396                         public override void processListener (FacesListener __p1) {
397                                 throw new NotSupportedException ();
398                         }
399                 }
400                 #endregion
401
402                 #region AspNetResponseWriter
403                 sealed class AspNetResponseWriter : java.io.Writer
404                 {
405                         readonly TextWriter _writer;
406                         public AspNetResponseWriter (TextWriter writer) {
407                                 _writer = writer;
408                         }
409                         public override void close () {
410                                 _writer.Close ();
411                         }
412
413                         public override void flush () {
414                                 _writer.Flush ();
415                         }
416
417                         public override void write (char [] __p1, int __p2, int __p3) {
418                                 _writer.Write (__p1, __p2, __p3);
419                         }
420
421                         public override void write (int __p1) {
422                                 _writer.Write ((char) __p1);
423                         }
424
425                         public override void write (char [] __p1) {
426                                 _writer.Write (__p1);
427                         }
428
429                         public override void write (string __p1) {
430                                 _writer.Write (__p1);
431                         }
432
433                         public override void write (string __p1, int __p2, int __p3) {
434                                 _writer.Write (__p1, __p2, __p3);
435                         }
436                 }
437                 #endregion
438
439                 #region StateSerializer
440                 public sealed class StateSerializer : java.io.Externalizable
441                 {
442                         object _state;
443
444                         public StateSerializer ()
445                         {
446                         }
447
448                         public StateSerializer (object state)
449                         {
450                                 _state = state;
451                         }
452
453                         public object State
454                         {
455                                 get { return _state; }
456                         }
457
458                         public void readExternal (java.io.ObjectInput __p1)
459                         {
460                                 Page page = CurrentPage;
461                                 ObjectStateFormatter osf = new ObjectStateFormatter (page);
462                                 ObjectInputStream inputStream = new ObjectInputStream (__p1);
463
464                                 if (page.NeedViewStateEncryption || page.EnableViewStateMac)
465                                         _state = osf.Deserialize ((string) inputStream.readObject ());
466                                 else
467                                         _state = osf.Deserialize (inputStream);
468                         }
469
470                         public void writeExternal (java.io.ObjectOutput __p1)
471                         {
472                                 Page page = CurrentPage;
473                                 ObjectStateFormatter osf = new ObjectStateFormatter (page);
474                                 ObjectOutputStream outputStream = new ObjectOutputStream (__p1);
475
476                                 if (page.NeedViewStateEncryption || page.EnableViewStateMac)
477                                         outputStream.writeObject (osf.Serialize (_state));
478                                 else
479                                         osf.Serialize (outputStream, _state);
480                         }
481
482                         Page CurrentPage
483                         {
484                                 get
485                                 {
486                                         HttpContext context = HttpContext.Current;
487                                         if (context.CurrentHandler is Page)
488                                                 return (Page) context.CurrentHandler;
489                                         
490                                         return context.CurrentHandlerInternal;
491                                 }
492                         }
493                 } 
494                 #endregion
495         }
496 }