Skip to content

Commit

Permalink
Support deserialising oic.wk.res for Resource Discovery
Browse files Browse the repository at this point in the history
  • Loading branch information
NZSmartie committed Aug 6, 2017
1 parent 5597511 commit bfb1053
Show file tree
Hide file tree
Showing 7 changed files with 350 additions and 24 deletions.
121 changes: 120 additions & 1 deletion OICNet.Tests/OicMessageSerialiserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public static void Setup()

mockResolver.Setup(c => c.GetResourseType("oic.r.core")).Returns(typeof(OicCoreResource));
mockResolver.Setup(c => c.GetResourseType("oic.r.audio")).Returns(typeof(ResourceTypes.Audio));
mockResolver.Setup(c => c.GetResourseType("oic.wk.res")).Returns(typeof(OicResource.DiscoverableResources));

_resolver = mockResolver.Object;
}
Expand All @@ -37,7 +38,17 @@ public IOicResource DeserialiseOicResourceCore(byte[] input, OicMessageContentTy
{
// Arrange
var serialiser = new OicMessageSerialiser(_resolver);
return serialiser.Deserialise(input, type);

//Only worried about the first result
return serialiser.Deserialise(input, type).First();
}

[Test, TestCaseSource(typeof(SerialiserTestCaseData), nameof(SerialiserTestCaseData.DeserialiseArrayTestCases))]
public IList<IOicResource> DeserialiseOicResourceCoreArray(byte[] input, OicMessageContentType type)
{
// Arrange
var serialiser = new OicMessageSerialiser(_resolver);
return serialiser.Deserialise(input, type).ToList();
}
}

Expand Down Expand Up @@ -166,5 +177,113 @@ public static IEnumerable DeserialiseTestCases
});
}
}

public static IEnumerable DeserialiseArrayTestCases
{
get
{
yield return new TestCaseData(
Encoding.UTF8.GetBytes(
@"[{""rt"": [""oic.wk.res""],""di"": ""0685B960-736F-46F7-BEC0-9E6CBD61ADC1"",""links"":[{""href"": ""/res"",""rel"": ""self"",""rt"": [""oic.r.collection""],""if"": [""oic.if.ll""]},{""href"": ""/smartDevice"",""rel"": ""contained"",""rt"": [""oic.d.smartDevice""],""if"": [""oic.if.a""]}]},{""rt"": [""oic.wk.res""],""di"": ""0685B960-736F-46F7-BEC0-9E6CBD61ADC1"",""links"":[{""href"": ""/res"",""rel"": ""self"",""rt"": [""oic.r.collection""],""if"": [""oic.if.ll""]},{""href"": ""/smartDevice"",""rel"": ""contained"",""rt"": [""oic.d.smartDevice""],""if"": [""oic.if.a""]}]}]"),
OicMessageContentType.ApplicationJson)
.Returns(new List<IOicResource>
{
new OicResource.DiscoverableResources
{
ResourceTypes = new List<string> {"oic.wk.res"},
DeviceId = new Guid("0685B960-736F-46F7-BEC0-9E6CBD61ADC1"),
Links = new List<OicResource.Link>
{
new OicResource.Link
{
Href = new Uri("/res", UriKind.Relative),
Rel = "self",
ResourceTypes = new List<string> {"oic.r.collection"},
Interfaces = new List<OicResourceInterface> {OicResourceInterface.LinkLists},
},
new OicResource.Link
{
Href = new Uri("/smartDevice", UriKind.Relative),
Rel = "contained",
ResourceTypes = new List<string> {"oic.d.smartDevice"},
Interfaces = new List<OicResourceInterface> {OicResourceInterface.Actuator},
}
}
},
new OicResource.DiscoverableResources
{
ResourceTypes = new List<string> {"oic.wk.res"},
DeviceId = new Guid("0685B960-736F-46F7-BEC0-9E6CBD61ADC1"),
Links = new List<OicResource.Link>
{
new OicResource.Link
{
Href = new Uri("/res", UriKind.Relative),
Rel = "self",
ResourceTypes = new List<string> {"oic.r.collection"},
Interfaces = new List<OicResourceInterface> {OicResourceInterface.LinkLists},
},
new OicResource.Link
{
Href = new Uri("/smartDevice", UriKind.Relative),
Rel = "contained",
ResourceTypes = new List<string> {"oic.d.smartDevice"},
Interfaces = new List<OicResourceInterface> {OicResourceInterface.Actuator},
}
}
}
});
yield return new TestCaseData(
new byte[]{ 0x82, 0xA3, 0x62, 0x72, 0x74, 0x81, 0x6A, 0x6F, 0x69, 0x63, 0x2E, 0x77, 0x6B, 0x2E, 0x72, 0x65, 0x73, 0x62, 0x64, 0x69, 0x78, 0x24, 0x30, 0x36, 0x38, 0x35, 0x42, 0x39, 0x36, 0x30, 0x2D, 0x37, 0x33, 0x36, 0x46, 0x2D, 0x34, 0x36, 0x46, 0x37, 0x2D, 0x42, 0x45, 0x43, 0x30, 0x2D, 0x39, 0x45, 0x36, 0x43, 0x42, 0x44, 0x36, 0x31, 0x41, 0x44, 0x43, 0x31, 0x65, 0x6C, 0x69, 0x6E, 0x6B, 0x73, 0x82, 0xA4, 0x64, 0x68, 0x72, 0x65, 0x66, 0x64, 0x2F, 0x72, 0x65, 0x73, 0x63, 0x72, 0x65, 0x6C, 0x64, 0x73, 0x65, 0x6C, 0x66, 0x62, 0x72, 0x74, 0x81, 0x70, 0x6F, 0x69, 0x63, 0x2E, 0x72, 0x2E, 0x63, 0x6F, 0x6C, 0x6C, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x62, 0x69, 0x66, 0x81, 0x69, 0x6F, 0x69, 0x63, 0x2E, 0x69, 0x66, 0x2E, 0x6C, 0x6C, 0xA4, 0x64, 0x68, 0x72, 0x65, 0x66, 0x6C, 0x2F, 0x73, 0x6D, 0x61, 0x72, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x63, 0x72, 0x65, 0x6C, 0x69, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x65, 0x64, 0x62, 0x72, 0x74, 0x81, 0x71, 0x6F, 0x69, 0x63, 0x2E, 0x64, 0x2E, 0x73, 0x6D, 0x61, 0x72, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x62, 0x69, 0x66, 0x81, 0x68, 0x6F, 0x69, 0x63, 0x2E, 0x69, 0x66, 0x2E, 0x61, 0xA3, 0x62, 0x72, 0x74, 0x81, 0x6A, 0x6F, 0x69, 0x63, 0x2E, 0x77, 0x6B, 0x2E, 0x72, 0x65, 0x73, 0x62, 0x64, 0x69, 0x78, 0x24, 0x30, 0x36, 0x38, 0x35, 0x42, 0x39, 0x36, 0x30, 0x2D, 0x37, 0x33, 0x36, 0x46, 0x2D, 0x34, 0x36, 0x46, 0x37, 0x2D, 0x42, 0x45, 0x43, 0x30, 0x2D, 0x39, 0x45, 0x36, 0x43, 0x42, 0x44, 0x36, 0x31, 0x41, 0x44, 0x43, 0x31, 0x65, 0x6C, 0x69, 0x6E, 0x6B, 0x73, 0x82, 0xA4, 0x64, 0x68, 0x72, 0x65, 0x66, 0x64, 0x2F, 0x72, 0x65, 0x73, 0x63, 0x72, 0x65, 0x6C, 0x64, 0x73, 0x65, 0x6C, 0x66, 0x62, 0x72, 0x74, 0x81, 0x70, 0x6F, 0x69, 0x63, 0x2E, 0x72, 0x2E, 0x63, 0x6F, 0x6C, 0x6C, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x62, 0x69, 0x66, 0x81, 0x69, 0x6F, 0x69, 0x63, 0x2E, 0x69, 0x66, 0x2E, 0x6C, 0x6C, 0xA4, 0x64, 0x68, 0x72, 0x65, 0x66, 0x6C, 0x2F, 0x73, 0x6D, 0x61, 0x72, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x63, 0x72, 0x65, 0x6C, 0x69, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x65, 0x64, 0x62, 0x72, 0x74, 0x81, 0x71, 0x6F, 0x69, 0x63, 0x2E, 0x64, 0x2E, 0x73, 0x6D, 0x61, 0x72, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x62, 0x69, 0x66, 0x81, 0x68, 0x6F, 0x69, 0x63, 0x2E, 0x69, 0x66, 0x2E, 0x61 },
OicMessageContentType.ApplicationCbor)
.Returns(new List<IOicResource>
{
new OicResource.DiscoverableResources
{
ResourceTypes = new List<string> {"oic.wk.res"},
DeviceId = new Guid("0685B960-736F-46F7-BEC0-9E6CBD61ADC1"),
Links = new List<OicResource.Link>
{
new OicResource.Link
{
Href = new Uri("/res", UriKind.Relative),
Rel = "self",
ResourceTypes = new List<string> {"oic.r.collection"},
Interfaces = new List<OicResourceInterface> {OicResourceInterface.LinkLists},
},
new OicResource.Link
{
Href = new Uri("/smartDevice", UriKind.Relative),
Rel = "contained",
ResourceTypes = new List<string> {"oic.d.smartDevice"},
Interfaces = new List<OicResourceInterface> {OicResourceInterface.Actuator},
}
}
},
new OicResource.DiscoverableResources
{
ResourceTypes = new List<string> {"oic.wk.res"},
DeviceId = new Guid("0685B960-736F-46F7-BEC0-9E6CBD61ADC1"),
Links = new List<OicResource.Link>
{
new OicResource.Link
{
Href = new Uri("/res", UriKind.Relative),
Rel = "self",
ResourceTypes = new List<string> {"oic.r.collection"},
Interfaces = new List<OicResourceInterface> {OicResourceInterface.LinkLists},
},
new OicResource.Link
{
Href = new Uri("/smartDevice", UriKind.Relative),
Rel = "contained",
ResourceTypes = new List<string> {"oic.d.smartDevice"},
Interfaces = new List<OicResourceInterface> {OicResourceInterface.Actuator},
}
}
}
});
}
}
}
}
2 changes: 1 addition & 1 deletion OICNet/OICNet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ More details about OIC here: https://openconnectivity.org/</Description>

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
<PackageReference Include="Newtonsoft.Json.Cbor" Version="0.2.0-alpha" />
<PackageReference Include="Newtonsoft.Json.Cbor" Version="0.3.3-alpha" />
<PackageReference Include="Newtonsoft.Json.Schema" Version="3.0.2" />
<PackageReference Include="System.ComponentModel" Version="4.3.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.3.0" />
Expand Down
40 changes: 20 additions & 20 deletions OICNet/OicMessageSerialiser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

using Newtonsoft.Json;
using Newtonsoft.Json.Cbor;
using Newtonsoft.Json.Cbor.Linq;
using Newtonsoft.Json.Linq;

namespace OICNet
Expand All @@ -29,41 +30,40 @@ public OicMessageSerialiser(IResourceTypeResolver resolver)

/// <summary>
/// Deserialses a OIC message into a object based on the message's resource-type ("rt") property
///
/// Todo: Support multiple resource types some how... Currently only supports the first resource type, any subsequent types are ignored.
/// </summary>
/// <param name="message"></param>
/// <param name="contentType"></param>
/// <returns></returns>
public IOicResource Deserialise(byte[] message, OicMessageContentType contentType)
public IEnumerable<IOicResource> Deserialise(byte[] message, OicMessageContentType contentType)
{
var serialiser = new JsonSerializer();
var stream = new MemoryStream(message);
OicCoreResource coreResource;
Type type;
JToken token;

switch (contentType)
{
case OicMessageContentType.ApplicationJson:
{
coreResource =
serialiser.Deserialize<OicCoreResource>(new JsonTextReader(new StreamReader(stream)));
type = _resolver.GetResourseType(coreResource.ResourceTypes.FirstOrDefault());

stream.Seek(0, SeekOrigin.Begin);
return (IOicResource)serialiser.Deserialize(new JsonTextReader(new StreamReader(stream)), type);
}
token = JToken.ReadFrom(new JsonTextReader(new StreamReader(stream)));
break;
case OicMessageContentType.ApplicationCbor:
{
coreResource = serialiser.Deserialize<OicCoreResource>(new CborDataReader(stream));
type = _resolver.GetResourseType(coreResource.ResourceTypes.FirstOrDefault());

stream.Seek(0, SeekOrigin.Begin);
return (IOicResource)serialiser.Deserialize(new CborDataReader(stream), type);
}
token = JToken.ReadFrom(new CborDataReader(stream));
break;
default:
throw new NotImplementedException();
}
if (token.Type == JTokenType.Array)
token = token.First;
while (token != null)
{
var rt = (string) token["rt"].FirstOrDefault();
var type = _resolver.GetResourseType(rt);
yield return (IOicResource) token.ToObject(type);

token = token.Next;
}
}

//Todo: support serialising multiple IOicResouces in an array/list
public byte[] Serialise(IOicResource resource, OicMessageContentType contentType)
{
var writer = new MemoryStream();
Expand Down
4 changes: 3 additions & 1 deletion OICNet/OicResolver.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Text;
using OICNet.OicResource;

namespace OICNet
{
Expand All @@ -15,13 +16,14 @@ public interface IResourceTypeResolver
/// <remarks>(Will) Support all OIC v1.1.0 defined resource-types</remarks>
public class OicResolver : IResourceTypeResolver
{
private Dictionary<string, Type> _resourceTypes;
private readonly Dictionary<string, Type> _resourceTypes;

public OicResolver()
{
// List of built in resource-types will go here (OIC v1.1.0)
_resourceTypes = new Dictionary<string, Type>
{
{ "oic.wk.res" ,typeof(DiscoverableResources) },
// Todo: In .Net Standard 2.0, replace hardcoded references with reflection, looking for classes with OicResourceTypeAttribute
{ "oic.r.core", typeof(OicCoreResource) },
{ "oic.r.audio", typeof(ResourceTypes.Audio) },
Expand Down
5 changes: 4 additions & 1 deletion OICNet/OicResource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public Task RetrieveAsync()
[MinLength(1), StringLength(64)]
public List<string> ResourceTypes { get; set; }

[JsonProperty("if", ItemConverterType = typeof(Newtonsoft.Json.Converters.StringEnumConverter)), JsonRequired()]
[JsonProperty("if", ItemConverterType = typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
public List<OicResourceInterface> Interfaces { get; set; }

[JsonProperty("n", NullValueHandling=NullValueHandling.Ignore)]
Expand All @@ -105,6 +105,7 @@ public Task RetrieveAsync()

#endregion


internal OicCoreResource(OicDevice device)
{
Device = device;
Expand All @@ -115,6 +116,8 @@ public OicCoreResource()

}

public virtual bool ShouldSerializeInterfaces() { return true; }

public override bool Equals(object obj)
{
var other = obj as OicCoreResource;
Expand Down
48 changes: 48 additions & 0 deletions OICNet/OicResource/DiscoverableResources.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;

using Newtonsoft.Json;
using OICNet.ResourceTypes;

namespace OICNet.OicResource
{
#pragma warning disable CS0659 // Type overrides Object.Equals(object o) but does not override Object.GetHashCode()
[OicResourceType("oic.wk.res")]
public class DiscoverableResources : OicCoreResource
{
// Hack to get around required "if" property in base-class
public override bool ShouldSerializeInterfaces() { return false; }

[JsonProperty("di", Required = Required.Always, Order = 10)]
public Guid DeviceId { get; set; }

/// <summary>
/// Supported messaging protocols
/// </summary>
[JsonProperty("mpro", Required = Required.DisallowNull, NullValueHandling = NullValueHandling.Ignore, Order = 10), StringLength(64)]
public string MessagingProtocols { get; set; }

[JsonProperty("links", Required = Required.Always, Order = 11)]
public List<Link> Links { get; set; }

public override bool Equals(object obj)
{
var other = obj as DiscoverableResources;
if (other == null)
return false;
if (!base.Equals(obj))
return false;
if (DeviceId != other.DeviceId)
return false;
if (MessagingProtocols != other.MessagingProtocols)
return false;
if (!Links.SequenceEqual(other.Links))
return false;
return true;
}
}
#pragma warning restore CS0659 // Type overrides Object.Equals(object o) but does not override Object.GetHashCode()
}
Loading

0 comments on commit bfb1053

Please sign in to comment.