New test.
[mono.git] / mcs / class / System.Web / System.Web.J2EE / PageMapper.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.Xml;
28 using System.IO;
29 using System.Collections;
30 using System.Web.Compilation;
31 using System.Collections.Specialized;
32 using System.Threading;
33 using vmw.common;
34
35 namespace System.Web.J2EE
36 {
37         /// <summary>
38         /// Class that allows reading assemblies.xml file for getting information about different types.
39         /// </summary>
40         public class PageMapper
41         {
42                 private static readonly string _fileListName = "/filelist.xml";
43                 private static readonly object LOCK_GETASSEMBLIESCACHEDDOCUMENT = new object();
44                 private static readonly object LOCK_GETFROMMAPPATHCACHE = new object();
45
46                 public static string GetFromMapPathCache(string key)
47                 {
48                         Hashtable answer = null;
49                         lock(LOCK_GETFROMMAPPATHCACHE)
50                         {
51                                 answer = (Hashtable) AppDomain.CurrentDomain.GetData(J2EEConsts.MAP_PATH_CACHE);
52                                 if (answer == null)
53                                 {
54                                         answer = new Hashtable();
55                                         CachedDocumentTypeStorage storage = (CachedDocumentTypeStorage)GetAssembliesCachedDocument();
56                                         IDictionaryEnumerator e = storage.GetEnumerator();
57                                         e.Reset();
58                                         while (e.MoveNext())
59                                         {                                       
60                                                 string currentFile = (string)((DictionaryEntry)e.Current).Key;
61                                                 answer[currentFile]= IAppDomainConfig.WAR_ROOT_SYMBOL + currentFile;
62                                         }
63                                         AppDomain.CurrentDomain.SetData(J2EEConsts.MAP_PATH_CACHE,answer);
64
65                                 }
66                         }
67                         return (string)answer[key];
68                 }
69
70                 // UNUSED METHOD
71                 //The method was used by runtime to force file names casesensitivity
72                 // problem. The filelist.xml file should contain correct file names,
73                 // but currently it is unused
74                 public static void LoadFileList()
75                 {
76                         Hashtable hashTable = (Hashtable) AppDomain.CurrentDomain.GetData(J2EEConsts.FILE_LIST_FILE);
77                         if (hashTable == null)
78                         {
79                                 XmlDocument doc;
80                                 try
81                                 {
82                                         Stream fs = (Stream)IOUtils.getStream(_fileListName);
83                                         if (fs == null)
84                                         {
85                                                 AppDomain.CurrentDomain.SetData(J2EEConsts.FILE_LIST_FILE, new Hashtable());
86                                                 return;
87                                         }
88
89                                         doc = new XmlDocument();
90                                         doc.Load(fs);
91                                 }
92                                 catch (Exception)
93                                 {
94 //                                      Console.WriteLine("filelist.xml was not found!!!");
95                                         AppDomain.CurrentDomain.SetData(J2EEConsts.FILE_LIST_FILE, new Hashtable());
96                                         return;
97                                 }
98 //                              Console.WriteLine("filelist.xml was found!!!");
99                                 if (doc != null && doc.DocumentElement.HasChildNodes)
100                                 {
101                                         hashTable = CollectionsUtil.CreateCaseInsensitiveHashtable();
102                                         XmlNodeList nodeList = doc.DocumentElement.ChildNodes;
103                                         for (int i = 0;i < nodeList.Count ; i++)
104                                         {
105                                                 string fileName = nodeList.Item(i).InnerText;
106                                                 hashTable.Add(fileName,fileName);
107                                         }
108                                         AppDomain.CurrentDomain.SetData(J2EEConsts.FILE_LIST_FILE, hashTable);
109                                 }
110                         }
111
112                 }
113
114                 private static ICachedXmlDoc GetAssembliesCachedDocument()
115                 {
116                         lock(LOCK_GETASSEMBLIESCACHEDDOCUMENT)
117                         {
118                                 ICachedXmlDoc doc = (ICachedXmlDoc) AppDomain.CurrentDomain.GetData(J2EEConsts.ASSEMBLIES_FILE);
119                                 if (doc == null)
120                                 {
121                                         doc = CreateDocument();
122                                         if (doc != null)
123                                                 AppDomain.CurrentDomain.SetData(J2EEConsts.ASSEMBLIES_FILE, doc);
124                                 }
125
126                                 return doc;
127                         }
128                 }
129
130                 private static ICachedXmlDoc CreateDocument()
131                 {
132                         return new CachedDocumentTypeStorage();
133                 }
134
135                 public static Type GetObjectType(string url)
136                 {
137 #if NET_2_0
138                         return GetCachedType(System.Web.Util.UrlUtils.RemoveDoubleSlashes(url));
139 #else
140                         return GetCachedType(url);
141 #endif
142                 }
143
144                 private static Type GetCachedType(string url)
145                 {
146                         ICachedXmlDoc doc = PageMapper.GetAssembliesCachedDocument();
147                         
148                         if (url.StartsWith(IAppDomainConfig.WAR_ROOT_SYMBOL))
149                                 url = url.Substring(IAppDomainConfig.WAR_ROOT_SYMBOL.Length);
150                         
151                         Type t = doc.Get(url);
152
153                         if (t == null)
154                                 throw new HttpException(404,"The requested resource (" + url + ") is not available.");
155
156                         return t;
157                 }
158
159                 #region ICachedXmlDoc interface
160                 interface ICachedXmlDoc
161                 {
162                         Type Get(string key);
163                         //bool ContainsKey(object key);
164                 }
165                 #endregion
166
167                 #region CachedDocumentTypeStorage class
168                 class CachedDocumentTypeStorage : ICachedXmlDoc
169                 {
170                         public static readonly ICachedXmlDoc DEFAULT_DOC =
171                                 new CachedDocumentTypeStorage(0);
172
173                         private static readonly int DEFAULT_PAGES_NUMBER = 25;
174
175                         private Hashtable _table;
176
177                         private CachedDocumentTypeStorage(int initTableSize)
178                         {
179                                 _table = Hashtable.Synchronized(new Hashtable(initTableSize));
180                         }
181
182                         public CachedDocumentTypeStorage() :
183                                 this(DEFAULT_PAGES_NUMBER)
184                         {}
185
186                         Type ICachedXmlDoc.Get(string o)
187                         {
188                                 return GetTypeByURL(o);
189                         }
190
191                         internal IDictionaryEnumerator GetEnumerator()
192                         {
193                                 return _table.GetEnumerator();                          
194                         }       
195
196                         public Type GetTypeByURL(string url)
197                         {
198                                 string lwUrl = url.ToLower();
199                                 lock (_table)
200                                 {
201                                         object retVal = _table[lwUrl];
202                                         if (retVal == null)
203                                         {
204                                                 PageCompiler compiler = new PageCompiler(url);
205                                                 retVal = compiler.GetCachedType();
206                                                 _table[lwUrl] = retVal;
207                                         }
208                                 
209                                         return (Type)retVal;
210                                 }
211                         }
212                 }
213                 #endregion
214
215         }
216
217         public class PageCompiler
218         {
219                 private static readonly string PAGE_XPATH = "preserve";
220                 private static readonly string ASSEM_ATTRIB_NAME = "assem";
221                 private static readonly string TYPE_ATTRIB_NAME = "type";
222                 private static string _parser = null;
223
224                 private Type _type = null;
225                 private string _xmlDescriptor = null;
226                 private string _url = null;
227                 private string _session = null;
228
229                 public PageCompiler(string url)
230                 {
231                         _url = url;
232                         _xmlDescriptor = GetDescFromUrl();
233                         _session = DateTime.Now.Ticks.ToString();
234                 }
235
236                 public Type GetCachedType()
237                 {
238                         if (_type != null)
239                                 return _type;
240                         
241                         string typeName = null;
242                 
243                         //if the desciptor exists in the war - get the type
244                         string descPath = String.Join("/", new string[]{"assemblies", _xmlDescriptor});
245
246                         try
247                         {
248 #if DEBUG
249                                 Console.WriteLine(descPath);
250 #endif
251                                 Stream fs = (Stream)IOUtils.getStream("/" + descPath);
252                                 if (fs != null)
253                                 {
254                                         typeName = GetTypeFromDescStream(fs);
255                                 }
256                         }
257                         catch (Exception ex)
258                         {
259 #if DEBUG
260                                 Console.WriteLine(ex);
261 #endif
262                                 //desc not in the war
263                                 typeName = null;
264                         }
265
266                         if (typeName != null)
267                         {
268                                 _type = Type.GetType(typeName);
269                                 return _type;
270                         }
271                         
272                         string fileName = Path.GetFileName(_url);
273             
274                         if (fileName.ToLower() != "defaultwsdlhelpgenerator.aspx")
275                         {
276                 string fullFileName = (fileName.ToLower() == "global.asax") ? _url : HttpContext.Current.Request.MapPath(_url);
277 #if DEBUG
278                 Console.WriteLine("fullFileName=" + fullFileName);
279 #endif                
280                                 if ( File.Exists(fullFileName) || Directory.Exists(fullFileName)) {
281                                         //type not found - run aspxparser
282                     string[] command = GetParserCmd(fileName.ToLower() == "global.asax");
283                                         if (J2EEUtils.RunProc(command) != 0)
284                                                 throw GetCompilerError();
285                                 }
286                                 else {
287                                         string message = "The requested resource (" + _url + ") is not available.";
288                                         throw new HttpException(404, message);
289                                 }
290
291                                 //if the desciptor exists in the real app dir - get the type
292                                 try {
293                                         StreamReader sr = new StreamReader (HttpContext.Current.Request.MapPath ("/" + descPath));
294                                         typeName = GetTypeFromDescStream (sr.BaseStream);
295                                         sr.Close ();
296                                 }
297                                 catch (Exception ex) {
298                                         Console.WriteLine (ex);
299                                         throw ex;
300                                 }
301                         }
302                         else
303                                 typeName = "ASP.defaultwsdlhelpgenerator_jvm_aspx";
304
305                         if (typeName != null)
306                         {
307                                 _type = Type.GetType(typeName);
308                                 return _type;
309                         }
310
311                         return null;
312                 }
313
314                 private string GetTypeFromDescStream(Stream fs)
315                 {
316                         if (fs != null)
317                         {
318                                 XmlDocument descXml = new XmlDocument();
319                                 descXml.Load(fs);
320                                 string assem = descXml.SelectSingleNode(PAGE_XPATH).Attributes[ASSEM_ATTRIB_NAME].Value;
321                                 string shortType = descXml.SelectSingleNode(PAGE_XPATH).Attributes[TYPE_ATTRIB_NAME].Value;
322                                 string typeName = String.Format("{0}, {1}",shortType,assem);
323                                 fs.Close();
324                                 return typeName;
325                         }
326
327                         return null;
328                 }
329
330                 private string[] GetParserCmd(bool globalAsax)
331                 {
332             string[] cmd = null;                        
333             if (globalAsax)
334             {
335                 cmd = new string[4];
336                 cmd[3] = "/buildglobalasax";
337             }
338             else
339             {
340                 cmd = new string[5];
341                 cmd[3] = "/aspxFiles:" + _url;
342                 cmd[4] = "/compilepages";
343             }
344             cmd[0] = GetParser();
345             cmd[1] = "/session:" + _session;
346             cmd[2] = "/appDir:" + (string)AppDomain.CurrentDomain.GetData(IAppDomainConfig.APP_PHYS_DIR);
347                         return cmd;
348                 }
349
350                 private string GetParser()
351                 {
352                         if (_parser == null)
353                         {
354                                 StreamReader sr =
355                                         File.OpenText(HttpContext.Current.Request.MapPath("/AspxParser.params"));
356                                 _parser = sr.ReadLine();
357                                 sr.Close();
358                         }
359
360                         return _parser;
361                 }
362
363                 private string GetDescFromUrl()
364                 {
365                         string fileName = Path.GetFileName(_url);
366                         
367                         if (fileName.ToLower() == "global.asax")
368                                 return "global.asax.xml";
369
370                         string id = GetIdFromUrl(_url);
371                         string[] descName = new string[3] {fileName, id, ".xml"} ;
372                         return string.Concat(descName).ToLower();
373                 }
374
375                 private string GetIdFromUrl(string path)
376                 {
377                         path = path.Trim('/');
378                         string fileName = Path.GetFileName(path);
379                         string id = string.Empty;
380
381                         path = path.Substring (path.IndexOf ("/") + 1);
382
383                         if (path.Length > fileName.Length)
384                                 id = "." + path.Substring(0,path.Length - fileName.Length).Replace('/','_');
385                         return id;      
386                 }
387
388                 private Exception GetCompilerError()
389                 {
390                         string _errFile = HttpContext.Current.Request.MapPath("/" + _session + ".vmwerr");
391                         
392                         if (!File.Exists(_errFile))
393                                 throw new FileNotFoundException("Internal Error",_errFile);
394
395                         StreamReader sr = new StreamReader(_errFile);
396                         string message = string.Empty, line = null, file = null, lineInFile = "0";
397
398                         while ((line = sr.ReadLine()) != null)
399                         {
400                                 if (line.StartsWith("Message: "))
401                                         message = line.Substring("Message: ".Length);
402                                 else if (line.StartsWith("File: "))
403                                         file = line.Substring("File: ".Length);
404                                 else if (line.StartsWith("Line: "))
405                                         lineInFile = line.Substring("Line: ".Length);
406                         }
407
408                         sr.Close();
409
410                         if (file != null)
411                         {
412                                 Location loc = new Location(null);
413                                 loc.Filename = file;
414                                 loc.BeginLine = int.Parse(lineInFile);
415                                 return new ParseException(loc,message);
416                         }
417
418                         if (message.IndexOf(typeof(FileNotFoundException).Name) != -1 &&
419                                 message.IndexOf(_url.Trim('\\','/').Replace('/','\\')) != -1)
420                                 message = "The requested resource (" + _url + ") is not available.";
421                         return new HttpException(404,(message !=  null ? message : string.Empty));
422                 }
423         }
424 }