Skip to content

Commit 2a590ee

Browse files
feat(bindings): add additional bindings (#45)
* feat(bindings): add additional bindings * docs: add XML documentation for binding serialization, parsing, and validation methods * refactor: Update binding serialization and testing for various protocols This commit updates the serialization logic across several bindings and corresponding test cases to align with newer API versions and improve data handling. In src/ByteBard.AsyncAPI.Bindings/IBMMQ/IBMMQMessageBinding.cs, the `Expiry` property type is updated from `int?` to `long?`, and the mapping in `FixedFieldMap` is adjusted to use `GetLongValue()`. In src/ByteBard.AsyncAPI.Bindings/IBMMQ/IBMMQServerBinding.cs, the serialization logic for `multiEndpointServer` is updated to use the strongly typed property `bool`. In src/ByteBard.AsyncAPI.Bindings/Queue.cs, the serialization of `isPartitioned` and `exclusive` properties is updated to use the strongly typed `bool` type. In src/ByteBard.AsyncAPI.Bindings/Topic.cs, the serialization of `durablePermitted` and `lastMsgRetained` properties is updated to use the strongly typed `bool` type. In src/ByteBard.AsyncAPI.Bindings/MQTT5/MQTT5ServerBinding.cs, the serialization logic for `SerializeProperties --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent 7e53ce9 commit 2a590ee

47 files changed

Lines changed: 2761 additions & 74 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
namespace ByteBard.AsyncAPI.Bindings.AnypointMQ
2+
{
3+
using System;
4+
using ByteBard.AsyncAPI.Models;
5+
using ByteBard.AsyncAPI.Readers.ParseNodes;
6+
using ByteBard.AsyncAPI.Writers;
7+
8+
/// <summary>Binding for an Anypoint MQ destination.</summary>
9+
public class AnypointMQChannelBinding : ChannelBinding<AnypointMQChannelBinding>
10+
{
11+
public string Destination { get; set; }
12+
13+
public string DestinationType { get; set; }
14+
15+
public override string BindingKey => "anypointmq";
16+
17+
protected override FixedFieldMap<AnypointMQChannelBinding> FixedFieldMap => new()
18+
{
19+
{ "destination", (a, n) => { a.Destination = n.GetScalarValue(); } },
20+
{ "destinationType", (a, n) => { a.DestinationType = n.GetScalarValue(); } },
21+
{ "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
22+
};
23+
24+
/// <summary>
25+
/// Writes the Anypoint MQ channel binding object and its extensions for AsyncAPI 2.0.
26+
/// </summary>
27+
/// <exception cref="ArgumentNullException"><paramref name="writer"/> is null.</exception>
28+
public override void SerializeV2(IAsyncApiWriter writer) => this.SerializeV3(writer);
29+
30+
/// <summary>
31+
/// Writes the Anypoint MQ channel binding object and its extensions for AsyncAPI 3.0.
32+
/// </summary>
33+
/// <exception cref="ArgumentNullException"><paramref name="writer"/> is null.</exception>
34+
public override void SerializeV3(IAsyncApiWriter writer) => this.SerializeProperties(writer);
35+
36+
/// <summary>
37+
/// Writes the Anypoint MQ channel binding object and its extensions for AsyncAPI 3.0.
38+
/// </summary>
39+
/// <remarks>An unset binding version is omitted.</remarks>
40+
/// <exception cref="ArgumentNullException"><paramref name="writer"/> is null.</exception>
41+
public override void SerializeProperties(IAsyncApiWriter writer)
42+
{
43+
if (writer is null) throw new ArgumentNullException(nameof(writer));
44+
writer.WriteStartObject();
45+
writer.WriteOptionalProperty("destination", this.Destination);
46+
writer.WriteOptionalProperty("destinationType", this.DestinationType);
47+
writer.WriteOptionalProperty(AsyncApiConstants.BindingVersion, this.BindingVersion);
48+
writer.WriteExtensions(this.Extensions);
49+
writer.WriteEndObject();
50+
}
51+
}
52+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
namespace ByteBard.AsyncAPI.Bindings.AnypointMQ
2+
{
3+
using System;
4+
using ByteBard.AsyncAPI.Models;
5+
using ByteBard.AsyncAPI.Readers;
6+
using ByteBard.AsyncAPI.Readers.ParseNodes;
7+
using ByteBard.AsyncAPI.Writers;
8+
9+
/// <summary>Binding for an Anypoint MQ message.</summary>
10+
public class AnypointMQMessageBinding : MessageBinding<AnypointMQMessageBinding>
11+
{
12+
/// <summary>Message headers described by a schema or schema reference.</summary>
13+
public AsyncApiJsonSchema Headers { get; set; }
14+
15+
public override string BindingKey => "anypointmq";
16+
17+
protected override FixedFieldMap<AnypointMQMessageBinding> FixedFieldMap => new()
18+
{
19+
{ "headers", (a, n) => { a.Headers = AsyncApiJsonSchemaDeserializer.LoadSchema(n); } },
20+
{ "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
21+
};
22+
23+
/// <summary>
24+
/// Writes the Anypoint MQ message binding object and its extensions for AsyncAPI 2.0.
25+
/// </summary>
26+
/// <exception cref="ArgumentNullException"><paramref name="writer"/> is null.</exception>
27+
public override void SerializeV2(IAsyncApiWriter writer)
28+
{
29+
if (writer is null) throw new ArgumentNullException(nameof(writer));
30+
writer.WriteStartObject();
31+
writer.WriteOptionalObject("headers", this.Headers, (w, h) => h.SerializeV2(w));
32+
writer.WriteOptionalProperty(AsyncApiConstants.BindingVersion, this.BindingVersion);
33+
writer.WriteExtensions(this.Extensions);
34+
writer.WriteEndObject();
35+
}
36+
37+
/// <summary>
38+
/// Writes the Anypoint MQ message binding object and its extensions for AsyncAPI 3.0.
39+
/// </summary>
40+
/// <exception cref="ArgumentNullException"><paramref name="writer"/> is null.</exception>
41+
public override void SerializeV3(IAsyncApiWriter writer) => this.SerializeProperties(writer);
42+
43+
/// <summary>
44+
/// Writes the Anypoint MQ message binding object and its extensions for AsyncAPI 3.0.
45+
/// </summary>
46+
/// <remarks>An unset binding version is omitted.</remarks>
47+
/// <exception cref="ArgumentNullException"><paramref name="writer"/> is null.</exception>
48+
public override void SerializeProperties(IAsyncApiWriter writer)
49+
{
50+
if (writer is null) throw new ArgumentNullException(nameof(writer));
51+
writer.WriteStartObject();
52+
writer.WriteOptionalObject("headers", this.Headers, (w, h) => h.SerializeV3(w));
53+
writer.WriteOptionalProperty(AsyncApiConstants.BindingVersion, this.BindingVersion);
54+
writer.WriteExtensions(this.Extensions);
55+
writer.WriteEndObject();
56+
}
57+
}
58+
}

‎src/ByteBard.AsyncAPI.Bindings/BindingHelpers.cs‎

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
11
namespace ByteBard.AsyncAPI.Bindings
22
{
3+
using System;
4+
using System.Collections.Generic;
35
using ByteBard.AsyncAPI.Models.Interfaces;
46
using ByteBard.AsyncAPI.Readers;
57
using ByteBard.AsyncAPI.Readers.ParseNodes;
68

79
public static class BindingHelpers
810
{
11+
/// <summary>
12+
/// Parses a nested object using the supplied field handlers.
13+
/// </summary>
14+
/// <param name="node">The nested object to parse.</param>
15+
/// <param name="fixedFieldMap">Handlers for recognized property names; other properties follow the reader's unmapped-member setting.</param>
16+
/// <returns>A new instance populated from recognized fields, which may be incomplete when field parsing reports errors.</returns>
17+
/// <remarks>Field-level reader and AsyncAPI exceptions are recorded as diagnostics; other handler exceptions propagate.</remarks>
18+
/// <exception cref="ByteBard.AsyncAPI.Readers.Exceptions.AsyncApiReaderException"><paramref name="node"/> is not a map.</exception>
919
public static T ParseMap<T>(this ParseNode node, FixedFieldMap<T> fixedFieldMap)
1020
where T : new()
1121
{
@@ -16,10 +26,11 @@ public static T ParseMap<T>(this ParseNode node, FixedFieldMap<T> fixedFieldMap)
1626
}
1727

1828
var instance = new T();
29+
var emptyPatternFields = new Dictionary<Func<string, bool>, Action<T, string, ParseNode>>();
1930

2031
foreach (var propertyNode in mapNode)
2132
{
22-
propertyNode.ParseField(instance, fixedFieldMap, null);
33+
propertyNode.ParseField(instance, fixedFieldMap, emptyPatternFields);
2334
}
2435

2536
return instance;
@@ -44,4 +55,4 @@ public static T ParseMapWithExtensions<T>(this ParseNode node, FixedFieldMap<T>
4455
return instance;
4556
}
4657
}
47-
}
58+
}
Lines changed: 70 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,59 @@
1-
namespace ByteBard.AsyncAPI.Bindings
1+
namespace ByteBard.AsyncAPI.Bindings
22
{
33
using System;
44
using System.Collections.Generic;
55
using ByteBard.AsyncAPI.Bindings.AMQP;
6+
using ByteBard.AsyncAPI.Bindings.AnypointMQ;
7+
using ByteBard.AsyncAPI.Bindings.GooglePubSub;
68
using ByteBard.AsyncAPI.Bindings.Http;
9+
using ByteBard.AsyncAPI.Bindings.IBMMQ;
10+
using ByteBard.AsyncAPI.Bindings.JMS;
711
using ByteBard.AsyncAPI.Bindings.Kafka;
812
using ByteBard.AsyncAPI.Bindings.MQTT;
13+
using ByteBard.AsyncAPI.Bindings.MQTT5;
14+
using ByteBard.AsyncAPI.Bindings.NATS;
915
using ByteBard.AsyncAPI.Bindings.Pulsar;
16+
using ByteBard.AsyncAPI.Bindings.ROS2;
1017
using ByteBard.AsyncAPI.Bindings.Sns;
18+
using ByteBard.AsyncAPI.Bindings.Solace;
1119
using ByteBard.AsyncAPI.Bindings.Sqs;
1220
using ByteBard.AsyncAPI.Bindings.WebSockets;
1321
using ByteBard.AsyncAPI.Models.Interfaces;
1422
using ByteBard.AsyncAPI.Readers.Interface;
1523

1624
public static class BindingsCollection
1725
{
18-
public static TCollection Add<TCollection, TItem>(
19-
this TCollection destination,
20-
IEnumerable<TItem> source)
21-
where TCollection : ICollection<TItem>
26+
/// <summary>
27+
/// Adds the source items to the destination collection.
28+
/// </summary>
29+
/// <returns>The same destination collection, after adding the items.</returns>
30+
/// <remarks>Enumeration and collection errors propagate; items already added are not rolled back.</remarks>
31+
/// <exception cref="ArgumentNullException"><paramref name="destination"/> or <paramref name="source"/> is null.</exception>
32+
/// <exception cref="NotSupportedException">The destination collection does not support adding items.</exception>
33+
public static TCollection Add<TCollection, TItem>(this TCollection destination, IEnumerable<TItem> source)
34+
where TCollection : ICollection<TItem>
2235
{
23-
if (destination == null)
24-
{
25-
throw new ArgumentNullException(nameof(destination));
26-
}
27-
28-
if (source == null)
29-
{
30-
throw new ArgumentNullException(nameof(source));
31-
}
32-
36+
if (destination == null) throw new ArgumentNullException(nameof(destination));
37+
if (source == null) throw new ArgumentNullException(nameof(source));
3338
if (destination is List<TItem> list)
3439
{
3540
list.AddRange(source);
3641
return destination;
3742
}
3843

39-
foreach (var item in source)
40-
{
41-
destination.Add(item);
42-
}
43-
44+
foreach (var item in source) destination.Add(item);
4445
return destination;
4546
}
4647

4748
public static ICollection<IBindingParser<IBinding>> All => new List<IBindingParser<IBinding>>
4849
{
49-
Pulsar,
50-
Kafka,
51-
Http,
52-
Websockets,
53-
Sqs,
54-
Sns,
55-
AMQP,
56-
MQTT,
50+
Pulsar, Kafka, Http, Websockets, Sqs, Sns, AMQP, MQTT, AnypointMQ, GooglePubSub,
51+
IBMMQ, JMS, MQTT5, NATS, ROS2, Solace,
5752
};
5853

5954
public static ICollection<IBindingParser<IBinding>> Http => new List<IBindingParser<IBinding>>
6055
{
61-
new HttpOperationBinding(),
62-
new HttpMessageBinding(),
56+
new HttpOperationBinding(), new HttpMessageBinding(),
6357
};
6458

6559
public static ICollection<IBindingParser<IBinding>> Websockets => new List<IBindingParser<IBinding>>
@@ -69,42 +63,72 @@ public static TCollection Add<TCollection, TItem>(
6963

7064
public static ICollection<IBindingParser<IBinding>> Kafka => new List<IBindingParser<IBinding>>
7165
{
72-
new KafkaServerBinding(),
73-
new KafkaChannelBinding(),
74-
new KafkaOperationBinding(),
75-
new KafkaMessageBinding(),
66+
new KafkaServerBinding(), new KafkaChannelBinding(), new KafkaOperationBinding(), new KafkaMessageBinding(),
7667
};
7768

7869
public static ICollection<IBindingParser<IBinding>> Pulsar => new List<IBindingParser<IBinding>>
7970
{
80-
new PulsarServerBinding(),
81-
new PulsarChannelBinding(),
71+
new PulsarServerBinding(), new PulsarChannelBinding(),
8272
};
8373

8474
public static ICollection<IBindingParser<IBinding>> Sqs => new List<IBindingParser<IBinding>>
8575
{
86-
new SqsChannelBinding(),
87-
new SqsOperationBinding(),
76+
new SqsChannelBinding(), new SqsOperationBinding(),
8877
};
8978

9079
public static ICollection<IBindingParser<IBinding>> Sns => new List<IBindingParser<IBinding>>
9180
{
92-
new SnsChannelBinding(),
93-
new SnsOperationBinding(),
81+
new SnsChannelBinding(), new SnsOperationBinding(),
9482
};
9583

9684
public static ICollection<IBindingParser<IBinding>> AMQP => new List<IBindingParser<IBinding>>
9785
{
98-
new AMQPChannelBinding(),
99-
new AMQPOperationBinding(),
100-
new AMQPMessageBinding(),
86+
new AMQPChannelBinding(), new AMQPOperationBinding(), new AMQPMessageBinding(),
87+
};
88+
89+
public static ICollection<IBindingParser<IBinding>> AnypointMQ => new List<IBindingParser<IBinding>>
90+
{
91+
new AnypointMQChannelBinding(), new AnypointMQMessageBinding(),
92+
};
93+
94+
public static ICollection<IBindingParser<IBinding>> GooglePubSub => new List<IBindingParser<IBinding>>
95+
{
96+
new GooglePubSubChannelBinding(), new GooglePubSubMessageBinding(),
97+
};
98+
99+
public static ICollection<IBindingParser<IBinding>> IBMMQ => new List<IBindingParser<IBinding>>
100+
{
101+
new IBMMQServerBinding(), new IBMMQChannelBinding(), new IBMMQMessageBinding(),
102+
};
103+
104+
public static ICollection<IBindingParser<IBinding>> JMS => new List<IBindingParser<IBinding>>
105+
{
106+
new JMSServerBinding(), new JMSChannelBinding(), new JMSMessageBinding(),
101107
};
102108

103109
public static ICollection<IBindingParser<IBinding>> MQTT => new List<IBindingParser<IBinding>>
104110
{
105-
new MQTTServerBinding(),
106-
new MQTTOperationBinding(),
107-
new MQTTMessageBinding(),
111+
new MQTTServerBinding(), new MQTTOperationBinding(), new MQTTMessageBinding(),
112+
};
113+
114+
public static ICollection<IBindingParser<IBinding>> MQTT5 => new List<IBindingParser<IBinding>>
115+
{
116+
new MQTT5ServerBinding(),
117+
};
118+
119+
public static ICollection<IBindingParser<IBinding>> NATS => new List<IBindingParser<IBinding>>
120+
{
121+
new NATSOperationBinding(),
122+
};
123+
124+
public static ICollection<IBindingParser<IBinding>> ROS2 => new List<IBindingParser<IBinding>>
125+
{
126+
new ROS2ServerBinding(), new ROS2OperationBinding(),
127+
};
128+
129+
public static ICollection<IBindingParser<IBinding>> Solace => new List<IBindingParser<IBinding>>
130+
{
131+
new SolaceServerBinding(), new SolaceOperationBinding(),
108132
};
109133
}
110134
}

0 commit comments

Comments
 (0)