diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs index 3d715cc90d..3bad06cf39 100644 --- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs @@ -131,15 +131,18 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore m_TakeStore = new List(); m_ReadStore = new List(); } - + public JsonStore(string value) : this() { + // This is going to throw an exception if the value is not + // a valid JSON chunk. Calling routines should catch the + // exception and handle it appropriately if (String.IsNullOrEmpty(value)) ValueStore = new OSDMap(); else ValueStore = OSDParser.DeserializeJson(value); } - + // ----------------------------------------------------------------- /// /// @@ -198,7 +201,37 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore // ----------------------------------------------------------------- public bool SetValue(string expr, string value, bool useJson) { - OSD ovalue = useJson ? OSDParser.DeserializeJson(value) : new OSDString(value); + OSD ovalue; + + // One note of caution... if you use an empty string in the + // structure it will be assumed to be a default value and will + // not be seialized in the json + + if (useJson) + { + // There doesn't appear to be a good way to determine if the + // value is valid Json other than to let the parser crash + try + { + ovalue = OSDParser.DeserializeJson(value); + } + catch (Exception e) + { + if (value.StartsWith("'") && value.EndsWith("'")) + { + ovalue = new OSDString(value.Substring(1,value.Length - 2)); + } + else + { + return false; + } + } + } + else + { + ovalue = new OSDString(value); + } + return SetValueFromExpression(expr,ovalue); } @@ -544,14 +577,14 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore // The path pointed to an intermediate hash structure if (result.Type == OSDType.Map) { - value = OSDParser.SerializeJsonString(result as OSDMap); + value = OSDParser.SerializeJsonString(result as OSDMap,true); return true; } // The path pointed to an intermediate hash structure if (result.Type == OSDType.Array) { - value = OSDParser.SerializeJsonString(result as OSDArray); + value = OSDParser.SerializeJsonString(result as OSDArray,true); return true; } diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs index f1ce856995..cc136615a4 100644 --- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs @@ -227,7 +227,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore } catch (Exception e) { - m_log.Error(string.Format("[JsonStore]: Unable to initialize store from {0}", value), e); + m_log.ErrorFormat("[JsonStore]: Unable to initialize store from {0}", value); return false; } diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs index af97ac7c0b..eb4bc2284b 100644 --- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs @@ -115,8 +115,26 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests TestHelpers.InMethod(); // TestHelpers.EnableLogging(); - UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); - Assert.That(storeId, Is.Not.EqualTo(UUID.Zero)); + // Test blank store + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); + Assert.That(storeId, Is.Not.EqualTo(UUID.Zero)); + } + + // Test single element store + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }"); + Assert.That(storeId, Is.Not.EqualTo(UUID.Zero)); + } + + // Test with an integer value + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 42.15 }"); + Assert.That(storeId, Is.Not.EqualTo(UUID.Zero)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "Hello"); + Assert.That(value, Is.EqualTo("42.15")); + } } [Test] @@ -153,19 +171,64 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests TestHelpers.InMethod(); // TestHelpers.EnableLogging(); - UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }"); + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Two' } }"); - string value = (string)InvokeOp("JsonGetValue", storeId, "Hello"); - Assert.That(value, Is.EqualTo("World")); + { + string value = (string)InvokeOp("JsonGetValue", storeId, "Hello.World"); + Assert.That(value, Is.EqualTo("Two")); + } + + // Test get of path section instead of leaf + { + string value = (string)InvokeOp("JsonGetValue", storeId, "Hello"); + Assert.That(value, Is.EqualTo("")); + } // Test get of non-existing value - string fakeValueGet = (string)InvokeOp("JsonGetValue", storeId, "foo"); - Assert.That(fakeValueGet, Is.EqualTo("")); + { + string fakeValueGet = (string)InvokeOp("JsonGetValue", storeId, "foo"); + Assert.That(fakeValueGet, Is.EqualTo("")); + } // Test get from non-existing store - UUID fakeStoreId = TestHelpers.ParseTail(0x500); - string fakeStoreValueGet = (string)InvokeOp("JsonGetValue", fakeStoreId, "Hello"); - Assert.That(fakeStoreValueGet, Is.EqualTo("")); + { + UUID fakeStoreId = TestHelpers.ParseTail(0x500); + string fakeStoreValueGet = (string)InvokeOp("JsonGetValue", fakeStoreId, "Hello"); + Assert.That(fakeStoreValueGet, Is.EqualTo("")); + } + } + + [Test] + public void TestJsonGetValueJson() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Two' } }"); + + { + string value = (string)InvokeOp("JsonGetValueJson", storeId, "Hello.World"); + Assert.That(value, Is.EqualTo("'Two'")); + } + + // Test get of path section instead of leaf + { + string value = (string)InvokeOp("JsonGetValueJson", storeId, "Hello"); + Assert.That(value, Is.EqualTo("{\"World\":\"Two\"}")); + } + + // Test get of non-existing value + { + string fakeValueGet = (string)InvokeOp("JsonGetValueJson", storeId, "foo"); + Assert.That(fakeValueGet, Is.EqualTo("")); + } + + // Test get from non-existing store + { + UUID fakeStoreId = TestHelpers.ParseTail(0x500); + string fakeStoreValueGet = (string)InvokeOp("JsonGetValueJson", fakeStoreId, "Hello"); + Assert.That(fakeStoreValueGet, Is.EqualTo("")); + } } // [Test] @@ -224,18 +287,62 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests TestHelpers.InMethod(); // TestHelpers.EnableLogging(); - UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }"); + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'One' } }"); - int result = (int)InvokeOp("JsonTestPath", storeId, "Hello"); - Assert.That(result, Is.EqualTo(1)); + { + int result = (int)InvokeOp("JsonTestPath", storeId, "Hello.World"); + Assert.That(result, Is.EqualTo(1)); + } - int result2 = (int)InvokeOp("JsonTestPath", storeId, "foo"); - Assert.That(result2, Is.EqualTo(0)); + // Test for path which does not resolve to a value. + { + int result = (int)InvokeOp("JsonTestPath", storeId, "Hello"); + Assert.That(result, Is.EqualTo(0)); + } + + { + int result2 = (int)InvokeOp("JsonTestPath", storeId, "foo"); + Assert.That(result2, Is.EqualTo(0)); + } // Test with fake store - UUID fakeStoreId = TestHelpers.ParseTail(0x500); - int fakeStoreValueRemove = (int)InvokeOp("JsonTestPath", fakeStoreId, "Hello"); - Assert.That(fakeStoreValueRemove, Is.EqualTo(0)); + { + UUID fakeStoreId = TestHelpers.ParseTail(0x500); + int fakeStoreValueRemove = (int)InvokeOp("JsonTestPath", fakeStoreId, "Hello"); + Assert.That(fakeStoreValueRemove, Is.EqualTo(0)); + } + } + + [Test] + public void TestJsonTestPathJson() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'One' } }"); + + { + int result = (int)InvokeOp("JsonTestPathJson", storeId, "Hello.World"); + Assert.That(result, Is.EqualTo(1)); + } + + // Test for path which does not resolve to a value. + { + int result = (int)InvokeOp("JsonTestPathJson", storeId, "Hello"); + Assert.That(result, Is.EqualTo(1)); + } + + { + int result2 = (int)InvokeOp("JsonTestPathJson", storeId, "foo"); + Assert.That(result2, Is.EqualTo(0)); + } + + // Test with fake store + { + UUID fakeStoreId = TestHelpers.ParseTail(0x500); + int fakeStoreValueRemove = (int)InvokeOp("JsonTestPathJson", fakeStoreId, "Hello"); + Assert.That(fakeStoreValueRemove, Is.EqualTo(0)); + } } [Test] @@ -244,18 +351,91 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests TestHelpers.InMethod(); // TestHelpers.EnableLogging(); - UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); - int result = (int)InvokeOp("JsonSetValue", storeId, "Fun", "Times"); - Assert.That(result, Is.EqualTo(1)); + int result = (int)InvokeOp("JsonSetValue", storeId, "Fun", "Times"); + Assert.That(result, Is.EqualTo(1)); - string value = (string)InvokeOp("JsonGetValue", storeId, "Fun"); - Assert.That(value, Is.EqualTo("Times")); + string value = (string)InvokeOp("JsonGetValue", storeId, "Fun"); + Assert.That(value, Is.EqualTo("Times")); + } + + // Test setting to location that does not exist. This should fail. + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); + + int result = (int)InvokeOp("JsonSetValue", storeId, "Fun.Circus", "Times"); + Assert.That(result, Is.EqualTo(0)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Circus"); + Assert.That(value, Is.EqualTo("")); + } // Test with fake store - UUID fakeStoreId = TestHelpers.ParseTail(0x500); - int fakeStoreValueSet = (int)InvokeOp("JsonSetValue", fakeStoreId, "Hello", "World"); - Assert.That(fakeStoreValueSet, Is.EqualTo(0)); + { + UUID fakeStoreId = TestHelpers.ParseTail(0x500); + int fakeStoreValueSet = (int)InvokeOp("JsonSetValue", fakeStoreId, "Hello", "World"); + Assert.That(fakeStoreValueSet, Is.EqualTo(0)); + } + } + + [Test] + public void TestJsonSetValueJson() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + // Single quoted token case + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); + + int result = (int)InvokeOp("JsonSetValueJson", storeId, "Fun", "'Times'"); + Assert.That(result, Is.EqualTo(1)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "Fun"); + Assert.That(value, Is.EqualTo("Times")); + } + + // Sub-tree case + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); + + int result = (int)InvokeOp("JsonSetValueJson", storeId, "Fun", "{ 'Filled' : 'Times' }"); + Assert.That(result, Is.EqualTo(1)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Filled"); + Assert.That(value, Is.EqualTo("Times")); + } + + // If setting single strings in JsonSetValueJson, these must be single quoted tokens, not bare strings. + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); + + int result = (int)InvokeOp("JsonSetValueJson", storeId, "Fun", "Times"); + Assert.That(result, Is.EqualTo(0)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "Fun"); + Assert.That(value, Is.EqualTo("")); + } + + // Test setting to location that does not exist. This should fail. + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); + + int result = (int)InvokeOp("JsonSetValueJson", storeId, "Fun.Circus", "'Times'"); + Assert.That(result, Is.EqualTo(0)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Circus"); + Assert.That(value, Is.EqualTo("")); + } + + // Test with fake store + { + UUID fakeStoreId = TestHelpers.ParseTail(0x500); + int fakeStoreValueSet = (int)InvokeOp("JsonSetValueJson", fakeStoreId, "Hello", "'World'"); + Assert.That(fakeStoreValueSet, Is.EqualTo(0)); + } } /// @@ -357,8 +537,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{}"); UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make", notecardName); Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); - - // These don't behave as I expect yet - reading to a path still seems to place the notecard contents at the root. + string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello"); Assert.That(value, Is.EqualTo("")); @@ -367,27 +546,24 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests } { - // Read notecard to new multi-component path + // Read notecard to new multi-component path. This should not work. UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{}"); UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make.it", notecardName); Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); - // These don't behave as I expect yet - reading to a path still seems to place the notecard contents at the root. string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello"); Assert.That(value, Is.EqualTo("")); - // TODO: Check that we are not expecting reading to a new path to work. value = (string)InvokeOp("JsonGetValue", receivingStoreId, "make.it.Hello"); Assert.That(value, Is.EqualTo("")); } { - // Read notecard to existing multi-component path + // Read notecard to existing multi-component path. This should work UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ 'make' : { 'it' : 'so' } }"); UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make.it", notecardName); Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); - // These don't behave as I expect yet - reading to a path still seems to place the notecard contents at the root. string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello"); Assert.That(value, Is.EqualTo("")); @@ -395,11 +571,21 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests Assert.That(value, Is.EqualTo("World")); } + { + // Read notecard to invalid path. This should not work. + UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ 'make' : { 'it' : 'so' } }"); + UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "/", notecardName); + Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); + + string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello"); + Assert.That(value, Is.EqualTo("")); + } + { // Try read notecard to fake store. UUID fakeStoreId = TestHelpers.ParseTail(0x500); UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, fakeStoreId, "", notecardName); - Assert.That(fakeStoreId, Is.Not.EqualTo(UUID.Zero)); + Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); string value = (string)InvokeOp("JsonGetValue", fakeStoreId, "Hello"); Assert.That(value, Is.EqualTo("")); diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs index f68612c15e..35ae44c315 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs @@ -52,7 +52,12 @@ namespace OpenSim.Region.ScriptEngine.Interfaces { bool Cancel(); void Abort(); - bool Wait(TimeSpan t); + + /// + /// Wait for the work item to complete. + /// + /// The number of milliseconds to wait. Must be >= -1 (Timeout.Infinite). + bool Wait(int t); } /// diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index c8ced435e1..26850c4582 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -603,7 +603,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance if (!m_coopTermination) { // If we're not co-operative terminating then try and wait for the event to complete before stopping - if (workItem.Wait(new TimeSpan((long)timeout * 100000))) + if (workItem.Wait(timeout)) return true; } else @@ -618,7 +618,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance // For now, we will wait forever since the event should always cleanly terminate once LSL loop // checking is implemented. May want to allow a shorter timeout option later. - if (workItem.Wait(TimeSpan.MaxValue)) + if (workItem.Wait(Timeout.Infinite)) { if (DebugLevel >= 1) m_log.DebugFormat( diff --git a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs index 2ac5c315af..8dd7677d7f 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs @@ -57,8 +57,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine wr.Abort(); } - public bool Wait(TimeSpan t) + public bool Wait(int t) { + // We use the integer version of WaitAll because the current version of SmartThreadPool has a bug with the + // TimeSpan version. The number of milliseconds in TimeSpan is an int64 so when STP casts it down to an + // int (32-bit) we can end up with bad values. This occurs on Windows though curious not on Mono 2.10.8 + // (or very likely other versions of Mono at least up until 3.0.3). return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false); } } diff --git a/bin/Ionic.Zip.dll b/bin/Ionic.Zip.dll index 95fa928855..e37f1bdea5 100755 Binary files a/bin/Ionic.Zip.dll and b/bin/Ionic.Zip.dll differ