2009-07-10 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel.Channels / SvcHttpHandlerFactory.cs
1 //
2 // SvcHttpHandlerFactory.cs
3 //
4 // Author:
5 //      Ankit Jain  <jankit@novell.com>
6 //
7 // Copyright (C) 2006 Novell, Inc.  http://www.novell.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 System;
30 using System.Collections;
31 using System.Collections.Generic;
32 using System.Collections.Specialized;
33 using System.IO;
34 using System.Reflection;
35 using System.ServiceModel;
36 using System.Web;
37 using System.Web.Caching;
38
39 namespace System.ServiceModel.Channels {
40
41         internal class SvcHttpHandlerFactory : IHttpHandlerFactory
42         {
43                 static Dictionary<string, SvcHttpHandler> handlers = new Dictionary<string, SvcHttpHandler> ();
44                 string privateBinPath;
45                 Type service_type, factory_type;
46
47                 public SvcHttpHandlerFactory ()
48                 {
49                         ServiceHostingEnvironment.InAspNet = true;
50                 }
51
52                 public IHttpHandler GetHandler (HttpContext context, string requestType, string url, string pathTranslated)
53                 {
54                         if (handlers.ContainsKey (url))
55                                 return handlers [url];
56                         
57                         LoadTypeFromSvc (pathTranslated, url, context);
58                         if (service_type == null)
59                                 throw new Exception (String.Format (
60                                         "Could not find service for url : '{0}'", url));
61                         
62                         SvcHttpHandler handler = new SvcHttpHandler (service_type, factory_type, url);
63                         handlers [url] = handler;
64
65                         return handler;
66                 }
67
68                 [MonoTODO]
69                 public void ReleaseHandler (IHttpHandler handler)
70                 {
71                         return;
72                 }
73
74                 internal static SvcHttpHandler GetHandler (string path)
75                 {
76                         return handlers [path];
77                 }
78
79                 void LoadTypeFromSvc (string path, string url, HttpContext context)
80                 {
81                         if (CachingCompiler.GetTypeFromCache (path) != null)
82                                 return;
83                         
84                         ServiceHostParser parser = new ServiceHostParser (path, url, context);
85                         
86                         parser.Parse ();
87                         if (parser.Program == null) {
88                                 //FIXME: Not caching, as parser.TypeName could be
89                                 //just typename or fully qualified name
90                                 service_type = GetTypeFromBin (parser.TypeName);
91                                 /*CachingCompiler.InsertType (
92                                         service_type, service_type.Assembly.Location, url, 
93                                         new CacheItemRemovedCallback (RemovedCallback));*/
94                         } else {
95                                 service_type = CachingCompiler.CompileAndGetType (
96                                         parser, url,
97                                         new CacheItemRemovedCallback (RemovedCallback));
98                         }
99
100                         if (parser.Factory != null) {
101                                 factory_type = GetTypeFromBin (parser.Factory);
102                                 /*CachingCompiler.InsertType (
103                                         factory_type, factory_type.Assembly.Location, url, 
104                                         new CacheItemRemovedCallback (RemovedCallback));*/
105                         }
106                 }
107                 
108                 string PrivateBinPath {
109                         get {
110                                 if (privateBinPath != null)
111                                         return privateBinPath;
112
113                                 AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
114                                 privateBinPath = setup.PrivateBinPath;
115                                         
116                                 if (!Path.IsPathRooted (privateBinPath)) {
117                                         string appbase = setup.ApplicationBase;
118                                         if (appbase.StartsWith ("file://")) {
119                                                 appbase = appbase.Substring (7);
120                                                 if (Path.DirectorySeparatorChar != '/')
121                                                         appbase = appbase.Replace ('/', Path.DirectorySeparatorChar);
122                                         }
123                                         privateBinPath = Path.Combine (appbase, privateBinPath);
124                                 }
125
126                                 return privateBinPath;
127                         }
128                 }
129
130                 //FIXME: Service="TypeName,TypeNamespace" not handled
131                 Type GetTypeFromBin (string typeName)
132                 {
133                         if (!Directory.Exists (PrivateBinPath))
134                                 throw new HttpException (String.Format ("Type {0} not found.", typeName));
135
136                         string [] binDlls = Directory.GetFiles (PrivateBinPath, "*.dll");
137                         Type result = null;
138                         foreach (string dll in binDlls) {
139                                 Assembly assembly = Assembly.LoadFrom (dll);
140                                 Type type = assembly.GetType (typeName, false);
141                                 if (type != null) {
142                                         if (result != null) 
143                                                 throw new HttpException (String.Format ("Type {0} is not unique.", typeName));
144
145                                         result = type;
146                                 } 
147                         }
148
149                         if (result == null)
150                                 throw new HttpException (String.Format ("Type {0} not found.", typeName));
151
152                         return result;
153                 }
154
155                 public static void RemovedCallback (string key, object value, CacheItemRemovedReason reason)
156                 {
157                         if (key.StartsWith (CachingCompiler.cacheTypePrefix)) {
158                                 string path = key.Remove (0, CachingCompiler.cacheTypePrefix.Length);
159
160                                 SvcHttpHandler handler;
161                                 if (!handlers.TryGetValue (path, out handler))
162                                         return;
163                                 handler.Close ();
164
165                                 handlers.Remove (path);
166                         }
167                 }
168         }
169 }