diff options
Diffstat (limited to 'OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs')
-rw-r--r-- | OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs | 236 |
1 files changed, 203 insertions, 33 deletions
diff --git a/OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs b/OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs index a868bd0..ddc37ed 100644 --- a/OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs +++ b/OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs | |||
@@ -30,24 +30,36 @@ using System.Collections.Generic; | |||
30 | using System.Reflection; | 30 | using System.Reflection; |
31 | using log4net; | 31 | using log4net; |
32 | using Mono.Addins; | 32 | using Mono.Addins; |
33 | using Nini.Config; | ||
33 | using OpenSim; | 34 | using OpenSim; |
34 | using OpenSim.Region.Framework.Interfaces; | 35 | using OpenSim.Region.Framework.Interfaces; |
35 | using OpenSim.Region.Framework.Scenes; | 36 | using OpenSim.Region.Framework.Scenes; |
36 | 37 | ||
37 | namespace OpenSim.ApplicationPlugins.RegionModulesController | 38 | namespace OpenSim.ApplicationPlugins.RegionModulesController |
38 | { | 39 | { |
39 | public class RegionModulesControllerPlugin : IRegionModulesController, IApplicationPlugin | 40 | public class RegionModulesControllerPlugin : IRegionModulesController, |
41 | IApplicationPlugin | ||
40 | { | 42 | { |
41 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 43 | // Logger |
44 | private static readonly ILog m_log = | ||
45 | LogManager.GetLogger( | ||
46 | MethodBase.GetCurrentMethod().DeclaringType); | ||
42 | 47 | ||
43 | private OpenSimBase m_openSim; // for getting the config | 48 | // Config access |
49 | private OpenSimBase m_openSim; | ||
44 | 50 | ||
51 | // Our name | ||
45 | private string m_name; | 52 | private string m_name; |
46 | 53 | ||
47 | private List<Type> m_nonSharedModules = new List<Type>(); | 54 | // Internal lists to collect information about modules present |
48 | private List<Type> m_sharedModules = new List<Type>(); | 55 | private List<TypeExtensionNode> m_nonSharedModules = |
56 | new List<TypeExtensionNode>(); | ||
57 | private List<TypeExtensionNode> m_sharedModules = | ||
58 | new List<TypeExtensionNode>(); | ||
49 | 59 | ||
50 | private List<ISharedRegionModule> m_sharedInstances = new List<ISharedRegionModule>(); | 60 | // List of shared module instances, for adding to Scenes |
61 | private List<ISharedRegionModule> m_sharedInstances = | ||
62 | new List<ISharedRegionModule>(); | ||
51 | 63 | ||
52 | #region IApplicationPlugin implementation | 64 | #region IApplicationPlugin implementation |
53 | 65 | ||
@@ -57,40 +69,136 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
57 | m_openSim = openSim; | 69 | m_openSim = openSim; |
58 | openSim.ApplicationRegistry.RegisterInterface<IRegionModulesController>(this); | 70 | openSim.ApplicationRegistry.RegisterInterface<IRegionModulesController>(this); |
59 | 71 | ||
72 | // Who we are | ||
60 | string id = AddinManager.CurrentAddin.Id; | 73 | string id = AddinManager.CurrentAddin.Id; |
61 | int pos = id.LastIndexOf("."); | ||
62 | if (pos == -1) m_name = id; | ||
63 | else m_name = id.Substring(pos + 1); | ||
64 | 74 | ||
65 | //ExtensionNodeList list = AddinManager.GetExtensionNodes("/OpenSim/RegionModules"); | 75 | // Make friendly name |
66 | // load all the (new) region-module classes | 76 | int pos = id.LastIndexOf("."); |
67 | foreach (TypeExtensionNode node in AddinManager.GetExtensionNodes("/OpenSim/RegionModules")) | 77 | if (pos == -1) |
78 | m_name = id; | ||
79 | else | ||
80 | m_name = id.Substring(pos + 1); | ||
81 | |||
82 | // The [Modules] section in the ini file | ||
83 | IConfig modulesConfig = | ||
84 | openSim.ConfigSource.Source.Configs["Modules"]; | ||
85 | if (modulesConfig == null) | ||
86 | modulesConfig = openSim.ConfigSource.Source.AddConfig("Modules"); | ||
87 | |||
88 | // Scan modules and load all that aren't disabled | ||
89 | foreach (TypeExtensionNode node in | ||
90 | AddinManager.GetExtensionNodes("/OpenSim/RegionModules")) | ||
68 | { | 91 | { |
69 | // TODO why does node.Type.isSubclassOf(typeof(ISharedRegionModule)) not work? | ||
70 | if (node.Type.GetInterface(typeof(ISharedRegionModule).ToString()) != null) | 92 | if (node.Type.GetInterface(typeof(ISharedRegionModule).ToString()) != null) |
71 | { | 93 | { |
94 | // Get the config string | ||
95 | string moduleString = | ||
96 | modulesConfig.GetString("Setup_" + node.Id, String.Empty); | ||
97 | |||
98 | // We have a selector | ||
99 | if (moduleString != String.Empty) | ||
100 | { | ||
101 | // Allow disabling modules even if they don't have | ||
102 | // support for it | ||
103 | if (moduleString == "disabled") | ||
104 | continue; | ||
105 | |||
106 | // Split off port, if present | ||
107 | string[] moduleParts = moduleString.Split(new char[] {'/'}, 2); | ||
108 | // Format is [port/][class] | ||
109 | string className = moduleParts[0]; | ||
110 | if (moduleParts.Length > 1) | ||
111 | className = moduleParts[1]; | ||
112 | |||
113 | // Match the class name if given | ||
114 | if (className != String.Empty && | ||
115 | node.Type.ToString() != className) | ||
116 | continue; | ||
117 | } | ||
118 | |||
72 | m_log.DebugFormat("[REGIONMODULES]: Found shared region module {0}, class {1}", node.Id, node.Type); | 119 | m_log.DebugFormat("[REGIONMODULES]: Found shared region module {0}, class {1}", node.Id, node.Type); |
73 | m_sharedModules.Add(node.Type); | 120 | m_sharedModules.Add(node); |
74 | } | 121 | } |
75 | else if (node.Type.GetInterface(typeof(INonSharedRegionModule).ToString()) != null) | 122 | else if (node.Type.GetInterface(typeof(INonSharedRegionModule).ToString()) != null) |
76 | { | 123 | { |
124 | // Get the config string | ||
125 | string moduleString = | ||
126 | modulesConfig.GetString("Setup_" + node.Id, String.Empty); | ||
127 | |||
128 | // We have a selector | ||
129 | if (moduleString != String.Empty) | ||
130 | { | ||
131 | // Allow disabling modules even if they don't have | ||
132 | // support for it | ||
133 | if (moduleString == "disabled") | ||
134 | continue; | ||
135 | |||
136 | // Split off port, if present | ||
137 | string[] moduleParts = moduleString.Split(new char[] {'/'}, 2); | ||
138 | // Format is [port/][class] | ||
139 | string className = moduleParts[0]; | ||
140 | if (moduleParts.Length > 1) | ||
141 | className = moduleParts[1]; | ||
142 | |||
143 | // Match the class name if given | ||
144 | if (className != String.Empty && | ||
145 | node.Type.ToString() != className) | ||
146 | continue; | ||
147 | } | ||
148 | |||
77 | m_log.DebugFormat("[REGIONMODULES]: Found non-shared region module {0}, class {1}", node.Id, node.Type); | 149 | m_log.DebugFormat("[REGIONMODULES]: Found non-shared region module {0}, class {1}", node.Id, node.Type); |
78 | m_nonSharedModules.Add(node.Type); | 150 | m_nonSharedModules.Add(node); |
79 | } | 151 | } |
80 | else | 152 | else |
81 | m_log.DebugFormat("[REGIONMODULES]: Found unknown type of module {0}, class {1}", node.Id, node.Type); | 153 | m_log.DebugFormat("[REGIONMODULES]: Found unknown type of module {0}, class {1}", node.Id, node.Type); |
82 | } | 154 | } |
83 | 155 | ||
84 | // now we've got all the region-module classes loaded, create one instance of every ISharedRegionModule, | 156 | // Load and init the module. We try a constructor with a port |
85 | // initialize and postinitialize it. This Initialise we are in is called before LoadRegion.PostInitialise | 157 | // if a port was given, fall back to one without if there is |
86 | // is called (which loads the regions), so we don't have any regions in the server yet. | 158 | // no port or the more specific constructor fails. |
87 | foreach (Type type in m_sharedModules) | 159 | // This will be removed, so that any module capable of using a port |
160 | // must provide a constructor with a port in the future. | ||
161 | // For now, we do this so migration is easy. | ||
162 | // | ||
163 | foreach (TypeExtensionNode node in m_sharedModules) | ||
88 | { | 164 | { |
89 | ISharedRegionModule module = (ISharedRegionModule)Activator.CreateInstance(type); | 165 | Object[] ctorArgs = new Object[] {(uint)0}; |
166 | |||
167 | // Read the config again | ||
168 | string moduleString = | ||
169 | modulesConfig.GetString("Setup_" + node.Id, String.Empty); | ||
170 | |||
171 | // Get the port number, if there is one | ||
172 | if (moduleString != String.Empty) | ||
173 | { | ||
174 | // Get the port number from the string | ||
175 | string[] moduleParts = moduleString.Split(new char[] {'/'}, | ||
176 | 2); | ||
177 | if (moduleParts.Length > 1) | ||
178 | ctorArgs[0] = Convert.ToUInt32(moduleParts[0]); | ||
179 | } | ||
180 | |||
181 | // Try loading and initilaizing the module, using the | ||
182 | // port if appropriate | ||
183 | ISharedRegionModule module = null; | ||
184 | |||
185 | try | ||
186 | { | ||
187 | module = (ISharedRegionModule)Activator.CreateInstance( | ||
188 | node.Type, ctorArgs); | ||
189 | } | ||
190 | catch | ||
191 | { | ||
192 | module = (ISharedRegionModule)Activator.CreateInstance( | ||
193 | node.Type); | ||
194 | } | ||
195 | |||
196 | // OK, we're up and running | ||
90 | m_sharedInstances.Add(module); | 197 | m_sharedInstances.Add(module); |
91 | module.Initialise(openSim.ConfigSource.Source); | 198 | module.Initialise(openSim.ConfigSource.Source); |
92 | } | 199 | } |
93 | 200 | ||
201 | // Immediately run PostInitialise on shared modules | ||
94 | foreach (ISharedRegionModule module in m_sharedInstances) | 202 | foreach (ISharedRegionModule module in m_sharedInstances) |
95 | { | 203 | { |
96 | module.PostInitialise(); | 204 | module.PostInitialise(); |
@@ -105,6 +213,8 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
105 | 213 | ||
106 | #region IPlugin implementation | 214 | #region IPlugin implementation |
107 | 215 | ||
216 | // We don't do that here | ||
217 | // | ||
108 | public void Initialise () | 218 | public void Initialise () |
109 | { | 219 | { |
110 | throw new System.NotImplementedException(); | 220 | throw new System.NotImplementedException(); |
@@ -114,9 +224,11 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
114 | 224 | ||
115 | #region IDisposable implementation | 225 | #region IDisposable implementation |
116 | 226 | ||
227 | // Cleanup | ||
228 | // | ||
117 | public void Dispose () | 229 | public void Dispose () |
118 | { | 230 | { |
119 | // we expect that all regions have been removed already | 231 | // We expect that all regions have been removed already |
120 | while (m_sharedInstances.Count > 0) | 232 | while (m_sharedInstances.Count > 0) |
121 | { | 233 | { |
122 | m_sharedInstances[0].Close(); | 234 | m_sharedInstances[0].Close(); |
@@ -147,6 +259,11 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
147 | 259 | ||
148 | #region IRegionModulesController implementation | 260 | #region IRegionModulesController implementation |
149 | 261 | ||
262 | // The root of all evil. | ||
263 | // This is where we handle adding the modules to scenes when they | ||
264 | // load. This means that here we deal with replaceable interfaces, | ||
265 | // nonshared modules, etc. | ||
266 | // | ||
150 | public void AddRegionToModules (Scene scene) | 267 | public void AddRegionToModules (Scene scene) |
151 | { | 268 | { |
152 | Dictionary<Type, ISharedRegionModule> deferredSharedModules = | 269 | Dictionary<Type, ISharedRegionModule> deferredSharedModules = |
@@ -154,12 +271,26 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
154 | Dictionary<Type, INonSharedRegionModule> deferredNonSharedModules = | 271 | Dictionary<Type, INonSharedRegionModule> deferredNonSharedModules = |
155 | new Dictionary<Type, INonSharedRegionModule>(); | 272 | new Dictionary<Type, INonSharedRegionModule>(); |
156 | 273 | ||
274 | // We need this to see if a module has already been loaded and | ||
275 | // has defined a replaceable interface. It's a generic call, | ||
276 | // so this can't be used directly. It will be used later | ||
157 | Type s = scene.GetType(); | 277 | Type s = scene.GetType(); |
158 | MethodInfo mi = s.GetMethod("RequestModuleInterface"); | 278 | MethodInfo mi = s.GetMethod("RequestModuleInterface"); |
159 | 279 | ||
160 | List<ISharedRegionModule> sharedlist = new List<ISharedRegionModule>(); | 280 | // This will hold the shared modules we actually load |
281 | List<ISharedRegionModule> sharedlist = | ||
282 | new List<ISharedRegionModule>(); | ||
283 | |||
284 | // Iterate over the shared modules that have been loaded | ||
285 | // Add them to the new Scene | ||
161 | foreach (ISharedRegionModule module in m_sharedInstances) | 286 | foreach (ISharedRegionModule module in m_sharedInstances) |
162 | { | 287 | { |
288 | // Here is where we check if a replaceable interface | ||
289 | // is defined. If it is, the module is checked against | ||
290 | // the interfaces already defined. If the interface is | ||
291 | // defined, we simply skip the module. Else, if the module | ||
292 | // defines a replaceable interface, we add it to the deferred | ||
293 | // list. | ||
163 | Type replaceableInterface = module.ReplaceableInterface; | 294 | Type replaceableInterface = module.ReplaceableInterface; |
164 | if (replaceableInterface != null) | 295 | if (replaceableInterface != null) |
165 | { | 296 | { |
@@ -185,11 +316,41 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
185 | sharedlist.Add(module); | 316 | sharedlist.Add(module); |
186 | } | 317 | } |
187 | 318 | ||
319 | IConfig modulesConfig = | ||
320 | m_openSim.ConfigSource.Source.Configs["Modules"]; | ||
321 | |||
322 | // Scan for, and load, nonshared modules | ||
188 | List<INonSharedRegionModule> list = new List<INonSharedRegionModule>(); | 323 | List<INonSharedRegionModule> list = new List<INonSharedRegionModule>(); |
189 | foreach (Type type in m_nonSharedModules) | 324 | foreach (TypeExtensionNode node in m_nonSharedModules) |
190 | { | 325 | { |
191 | INonSharedRegionModule module = (INonSharedRegionModule)Activator.CreateInstance(type); | 326 | Object[] ctorArgs = new Object[] {0}; |
327 | |||
328 | // Read the config | ||
329 | string moduleString = | ||
330 | modulesConfig.GetString("Setup_" + node.Id, String.Empty); | ||
331 | |||
332 | // Get the port number, if there is one | ||
333 | if (moduleString != String.Empty) | ||
334 | { | ||
335 | // Get the port number from the string | ||
336 | string[] moduleParts = moduleString.Split(new char[] {'/'}, | ||
337 | 2); | ||
338 | if (moduleParts.Length > 1) | ||
339 | ctorArgs[0] = Convert.ToUInt32(moduleParts[0]); | ||
340 | } | ||
192 | 341 | ||
342 | // Actually load it | ||
343 | INonSharedRegionModule module = null; | ||
344 | try | ||
345 | { | ||
346 | module = (INonSharedRegionModule)Activator.CreateInstance(node.Type, ctorArgs); | ||
347 | } | ||
348 | catch | ||
349 | { | ||
350 | module = (INonSharedRegionModule)Activator.CreateInstance(node.Type); | ||
351 | } | ||
352 | |||
353 | // Check for replaceable interfaces | ||
193 | Type replaceableInterface = module.ReplaceableInterface; | 354 | Type replaceableInterface = module.ReplaceableInterface; |
194 | if (replaceableInterface != null) | 355 | if (replaceableInterface != null) |
195 | { | 356 | { |
@@ -209,11 +370,16 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
209 | m_log.DebugFormat("[REGIONMODULE]: Adding scene {0} to non-shared module {1}", | 370 | m_log.DebugFormat("[REGIONMODULE]: Adding scene {0} to non-shared module {1}", |
210 | scene.RegionInfo.RegionName, module.Name); | 371 | scene.RegionInfo.RegionName, module.Name); |
211 | 372 | ||
373 | // Initialise the module | ||
212 | module.Initialise(m_openSim.ConfigSource.Source); | 374 | module.Initialise(m_openSim.ConfigSource.Source); |
213 | 375 | ||
214 | list.Add(module); | 376 | list.Add(module); |
215 | } | 377 | } |
216 | 378 | ||
379 | // Now add the modules that we found to the scene. If a module | ||
380 | // wishes to override a replaceable interface, it needs to | ||
381 | // register it in Initialise, so that the deferred module | ||
382 | // won't load. | ||
217 | foreach (INonSharedRegionModule module in list) | 383 | foreach (INonSharedRegionModule module in list) |
218 | { | 384 | { |
219 | module.AddRegion(scene); | 385 | module.AddRegion(scene); |
@@ -223,9 +389,9 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
223 | // Now all modules without a replaceable base interface are loaded | 389 | // Now all modules without a replaceable base interface are loaded |
224 | // Replaceable modules have either been skipped, or omitted. | 390 | // Replaceable modules have either been skipped, or omitted. |
225 | // Now scan the deferred modules here | 391 | // Now scan the deferred modules here |
226 | |||
227 | foreach (ISharedRegionModule module in deferredSharedModules.Values) | 392 | foreach (ISharedRegionModule module in deferredSharedModules.Values) |
228 | { | 393 | { |
394 | // Determine if the interface has been replaced | ||
229 | Type replaceableInterface = module.ReplaceableInterface; | 395 | Type replaceableInterface = module.ReplaceableInterface; |
230 | MethodInfo mii = mi.MakeGenericMethod(replaceableInterface); | 396 | MethodInfo mii = mi.MakeGenericMethod(replaceableInterface); |
231 | 397 | ||
@@ -238,15 +404,20 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
238 | m_log.DebugFormat("[REGIONMODULE]: Adding scene {0} to shared module {1} (deferred)", | 404 | m_log.DebugFormat("[REGIONMODULE]: Adding scene {0} to shared module {1} (deferred)", |
239 | scene.RegionInfo.RegionName, module.Name); | 405 | scene.RegionInfo.RegionName, module.Name); |
240 | 406 | ||
407 | // Not replaced, load the module | ||
241 | module.AddRegion(scene); | 408 | module.AddRegion(scene); |
242 | scene.AddRegionModule(module.Name, module); | 409 | scene.AddRegionModule(module.Name, module); |
243 | 410 | ||
244 | sharedlist.Add(module); | 411 | sharedlist.Add(module); |
245 | } | 412 | } |
246 | 413 | ||
247 | List<INonSharedRegionModule> deferredlist = new List<INonSharedRegionModule>(); | 414 | // Same thing for nonshared modules, load them unless overridden |
415 | List<INonSharedRegionModule> deferredlist = | ||
416 | new List<INonSharedRegionModule>(); | ||
417 | |||
248 | foreach (INonSharedRegionModule module in deferredNonSharedModules.Values) | 418 | foreach (INonSharedRegionModule module in deferredNonSharedModules.Values) |
249 | { | 419 | { |
420 | // Check interface override | ||
250 | Type replaceableInterface = module.ReplaceableInterface; | 421 | Type replaceableInterface = module.ReplaceableInterface; |
251 | if (replaceableInterface != null) | 422 | if (replaceableInterface != null) |
252 | { | 423 | { |
@@ -268,7 +439,8 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
268 | deferredlist.Add(module); | 439 | deferredlist.Add(module); |
269 | } | 440 | } |
270 | 441 | ||
271 | foreach (IRegionModuleBase module in deferredlist) | 442 | // Finally, load valid deferred modules |
443 | foreach (INonSharedRegionModule module in deferredlist) | ||
272 | { | 444 | { |
273 | module.AddRegion(scene); | 445 | module.AddRegion(scene); |
274 | scene.AddRegionModule(module.Name, module); | 446 | scene.AddRegionModule(module.Name, module); |
@@ -284,16 +456,14 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
284 | // and unneccessary caching logic repeated in all modules. | 456 | // and unneccessary caching logic repeated in all modules. |
285 | // The extra function stub is just that much cleaner | 457 | // The extra function stub is just that much cleaner |
286 | // | 458 | // |
287 | foreach (IRegionModuleBase module in sharedlist) | 459 | foreach (ISharedRegionModule module in sharedlist) |
288 | { | 460 | { |
289 | try { module.RegionLoaded(scene); } | 461 | module.RegionLoaded(scene); |
290 | catch (Exception ex) { m_log.Error("[REGIONMODULE]: Exception while loading shared region module " + module + ": " + ex.Message, ex); } | ||
291 | } | 462 | } |
292 | 463 | ||
293 | foreach (IRegionModuleBase module in list) | 464 | foreach (INonSharedRegionModule module in list) |
294 | { | 465 | { |
295 | try { module.RegionLoaded(scene); } | 466 | module.RegionLoaded(scene); |
296 | catch (Exception ex) { m_log.Error("[REGIONMODULE]: Exception while loading non-shared region module " + module + ": " + ex.Message, ex); } | ||
297 | } | 467 | } |
298 | } | 468 | } |
299 | 469 | ||