opensim – 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.IO;
30 using System.Reflection;
31 using System.Xml;
32 using System.Xml.Serialization;
33 using System.Text;
34 using System.Collections.Generic;
35 using log4net;
36 using Nini.Config;
37 using OpenSim.Framework;
38 using OpenMetaverse;
39 using Mono.Addins;
40 using OpenSim.Framework.Servers.HttpServer;
41 using OpenSim.Framework.Servers;
42  
43  
44 [assembly:AddinRoot("Robust", "0.1")]
45 namespace OpenSim.Server.Base
46 {
47 [TypeExtensionPoint(Path="/Robust/Connector", Name="RobustConnector")]
48 public interface IRobustConnector
49 {
50 string ConfigName
51 {
52 get;
53 }
54  
55 bool Enabled
56 {
57 get;
58 }
59  
60 string PluginPath
61 {
62 get;
63 set;
64 }
65  
66 uint Configure(IConfigSource config);
67 void Initialize(IHttpServer server);
68 void Unload();
69 }
70  
71 public class PluginLoader
72 {
73 static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
74  
75 public AddinRegistry Registry
76 {
77 get;
78 private set;
79 }
80  
81 public IConfigSource Config
82 {
83 get;
84 private set;
85 }
86  
87 public PluginLoader(IConfigSource config, string registryPath)
88 {
89 Config = config;
90  
91 Registry = new AddinRegistry(registryPath, ".");
92 suppress_console_output_(true);
93 AddinManager.Initialize(registryPath);
94 suppress_console_output_(false);
95 AddinManager.Registry.Update();
96 CommandManager commandmanager = new CommandManager(Registry);
97 AddinManager.AddExtensionNodeHandler("/Robust/Connector", OnExtensionChanged);
98 }
99  
100 private static TextWriter prev_console_;
101 // Temporarily masking the errors reported on start
102 // This is caused by a non-managed dll in the ./bin dir
103 // when the registry is initialized. The dll belongs to
104 // libomv, which has a hard-coded path to "." for pinvoke
105 // to load the openjpeg dll
106 //
107 // Will look for a way to fix, but for now this keeps the
108 // confusion to a minimum. this was copied from our region
109 // plugin loader, we have been doing this in there for a long time.
110 //
111 public void suppress_console_output_(bool save)
112 {
113 if (save)
114 {
115 prev_console_ = System.Console.Out;
116 System.Console.SetOut(new StreamWriter(Stream.Null));
117 }
118 else
119 {
120 if (prev_console_ != null)
121 System.Console.SetOut(prev_console_);
122 }
123 }
124  
125 private void OnExtensionChanged(object s, ExtensionNodeEventArgs args)
126 {
127 IRobustConnector connector = (IRobustConnector)args.ExtensionObject;
128 Addin a = Registry.GetAddin(args.ExtensionNode.Addin.Id);
129  
130 if(a == null)
131 {
132 Registry.Rebuild(null);
133 a = Registry.GetAddin(args.ExtensionNode.Addin.Id);
134 }
135  
136 switch(args.Change)
137 {
138 case ExtensionChange.Add:
139 if (a.AddinFile.Contains(Registry.DefaultAddinsFolder))
140 {
141 m_log.InfoFormat("[SERVER UTILS]: Adding {0} from registry", a.Name);
142 connector.PluginPath = System.IO.Path.Combine(Registry.DefaultAddinsFolder,a.Name.Replace(',', '.')); }
143 else
144 {
145 m_log.InfoFormat("[SERVER UTILS]: Adding {0} from ./bin", a.Name);
146 connector.PluginPath = a.AddinFile;
147 }
148 LoadPlugin(connector);
149 break;
150 case ExtensionChange.Remove:
151 m_log.InfoFormat("[SERVER UTILS]: Removing {0}", a.Name);
152 UnloadPlugin(connector);
153 break;
154 }
155 }
156  
157 private void LoadPlugin(IRobustConnector connector)
158 {
159 IHttpServer server = null;
160 uint port = connector.Configure(Config);
161  
162 if(connector.Enabled)
163 {
164 server = GetServer(connector, port);
165 connector.Initialize(server);
166 }
167 else
168 {
169 m_log.InfoFormat("[SERVER UTILS]: {0} Disabled.", connector.ConfigName);
170 }
171 }
172  
173 private void UnloadPlugin(IRobustConnector connector)
174 {
175 m_log.InfoFormat("[SERVER UTILS]: Unloading {0}", connector.ConfigName);
176  
177 connector.Unload();
178 }
179  
180 private IHttpServer GetServer(IRobustConnector connector, uint port)
181 {
182 IHttpServer server;
183  
184 if(port != 0)
185 server = MainServer.GetHttpServer(port);
186 else
187 server = MainServer.Instance;
188  
189 return server;
190 }
191 }
192  
193 public static class ServerUtils
194 {
195 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
196  
197 public static byte[] SerializeResult(XmlSerializer xs, object data)
198 {
199 MemoryStream ms = new MemoryStream();
200 XmlTextWriter xw = new XmlTextWriter(ms, Util.UTF8);
201 xw.Formatting = Formatting.Indented;
202 xs.Serialize(xw, data);
203 xw.Flush();
204  
205 ms.Seek(0, SeekOrigin.Begin);
206 byte[] ret = ms.GetBuffer();
207 Array.Resize(ref ret, (int)ms.Length);
208  
209 return ret;
210 }
211  
212 /// <summary>
213 /// Load a plugin from a dll with the given class or interface
214 /// </summary>
215 /// <param name="dllName"></param>
216 /// <param name="args">The arguments which control which constructor is invoked on the plugin</param>
217 /// <returns></returns>
218 public static T LoadPlugin<T> (string dllName, Object[] args) where T:class
219 {
220 // This is good to debug configuration problems
221 //if (dllName == string.Empty)
222 // Util.PrintCallStack();
223  
224 string className = String.Empty;
225  
226 // The path for a dynamic plugin will contain ":" on Windows
227 string[] parts = dllName.Split (new char[] {':'});
228  
229 if (parts [0].Length > 1)
230 {
231 dllName = parts [0];
232 if (parts.Length > 1)
233 className = parts[1];
234 }
235 else
236 {
237 // This is Windows - we must replace the ":" in the path
238 dllName = String.Format ("{0}:{1}", parts [0], parts [1]);
239 if (parts.Length > 2)
240 className = parts[2];
241 }
242  
243 return LoadPlugin<T>(dllName, className, args);
244 }
245  
246 /// <summary>
247 /// Load a plugin from a dll with the given class or interface
248 /// </summary>
249 /// <param name="dllName"></param>
250 /// <param name="className"></param>
251 /// <param name="args">The arguments which control which constructor is invoked on the plugin</param>
252 /// <returns></returns>
253 public static T LoadPlugin<T>(string dllName, string className, Object[] args) where T:class
254 {
255 string interfaceName = typeof(T).ToString();
256  
257 try
258 {
259 Assembly pluginAssembly = Assembly.LoadFrom(dllName);
260  
261 foreach (Type pluginType in pluginAssembly.GetTypes())
262 {
263 if (pluginType.IsPublic)
264 {
265 if (className != String.Empty
266 && pluginType.ToString() != pluginType.Namespace + "." + className)
267 continue;
268  
269 Type typeInterface = pluginType.GetInterface(interfaceName, true);
270  
271 if (typeInterface != null)
272 {
273 T plug = null;
274 try
275 {
276 plug = (T)Activator.CreateInstance(pluginType,
277 args);
278 }
279 catch (Exception e)
280 {
281 if (!(e is System.MissingMethodException))
282 {
283 m_log.ErrorFormat("[SERVER UTILS]: Error loading plugin {0} from {1}. Exception: {2}, {3}",
284 interfaceName,
285 dllName,
286 e.InnerException == null ? e.Message : e.InnerException.Message,
287 e.StackTrace);
288 }
289 m_log.ErrorFormat("[SERVER UTILS]: Error loading plugin {0}: {1} args.Length {2}", dllName, e.Message, args.Length);
290 return null;
291 }
292  
293 return plug;
294 }
295 }
296 }
297  
298 return null;
299 }
300 catch (ReflectionTypeLoadException rtle)
301 {
302 m_log.Error(string.Format("[SERVER UTILS]: Error loading plugin from {0}:\n{1}", dllName,
303 String.Join("\n", Array.ConvertAll(rtle.LoaderExceptions, e => e.ToString()))),
304 rtle);
305 return null;
306 }
307 catch (Exception e)
308 {
309 m_log.Error(string.Format("[SERVER UTILS]: Error loading plugin from {0}", dllName), e);
310 return null;
311 }
312 }
313  
314 public static Dictionary<string, object> ParseQueryString(string query)
315 {
316 Dictionary<string, object> result = new Dictionary<string, object>();
317 string[] terms = query.Split(new char[] {'&'});
318  
319 if (terms.Length == 0)
320 return result;
321  
322 foreach (string t in terms)
323 {
324 string[] elems = t.Split(new char[] {'='});
325 if (elems.Length == 0)
326 continue;
327  
328 string name = System.Web.HttpUtility.UrlDecode(elems[0]);
329 string value = String.Empty;
330  
331 if (elems.Length > 1)
332 value = System.Web.HttpUtility.UrlDecode(elems[1]);
333  
334 if (name.EndsWith("[]"))
335 {
336 string cleanName = name.Substring(0, name.Length - 2);
337 if (result.ContainsKey(cleanName))
338 {
339 if (!(result[cleanName] is List<string>))
340 continue;
341  
342 List<string> l = (List<string>)result[cleanName];
343  
344 l.Add(value);
345 }
346 else
347 {
348 List<string> newList = new List<string>();
349  
350 newList.Add(value);
351  
352 result[cleanName] = newList;
353 }
354 }
355 else
356 {
357 if (!result.ContainsKey(name))
358 result[name] = value;
359 }
360 }
361  
362 return result;
363 }
364  
365 public static string BuildQueryString(Dictionary<string, object> data)
366 {
367 string qstring = String.Empty;
368  
369 string part;
370  
371 foreach (KeyValuePair<string, object> kvp in data)
372 {
373 if (kvp.Value is List<string>)
374 {
375 List<string> l = (List<String>)kvp.Value;
376  
377 foreach (string s in l)
378 {
379 part = System.Web.HttpUtility.UrlEncode(kvp.Key) +
380 "[]=" + System.Web.HttpUtility.UrlEncode(s);
381  
382 if (qstring != String.Empty)
383 qstring += "&";
384  
385 qstring += part;
386 }
387 }
388 else
389 {
390 if (kvp.Value.ToString() != String.Empty)
391 {
392 part = System.Web.HttpUtility.UrlEncode(kvp.Key) +
393 "=" + System.Web.HttpUtility.UrlEncode(kvp.Value.ToString());
394 }
395 else
396 {
397 part = System.Web.HttpUtility.UrlEncode(kvp.Key);
398 }
399  
400 if (qstring != String.Empty)
401 qstring += "&";
402  
403 qstring += part;
404 }
405 }
406  
407 return qstring;
408 }
409  
410 public static string BuildXmlResponse(Dictionary<string, object> data)
411 {
412 XmlDocument doc = new XmlDocument();
413  
414 XmlNode xmlnode = doc.CreateNode(XmlNodeType.XmlDeclaration,
415 "", "");
416  
417 doc.AppendChild(xmlnode);
418  
419 XmlElement rootElement = doc.CreateElement("", "ServerResponse",
420 "");
421  
422 doc.AppendChild(rootElement);
423  
424 BuildXmlData(rootElement, data);
425  
426 return doc.InnerXml;
427 }
428  
429 private static void BuildXmlData(XmlElement parent, Dictionary<string, object> data)
430 {
431 foreach (KeyValuePair<string, object> kvp in data)
432 {
433 if (kvp.Value == null)
434 continue;
435  
436 XmlElement elem = parent.OwnerDocument.CreateElement("",
437 XmlConvert.EncodeLocalName(kvp.Key), "");
438  
439 if (kvp.Value is Dictionary<string, object>)
440 {
441 XmlAttribute type = parent.OwnerDocument.CreateAttribute("",
442 "type", "");
443 type.Value = "List";
444  
445 elem.Attributes.Append(type);
446  
447 BuildXmlData(elem, (Dictionary<string, object>)kvp.Value);
448 }
449 else
450 {
451 elem.AppendChild(parent.OwnerDocument.CreateTextNode(
452 kvp.Value.ToString()));
453 }
454  
455 parent.AppendChild(elem);
456 }
457 }
458  
459 public static Dictionary<string, object> ParseXmlResponse(string data)
460 {
461 //m_log.DebugFormat("[XXX]: received xml string: {0}", data);
462  
463 Dictionary<string, object> ret = new Dictionary<string, object>();
464  
465 XmlDocument doc = new XmlDocument();
466  
467 doc.LoadXml(data);
468  
469 XmlNodeList rootL = doc.GetElementsByTagName("ServerResponse");
470  
471 if (rootL.Count != 1)
472 return ret;
473  
474 XmlNode rootNode = rootL[0];
475  
476 ret = ParseElement(rootNode);
477  
478 return ret;
479 }
480  
481 private static Dictionary<string, object> ParseElement(XmlNode element)
482 {
483 Dictionary<string, object> ret = new Dictionary<string, object>();
484  
485 XmlNodeList partL = element.ChildNodes;
486  
487 foreach (XmlNode part in partL)
488 {
489 XmlNode type = part.Attributes.GetNamedItem("type");
490 if (type == null || type.Value != "List")
491 {
492 ret[XmlConvert.DecodeName(part.Name)] = part.InnerText;
493 }
494 else
495 {
496 ret[XmlConvert.DecodeName(part.Name)] = ParseElement(part);
497 }
498 }
499  
500 return ret;
501 }
502  
503 public static IConfig GetConfig(string configFile, string configName)
504 {
505 IConfig config;
506  
507 if (File.Exists(configFile))
508 {
509 IConfigSource configsource = new IniConfigSource(configFile);
510 config = configsource.Configs[configName];
511 }
512 else
513 config = null;
514  
515 return config;
516 }
517  
518 public static IConfigSource LoadInitialConfig(string url)
519 {
520 IConfigSource source = new XmlConfigSource();
521 m_log.InfoFormat("[SERVER UTILS]: {0} is a http:// URI, fetching ...", url);
522  
523 // The ini file path is a http URI
524 // Try to read it
525 try
526 {
527 XmlReader r = XmlReader.Create(url);
528 IConfigSource cs = new XmlConfigSource(r);
529 source.Merge(cs);
530 }
531 catch (Exception e)
532 {
533 m_log.FatalFormat("[SERVER UTILS]: Exception reading config from URI {0}\n" + e.ToString(), url);
534 Environment.Exit(1);
535 }
536  
537 return source;
538 }
539 }
540 }