opensim-development – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 1 /*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27  
28 using System;
29 using System.Collections.Generic;
30 using System.IO;
31 using System.Reflection;
32 using log4net;
33 using Mono.Addins;
34  
35 namespace OpenSim.Framework
36 {
37 /// <summary>
38 /// Exception thrown if an incorrect number of plugins are loaded
39 /// </summary>
40 public class PluginConstraintViolatedException : Exception
41 {
42 public PluginConstraintViolatedException () : base() {}
43 public PluginConstraintViolatedException (string msg) : base(msg) {}
44 public PluginConstraintViolatedException (string msg, Exception e) : base(msg, e) {}
45 }
46  
47 /// <summary>
48 /// Classes wishing to impose constraints on plugin loading must implement
49 /// this class and pass it to PluginLoader AddConstraint()
50 /// </summary>
51 public interface IPluginConstraint
52 {
53 string Message { get; }
54 bool Apply(string extpoint);
55 }
56  
57 /// <summary>
58 /// Classes wishing to select specific plugins from a range of possible options
59 /// must implement this class and pass it to PluginLoader Load()
60 /// </summary>
61 public interface IPluginFilter
62 {
63 bool Apply(PluginExtensionNode plugin);
64 }
65  
66 /// <summary>
67 /// Generic Plugin Loader
68 /// </summary>
69 public class PluginLoader <T> : IDisposable where T : IPlugin
70 {
71 private const int max_loadable_plugins = 10000;
72  
73 private List<T> loaded = new List<T>();
74 private List<string> extpoints = new List<string>();
75 private PluginInitialiserBase initialiser;
76  
77 private Dictionary<string,IPluginConstraint> constraints
78 = new Dictionary<string,IPluginConstraint>();
79  
80 private Dictionary<string,IPluginFilter> filters
81 = new Dictionary<string,IPluginFilter>();
82  
83 private static readonly ILog log
84 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
85  
86 public PluginInitialiserBase Initialiser
87 {
88 set { initialiser = value; }
89 get { return initialiser; }
90 }
91  
92 public List<T> Plugins
93 {
94 get { return loaded; }
95 }
96  
97 public T Plugin
98 {
99 get { return (loaded.Count == 1)? loaded [0] : default (T); }
100 }
101  
102 public PluginLoader()
103 {
104 Initialiser = new PluginInitialiserBase();
105 initialise_plugin_dir_(".");
106 }
107  
108 public PluginLoader(PluginInitialiserBase init)
109 {
110 Initialiser = init;
111 initialise_plugin_dir_(".");
112 }
113  
114 public PluginLoader(PluginInitialiserBase init, string dir)
115 {
116 Initialiser = init;
117 initialise_plugin_dir_(dir);
118 }
119  
120 public void Add(string extpoint)
121 {
122 if (extpoints.Contains(extpoint))
123 return;
124  
125 extpoints.Add(extpoint);
126 }
127  
128 public void Add(string extpoint, IPluginConstraint cons)
129 {
130 Add(extpoint);
131 AddConstraint(extpoint, cons);
132 }
133  
134 public void Add(string extpoint, IPluginFilter filter)
135 {
136 Add(extpoint);
137 AddFilter(extpoint, filter);
138 }
139  
140 public void AddConstraint(string extpoint, IPluginConstraint cons)
141 {
142 constraints.Add(extpoint, cons);
143 }
144  
145 public void AddFilter(string extpoint, IPluginFilter filter)
146 {
147 filters.Add(extpoint, filter);
148 }
149  
150 public void Load(string extpoint)
151 {
152 Add(extpoint);
153 Load();
154 }
155  
156 public void Load()
157 {
158 foreach (string ext in extpoints)
159 {
160 log.Info("[PLUGINS]: Loading extension point " + ext);
161  
162 if (constraints.ContainsKey(ext))
163 {
164 IPluginConstraint cons = constraints[ext];
165 if (cons.Apply(ext))
166 log.Error("[PLUGINS]: " + ext + " failed constraint: " + cons.Message);
167 }
168  
169 IPluginFilter filter = null;
170  
171 if (filters.ContainsKey(ext))
172 filter = filters[ext];
173  
174 List<T> loadedPlugins = new List<T>();
175 foreach (PluginExtensionNode node in AddinManager.GetExtensionNodes(ext))
176 {
177 log.Info("[PLUGINS]: Trying plugin " + node.Path);
178  
179 if ((filter != null) && (filter.Apply(node) == false))
180 continue;
181  
182 T plugin = (T)node.CreateInstance();
183 loadedPlugins.Add(plugin);
184 }
185  
186 // We do Initialise() in a second loop after CreateInstance
187 // So that modules who need init before others can do it
188 // Example: Script Engine Component System needs to load its components before RegionLoader starts
189 foreach (T plugin in loadedPlugins)
190 {
191 Initialiser.Initialise(plugin);
192 Plugins.Add(plugin);
193 }
194 }
195 }
196  
197 /// <summary>
198 /// Unregisters Mono.Addins event handlers, allowing temporary Mono.Addins
199 /// data to be garbage collected. Since the plugins created by this loader
200 /// are meant to outlive the loader itself, they must be disposed separately
201 /// </summary>
202 public void Dispose()
203 {
204 AddinManager.AddinLoadError -= on_addinloaderror_;
205 AddinManager.AddinLoaded -= on_addinloaded_;
206 }
207  
208 private void initialise_plugin_dir_(string dir)
209 {
210 if (AddinManager.IsInitialized == true)
211 return;
212  
213 log.Info("[PLUGINS]: Initializing addin manager");
214  
215 AddinManager.AddinLoadError += on_addinloaderror_;
216 AddinManager.AddinLoaded += on_addinloaded_;
217  
218 clear_registry_();
219  
220 suppress_console_output_(true);
221 AddinManager.Initialize(dir);
222 AddinManager.Registry.Update(null);
223 suppress_console_output_(false);
224 }
225  
226 private void on_addinloaded_(object sender, AddinEventArgs args)
227 {
228 log.Info ("[PLUGINS]: Plugin Loaded: " + args.AddinId);
229 }
230  
231 private void on_addinloaderror_(object sender, AddinErrorEventArgs args)
232 {
233 if (args.Exception == null)
234 log.Error ("[PLUGINS]: Plugin Error: "
235 + args.Message);
236 else
237 log.Error ("[PLUGINS]: Plugin Error: "
238 + args.Exception.Message + "\n"
239 + args.Exception.StackTrace);
240 }
241  
242 private void clear_registry_()
243 {
244 // The Mono addin manager (in Mono.Addins.dll version 0.2.0.0)
245 // occasionally seems to corrupt its addin cache
246 // Hence, as a temporary solution we'll remove it before each startup
247 try
248 {
249 if (Directory.Exists("addin-db-000"))
250 Directory.Delete("addin-db-000", true);
251  
252 if (Directory.Exists("addin-db-001"))
253 Directory.Delete("addin-db-001", true);
254 }
255 catch (IOException)
256 {
257 // If multiple services are started simultaneously, they may
258 // each test whether the directory exists at the same time, and
259 // attempt to delete the directory at the same time. However,
260 // one of the services will likely succeed first, causing the
261 // second service to throw an IOException. We catch it here and
262 // continue on our merry way.
263 // Mike 2008.08.01, patch from Zaki
264 }
265 }
266  
267 private static TextWriter prev_console_;
268 public void suppress_console_output_(bool save)
269 {
270 if (save)
271 {
272 prev_console_ = System.Console.Out;
273 System.Console.SetOut(new StreamWriter(Stream.Null));
274 }
275 else
276 {
277 if (prev_console_ != null)
278 System.Console.SetOut(prev_console_);
279 }
280 }
281 }
282  
283 public class PluginExtensionNode : ExtensionNode
284 {
285 [NodeAttribute]
286 string id = "";
287  
288 [NodeAttribute]
289 string provider = "";
290  
291 [NodeAttribute]
292 string type = "";
293  
294 Type typeobj;
295  
296 public string ID { get { return id; } }
297 public string Provider { get { return provider; } }
298 public string TypeName { get { return type; } }
299  
300 public Type TypeObject
301 {
302 get
303 {
304 if (typeobj != null)
305 return typeobj;
306  
307 if (type.Length == 0)
308 throw new InvalidOperationException("Type name not specified.");
309  
310 return typeobj = Addin.GetType(type, true);
311 }
312 }
313  
314 public object CreateInstance()
315 {
316 return Activator.CreateInstance(TypeObject);
317 }
318 }
319  
320 /// <summary>
321 /// Constraint that bounds the number of plugins to be loaded.
322 /// </summary>
323 public class PluginCountConstraint : IPluginConstraint
324 {
325 private int min;
326 private int max;
327  
328 public PluginCountConstraint(int exact)
329 {
330 min = exact;
331 max = exact;
332 }
333  
334 public PluginCountConstraint(int minimum, int maximum)
335 {
336 min = minimum;
337 max = maximum;
338 }
339  
340 public string Message
341 {
342 get
343 {
344 return "The number of plugins is constrained to the interval ["
345 + min + ", " + max + "]";
346 }
347 }
348  
349 public bool Apply (string extpoint)
350 {
351 int count = AddinManager.GetExtensionNodes(extpoint).Count;
352  
353 if ((count < min) || (count > max))
354 throw new PluginConstraintViolatedException(Message);
355  
356 return true;
357 }
358 }
359  
360 /// <summary>
361 /// Filters out which plugin to load based on the plugin name or names given. Plugin names are contained in
362 /// their addin.xml
363 /// </summary>
364 public class PluginProviderFilter : IPluginFilter
365 {
366 private string[] m_filters;
367  
368 /// <summary>
369 /// Constructor.
370 /// </summary>
371 /// <param name="p">
372 /// Plugin name or names on which to filter. Multiple names should be separated by commas.
373 /// </param>
374 public PluginProviderFilter(string p)
375 {
376 m_filters = p.Split(',');
377  
378 for (int i = 0; i < m_filters.Length; i++)
379 {
380 m_filters[i] = m_filters[i].Trim();
381 }
382 }
383  
384 /// <summary>
385 /// Apply this filter to the given plugin.
386 /// </summary>
387 /// <param name="plugin"></param>
388 /// <returns>true if the plugin's name matched one of the filters, false otherwise.</returns>
389 public bool Apply (PluginExtensionNode plugin)
390 {
391 for (int i = 0; i < m_filters.Length; i++)
392 {
393 if (m_filters[i] == plugin.Provider)
394 {
395 return true;
396 }
397 }
398  
399 return false;
400 }
401 }
402  
403 /// <summary>
404 /// Filters plugins according to their ID. Plugin IDs are contained in their addin.xml
405 /// </summary>
406 public class PluginIdFilter : IPluginFilter
407 {
408 private string[] m_filters;
409  
410 /// <summary>
411 /// Constructor.
412 /// </summary>
413 /// <param name="p">
414 /// Plugin ID or IDs on which to filter. Multiple names should be separated by commas.
415 /// </param>
416 public PluginIdFilter(string p)
417 {
418 m_filters = p.Split(',');
419  
420 for (int i = 0; i < m_filters.Length; i++)
421 {
422 m_filters[i] = m_filters[i].Trim();
423 }
424 }
425  
426 /// <summary>
427 /// Apply this filter to <paramref name="plugin" />.
428 /// </summary>
429 /// <param name="plugin">PluginExtensionNode instance to check whether it passes the filter.</param>
430 /// <returns>true if the plugin's ID matches one of the filters, false otherwise.</returns>
431 public bool Apply (PluginExtensionNode plugin)
432 {
433 for (int i = 0; i < m_filters.Length; i++)
434 {
435 if (m_filters[i] == plugin.ID)
436 {
437 return true;
438 }
439 }
440  
441 return false;
442 }
443 }
444 }