In .:
[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                         return GetCachedType(url);
138                 }
139
140                 private static Type GetCachedType(string url)
141                 {
142                         ICachedXmlDoc doc = PageMapper.GetAssembliesCachedDocument();
143                         
144                         if (url.StartsWith(IAppDomainConfig.WAR_ROOT_SYMBOL))
145                                 url = url.Substring(IAppDomainConfig.WAR_ROOT_SYMBOL.Length);
146                         
147                         Type t = doc.Get(url);
148
149                         if (t == null)
150                                 throw new HttpException(404,"The requested resource (" + url + ") is not available.");
151
152                         return t;
153                 }
154
155                 #region ICachedXmlDoc interface
156                 interface ICachedXmlDoc
157                 {
158                         Type Get(string key);
159                         //bool ContainsKey(object key);
160                 }
161                 #endregion
162
163                 #region CachedDocumentTypeStorage class
164                 class CachedDocumentTypeStorage : ICachedXmlDoc
165                 {
166                         public static readonly ICachedXmlDoc DEFAULT_DOC =
167                                 new CachedDocumentTypeStorage(0);
168
169                         private static readonly int DEFAULT_PAGES_NUMBER = 25;
170
171                         private Hashtable _table;
172
173                         private CachedDocumentTypeStorage(int initTableSize)
174                         {
175                                 _table = Hashtable.Synchronized(new Hashtable(initTableSize));
176                         }
177
178                         public CachedDocumentTypeStorage() :
179                                 this(DEFAULT_PAGES_NUMBER)
180                         {}
181
182                         Type ICachedXmlDoc.Get(string o)
183                         {
184                                 return GetTypeByURL(o);
185                         }
186
187                         internal IDictionaryEnumerator GetEnumerator()
188                         {
189                                 return _table.GetEnumerator();                          
190                         }       
191
192                         public Type GetTypeByURL(string url)
193                         {
194                                 string lwUrl = url.ToLower();
195                                 lock (_table)
196                                 {
197                                         object retVal = _table[lwUrl];
198                                         if (retVal == null)
199                                         {
200                                                 PageCompiler compiler = new PageCompiler(url);
201                                                 retVal = compiler.GetCachedType();
202                                                 _table[lwUrl] = retVal;
203                                         }
204                                 
205                                         return (Type)retVal;
206                                 }
207                         }
208                 }
209                 #endregion
210
211         }
212
213         public class PageCompiler
214         {
215                 private static readonly string PAGE_XPATH = "preserve";
216                 private static readonly string ASSEM_ATTRIB_NAME = "assem";
217                 private static readonly string TYPE_ATTRIB_NAME = "type";
218                 private static string _parser = null;
219
220                 private Type _type = null;
221                 private string _xmlDescriptor = null;
222                 private string _url = null;
223                 private string _session = null;
224
225                 public PageCompiler(string url)
226                 {
227                         _url = url;
228                         _xmlDescriptor = GetDescFromUrl();
229                         _session = DateTime.Now.Ticks.ToString();
230                 }
231
232                 public Type GetCachedType()
233                 {
234                         if (_type != null)
235                                 return _type;
236                         
237                         string typeName = null;
238                 
239                         //if the desciptor exists in the war - get the type
240                         string descPath = String.Join("/", new string[]{"assemblies", _xmlDescriptor});
241
242                         try
243                         {
244 #if DEBUG
245                                 Console.WriteLine(descPath);
246 #endif
247                                 Stream fs = (Stream)IOUtils.getStream("/" + descPath);
248                                 if (fs != null)
249                                 {
250                                         typeName = GetTypeFromDescStream(fs);
251                                 }
252                         }
253                         catch (Exception ex)
254                         {
255 #if DEBUG
256                                 Console.WriteLine(ex);
257 #endif
258                                 //desc not in the war
259                                 typeName = null;
260                         }
261
262                         if (typeName != null)
263                         {
264                                 _type = Type.GetType(typeName);
265                                 return _type;
266                         }
267                         
268                         string fileName = Path.GetFileName(_url);
269                         if (fileName.ToLower() != "global.asax"
270                                 && fileName.ToLower() != "defaultwsdlhelpgenerator.aspx")
271                         {
272                                 string fullFileName = HttpContext.Current.Request.MapPath(_url);
273                                 if ( File.Exists(fullFileName) ) {
274                                         //type not found - run aspxparser
275                                         string[] command = GetParserCmd();
276                                         if (J2EEUtils.RunProc(command) != 0)
277                                                 throw GetCompilerError();
278                                 }
279                                 else {
280                                         string message = "The requested resource (" + _url + ") is not available.";
281                                         throw new HttpException(404, message);
282                                 }
283                         }
284                         //if the desciptor exists in the real app dir - get the type
285                         try
286                         {
287                                 StreamReader sr = new StreamReader(HttpContext.Current.Request.MapPath("/" + descPath));
288                                 typeName = GetTypeFromDescStream(sr.BaseStream);
289                                 sr.Close();
290                         }
291                         catch (Exception ex)
292                         {
293                                 Console.WriteLine(ex);
294                                 throw ex;
295                         }
296
297                         if (typeName != null)
298                         {
299                                 _type = Type.GetType(typeName);
300                                 return _type;
301                         }
302
303                         return null;
304                 }
305
306                 private string GetTypeFromDescStream(Stream fs)
307                 {
308                         if (fs != null)
309                         {
310                                 XmlDocument descXml = new XmlDocument();
311                                 descXml.Load(fs);
312                                 string assem = descXml.SelectSingleNode(PAGE_XPATH).Attributes[ASSEM_ATTRIB_NAME].Value;
313                                 string shortType = descXml.SelectSingleNode(PAGE_XPATH).Attributes[TYPE_ATTRIB_NAME].Value;
314                                 string typeName = String.Format("{0}, {1}",shortType,assem);
315                                 fs.Close();
316                                 return typeName;
317                         }
318
319                         return null;
320                 }
321
322                 private string[] GetParserCmd()
323                 {
324                         string[] cmd = new string[5];
325                         cmd[0] = GetParser();
326                         cmd[1] = "/aspxFiles:" + _url.Trim('/').Replace('/','\\');
327                         cmd[2] = "/session:" + _session;
328                         cmd[3] = "/appDir:" + (string)AppDomain.CurrentDomain.GetData(IAppDomainConfig.APP_PHYS_DIR);
329                         cmd[4] = "/compilepages";
330                         return cmd;
331                 }
332
333                 private string GetParser()
334                 {
335                         if (_parser == null)
336                         {
337                                 StreamReader sr =
338                                         File.OpenText(HttpContext.Current.Request.MapPath("/AspxParser.params"));
339                                 _parser = sr.ReadLine();
340                                 sr.Close();
341                         }
342
343                         return _parser;
344                 }
345
346                 private string GetDescFromUrl()
347                 {
348                         string fileName = Path.GetFileName(_url);
349                         
350                         if (fileName.ToLower() == "global.asax")
351                                 return "global.asax.xml";
352
353                         string id = GetIdFromUrl(_url);
354                         string[] descName = new string[3] {fileName, id, ".xml"} ;
355                         return string.Concat(descName).ToLower();
356                 }
357
358                 private string GetIdFromUrl(string path)
359                 {
360                         path = path.Trim('/');
361                         string fileName = Path.GetFileName(path);
362                         string id = string.Empty;
363                         if (path.Length > fileName.Length)
364                                 id = "." + path.Substring(0,path.Length - fileName.Length).Replace('/','_');
365                         return id;      
366                 }
367
368                 private Exception GetCompilerError()
369                 {
370                         string _errFile = HttpContext.Current.Request.MapPath("/" + _session + ".vmwerr");
371                         
372                         if (!File.Exists(_errFile))
373                                 throw new FileNotFoundException("Internal Error",_errFile);
374
375                         StreamReader sr = new StreamReader(_errFile);
376                         string message = string.Empty, line = null, file = null, lineInFile = "0";
377
378                         while ((line = sr.ReadLine()) != null)
379                         {
380                                 if (line.StartsWith("Message: "))
381                                         message = line.Substring("Message: ".Length);
382                                 else if (line.StartsWith("File: "))
383                                         file = line.Substring("File: ".Length);
384                                 else if (line.StartsWith("Line: "))
385                                         lineInFile = line.Substring("Line: ".Length);
386                         }
387
388                         sr.Close();
389
390                         if (file != null)
391                         {
392                                 Location loc = new Location(null);
393                                 loc.Filename = file;
394                                 loc.BeginLine = int.Parse(lineInFile);
395                                 return new ParseException(loc,message);
396                         }
397
398                         if (message.IndexOf(typeof(FileNotFoundException).Name) != -1 &&
399                                 message.IndexOf(_url.Trim('\\','/').Replace('/','\\')) != -1)
400                                 message = "The requested resource (" + _url + ") is not available.";
401                         return new HttpException(404,(message !=  null ? message : string.Empty));
402                 }
403         }
404 }