diff options
Cleanup and comment the region module loader. Add support for configuring
a server port to use for modules in a generic way and also add support
for disabling modules that don't support proper disabling.
Add support for selective loading by class name (advanced users only)
Diffstat (limited to 'OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs')
-rw-r--r-- | OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs | 199 |
1 files changed, 173 insertions, 26 deletions
diff --git a/OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs b/OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs index f30a18b..13cb34c 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,111 @@ 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(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 | { |
77 | m_log.DebugFormat("[REGIONMODULES]: Found non-shared region module {0}, class {1}", node.Id, node.Type); | 124 | m_log.DebugFormat("[REGIONMODULES]: Found non-shared region module {0}, class {1}", node.Id, node.Type); |
78 | m_nonSharedModules.Add(node.Type); | 125 | m_nonSharedModules.Add(node); |
79 | } | 126 | } |
80 | else | 127 | else |
81 | m_log.DebugFormat("[REGIONMODULES]: Found unknown type of module {0}, class {1}", node.Id, node.Type); | 128 | m_log.DebugFormat("[REGIONMODULES]: Found unknown type of module {0}, class {1}", node.Id, node.Type); |
82 | } | 129 | } |
83 | 130 | ||
84 | // now we've got all the region-module classes loaded, create one instance of every ISharedRegionModule, | 131 | // 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 | 132 | // 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. | 133 | // no port or the more specific constructor fails. |
87 | foreach (Type type in m_sharedModules) | 134 | // This will be removed, so that any module capable of using a port |
135 | // must provide a constructor with a port in the future. | ||
136 | // For now, we do this so migration is easy. | ||
137 | // | ||
138 | foreach (TypeExtensionNode node in m_sharedModules) | ||
88 | { | 139 | { |
89 | ISharedRegionModule module = (ISharedRegionModule)Activator.CreateInstance(type); | 140 | Object[] ctorArgs = new Object[] {0}; |
141 | |||
142 | // Read the config again | ||
143 | string moduleString = | ||
144 | modulesConfig.GetString(node.Id, String.Empty); | ||
145 | |||
146 | // Get the port number, if there is one | ||
147 | if (moduleString != String.Empty) | ||
148 | { | ||
149 | // Get the port number from the string | ||
150 | string[] moduleParts = moduleString.Split(new char[] {'/'}, | ||
151 | 2); | ||
152 | if (moduleParts.Length > 1) | ||
153 | ctorArgs[0] = Convert.ToUInt32(moduleParts[0]); | ||
154 | } | ||
155 | |||
156 | // Try loading and initilaizing the module, using the | ||
157 | // port if appropriate | ||
158 | ISharedRegionModule module = null; | ||
159 | |||
160 | try | ||
161 | { | ||
162 | module = (ISharedRegionModule)Activator.CreateInstance( | ||
163 | node.Type, ctorArgs); | ||
164 | } | ||
165 | catch | ||
166 | { | ||
167 | module = (ISharedRegionModule)Activator.CreateInstance( | ||
168 | node.Type); | ||
169 | } | ||
170 | |||
171 | // OK, we're up and running | ||
90 | m_sharedInstances.Add(module); | 172 | m_sharedInstances.Add(module); |
91 | module.Initialise(openSim.ConfigSource.Source); | 173 | module.Initialise(openSim.ConfigSource.Source); |
92 | } | 174 | } |
93 | 175 | ||
176 | // Immediately run PostInitialise on shared modules | ||
94 | foreach (ISharedRegionModule module in m_sharedInstances) | 177 | foreach (ISharedRegionModule module in m_sharedInstances) |
95 | { | 178 | { |
96 | module.PostInitialise(); | 179 | module.PostInitialise(); |
@@ -105,6 +188,8 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
105 | 188 | ||
106 | #region IPlugin implementation | 189 | #region IPlugin implementation |
107 | 190 | ||
191 | // We don't do that here | ||
192 | // | ||
108 | public void Initialise () | 193 | public void Initialise () |
109 | { | 194 | { |
110 | throw new System.NotImplementedException(); | 195 | throw new System.NotImplementedException(); |
@@ -114,9 +199,11 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
114 | 199 | ||
115 | #region IDisposable implementation | 200 | #region IDisposable implementation |
116 | 201 | ||
202 | // Cleanup | ||
203 | // | ||
117 | public void Dispose () | 204 | public void Dispose () |
118 | { | 205 | { |
119 | // we expect that all regions have been removed already | 206 | // We expect that all regions have been removed already |
120 | while (m_sharedInstances.Count > 0) | 207 | while (m_sharedInstances.Count > 0) |
121 | { | 208 | { |
122 | m_sharedInstances[0].Close(); | 209 | m_sharedInstances[0].Close(); |
@@ -147,6 +234,11 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
147 | 234 | ||
148 | #region IRegionModulesController implementation | 235 | #region IRegionModulesController implementation |
149 | 236 | ||
237 | // The root of all evil. | ||
238 | // This is where we handle adding the modules to scenes when they | ||
239 | // load. This means that here we deal with replaceable interfaces, | ||
240 | // nonshared modules, etc. | ||
241 | // | ||
150 | public void AddRegionToModules (Scene scene) | 242 | public void AddRegionToModules (Scene scene) |
151 | { | 243 | { |
152 | Dictionary<Type, ISharedRegionModule> deferredSharedModules = | 244 | Dictionary<Type, ISharedRegionModule> deferredSharedModules = |
@@ -154,12 +246,26 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
154 | Dictionary<Type, INonSharedRegionModule> deferredNonSharedModules = | 246 | Dictionary<Type, INonSharedRegionModule> deferredNonSharedModules = |
155 | new Dictionary<Type, INonSharedRegionModule>(); | 247 | new Dictionary<Type, INonSharedRegionModule>(); |
156 | 248 | ||
249 | // We need this to see if a module has already been loaded and | ||
250 | // has defined a replaceable interface. It's a generic call, | ||
251 | // so this can't be used directly. It will be used later | ||
157 | Type s = scene.GetType(); | 252 | Type s = scene.GetType(); |
158 | MethodInfo mi = s.GetMethod("RequestModuleInterface"); | 253 | MethodInfo mi = s.GetMethod("RequestModuleInterface"); |
159 | 254 | ||
160 | List<ISharedRegionModule> sharedlist = new List<ISharedRegionModule>(); | 255 | // This will hold the shared modules we actually load |
256 | List<ISharedRegionModule> sharedlist = | ||
257 | new List<ISharedRegionModule>(); | ||
258 | |||
259 | // Iterate over the shared modules that have been loaded | ||
260 | // Add them to the new Scene | ||
161 | foreach (ISharedRegionModule module in m_sharedInstances) | 261 | foreach (ISharedRegionModule module in m_sharedInstances) |
162 | { | 262 | { |
263 | // Here is where we check if a replaceable interface | ||
264 | // is defined. If it is, the module is checked against | ||
265 | // the interfaces already defined. If the interface is | ||
266 | // defined, we simply skip the module. Else, if the module | ||
267 | // defines a replaceable interface, we add it to the deferred | ||
268 | // list. | ||
163 | Type replaceableInterface = module.ReplaceableInterface; | 269 | Type replaceableInterface = module.ReplaceableInterface; |
164 | if (replaceableInterface != null) | 270 | if (replaceableInterface != null) |
165 | { | 271 | { |
@@ -185,11 +291,41 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
185 | sharedlist.Add(module); | 291 | sharedlist.Add(module); |
186 | } | 292 | } |
187 | 293 | ||
294 | IConfig modulesConfig = | ||
295 | m_openSim.ConfigSource.Source.Configs["Modules"]; | ||
296 | |||
297 | // Scan for, and load, nonshared modules | ||
188 | List<INonSharedRegionModule> list = new List<INonSharedRegionModule>(); | 298 | List<INonSharedRegionModule> list = new List<INonSharedRegionModule>(); |
189 | foreach (Type type in m_nonSharedModules) | 299 | foreach (TypeExtensionNode node in m_nonSharedModules) |
190 | { | 300 | { |
191 | INonSharedRegionModule module = (INonSharedRegionModule)Activator.CreateInstance(type); | 301 | Object[] ctorArgs = new Object[] {0}; |
302 | |||
303 | // Read the config | ||
304 | string moduleString = | ||
305 | modulesConfig.GetString(node.Id, String.Empty); | ||
306 | |||
307 | // Get the port number, if there is one | ||
308 | if (moduleString != String.Empty) | ||
309 | { | ||
310 | // Get the port number from the string | ||
311 | string[] moduleParts = moduleString.Split(new char[] {'/'}, | ||
312 | 2); | ||
313 | if (moduleParts.Length > 1) | ||
314 | ctorArgs[0] = Convert.ToUInt32(moduleParts[0]); | ||
315 | } | ||
192 | 316 | ||
317 | // Actually load it | ||
318 | INonSharedRegionModule module = null; | ||
319 | try | ||
320 | { | ||
321 | module = (INonSharedRegionModule)Activator.CreateInstance(node.Type, ctorArgs); | ||
322 | } | ||
323 | catch | ||
324 | { | ||
325 | module = (INonSharedRegionModule)Activator.CreateInstance(node.Type); | ||
326 | } | ||
327 | |||
328 | // Check for replaceable interfaces | ||
193 | Type replaceableInterface = module.ReplaceableInterface; | 329 | Type replaceableInterface = module.ReplaceableInterface; |
194 | if (replaceableInterface != null) | 330 | if (replaceableInterface != null) |
195 | { | 331 | { |
@@ -209,11 +345,16 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
209 | m_log.DebugFormat("[REGIONMODULE]: Adding scene {0} to non-shared module {1}", | 345 | m_log.DebugFormat("[REGIONMODULE]: Adding scene {0} to non-shared module {1}", |
210 | scene.RegionInfo.RegionName, module.Name); | 346 | scene.RegionInfo.RegionName, module.Name); |
211 | 347 | ||
348 | // Initialise the module | ||
212 | module.Initialise(m_openSim.ConfigSource.Source); | 349 | module.Initialise(m_openSim.ConfigSource.Source); |
213 | 350 | ||
214 | list.Add(module); | 351 | list.Add(module); |
215 | } | 352 | } |
216 | 353 | ||
354 | // Now add the modules that we found to the scene. If a module | ||
355 | // wishes to override a replaceable interface, it needs to | ||
356 | // register it in Initialise, so that the deferred module | ||
357 | // won't load. | ||
217 | foreach (INonSharedRegionModule module in list) | 358 | foreach (INonSharedRegionModule module in list) |
218 | { | 359 | { |
219 | module.AddRegion(scene); | 360 | module.AddRegion(scene); |
@@ -223,9 +364,9 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
223 | // Now all modules without a replaceable base interface are loaded | 364 | // Now all modules without a replaceable base interface are loaded |
224 | // Replaceable modules have either been skipped, or omitted. | 365 | // Replaceable modules have either been skipped, or omitted. |
225 | // Now scan the deferred modules here | 366 | // Now scan the deferred modules here |
226 | |||
227 | foreach (ISharedRegionModule module in deferredSharedModules.Values) | 367 | foreach (ISharedRegionModule module in deferredSharedModules.Values) |
228 | { | 368 | { |
369 | // Determine if the interface has been replaced | ||
229 | Type replaceableInterface = module.ReplaceableInterface; | 370 | Type replaceableInterface = module.ReplaceableInterface; |
230 | MethodInfo mii = mi.MakeGenericMethod(replaceableInterface); | 371 | MethodInfo mii = mi.MakeGenericMethod(replaceableInterface); |
231 | 372 | ||
@@ -238,15 +379,20 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
238 | m_log.DebugFormat("[REGIONMODULE]: Adding scene {0} to shared module {1} (deferred)", | 379 | m_log.DebugFormat("[REGIONMODULE]: Adding scene {0} to shared module {1} (deferred)", |
239 | scene.RegionInfo.RegionName, module.Name); | 380 | scene.RegionInfo.RegionName, module.Name); |
240 | 381 | ||
382 | // Not replaced, load the module | ||
241 | module.AddRegion(scene); | 383 | module.AddRegion(scene); |
242 | scene.AddRegionModule(module.Name, module); | 384 | scene.AddRegionModule(module.Name, module); |
243 | 385 | ||
244 | sharedlist.Add(module); | 386 | sharedlist.Add(module); |
245 | } | 387 | } |
246 | 388 | ||
247 | List<INonSharedRegionModule> deferredlist = new List<INonSharedRegionModule>(); | 389 | // Same thing for nonshared modules, load them unless overridden |
390 | List<INonSharedRegionModule> deferredlist = | ||
391 | new List<INonSharedRegionModule>(); | ||
392 | |||
248 | foreach (INonSharedRegionModule module in deferredNonSharedModules.Values) | 393 | foreach (INonSharedRegionModule module in deferredNonSharedModules.Values) |
249 | { | 394 | { |
395 | // Check interface override | ||
250 | Type replaceableInterface = module.ReplaceableInterface; | 396 | Type replaceableInterface = module.ReplaceableInterface; |
251 | if (replaceableInterface != null) | 397 | if (replaceableInterface != null) |
252 | { | 398 | { |
@@ -268,6 +414,7 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
268 | deferredlist.Add(module); | 414 | deferredlist.Add(module); |
269 | } | 415 | } |
270 | 416 | ||
417 | // Finally, load valid deferred modules | ||
271 | foreach (INonSharedRegionModule module in deferredlist) | 418 | foreach (INonSharedRegionModule module in deferredlist) |
272 | { | 419 | { |
273 | module.AddRegion(scene); | 420 | module.AddRegion(scene); |