1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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
18 using System
.Runtime
.Remoting
;
21 using Castle
.MicroKernel
;
22 using Castle
.MicroKernel
.ModelBuilder
;
23 using Castle
.MicroKernel
.Facilities
;
24 using Castle
.MicroKernel
.SubSystems
.Conversion
;
37 /// Inspects the model looking for remote component configuration. If found,
38 /// do the component Remoting configuration.
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";
51 /// Initializes a new instance of the <see cref="RemotingInspector"/> class.
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)
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
);
112 case RemotingStrategy
.Singleton
:
114 CheckURIIsNotNull(uri
, model
.Name
);
116 RemotingConfiguration
.RegisterWellKnownServiceType(type
, uri
, WellKnownObjectMode
.Singleton
);
120 case RemotingStrategy
.SingleCall
:
122 CheckURIIsNotNull(uri
, model
.Name
);
124 RemotingConfiguration
.RegisterWellKnownServiceType(type
, uri
, WellKnownObjectMode
.SingleCall
);
128 case RemotingStrategy
.ClientActivated
:
130 RemotingConfiguration
.RegisterActivatedServiceType(type
);
134 case RemotingStrategy
.Component
:
136 localRegistry
.AddComponentEntry(model
);
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
);
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"]);
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
);
193 case RemotingStrategy
.ClientActivated
:
197 if (!skipRemotingRegistration
)
199 RemotingConfiguration
.RegisterActivatedClientType(type
, baseUri
);
202 model
.ExtendedProperties
.Add("remoting.appuri", baseUri
);
203 model
.CustomComponentActivator
= typeof(RemoteClientActivatedActivator
);
207 case RemotingStrategy
.Component
:
209 model
.ExtendedProperties
.Add("remoting.remoteregistry", remoteRegistry
);
210 model
.CustomComponentActivator
= typeof(RemoteActivatorThroughRegistry
);
214 case RemotingStrategy
.RecoverableComponent
:
218 String remoteUri
= BuildUri(uri
);
220 model
.ExtendedProperties
.Add("remoting.uri", remoteUri
);
221 model
.ExtendedProperties
.Add("remoting.remoteregistry", remoteRegistry
);
222 model
.CustomComponentActivator
= typeof(RemoteActivatorThroughConnector
);
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"];
264 if (client
!= RemotingStrategy
.None
&& baseUri
!= null && value == null)
266 uriText
= BuildUri(componentId
);
276 private String
BuildUri(String cpntUri
)
280 if (baseUri
.EndsWith("/"))
282 uriText
= SetUriExtensionIfNeeded(String
.Format("{0}{1}", baseUri
, cpntUri
));
286 uriText
= SetUriExtensionIfNeeded(String
.Format("{0}/{1}", baseUri
, cpntUri
));
292 private static string SetUriExtensionIfNeeded(string uri
)
294 if (!uri
.EndsWith(".rem"))
296 return uri
+ UriExtension
;
302 private String
ConstructServerURI(RemotingStrategy server
, String componentId
, ComponentModel model
)
304 if (server
== RemotingStrategy
.ClientActivated
) return null;
306 String
value = model
.Configuration
.Attributes
["uri"];
312 uriText
= SetUriExtensionIfNeeded(componentId
);
316 uriText
= SetUriExtensionIfNeeded(value);
323 /// Client components are not created by the container
324 /// so there's no point collecting constructor dependencies
326 /// <param name="model"></param>
327 private void ResetDependencies(ComponentModel model
)
329 model
.Dependencies
.Clear();
330 model
.Constructors
.Clear();
333 private void CheckHasBaseURI()
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
)
346 String message
= String
.Format("Could not obtain (or infer) " +
347 "URI for remote component {0}", componentId
);
349 throw new FacilityException(message
);