aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs498
1 files changed, 498 insertions, 0 deletions
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs
new file mode 100644
index 0000000..49556b6
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs
@@ -0,0 +1,498 @@
1/*
2 * Copyright (c) Contributors
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 OpenSim 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 */
27using Mono.Addins;
28
29using System;
30using System.Reflection;
31using System.Threading;
32using System.Text;
33using System.Net;
34using System.Net.Sockets;
35using log4net;
36using Nini.Config;
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39using OpenSim.Framework;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes;
42using System.Collections.Generic;
43using System.Text.RegularExpressions;
44
45namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
46{
47 public class JsonStore
48 {
49 private static readonly ILog m_log =
50 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51
52 private OSD m_ValueStore;
53
54 protected class TakeValueCallbackClass
55 {
56 public string Path { get; set; }
57 public bool UseJson { get; set; }
58 public TakeValueCallback Callback { get; set; }
59
60 public TakeValueCallbackClass(string spath, bool usejson, TakeValueCallback cback)
61 {
62 Path = spath;
63 UseJson = usejson;
64 Callback = cback;
65 }
66 }
67
68 protected List<TakeValueCallbackClass> m_TakeStore;
69 protected List<TakeValueCallbackClass> m_ReadStore;
70
71
72 // -----------------------------------------------------------------
73 /// <summary>
74 ///
75 /// </summary>
76 // -----------------------------------------------------------------
77 public JsonStore(string value = "")
78 {
79 m_TakeStore = new List<TakeValueCallbackClass>();
80 m_ReadStore = new List<TakeValueCallbackClass>();
81
82 if (String.IsNullOrEmpty(value))
83 m_ValueStore = new OSDMap();
84 else
85 m_ValueStore = OSDParser.DeserializeJson(value);
86 }
87
88 // -----------------------------------------------------------------
89 /// <summary>
90 ///
91 /// </summary>
92 // -----------------------------------------------------------------
93 public bool TestPath(string expr, bool useJson)
94 {
95 Stack<string> path = ParsePathExpression(expr);
96 OSD result = ProcessPathExpression(m_ValueStore,path);
97
98 if (result == null)
99 return false;
100
101 if (useJson || result.Type == OSDType.String)
102 return true;
103
104 return false;
105 }
106
107 // -----------------------------------------------------------------
108 /// <summary>
109 ///
110 /// </summary>
111 // -----------------------------------------------------------------
112 public bool GetValue(string expr, out string value, bool useJson)
113 {
114 Stack<string> path = ParsePathExpression(expr);
115 OSD result = ProcessPathExpression(m_ValueStore,path);
116 return ConvertOutputValue(result,out value,useJson);
117 }
118
119
120 // -----------------------------------------------------------------
121 /// <summary>
122 ///
123 /// </summary>
124 // -----------------------------------------------------------------
125 public bool RemoveValue(string expr)
126 {
127 return SetValueFromExpression(expr,null);
128 }
129
130 // -----------------------------------------------------------------
131 /// <summary>
132 ///
133 /// </summary>
134 // -----------------------------------------------------------------
135 public bool SetValue(string expr, string value, bool useJson)
136 {
137 OSD ovalue = useJson ? OSDParser.DeserializeJson(value) : new OSDString(value);
138 return SetValueFromExpression(expr,ovalue);
139 }
140
141 // -----------------------------------------------------------------
142 /// <summary>
143 ///
144 /// </summary>
145 // -----------------------------------------------------------------
146 public bool TakeValue(string expr, bool useJson, TakeValueCallback cback)
147 {
148 Stack<string> path = ParsePathExpression(expr);
149 string pexpr = PathExpressionToKey(path);
150
151 OSD result = ProcessPathExpression(m_ValueStore,path);
152 if (result == null)
153 {
154 m_TakeStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback));
155 return false;
156 }
157
158 string value = String.Empty;
159 if (! ConvertOutputValue(result,out value,useJson))
160 {
161 // the structure does not match the request so i guess we'll wait
162 m_TakeStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback));
163 return false;
164 }
165
166 SetValueFromExpression(expr,null);
167 cback(value);
168
169 return true;
170 }
171
172 // -----------------------------------------------------------------
173 /// <summary>
174 ///
175 /// </summary>
176 // -----------------------------------------------------------------
177 public bool ReadValue(string expr, bool useJson, TakeValueCallback cback)
178 {
179 Stack<string> path = ParsePathExpression(expr);
180 string pexpr = PathExpressionToKey(path);
181
182 OSD result = ProcessPathExpression(m_ValueStore,path);
183 if (result == null)
184 {
185 m_ReadStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback));
186 return false;
187 }
188
189 string value = String.Empty;
190 if (! ConvertOutputValue(result,out value,useJson))
191 {
192 // the structure does not match the request so i guess we'll wait
193 m_ReadStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback));
194 return false;
195 }
196
197 cback(value);
198
199 return true;
200 }
201
202 // -----------------------------------------------------------------
203 /// <summary>
204 ///
205 /// </summary>
206 // -----------------------------------------------------------------
207 protected bool SetValueFromExpression(string expr, OSD ovalue)
208 {
209 Stack<string> path = ParsePathExpression(expr);
210 if (path.Count == 0)
211 {
212 m_ValueStore = ovalue;
213 return true;
214 }
215
216 string pkey = path.Pop();
217 string pexpr = PathExpressionToKey(path);
218 if (pexpr != "")
219 pexpr += ".";
220
221 OSD result = ProcessPathExpression(m_ValueStore,path);
222 if (result == null)
223 return false;
224
225 Regex aPattern = new Regex("\\[([0-9]+|\\+)\\]");
226 MatchCollection amatches = aPattern.Matches(pkey,0);
227
228 if (amatches.Count > 0)
229 {
230 if (result.Type != OSDType.Array)
231 return false;
232
233 OSDArray amap = result as OSDArray;
234
235 Match match = amatches[0];
236 GroupCollection groups = match.Groups;
237 string akey = groups[1].Value;
238
239 if (akey == "+")
240 {
241 string npkey = String.Format("[{0}]",amap.Count);
242
243 amap.Add(ovalue);
244 InvokeNextCallback(pexpr + npkey);
245 return true;
246 }
247
248 int aval = Convert.ToInt32(akey);
249 if (0 <= aval && aval < amap.Count)
250 {
251 if (ovalue == null)
252 amap.RemoveAt(aval);
253 else
254 {
255 amap[aval] = ovalue;
256 InvokeNextCallback(pexpr + pkey);
257 }
258 return true;
259 }
260
261 return false;
262 }
263
264 Regex hPattern = new Regex("{([^}]+)}");
265 MatchCollection hmatches = hPattern.Matches(pkey,0);
266
267 if (hmatches.Count > 0)
268 {
269 Match match = hmatches[0];
270 GroupCollection groups = match.Groups;
271 string hkey = groups[1].Value;
272
273 if (result is OSDMap)
274 {
275 OSDMap hmap = result as OSDMap;
276 if (ovalue != null)
277 {
278 hmap[hkey] = ovalue;
279 InvokeNextCallback(pexpr + pkey);
280 }
281 else if (hmap.ContainsKey(hkey))
282 hmap.Remove(hkey);
283
284 return true;
285 }
286
287 return false;
288 }
289
290 // Shouldn't get here if the path was checked correctly
291 m_log.WarnFormat("[JsonStore] invalid path expression");
292 return false;
293 }
294
295 // -----------------------------------------------------------------
296 /// <summary>
297 ///
298 /// </summary>
299 // -----------------------------------------------------------------
300 protected bool InvokeNextCallback(string pexpr)
301 {
302 // Process all of the reads that match the expression first
303 List<TakeValueCallbackClass> reads =
304 m_ReadStore.FindAll(delegate(TakeValueCallbackClass tb) { return pexpr.StartsWith(tb.Path); });
305
306 foreach (TakeValueCallbackClass readcb in reads)
307 {
308 m_ReadStore.Remove(readcb);
309 ReadValue(readcb.Path,readcb.UseJson,readcb.Callback);
310 }
311
312 // Process one take next
313 TakeValueCallbackClass takecb =
314 m_TakeStore.Find(delegate(TakeValueCallbackClass tb) { return pexpr.StartsWith(tb.Path); });
315
316 if (takecb != null)
317 {
318 m_TakeStore.Remove(takecb);
319 TakeValue(takecb.Path,takecb.UseJson,takecb.Callback);
320
321 return true;
322 }
323
324 return false;
325 }
326
327 // -----------------------------------------------------------------
328 /// <summary>
329 /// Parse the path expression and put the components into a stack. We
330 /// use a stack because we process the path in inverse order later
331 /// </summary>
332 // -----------------------------------------------------------------
333 protected static Stack<string> ParsePathExpression(string path)
334 {
335 Stack<string> m_path = new Stack<string>();
336
337 // add front and rear separators
338 path = "." + path + ".";
339
340 // add separators for quoted paths
341 Regex pass1 = new Regex("{[^}]+}");
342 path = pass1.Replace(path,".$0.",-1,0);
343
344 // add separators for array references
345 Regex pass2 = new Regex("(\\[[0-9]+\\]|\\[\\+\\])");
346 path = pass2.Replace(path,".$0.",-1,0);
347
348 // add quotes to bare identifier
349 Regex pass3 = new Regex("\\.([a-zA-Z]+)");
350 path = pass3.Replace(path,".{$1}",-1,0);
351
352 // remove extra separators
353 Regex pass4 = new Regex("\\.+");
354 path = pass4.Replace(path,".",-1,0);
355
356 Regex validate = new Regex("^\\.(({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])\\.)+$");
357 if (validate.IsMatch(path))
358 {
359 Regex parser = new Regex("\\.({[^}]+}|\\[[0-9]+\\]|\\[\\+\\]+)");
360 MatchCollection matches = parser.Matches(path,0);
361 foreach (Match match in matches)
362 m_path.Push(match.Groups[1].Value);
363 }
364
365 return m_path;
366 }
367
368 // -----------------------------------------------------------------
369 /// <summary>
370 ///
371 /// </summary>
372 /// <param>path is a stack where the top level of the path is at the bottom of the stack</param>
373 // -----------------------------------------------------------------
374 protected static OSD ProcessPathExpression(OSD map, Stack<string> path)
375 {
376 if (path.Count == 0)
377 return map;
378
379 string pkey = path.Pop();
380
381 OSD rmap = ProcessPathExpression(map,path);
382 if (rmap == null)
383 return null;
384
385 // ---------- Check for an array index ----------
386 Regex aPattern = new Regex("\\[([0-9]+)\\]");
387 MatchCollection amatches = aPattern.Matches(pkey,0);
388
389 if (amatches.Count > 0)
390 {
391 if (rmap.Type != OSDType.Array)
392 {
393 m_log.WarnFormat("[JsonStore] wrong type for key {2}, expecting {0}, got {1}",OSDType.Array,rmap.Type,pkey);
394 return null;
395 }
396
397 OSDArray amap = rmap as OSDArray;
398
399 Match match = amatches[0];
400 GroupCollection groups = match.Groups;
401 string akey = groups[1].Value;
402 int aval = Convert.ToInt32(akey);
403
404 if (aval < amap.Count)
405 return (OSD) amap[aval];
406
407 return null;
408 }
409
410 // ---------- Check for a hash index ----------
411 Regex hPattern = new Regex("{([^}]+)}");
412 MatchCollection hmatches = hPattern.Matches(pkey,0);
413
414 if (hmatches.Count > 0)
415 {
416 if (rmap.Type != OSDType.Map)
417 {
418 m_log.WarnFormat("[JsonStore] wrong type for key {2}, expecting {0}, got {1}",OSDType.Map,rmap.Type,pkey);
419 return null;
420 }
421
422 OSDMap hmap = rmap as OSDMap;
423
424 Match match = hmatches[0];
425 GroupCollection groups = match.Groups;
426 string hkey = groups[1].Value;
427
428 if (hmap.ContainsKey(hkey))
429 return (OSD) hmap[hkey];
430
431 return null;
432 }
433
434 // Shouldn't get here if the path was checked correctly
435 m_log.WarnFormat("[JsonStore] Path type (unknown) does not match the structure");
436 return null;
437 }
438
439 // -----------------------------------------------------------------
440 /// <summary>
441 ///
442 /// </summary>
443 // -----------------------------------------------------------------
444 protected static bool ConvertOutputValue(OSD result, out string value, bool useJson)
445 {
446 value = String.Empty;
447
448 // If we couldn't process the path
449 if (result == null)
450 return false;
451
452 if (useJson)
453 {
454 // The path pointed to an intermediate hash structure
455 if (result.Type == OSDType.Map)
456 {
457 value = OSDParser.SerializeJsonString(result as OSDMap);
458 return true;
459 }
460
461 // The path pointed to an intermediate hash structure
462 if (result.Type == OSDType.Array)
463 {
464 value = OSDParser.SerializeJsonString(result as OSDArray);
465 return true;
466 }
467
468 value = "'" + result.AsString() + "'";
469 return true;
470 }
471
472 if (result.Type == OSDType.String)
473 {
474 value = result.AsString();
475 return true;
476 }
477
478 return false;
479 }
480
481 // -----------------------------------------------------------------
482 /// <summary>
483 ///
484 /// </summary>
485 // -----------------------------------------------------------------
486 protected static string PathExpressionToKey(Stack<string> path)
487 {
488 if (path.Count == 0)
489 return "";
490
491 string pkey = "";
492 foreach (string k in path)
493 pkey = (pkey == "") ? k : (k + "." + pkey);
494
495 return pkey;
496 }
497 }
498}