clockwerk-opensim-stable – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | vero | 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 | */ |
||
27 | using Mono.Addins; |
||
28 | |||
29 | using System; |
||
30 | using System.Reflection; |
||
31 | using System.Threading; |
||
32 | using System.Text; |
||
33 | using System.Net; |
||
34 | using System.Net.Sockets; |
||
35 | using log4net; |
||
36 | using Nini.Config; |
||
37 | using OpenMetaverse; |
||
38 | using OpenMetaverse.StructuredData; |
||
39 | using OpenSim.Framework; |
||
40 | using OpenSim.Region.Framework.Interfaces; |
||
41 | using OpenSim.Region.Framework.Scenes; |
||
42 | using System.Collections.Generic; |
||
43 | using System.Text.RegularExpressions; |
||
44 | |||
45 | namespace 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 | protected virtual OSD ValueStore { get; set; } |
||
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 | // add separators for quoted paths and array references |
||
72 | protected static Regex m_ParsePassOne = new Regex("({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])"); |
||
73 | |||
74 | // add quotes to bare identifiers which are limited to alphabetic characters |
||
75 | protected static Regex m_ParsePassThree = new Regex("(?<!{[^}]*)\\.([a-zA-Z]+)(?=\\.)"); |
||
76 | |||
77 | // remove extra separator characters |
||
78 | protected static Regex m_ParsePassFour = new Regex("\\.+"); |
||
79 | |||
80 | // expression used to validate the full path, this is canonical representation |
||
81 | protected static Regex m_ValidatePath = new Regex("^\\.(({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])\\.)*$"); |
||
82 | |||
83 | // expression used to match path components |
||
84 | protected static Regex m_PathComponent = new Regex("\\.({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])"); |
||
85 | |||
86 | // extract the internals of an array reference |
||
87 | protected static Regex m_SimpleArrayPattern = new Regex("^\\[([0-9]+)\\]$"); |
||
88 | protected static Regex m_ArrayPattern = new Regex("^\\[([0-9]+|\\+)\\]$"); |
||
89 | |||
90 | // extract the internals of a has reference |
||
91 | protected static Regex m_HashPattern = new Regex("^{([^}]+)}$"); |
||
92 | |||
93 | // ----------------------------------------------------------------- |
||
94 | /// <summary> |
||
95 | /// This is a simple estimator for the size of the stored data, it |
||
96 | /// is not precise, but should be close enough to implement reasonable |
||
97 | /// limits on the storage space used |
||
98 | /// </summary> |
||
99 | // ----------------------------------------------------------------- |
||
100 | public int StringSpace { get; set; } |
||
101 | |||
102 | // ----------------------------------------------------------------- |
||
103 | /// <summary> |
||
104 | /// |
||
105 | /// </summary> |
||
106 | // ----------------------------------------------------------------- |
||
107 | public static bool CanonicalPathExpression(string ipath, out string opath) |
||
108 | { |
||
109 | Stack<string> path; |
||
110 | if (! ParsePathExpression(ipath,out path)) |
||
111 | { |
||
112 | opath = ""; |
||
113 | return false; |
||
114 | } |
||
115 | |||
116 | opath = PathExpressionToKey(path); |
||
117 | return true; |
||
118 | } |
||
119 | |||
120 | // ----------------------------------------------------------------- |
||
121 | /// <summary> |
||
122 | /// |
||
123 | /// </summary> |
||
124 | // ----------------------------------------------------------------- |
||
125 | public JsonStore() |
||
126 | { |
||
127 | StringSpace = 0; |
||
128 | m_TakeStore = new List<TakeValueCallbackClass>(); |
||
129 | m_ReadStore = new List<TakeValueCallbackClass>(); |
||
130 | } |
||
131 | |||
132 | public JsonStore(string value) : this() |
||
133 | { |
||
134 | // This is going to throw an exception if the value is not |
||
135 | // a valid JSON chunk. Calling routines should catch the |
||
136 | // exception and handle it appropriately |
||
137 | if (String.IsNullOrEmpty(value)) |
||
138 | ValueStore = new OSDMap(); |
||
139 | else |
||
140 | ValueStore = OSDParser.DeserializeJson(value); |
||
141 | } |
||
142 | |||
143 | // ----------------------------------------------------------------- |
||
144 | /// <summary> |
||
145 | /// |
||
146 | /// </summary> |
||
147 | // ----------------------------------------------------------------- |
||
148 | public JsonStoreNodeType GetNodeType(string expr) |
||
149 | { |
||
150 | Stack<string> path; |
||
151 | if (! ParsePathExpression(expr,out path)) |
||
152 | return JsonStoreNodeType.Undefined; |
||
153 | |||
154 | OSD result = ProcessPathExpression(ValueStore,path); |
||
155 | |||
156 | if (result == null) |
||
157 | return JsonStoreNodeType.Undefined; |
||
158 | |||
159 | if (result is OSDMap) |
||
160 | return JsonStoreNodeType.Object; |
||
161 | |||
162 | if (result is OSDArray) |
||
163 | return JsonStoreNodeType.Array; |
||
164 | |||
165 | if (OSDBaseType(result.Type)) |
||
166 | return JsonStoreNodeType.Value; |
||
167 | |||
168 | return JsonStoreNodeType.Undefined; |
||
169 | } |
||
170 | |||
171 | // ----------------------------------------------------------------- |
||
172 | /// <summary> |
||
173 | /// |
||
174 | /// </summary> |
||
175 | // ----------------------------------------------------------------- |
||
176 | public JsonStoreValueType GetValueType(string expr) |
||
177 | { |
||
178 | Stack<string> path; |
||
179 | if (! ParsePathExpression(expr,out path)) |
||
180 | return JsonStoreValueType.Undefined; |
||
181 | |||
182 | OSD result = ProcessPathExpression(ValueStore,path); |
||
183 | |||
184 | if (result == null) |
||
185 | return JsonStoreValueType.Undefined; |
||
186 | |||
187 | if (result is OSDMap) |
||
188 | return JsonStoreValueType.Undefined; |
||
189 | |||
190 | if (result is OSDArray) |
||
191 | return JsonStoreValueType.Undefined; |
||
192 | |||
193 | if (result is OSDBoolean) |
||
194 | return JsonStoreValueType.Boolean; |
||
195 | |||
196 | if (result is OSDInteger) |
||
197 | return JsonStoreValueType.Integer; |
||
198 | |||
199 | if (result is OSDReal) |
||
200 | return JsonStoreValueType.Float; |
||
201 | |||
202 | if (result is OSDString) |
||
203 | return JsonStoreValueType.String; |
||
204 | |||
205 | return JsonStoreValueType.Undefined; |
||
206 | } |
||
207 | |||
208 | // ----------------------------------------------------------------- |
||
209 | /// <summary> |
||
210 | /// |
||
211 | /// </summary> |
||
212 | // ----------------------------------------------------------------- |
||
213 | public int ArrayLength(string expr) |
||
214 | { |
||
215 | Stack<string> path; |
||
216 | if (! ParsePathExpression(expr,out path)) |
||
217 | return -1; |
||
218 | |||
219 | OSD result = ProcessPathExpression(ValueStore,path); |
||
220 | if (result != null && result.Type == OSDType.Array) |
||
221 | { |
||
222 | OSDArray arr = result as OSDArray; |
||
223 | return arr.Count; |
||
224 | } |
||
225 | |||
226 | return -1; |
||
227 | } |
||
228 | |||
229 | // ----------------------------------------------------------------- |
||
230 | /// <summary> |
||
231 | /// |
||
232 | /// </summary> |
||
233 | // ----------------------------------------------------------------- |
||
234 | public bool GetValue(string expr, out string value, bool useJson) |
||
235 | { |
||
236 | Stack<string> path; |
||
237 | if (! ParsePathExpression(expr,out path)) |
||
238 | { |
||
239 | value = ""; |
||
240 | return false; |
||
241 | } |
||
242 | |||
243 | OSD result = ProcessPathExpression(ValueStore,path); |
||
244 | return ConvertOutputValue(result,out value,useJson); |
||
245 | } |
||
246 | |||
247 | |||
248 | // ----------------------------------------------------------------- |
||
249 | /// <summary> |
||
250 | /// |
||
251 | /// </summary> |
||
252 | // ----------------------------------------------------------------- |
||
253 | public bool RemoveValue(string expr) |
||
254 | { |
||
255 | return SetValueFromExpression(expr,null); |
||
256 | } |
||
257 | |||
258 | // ----------------------------------------------------------------- |
||
259 | /// <summary> |
||
260 | /// |
||
261 | /// </summary> |
||
262 | // ----------------------------------------------------------------- |
||
263 | public bool SetValue(string expr, string value, bool useJson) |
||
264 | { |
||
265 | OSD ovalue; |
||
266 | |||
267 | // One note of caution... if you use an empty string in the |
||
268 | // structure it will be assumed to be a default value and will |
||
269 | // not be seialized in the json |
||
270 | |||
271 | if (useJson) |
||
272 | { |
||
273 | // There doesn't appear to be a good way to determine if the |
||
274 | // value is valid Json other than to let the parser crash |
||
275 | try |
||
276 | { |
||
277 | ovalue = OSDParser.DeserializeJson(value); |
||
278 | } |
||
279 | catch (Exception e) |
||
280 | { |
||
281 | if (value.StartsWith("'") && value.EndsWith("'")) |
||
282 | { |
||
283 | ovalue = new OSDString(value.Substring(1,value.Length - 2)); |
||
284 | } |
||
285 | else |
||
286 | { |
||
287 | return false; |
||
288 | } |
||
289 | } |
||
290 | } |
||
291 | else |
||
292 | { |
||
293 | ovalue = new OSDString(value); |
||
294 | } |
||
295 | |||
296 | return SetValueFromExpression(expr,ovalue); |
||
297 | } |
||
298 | |||
299 | // ----------------------------------------------------------------- |
||
300 | /// <summary> |
||
301 | /// |
||
302 | /// </summary> |
||
303 | // ----------------------------------------------------------------- |
||
304 | public bool TakeValue(string expr, bool useJson, TakeValueCallback cback) |
||
305 | { |
||
306 | Stack<string> path; |
||
307 | if (! ParsePathExpression(expr,out path)) |
||
308 | return false; |
||
309 | |||
310 | string pexpr = PathExpressionToKey(path); |
||
311 | |||
312 | OSD result = ProcessPathExpression(ValueStore,path); |
||
313 | if (result == null) |
||
314 | { |
||
315 | m_TakeStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback)); |
||
316 | return false; |
||
317 | } |
||
318 | |||
319 | string value = String.Empty; |
||
320 | if (! ConvertOutputValue(result,out value,useJson)) |
||
321 | { |
||
322 | // the structure does not match the request so i guess we'll wait |
||
323 | m_TakeStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback)); |
||
324 | return false; |
||
325 | } |
||
326 | |||
327 | SetValueFromExpression(expr,null); |
||
328 | cback(value); |
||
329 | |||
330 | return true; |
||
331 | } |
||
332 | |||
333 | // ----------------------------------------------------------------- |
||
334 | /// <summary> |
||
335 | /// |
||
336 | /// </summary> |
||
337 | // ----------------------------------------------------------------- |
||
338 | public bool ReadValue(string expr, bool useJson, TakeValueCallback cback) |
||
339 | { |
||
340 | Stack<string> path; |
||
341 | if (! ParsePathExpression(expr,out path)) |
||
342 | return false; |
||
343 | |||
344 | string pexpr = PathExpressionToKey(path); |
||
345 | |||
346 | OSD result = ProcessPathExpression(ValueStore,path); |
||
347 | if (result == null) |
||
348 | { |
||
349 | m_ReadStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback)); |
||
350 | return false; |
||
351 | } |
||
352 | |||
353 | string value = String.Empty; |
||
354 | if (! ConvertOutputValue(result,out value,useJson)) |
||
355 | { |
||
356 | // the structure does not match the request so i guess we'll wait |
||
357 | m_ReadStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback)); |
||
358 | return false; |
||
359 | } |
||
360 | |||
361 | cback(value); |
||
362 | |||
363 | return true; |
||
364 | } |
||
365 | |||
366 | // ----------------------------------------------------------------- |
||
367 | /// <summary> |
||
368 | /// |
||
369 | /// </summary> |
||
370 | // ----------------------------------------------------------------- |
||
371 | protected bool SetValueFromExpression(string expr, OSD ovalue) |
||
372 | { |
||
373 | Stack<string> path; |
||
374 | if (! ParsePathExpression(expr,out path)) |
||
375 | return false; |
||
376 | |||
377 | if (path.Count == 0) |
||
378 | { |
||
379 | ValueStore = ovalue; |
||
380 | StringSpace = 0; |
||
381 | return true; |
||
382 | } |
||
383 | |||
384 | // pkey will be the final element in the path, we pull it out here to make sure |
||
385 | // that the assignment works correctly |
||
386 | string pkey = path.Pop(); |
||
387 | string pexpr = PathExpressionToKey(path); |
||
388 | if (pexpr != "") |
||
389 | pexpr += "."; |
||
390 | |||
391 | OSD result = ProcessPathExpression(ValueStore,path); |
||
392 | if (result == null) |
||
393 | return false; |
||
394 | |||
395 | // Check pkey, the last element in the path, for and extract array references |
||
396 | MatchCollection amatches = m_ArrayPattern.Matches(pkey,0); |
||
397 | if (amatches.Count > 0) |
||
398 | { |
||
399 | if (result.Type != OSDType.Array) |
||
400 | return false; |
||
401 | |||
402 | OSDArray amap = result as OSDArray; |
||
403 | |||
404 | Match match = amatches[0]; |
||
405 | GroupCollection groups = match.Groups; |
||
406 | string akey = groups[1].Value; |
||
407 | |||
408 | if (akey == "+") |
||
409 | { |
||
410 | string npkey = String.Format("[{0}]",amap.Count); |
||
411 | |||
412 | if (ovalue != null) |
||
413 | { |
||
414 | StringSpace += ComputeSizeOf(ovalue); |
||
415 | |||
416 | amap.Add(ovalue); |
||
417 | InvokeNextCallback(pexpr + npkey); |
||
418 | } |
||
419 | return true; |
||
420 | } |
||
421 | |||
422 | int aval = Convert.ToInt32(akey); |
||
423 | if (0 <= aval && aval < amap.Count) |
||
424 | { |
||
425 | if (ovalue == null) |
||
426 | { |
||
427 | StringSpace -= ComputeSizeOf(amap[aval]); |
||
428 | amap.RemoveAt(aval); |
||
429 | } |
||
430 | else |
||
431 | { |
||
432 | StringSpace -= ComputeSizeOf(amap[aval]); |
||
433 | StringSpace += ComputeSizeOf(ovalue); |
||
434 | amap[aval] = ovalue; |
||
435 | InvokeNextCallback(pexpr + pkey); |
||
436 | } |
||
437 | return true; |
||
438 | } |
||
439 | |||
440 | return false; |
||
441 | } |
||
442 | |||
443 | // Check for and extract hash references |
||
444 | MatchCollection hmatches = m_HashPattern.Matches(pkey,0); |
||
445 | if (hmatches.Count > 0) |
||
446 | { |
||
447 | Match match = hmatches[0]; |
||
448 | GroupCollection groups = match.Groups; |
||
449 | string hkey = groups[1].Value; |
||
450 | |||
451 | if (result is OSDMap) |
||
452 | { |
||
453 | // this is the assignment case |
||
454 | OSDMap hmap = result as OSDMap; |
||
455 | if (ovalue != null) |
||
456 | { |
||
457 | StringSpace -= ComputeSizeOf(hmap[hkey]); |
||
458 | StringSpace += ComputeSizeOf(ovalue); |
||
459 | |||
460 | hmap[hkey] = ovalue; |
||
461 | InvokeNextCallback(pexpr + pkey); |
||
462 | return true; |
||
463 | } |
||
464 | |||
465 | // this is the remove case |
||
466 | if (hmap.ContainsKey(hkey)) |
||
467 | { |
||
468 | StringSpace -= ComputeSizeOf(hmap[hkey]); |
||
469 | hmap.Remove(hkey); |
||
470 | return true; |
||
471 | } |
||
472 | |||
473 | return false; |
||
474 | } |
||
475 | |||
476 | return false; |
||
477 | } |
||
478 | |||
479 | // Shouldn't get here if the path was checked correctly |
||
480 | m_log.WarnFormat("[JsonStore] invalid path expression"); |
||
481 | return false; |
||
482 | } |
||
483 | |||
484 | // ----------------------------------------------------------------- |
||
485 | /// <summary> |
||
486 | /// |
||
487 | /// </summary> |
||
488 | // ----------------------------------------------------------------- |
||
489 | protected bool InvokeNextCallback(string pexpr) |
||
490 | { |
||
491 | // Process all of the reads that match the expression first |
||
492 | List<TakeValueCallbackClass> reads = |
||
493 | m_ReadStore.FindAll(delegate(TakeValueCallbackClass tb) { return pexpr.StartsWith(tb.Path); }); |
||
494 | |||
495 | foreach (TakeValueCallbackClass readcb in reads) |
||
496 | { |
||
497 | m_ReadStore.Remove(readcb); |
||
498 | ReadValue(readcb.Path,readcb.UseJson,readcb.Callback); |
||
499 | } |
||
500 | |||
501 | // Process one take next |
||
502 | TakeValueCallbackClass takecb = |
||
503 | m_TakeStore.Find(delegate(TakeValueCallbackClass tb) { return pexpr.StartsWith(tb.Path); }); |
||
504 | |||
505 | if (takecb != null) |
||
506 | { |
||
507 | m_TakeStore.Remove(takecb); |
||
508 | TakeValue(takecb.Path,takecb.UseJson,takecb.Callback); |
||
509 | |||
510 | return true; |
||
511 | } |
||
512 | |||
513 | return false; |
||
514 | } |
||
515 | |||
516 | // ----------------------------------------------------------------- |
||
517 | /// <summary> |
||
518 | /// Parse the path expression and put the components into a stack. We |
||
519 | /// use a stack because we process the path in inverse order later |
||
520 | /// </summary> |
||
521 | // ----------------------------------------------------------------- |
||
522 | protected static bool ParsePathExpression(string expr, out Stack<string> path) |
||
523 | { |
||
524 | path = new Stack<string>(); |
||
525 | |||
526 | // add front and rear separators |
||
527 | expr = "." + expr + "."; |
||
528 | |||
529 | // add separators for quoted exprs and array references |
||
530 | expr = m_ParsePassOne.Replace(expr,".$1.",-1,0); |
||
531 | |||
532 | // add quotes to bare identifier |
||
533 | expr = m_ParsePassThree.Replace(expr,".{$1}",-1,0); |
||
534 | |||
535 | // remove extra separators |
||
536 | expr = m_ParsePassFour.Replace(expr,".",-1,0); |
||
537 | |||
538 | // validate the results (catches extra quote characters for example) |
||
539 | if (m_ValidatePath.IsMatch(expr)) |
||
540 | { |
||
541 | MatchCollection matches = m_PathComponent.Matches(expr,0); |
||
542 | foreach (Match match in matches) |
||
543 | path.Push(match.Groups[1].Value); |
||
544 | |||
545 | return true; |
||
546 | } |
||
547 | |||
548 | return false; |
||
549 | } |
||
550 | |||
551 | // ----------------------------------------------------------------- |
||
552 | /// <summary> |
||
553 | /// |
||
554 | /// </summary> |
||
555 | /// <param>path is a stack where the top level of the path is at the bottom of the stack</param> |
||
556 | // ----------------------------------------------------------------- |
||
557 | protected static OSD ProcessPathExpression(OSD map, Stack<string> path) |
||
558 | { |
||
559 | if (path.Count == 0) |
||
560 | return map; |
||
561 | |||
562 | string pkey = path.Pop(); |
||
563 | |||
564 | OSD rmap = ProcessPathExpression(map,path); |
||
565 | if (rmap == null) |
||
566 | return null; |
||
567 | |||
568 | // ---------- Check for an array index ---------- |
||
569 | MatchCollection amatches = m_SimpleArrayPattern.Matches(pkey,0); |
||
570 | |||
571 | if (amatches.Count > 0) |
||
572 | { |
||
573 | if (rmap.Type != OSDType.Array) |
||
574 | { |
||
575 | m_log.WarnFormat("[JsonStore] wrong type for key {2}, expecting {0}, got {1}",OSDType.Array,rmap.Type,pkey); |
||
576 | return null; |
||
577 | } |
||
578 | |||
579 | OSDArray amap = rmap as OSDArray; |
||
580 | |||
581 | Match match = amatches[0]; |
||
582 | GroupCollection groups = match.Groups; |
||
583 | string akey = groups[1].Value; |
||
584 | int aval = Convert.ToInt32(akey); |
||
585 | |||
586 | if (aval < amap.Count) |
||
587 | return (OSD) amap[aval]; |
||
588 | |||
589 | return null; |
||
590 | } |
||
591 | |||
592 | // ---------- Check for a hash index ---------- |
||
593 | MatchCollection hmatches = m_HashPattern.Matches(pkey,0); |
||
594 | |||
595 | if (hmatches.Count > 0) |
||
596 | { |
||
597 | if (rmap.Type != OSDType.Map) |
||
598 | { |
||
599 | m_log.WarnFormat("[JsonStore] wrong type for key {2}, expecting {0}, got {1}",OSDType.Map,rmap.Type,pkey); |
||
600 | return null; |
||
601 | } |
||
602 | |||
603 | OSDMap hmap = rmap as OSDMap; |
||
604 | |||
605 | Match match = hmatches[0]; |
||
606 | GroupCollection groups = match.Groups; |
||
607 | string hkey = groups[1].Value; |
||
608 | |||
609 | if (hmap.ContainsKey(hkey)) |
||
610 | return (OSD) hmap[hkey]; |
||
611 | |||
612 | return null; |
||
613 | } |
||
614 | |||
615 | // Shouldn't get here if the path was checked correctly |
||
616 | m_log.WarnFormat("[JsonStore] Path type (unknown) does not match the structure"); |
||
617 | return null; |
||
618 | } |
||
619 | |||
620 | // ----------------------------------------------------------------- |
||
621 | /// <summary> |
||
622 | /// |
||
623 | /// </summary> |
||
624 | // ----------------------------------------------------------------- |
||
625 | protected static bool ConvertOutputValue(OSD result, out string value, bool useJson) |
||
626 | { |
||
627 | value = String.Empty; |
||
628 | |||
629 | // If we couldn't process the path |
||
630 | if (result == null) |
||
631 | return false; |
||
632 | |||
633 | if (useJson) |
||
634 | { |
||
635 | // The path pointed to an intermediate hash structure |
||
636 | if (result.Type == OSDType.Map) |
||
637 | { |
||
638 | value = OSDParser.SerializeJsonString(result as OSDMap,true); |
||
639 | return true; |
||
640 | } |
||
641 | |||
642 | // The path pointed to an intermediate hash structure |
||
643 | if (result.Type == OSDType.Array) |
||
644 | { |
||
645 | value = OSDParser.SerializeJsonString(result as OSDArray,true); |
||
646 | return true; |
||
647 | } |
||
648 | |||
649 | value = "'" + result.AsString() + "'"; |
||
650 | return true; |
||
651 | } |
||
652 | |||
653 | if (OSDBaseType(result.Type)) |
||
654 | { |
||
655 | value = result.AsString(); |
||
656 | return true; |
||
657 | } |
||
658 | |||
659 | return false; |
||
660 | } |
||
661 | |||
662 | // ----------------------------------------------------------------- |
||
663 | /// <summary> |
||
664 | /// |
||
665 | /// </summary> |
||
666 | // ----------------------------------------------------------------- |
||
667 | protected static string PathExpressionToKey(Stack<string> path) |
||
668 | { |
||
669 | if (path.Count == 0) |
||
670 | return ""; |
||
671 | |||
672 | string pkey = ""; |
||
673 | foreach (string k in path) |
||
674 | pkey = (pkey == "") ? k : (k + "." + pkey); |
||
675 | |||
676 | return pkey; |
||
677 | } |
||
678 | |||
679 | // ----------------------------------------------------------------- |
||
680 | /// <summary> |
||
681 | /// |
||
682 | /// </summary> |
||
683 | // ----------------------------------------------------------------- |
||
684 | protected static bool OSDBaseType(OSDType type) |
||
685 | { |
||
686 | // Should be the list of base types for which AsString() returns |
||
687 | // something useful |
||
688 | if (type == OSDType.Boolean) |
||
689 | return true; |
||
690 | if (type == OSDType.Integer) |
||
691 | return true; |
||
692 | if (type == OSDType.Real) |
||
693 | return true; |
||
694 | if (type == OSDType.String) |
||
695 | return true; |
||
696 | if (type == OSDType.UUID) |
||
697 | return true; |
||
698 | if (type == OSDType.Date) |
||
699 | return true; |
||
700 | if (type == OSDType.URI) |
||
701 | return true; |
||
702 | |||
703 | return false; |
||
704 | } |
||
705 | |||
706 | // ----------------------------------------------------------------- |
||
707 | /// <summary> |
||
708 | /// |
||
709 | /// </summary> |
||
710 | // ----------------------------------------------------------------- |
||
711 | protected static int ComputeSizeOf(OSD value) |
||
712 | { |
||
713 | string sval; |
||
714 | |||
715 | if (ConvertOutputValue(value,out sval,true)) |
||
716 | return sval.Length; |
||
717 | |||
718 | return 0; |
||
719 | } |
||
720 | } |
||
721 | |||
722 | // ----------------------------------------------------------------- |
||
723 | /// <summary> |
||
724 | /// </summary> |
||
725 | // ----------------------------------------------------------------- |
||
726 | public class JsonObjectStore : JsonStore |
||
727 | { |
||
728 | private static readonly ILog m_log = |
||
729 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
||
730 | |||
731 | private Scene m_scene; |
||
732 | private UUID m_objectID; |
||
733 | |||
734 | protected override OSD ValueStore |
||
735 | { |
||
736 | get |
||
737 | { |
||
738 | SceneObjectPart sop = m_scene.GetSceneObjectPart(m_objectID); |
||
739 | if (sop == null) |
||
740 | { |
||
741 | // This is bad |
||
742 | return null; |
||
743 | } |
||
744 | |||
745 | return sop.DynAttrs.TopLevelMap; |
||
746 | } |
||
747 | |||
748 | // cannot set the top level |
||
749 | set |
||
750 | { |
||
751 | m_log.InfoFormat("[JsonStore] cannot set top level value in object store"); |
||
752 | } |
||
753 | } |
||
754 | |||
755 | public JsonObjectStore(Scene scene, UUID oid) : base() |
||
756 | { |
||
757 | m_scene = scene; |
||
758 | m_objectID = oid; |
||
759 | |||
760 | // the size limit is imposed on whatever is already in the store |
||
761 | StringSpace = ComputeSizeOf(ValueStore); |
||
762 | } |
||
763 | } |
||
764 | |||
765 | } |