Added container accessor to Castle.Core
[castle.git] / InversionOfControl / Castle.MicroKernel / Facilities / Remoting / RemotingInspector.cs
blob4b7aa431da13b92d328cdc1329426e81f6e5b6cf
1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle.Facilities.Remoting
17 using System;
18 using System.Runtime.Remoting;
19 using Castle.Core;
21 using Castle.MicroKernel;
22 using Castle.MicroKernel.ModelBuilder;
23 using Castle.MicroKernel.Facilities;
24 using Castle.MicroKernel.SubSystems.Conversion;
26 enum RemotingStrategy
28 None,
29 Singleton,
30 SingleCall,
31 ClientActivated,
32 Component,
33 RecoverableComponent
36 /// <summary>
37 /// Inspects the model looking for remote component configuration. If found,
38 /// do the component Remoting configuration.
39 /// </summary>
40 public class RemotingInspector : IContributeComponentModelConstruction
42 private readonly RemotingRegistry remoteRegistry;
43 private readonly RemotingRegistry localRegistry;
44 private readonly ITypeConverter converter;
45 private readonly String baseUri;
46 private readonly bool isServer, isClient;
48 private const string UriExtension = ".rem";
50 /// <summary>
51 /// Initializes a new instance of the <see cref="RemotingInspector"/> class.
52 /// </summary>
53 /// <param name="converter">The converter.</param>
54 /// <param name="isServer">if set to <c>true</c> is a server.</param>
55 /// <param name="isClient">if set to <c>true</c> is a client.</param>
56 /// <param name="baseUri">The base URI.</param>
57 /// <param name="remoteRegistry">The remote registry.</param>
58 /// <param name="localRegistry">The local registry.</param>
59 public RemotingInspector(ITypeConverter converter, bool isServer, bool isClient,
60 String baseUri, RemotingRegistry remoteRegistry, RemotingRegistry localRegistry)
62 this.converter = converter;
63 this.isServer = isServer;
64 this.isClient = isClient;
65 this.baseUri = baseUri;
66 this.remoteRegistry = remoteRegistry;
67 this.localRegistry = localRegistry;
70 public void ProcessModel(IKernel kernel, ComponentModel model)
72 if (model.Configuration == null) return;
74 String remoteserverAttValue = model.Configuration.Attributes["remoteserver"];
75 String remoteclientAttValue = model.Configuration.Attributes["remoteclient"];
77 RemotingStrategy server = RemotingStrategy.None;
78 RemotingStrategy client = RemotingStrategy.None;
80 if (remoteserverAttValue == null && remoteclientAttValue == null)
82 return;
85 if (remoteserverAttValue != null)
87 server = (RemotingStrategy)
88 converter.PerformConversion(remoteserverAttValue, typeof(RemotingStrategy));
91 if (remoteclientAttValue != null)
93 client = (RemotingStrategy)
94 converter.PerformConversion(remoteclientAttValue, typeof(RemotingStrategy));
97 DoSemanticCheck(server, model, client);
99 ConfigureServerComponent(server, model.Implementation, model);
101 ConfigureClientComponent(client, model.Service, model);
104 private void ConfigureServerComponent(RemotingStrategy server, Type type, ComponentModel model)
106 if (server == RemotingStrategy.None) return;
108 String uri = ConstructServerURI(server, model.Name, model);
110 switch (server)
112 case RemotingStrategy.Singleton:
114 CheckURIIsNotNull(uri, model.Name);
116 RemotingConfiguration.RegisterWellKnownServiceType(type, uri, WellKnownObjectMode.Singleton);
118 break;
120 case RemotingStrategy.SingleCall:
122 CheckURIIsNotNull(uri, model.Name);
124 RemotingConfiguration.RegisterWellKnownServiceType(type, uri, WellKnownObjectMode.SingleCall);
126 break;
128 case RemotingStrategy.ClientActivated:
130 RemotingConfiguration.RegisterActivatedServiceType(type);
132 break;
134 case RemotingStrategy.Component:
136 localRegistry.AddComponentEntry(model);
138 break;
140 case RemotingStrategy.RecoverableComponent:
142 CheckURIIsNotNull(uri, model.Name);
144 ValidateLifeStyle(model);
146 localRegistry.AddComponentEntry(model);
148 model.ExtendedProperties.Add("remoting.uri", uri);
149 model.ExtendedProperties.Add("remoting.afinity", true);
151 model.CustomComponentActivator = typeof(RemoteMarshallerActivator);
153 break;
158 private static void ValidateLifeStyle(ComponentModel model)
160 if (model.LifestyleType != LifestyleType.Singleton &&
161 model.LifestyleType != LifestyleType.Undefined)
163 throw new FacilityException(String.Format("Component {0} is marked as a 'RecoverableComponent' but is using a lifestyle " +
164 "different than Singleton. Unfortunatelly Singleton is the only lifestyle supported for this of remoting component configuration", model.Name));
168 private void ConfigureClientComponent(RemotingStrategy client, Type type, ComponentModel model)
170 if (client == RemotingStrategy.None) return;
172 ResetDependencies(model);
174 String uri = ConstructClientURI(client, model.Name, model);
176 bool skipRemotingRegistration = Convert.ToBoolean(model.Configuration.Attributes["skipRemotingRegistration"]);
178 switch (client)
180 case RemotingStrategy.Singleton:
181 case RemotingStrategy.SingleCall:
183 if (!skipRemotingRegistration)
185 RemotingConfiguration.RegisterWellKnownClientType(type, uri);
188 model.ExtendedProperties.Add("remoting.uri", uri);
189 model.CustomComponentActivator = typeof(RemoteActivator);
191 break;
193 case RemotingStrategy.ClientActivated:
195 CheckHasBaseURI();
197 if (!skipRemotingRegistration)
199 RemotingConfiguration.RegisterActivatedClientType(type, baseUri);
202 model.ExtendedProperties.Add("remoting.appuri", baseUri);
203 model.CustomComponentActivator = typeof(RemoteClientActivatedActivator);
205 break;
207 case RemotingStrategy.Component:
209 model.ExtendedProperties.Add("remoting.remoteregistry", remoteRegistry);
210 model.CustomComponentActivator = typeof(RemoteActivatorThroughRegistry);
212 break;
214 case RemotingStrategy.RecoverableComponent:
216 CheckHasBaseURI();
218 String remoteUri = BuildUri(uri);
220 model.ExtendedProperties.Add("remoting.uri", remoteUri);
221 model.ExtendedProperties.Add("remoting.remoteregistry", remoteRegistry);
222 model.CustomComponentActivator = typeof(RemoteActivatorThroughConnector);
224 break;
229 private void DoSemanticCheck(RemotingStrategy server, ComponentModel model, RemotingStrategy client)
231 if (server != RemotingStrategy.None && client != RemotingStrategy.None)
233 String message = String.Format("Component {0} cannot be a remote server and a client "+
234 "at the same time", model.Name);
236 throw new FacilityException(message);
239 if (server == RemotingStrategy.Component && !isServer)
241 String message = String.Format("Component {0} was marked with remoteserver='component', " +
242 "but you must enable the remoting facility with isServer='true' to serve components this way", model.Name);
244 throw new FacilityException(message);
247 if (client == RemotingStrategy.Component && !isClient)
249 String message = String.Format("Component {0} was marked with remoteserver='component', " +
250 "but you must enable the remoting facility with isServer='true' to serve components this way", model.Name);
252 throw new FacilityException(message);
256 private String ConstructClientURI(RemotingStrategy client, String componentId, ComponentModel model)
258 if (client == RemotingStrategy.ClientActivated) return null;
260 String value = model.Configuration.Attributes["uri"];
262 String uriText;
264 if (client != RemotingStrategy.None && baseUri != null && value == null)
266 uriText = BuildUri(componentId);
268 else
270 uriText = value;
273 return uriText;
276 private String BuildUri(String cpntUri)
278 String uriText;
280 if (baseUri.EndsWith("/"))
282 uriText = SetUriExtensionIfNeeded(String.Format("{0}{1}", baseUri, cpntUri));
284 else
286 uriText = SetUriExtensionIfNeeded(String.Format("{0}/{1}", baseUri, cpntUri));
289 return uriText;
292 private static string SetUriExtensionIfNeeded(string uri)
294 if (!uri.EndsWith(".rem"))
296 return uri + UriExtension;
299 return uri;
302 private String ConstructServerURI(RemotingStrategy server, String componentId, ComponentModel model)
304 if (server == RemotingStrategy.ClientActivated) return null;
306 String value = model.Configuration.Attributes["uri"];
308 String uriText;
310 if (value == null)
312 uriText = SetUriExtensionIfNeeded(componentId);
314 else
316 uriText = SetUriExtensionIfNeeded(value);
319 return uriText;
322 /// <summary>
323 /// Client components are not created by the container
324 /// so there's no point collecting constructor dependencies
325 /// </summary>
326 /// <param name="model"></param>
327 private void ResetDependencies(ComponentModel model)
329 model.Dependencies.Clear();
330 model.Constructors.Clear();
333 private void CheckHasBaseURI()
335 if (baseUri == null)
337 String message = "baseUri must be defined in order to use client activated objects";
338 throw new FacilityException(message);
342 private void CheckURIIsNotNull(String uri, String componentId)
344 if (uri == null)
346 String message = String.Format("Could not obtain (or infer) " +
347 "URI for remote component {0}", componentId);
349 throw new FacilityException(message);