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 System.Text;
33 using System.Text.RegularExpressions;
34 using System.Xml;
35 using log4net;
36 using OpenSim.Region.DataSnapshot.Interfaces;
37 using OpenSim.Region.Framework.Scenes;
38  
39 namespace OpenSim.Region.DataSnapshot
40 {
41 public class SnapshotStore
42 {
43 #region Class Members
44 private String m_directory = "unyuu"; //not an attempt at adding RM references to core SVN, honest
45 private Dictionary<Scene, bool> m_scenes = null;
46 private List<IDataSnapshotProvider> m_providers = null;
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 private Dictionary<String, String> m_gridinfo = null;
49 private bool m_cacheEnabled = true;
50 private string m_listener_port = "9000"; //TODO: Set default port over 9000
51 private string m_hostname = "127.0.0.1";
52 #endregion
53  
54 public SnapshotStore(string directory, Dictionary<String, String> gridinfo, string port, string hostname) {
55 m_directory = directory;
56 m_scenes = new Dictionary<Scene, bool>();
57 m_providers = new List<IDataSnapshotProvider>();
58 m_gridinfo = gridinfo;
59 m_listener_port = port;
60 m_hostname = hostname;
61  
62 if (Directory.Exists(m_directory))
63 {
64 m_log.Info("[DATASNAPSHOT]: Response and fragment cache directory already exists.");
65 }
66 else
67 {
68 // Try to create the directory.
69 m_log.Info("[DATASNAPSHOT]: Creating directory " + m_directory);
70 try
71 {
72 Directory.CreateDirectory(m_directory);
73 }
74 catch (Exception e)
75 {
76 m_log.Error("[DATASNAPSHOT]: Failed to create directory " + m_directory, e);
77  
78 //This isn't a horrible problem, just disable cacheing.
79 m_cacheEnabled = false;
80 m_log.Error("[DATASNAPSHOT]: Could not create directory, response cache has been disabled.");
81 }
82 }
83 }
84  
85 public void ForceSceneStale(Scene scene) {
86 m_scenes[scene] = true;
87 }
88  
89 #region Fragment storage
90 public XmlNode GetFragment(IDataSnapshotProvider provider, XmlDocument factory)
91 {
92 XmlNode data = null;
93  
94 if (provider.Stale || !m_cacheEnabled)
95 {
96 data = provider.RequestSnapshotData(factory);
97  
98 if (m_cacheEnabled)
99 {
100 String path = DataFileNameFragment(provider.GetParentScene, provider.Name);
101  
102 try
103 {
104 using (XmlTextWriter snapXWriter = new XmlTextWriter(path, Encoding.Default))
105 {
106 snapXWriter.Formatting = Formatting.Indented;
107 snapXWriter.WriteStartDocument();
108 data.WriteTo(snapXWriter);
109 snapXWriter.WriteEndDocument();
110 }
111 }
112 catch (Exception e)
113 {
114 m_log.WarnFormat("[DATASNAPSHOT]: Exception on writing to file {0}: {1}", path, e.Message);
115 }
116  
117 }
118  
119 //mark provider as not stale, parent scene as stale
120 provider.Stale = false;
121 m_scenes[provider.GetParentScene] = true;
122  
123 m_log.Debug("[DATASNAPSHOT]: Generated fragment response for provider type " + provider.Name);
124 }
125 else
126 {
127 String path = DataFileNameFragment(provider.GetParentScene, provider.Name);
128  
129 XmlDocument fragDocument = new XmlDocument();
130 fragDocument.PreserveWhitespace = true;
131 fragDocument.Load(path);
132 foreach (XmlNode node in fragDocument)
133 {
134 data = factory.ImportNode(node, true);
135 }
136  
137 m_log.Debug("[DATASNAPSHOT]: Retrieved fragment response for provider type " + provider.Name);
138 }
139  
140 return data;
141 }
142 #endregion
143  
144 #region Response storage
145 public XmlNode GetScene(Scene scene, XmlDocument factory)
146 {
147 m_log.Debug("[DATASNAPSHOT]: Data requested for scene " + scene.RegionInfo.RegionName);
148  
149 if (!m_scenes.ContainsKey(scene)) {
150 m_scenes.Add(scene, true); //stale by default
151 }
152  
153 XmlNode regionElement = null;
154  
155 if (!m_scenes[scene])
156 {
157 m_log.Debug("[DATASNAPSHOT]: Attempting to retrieve snapshot from cache.");
158 //get snapshot from cache
159 String path = DataFileNameScene(scene);
160  
161 XmlDocument fragDocument = new XmlDocument();
162 fragDocument.PreserveWhitespace = true;
163  
164 fragDocument.Load(path);
165  
166 foreach (XmlNode node in fragDocument)
167 {
168 regionElement = factory.ImportNode(node, true);
169 }
170  
171 m_log.Debug("[DATASNAPSHOT]: Obtained snapshot from cache for " + scene.RegionInfo.RegionName);
172 }
173 else
174 {
175 m_log.Debug("[DATASNAPSHOT]: Attempting to generate snapshot.");
176 //make snapshot
177 regionElement = MakeRegionNode(scene, factory);
178  
179 regionElement.AppendChild(GetGridSnapshotData(factory));
180 XmlNode regionData = factory.CreateNode(XmlNodeType.Element, "data", "");
181  
182 foreach (IDataSnapshotProvider dataprovider in m_providers)
183 {
184 if (dataprovider.GetParentScene == scene)
185 {
186 regionData.AppendChild(GetFragment(dataprovider, factory));
187 }
188 }
189  
190 regionElement.AppendChild(regionData);
191  
192 factory.AppendChild(regionElement);
193  
194 //save snapshot
195 String path = DataFileNameScene(scene);
196  
197 try
198 {
199 using (XmlTextWriter snapXWriter = new XmlTextWriter(path, Encoding.Default))
200 {
201 snapXWriter.Formatting = Formatting.Indented;
202 snapXWriter.WriteStartDocument();
203 regionElement.WriteTo(snapXWriter);
204 snapXWriter.WriteEndDocument();
205 }
206 }
207 catch (Exception e)
208 {
209 m_log.WarnFormat("[DATASNAPSHOT]: Exception on writing to file {0}: {1}", path, e.Message);
210 }
211  
212 m_scenes[scene] = false;
213  
214 m_log.Debug("[DATASNAPSHOT]: Generated new snapshot for " + scene.RegionInfo.RegionName);
215 }
216  
217 return regionElement;
218 }
219  
220 #endregion
221  
222 #region Helpers
223 private string DataFileNameFragment(Scene scene, String fragmentName)
224 {
225 return Path.Combine(m_directory, Path.ChangeExtension(Sanitize(scene.RegionInfo.RegionName + "_" + fragmentName), "xml"));
226 }
227  
228 private string DataFileNameScene(Scene scene)
229 {
230 return Path.Combine(m_directory, Path.ChangeExtension(Sanitize(scene.RegionInfo.RegionName), "xml"));
231 //return (m_snapsDir + Path.DirectorySeparatorChar + scene.RegionInfo.RegionName + ".xml");
232 }
233  
234 private static string Sanitize(string name)
235 {
236 string invalidChars = Regex.Escape(new string(Path.GetInvalidFileNameChars()));
237 string invalidReStr = string.Format(@"[{0}]", invalidChars);
238 string newname = Regex.Replace(name, invalidReStr, "_");
239 return newname.Replace('.', '_');
240 }
241  
242 private XmlNode MakeRegionNode(Scene scene, XmlDocument basedoc)
243 {
244 XmlNode docElement = basedoc.CreateNode(XmlNodeType.Element, "region", "");
245  
246 XmlAttribute attr = basedoc.CreateAttribute("category");
247 attr.Value = GetRegionCategory(scene);
248 docElement.Attributes.Append(attr);
249  
250 attr = basedoc.CreateAttribute("entities");
251 attr.Value = scene.Entities.Count.ToString();
252 docElement.Attributes.Append(attr);
253  
254 //attr = basedoc.CreateAttribute("parcels");
255 //attr.Value = scene.LandManager.landList.Count.ToString();
256 //docElement.Attributes.Append(attr);
257  
258  
259 XmlNode infoblock = basedoc.CreateNode(XmlNodeType.Element, "info", "");
260  
261 XmlNode infopiece = basedoc.CreateNode(XmlNodeType.Element, "uuid", "");
262 infopiece.InnerText = scene.RegionInfo.RegionID.ToString();
263 infoblock.AppendChild(infopiece);
264  
265 infopiece = basedoc.CreateNode(XmlNodeType.Element, "url", "");
266 infopiece.InnerText = "http://" + m_hostname + ":" + m_listener_port;
267 infoblock.AppendChild(infopiece);
268  
269 infopiece = basedoc.CreateNode(XmlNodeType.Element, "name", "");
270 infopiece.InnerText = scene.RegionInfo.RegionName;
271 infoblock.AppendChild(infopiece);
272  
273 infopiece = basedoc.CreateNode(XmlNodeType.Element, "handle", "");
274 infopiece.InnerText = scene.RegionInfo.RegionHandle.ToString();
275 infoblock.AppendChild(infopiece);
276  
277 docElement.AppendChild(infoblock);
278  
279 m_log.Debug("[DATASNAPSHOT]: Generated region node");
280 return docElement;
281 }
282  
283 private String GetRegionCategory(Scene scene)
284 {
285 if (scene.RegionInfo.RegionSettings.Maturity == 0)
286 return "PG";
287  
288 if (scene.RegionInfo.RegionSettings.Maturity == 1)
289 return "Mature";
290  
291 if (scene.RegionInfo.RegionSettings.Maturity == 2)
292 return "Adult";
293  
294 return "Unknown";
295 }
296  
297 private XmlNode GetGridSnapshotData(XmlDocument factory)
298 {
299 XmlNode griddata = factory.CreateNode(XmlNodeType.Element, "grid", "");
300  
301 foreach (KeyValuePair<String, String> GridData in m_gridinfo)
302 {
303 //TODO: make it lowercase tag names for diva
304 XmlNode childnode = factory.CreateNode(XmlNodeType.Element, GridData.Key, "");
305 childnode.InnerText = GridData.Value;
306 griddata.AppendChild(childnode);
307 }
308  
309 m_log.Debug("[DATASNAPSHOT]: Got grid snapshot data");
310  
311 return griddata;
312 }
313 #endregion
314  
315 #region Manage internal collections
316 public void AddScene(Scene newScene)
317 {
318 m_scenes.Add(newScene, true);
319 }
320  
321 public void RemoveScene(Scene deadScene)
322 {
323 m_scenes.Remove(deadScene);
324 }
325  
326 public void AddProvider(IDataSnapshotProvider newProvider)
327 {
328 m_providers.Add(newProvider);
329 }
330  
331 public void RemoveProvider(IDataSnapshotProvider deadProvider)
332 {
333 m_providers.Remove(deadProvider);
334 }
335 #endregion
336 }
337 }