2009-06-30 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mcs / class / corlib / System.Runtime.Remoting.Activation / ActivationServices.cs
1 //
2 // System.Runtime.Remoting.ActivationServices.cs
3 //
4 // Author: Lluis Sanchez Gual (lluis@ideary.com)
5 //
6 // (C) 2002, Lluis Sanchez Gual
7 //
8
9 //
10 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System;
33 using System.Threading;
34 using System.Runtime.Remoting.Messaging;
35 using System.Runtime.Remoting.Activation;
36 using System.Runtime.Remoting.Contexts;
37 using System.Runtime.Remoting.Proxies;
38 using System.Reflection;
39 using System.Runtime.CompilerServices;
40 using System.Collections;
41 using System.Runtime.Remoting.Channels;
42
43 namespace System.Runtime.Remoting.Activation
44 {
45         internal class ActivationServices
46         {
47                 static IActivator _constructionActivator = new ConstructionLevelActivator ();
48
49                 public static IMessage Activate (RemotingProxy proxy, ConstructionCall ctorCall)
50                 {
51                         IMessage response;
52                         ctorCall.SourceProxy = proxy;
53
54                         if (Thread.CurrentContext.HasExitSinks && !ctorCall.IsContextOk)
55                                 response = Thread.CurrentContext.GetClientContextSinkChain ().SyncProcessMessage (ctorCall);
56                         else
57                                 response = RemoteActivate (ctorCall);
58
59                         if (response is IConstructionReturnMessage && ((IConstructionReturnMessage)response).Exception == null && proxy.ObjectIdentity == null)
60                         {
61                                 Identity identity = RemotingServices.GetMessageTargetIdentity (ctorCall);
62                                 proxy.AttachIdentity (identity);
63                         }
64
65                         return response;
66                 }
67
68                 public static IMessage RemoteActivate (IConstructionCallMessage ctorCall)
69                 {
70                         try 
71                         {
72                                 return ctorCall.Activator.Activate (ctorCall);
73                         }
74                         catch (Exception ex) 
75                         {
76                                 return new ReturnMessage (ex, ctorCall);
77                         }               
78                 }
79
80                 public static object CreateProxyFromAttributes (Type type, object[] activationAttributes)
81                 {
82                         string activationUrl = null;
83                         foreach (object attr in activationAttributes)
84                         {
85                                 if (!(attr is IContextAttribute)) throw new RemotingException ("Activation attribute does not implement the IContextAttribute interface");
86                                 if (attr is UrlAttribute) activationUrl = ((UrlAttribute)attr).UrlValue;
87                         }
88
89                         if (activationUrl != null)
90                                 return RemotingServices.CreateClientProxy (type, activationUrl, activationAttributes);
91
92                         ActivatedClientTypeEntry activatedEntry = RemotingConfiguration.IsRemotelyActivatedClientType (type);
93                         if (activatedEntry != null)
94                                 return RemotingServices.CreateClientProxy (activatedEntry, activationAttributes);
95
96                         if (type.IsContextful)
97                                 return RemotingServices.CreateClientProxyForContextBound (type, activationAttributes);
98                         
99                         return null;
100                 }
101
102                 public static ConstructionCall CreateConstructionCall (Type type, string activationUrl, object[] activationAttributes)
103                 {
104                         ConstructionCall ctorCall = new ConstructionCall (type);
105
106                         if (!type.IsContextful) 
107                         {
108                                 // Must be a remote activated object
109                                 ctorCall.Activator = new AppDomainLevelActivator (activationUrl, _constructionActivator);
110                                 ctorCall.IsContextOk = false;   // It'll be activated in a remote context
111                                 return ctorCall;
112                         }
113
114                         // It is a CBO. Need collect context properties and
115                         // check if a new context is needed.
116
117                         IActivator activatorChain = _constructionActivator;
118                         activatorChain = new ContextLevelActivator (activatorChain);
119
120                         ArrayList attributes = new ArrayList ();
121                         if (activationAttributes != null) attributes.AddRange (activationAttributes);
122
123                         bool isContextOk = (activationUrl == ChannelServices.CrossContextUrl);  // Remote CBOs are always created in a new context
124                         Context currentContext = Threading.Thread.CurrentContext;
125
126                         if (isContextOk) 
127                         {
128                                 foreach (IContextAttribute attr in attributes) 
129                                 {
130                                         if (!attr.IsContextOK (currentContext, ctorCall)) 
131                                         {
132                                                 isContextOk = false;
133                                                 break;
134                                         }
135                                 }
136                         }
137
138                         object[] typeAttributes = type.GetCustomAttributes (true);
139                         foreach (object attr in typeAttributes) 
140                         {
141                                 if (attr is IContextAttribute) 
142                                 {
143                                         isContextOk = isContextOk && ((IContextAttribute)attr).IsContextOK (currentContext, ctorCall);
144                                         attributes.Add (attr);
145                                 }
146                         }
147
148                         if (!isContextOk)
149                         {
150                                 // A new context is needed. Collect the context properties and chain
151                                 // the context level activator.
152
153                                 ctorCall.SetActivationAttributes (attributes.ToArray());
154
155                                 foreach (IContextAttribute attr in attributes)
156                                         attr.GetPropertiesForNewContext (ctorCall);
157                         }
158
159                         if (activationUrl != ChannelServices.CrossContextUrl)
160                                 activatorChain = new AppDomainLevelActivator (activationUrl, activatorChain);
161                         
162                         ctorCall.Activator = activatorChain;
163                         ctorCall.IsContextOk = isContextOk;
164
165                         return ctorCall;
166                 }
167
168                 public static IMessage CreateInstanceFromMessage (IConstructionCallMessage ctorCall)
169                 {
170                         object obj = AllocateUninitializedClassInstance (ctorCall.ActivationType);
171
172                         ServerIdentity identity = (ServerIdentity) RemotingServices.GetMessageTargetIdentity (ctorCall);
173                         identity.AttachServerObject ((MarshalByRefObject) obj, Threading.Thread.CurrentContext);
174
175                         ConstructionCall call = ctorCall as ConstructionCall;
176                         if (ctorCall.ActivationType.IsContextful && call != null && call.SourceProxy != null)
177                         {
178                                 call.SourceProxy.AttachIdentity (identity);
179                                 MarshalByRefObject target = (MarshalByRefObject) call.SourceProxy.GetTransparentProxy ();
180                                 RemotingServices.InternalExecuteMessage (target, ctorCall);
181                         }
182                         else
183                                 ctorCall.MethodBase.Invoke (obj, ctorCall.Args);
184
185                         return new ConstructionResponse (obj, null, ctorCall);
186                 }
187
188                 public static object CreateProxyForType (Type type)
189                 {
190                         // Called by the runtime when creating an instance of a type
191                         // that has been registered as remotely activated.
192
193                         // First of all check for remote activation. If the object is not remote, then
194                         // it may be contextbound.
195
196                         ActivatedClientTypeEntry activatedEntry = RemotingConfiguration.IsRemotelyActivatedClientType (type);
197                         if (activatedEntry != null)
198                                 return RemotingServices.CreateClientProxy (activatedEntry, null);
199
200                         WellKnownClientTypeEntry wellknownEntry = RemotingConfiguration.IsWellKnownClientType (type);
201                         if (wellknownEntry != null)
202                                 return RemotingServices.CreateClientProxy (wellknownEntry);
203
204                         if (type.IsContextful)
205                                 return RemotingServices.CreateClientProxyForContextBound (type, null);
206
207                         if (type.IsCOMObject) {
208                                 return RemotingServices.CreateClientProxyForComInterop (type);
209                         }
210
211                         return null;
212                 }
213
214                 // Allocates an uninitialized instance. It never creates proxies.
215                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
216                 public static extern object AllocateUninitializedClassInstance (Type type);
217
218                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
219                 public extern static void EnableProxyActivation (Type type, bool enable);
220         }
221 }