Skip to content

Commit

Permalink
W-12689952: add ibmmq server binding in async21+
Browse files Browse the repository at this point in the history
- add server binding model, parser and emitter
- add unit validation and cycle tests
- add model to APIEntities and model.md
  • Loading branch information
arielmirra committed Feb 7, 2024
1 parent ef7c133 commit 8c5df8d
Show file tree
Hide file tree
Showing 14 changed files with 320 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package amf.apicontract.client.platform.model.domain.bindings.ibmmq

import amf.apicontract.client.platform.model.domain.bindings.{BindingVersion, ServerBinding}
import amf.apicontract.client.scala.model.domain.bindings.ibmmq.{IBMMQServerBinding => InternalIBMMQServerBinding}
import amf.apicontract.internal.convert.ApiClientConverters._
import amf.core.client.platform.model
import amf.core.client.platform.model.{BoolField, IntField, StrField}

import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel}

@JSExportAll
case class IBMMQServerBinding(override private[amf] val _internal: InternalIBMMQServerBinding)
extends ServerBinding
with BindingVersion {
@JSExportTopLevel("IBMMQServerBinding")
def this() = this(InternalIBMMQServerBinding())

def groupId: StrField = _internal.groupId
def ccdtQueueManagerName: StrField = _internal.ccdtQueueManagerName
def cipherSpec: StrField = _internal.cipherSpec
def multiEndpointServer: BoolField = _internal.multiEndpointServer
def heartBeatInterval: IntField = _internal.heartBeatInterval

def withGroupId(groupId: String): this.type = {
_internal.withGroupId(groupId)
this
}

def withCcdtQueueManagerName(ccdtQueueManagerName: String): this.type = {
_internal.withCcdtQueueManagerName(ccdtQueueManagerName)
this
}

def withCipherSpec(cipherSpec: String): this.type = {
_internal.withCipherSpec(cipherSpec)
this
}

def withMultiEndpointServer(multiEndpointServer: Boolean): this.type = {
_internal.withMultiEndpointServer(multiEndpointServer)
this
}

def withHeartBeatInterval(heartBeatInterval: Int): this.type = {
_internal.withHeartBeatInterval(heartBeatInterval)
this
}

override protected def bindingVersion: model.StrField = _internal.bindingVersion

override def withBindingVersion(bindingVersion: String): this.type = {
_internal.withBindingVersion(bindingVersion)
this
}

override def linkCopy(): IBMMQServerBinding = _internal.linkCopy()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package amf.apicontract.client.scala.model.domain.bindings.ibmmq

import amf.apicontract.client.scala.model.domain.bindings.{BindingVersion, ServerBinding}
import amf.apicontract.internal.metamodel.domain.bindings.IBMMQServerBindingModel
import amf.apicontract.internal.metamodel.domain.bindings.IBMMQServerBindingModel._
import amf.apicontract.internal.spec.async.parser.bindings.Bindings.IBMMQ
import amf.core.client.scala.model.domain.{DomainElement, Linkable}
import amf.core.client.scala.model.{BoolField, IntField, StrField}
import amf.core.internal.metamodel.Field
import amf.core.internal.parser.domain.{Annotations, Fields}
import amf.shapes.client.scala.model.domain.Key

class IBMMQServerBinding(override val fields: Fields, override val annotations: Annotations)
extends ServerBinding
with BindingVersion
with Key {

override protected def bindingVersionField: Field = BindingVersion
override def meta: IBMMQServerBindingModel.type = IBMMQServerBindingModel

def groupId: StrField = fields.field(GroupId)
def ccdtQueueManagerName: StrField = fields.field(CcdtQueueManagerName)
def cipherSpec: StrField = fields.field(CipherSpec)
def multiEndpointServer: BoolField = fields.field(MultiEndpointServer)
def heartBeatInterval: IntField = fields.field(HeartBeatInterval)

def withGroupId(groupId: String): this.type = set(GroupId, groupId)
def withCcdtQueueManagerName(ccdtQueueManagerName: String): this.type =
set(CcdtQueueManagerName, ccdtQueueManagerName)
def withCipherSpec(cipherSpec: String): this.type = set(CipherSpec, cipherSpec)
def withMultiEndpointServer(multiEndpointServer: Boolean): this.type = set(MultiEndpointServer, multiEndpointServer)
def withHeartBeatInterval(heartBeatInterval: Int): this.type = set(HeartBeatInterval, heartBeatInterval)

override def key: StrField = fields.field(IBMMQServerBindingModel.key)

override def componentId: String = s"/$IBMMQ-server"

override def linkCopy(): IBMMQServerBinding = IBMMQServerBinding()

override protected def classConstructor: (Fields, Annotations) => Linkable with DomainElement =
IBMMQServerBinding.apply
}

object IBMMQServerBinding {

def apply(): IBMMQServerBinding = apply(Annotations())

def apply(annotations: Annotations): IBMMQServerBinding = apply(Fields(), annotations)

def apply(fields: Fields, annotations: Annotations): IBMMQServerBinding =
new IBMMQServerBinding(fields, annotations)
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import amf.apicontract.client.scala.model.domain.bindings.amqp.{
Amqp091Queue
}
import amf.apicontract.client.scala.model.domain.bindings.http.{HttpMessageBinding, HttpOperationBinding}
import amf.apicontract.client.scala.model.domain.bindings.ibmmq.IBMMQMessageBinding
import amf.apicontract.client.scala.model.domain.bindings.ibmmq.{IBMMQMessageBinding, IBMMQServerBinding}
import amf.apicontract.client.scala.model.domain.bindings.kafka.{KafkaMessageBinding, KafkaOperationBinding}
import amf.apicontract.client.scala.model.domain.bindings.mqtt.{
MqttMessageBinding,
Expand Down Expand Up @@ -114,6 +114,7 @@ trait ApiBaseConverter
with Amqp091ChannelExchangeConverter
with Amqp091QueueConverter
with IBBMQMessageBindingConverter
with IBBMQServerBindingConverter
with ChannelBindingConverter
with OperationBindingConverter
with MessageBindingConverter
Expand Down Expand Up @@ -322,6 +323,15 @@ trait IBBMQMessageBindingConverter extends PlatformSecrets {
}
}

trait IBBMQServerBindingConverter extends PlatformSecrets {
implicit object IBBMQServerBindingMatcher
extends BidirectionalMatcher[IBMMQServerBinding, domain.bindings.ibmmq.IBMMQServerBinding] {
override def asClient(from: IBMMQServerBinding): domain.bindings.ibmmq.IBMMQServerBinding =
platform.wrap[domain.bindings.ibmmq.IBMMQServerBinding](from)
override def asInternal(from: domain.bindings.ibmmq.IBMMQServerBinding): IBMMQServerBinding = from._internal
}
}

trait EndPointConverter extends PlatformSecrets {

implicit object EndPointMatcher extends BidirectionalMatcher[EndPoint, domain.EndPoint] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import amf.apicontract.client.platform.model.domain.api.{AsyncApi, WebApi}
import amf.apicontract.client.platform.model.domain.bindings._
import amf.apicontract.client.platform.model.domain.bindings.amqp._
import amf.apicontract.client.platform.model.domain.bindings.http.{HttpMessageBinding, HttpOperationBinding}
import amf.apicontract.client.platform.model.domain.bindings.ibmmq.IBMMQMessageBinding
import amf.apicontract.client.platform.model.domain.bindings.ibmmq.{IBMMQMessageBinding, IBMMQServerBinding}
import amf.apicontract.client.platform.model.domain.bindings.kafka.{KafkaMessageBinding, KafkaOperationBinding}
import amf.apicontract.client.platform.model.domain.bindings.mqtt.{
MqttMessageBinding,
Expand Down Expand Up @@ -278,6 +278,9 @@ private[amf] object ApiRegister extends UniqueInitializer with PlatformSecrets {
platform.registerWrapper(IBMMQMessageBindingModel) {
case s: amf.apicontract.client.scala.model.domain.bindings.ibmmq.IBMMQMessageBinding => IBMMQMessageBinding(s)
}
platform.registerWrapper(IBMMQServerBindingModel) {
case s: amf.apicontract.client.scala.model.domain.bindings.ibmmq.IBMMQServerBinding => IBMMQServerBinding(s)
}
platform.registerWrapper(APIContractProcessingDataModel) {
case s: amf.apicontract.client.scala.model.document.APIContractProcessingData => APIContractProcessingData(s)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ private[amf] object APIEntities extends Entities {
ComponentModuleModel,
ParameterFederationMetadataModel,
EndpointFederationMetadataModel,
IBMMQMessageBindingModel
IBMMQMessageBindingModel,
IBMMQServerBindingModel
)
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package amf.apicontract.internal.metamodel.domain.bindings

import amf.apicontract.client.scala.model.domain.bindings.ibmmq.IBMMQMessageBinding
import amf.apicontract.client.scala.model.domain.bindings.ibmmq.{IBMMQMessageBinding, IBMMQServerBinding}
import amf.core.client.scala.model.domain.AmfObject
import amf.core.client.scala.vocabulary.Namespace.ApiBinding
import amf.core.client.scala.vocabulary.ValueType
import amf.core.internal.metamodel.Field
import amf.core.internal.metamodel.Type.{Int, Str}
import amf.core.internal.metamodel.Type.{Bool, Int, Str}
import amf.core.internal.metamodel.domain.{ModelDoc, ModelVocabularies}

object IBMMQMessageBindingModel extends MessageBindingModel with BindingVersion {
Expand Down Expand Up @@ -60,3 +60,78 @@ object IBMMQMessageBindingModel extends MessageBindingModel with BindingVersion

override val doc: ModelDoc = ModelDoc(ModelVocabularies.ApiBinding, "IBMMQMessageBinding")
}

object IBMMQServerBindingModel extends ServerBindingModel with BindingVersion {
val GroupId: Field =
Field(
Str,
ApiBinding + "groupId",
ModelDoc(
ModelVocabularies.ApiBinding,
"groupId",
"Defines a logical group of IBM MQ server objects. This is necessary to specify multi-endpoint configurations used in high availability deployments. If omitted, the server object is not part of a group."
)
)

val CcdtQueueManagerName: Field =
Field(
Str,
ApiBinding + "ccdtQueueManagerName",
ModelDoc(
ModelVocabularies.ApiBinding,
"ccdtQueueManagerName",
"The name of the IBM MQ queue manager to bind to in the CCDT file."
)
)

val CipherSpec: Field =
Field(
Str,
ApiBinding + "cipherSpec",
ModelDoc(
ModelVocabularies.ApiBinding,
"cipherSpec",
"The recommended cipher specification used to establish a TLS connection between the client and the IBM MQ queue manager."
)
)

val MultiEndpointServer: Field =
Field(
Bool,
ApiBinding + "multiEndpointServer",
ModelDoc(
ModelVocabularies.ApiBinding,
"multiEndpointServer",
"If multiEndpointServer is true then multiple connections can be workload balanced and applications should not make assumptions as to where messages are processed. Where message ordering, or affinity to specific message resources is necessary, a single endpoint (multiEndpointServer = false) may be required."
)
)

val HeartBeatInterval: Field =
Field(
Int,
ApiBinding + "heartBeatInterval",
ModelDoc(
ModelVocabularies.ApiBinding,
"heartBeatInterval",
"The recommended value (in seconds) for the heartbeat sent to the queue manager during periods of inactivity. A value of zero means that no heart beats are sent. A value of 1 means that the client will use the value defined by the queue manager."
)
)

override def modelInstance: AmfObject = IBMMQServerBinding()

override def fields: List[Field] =
List(
GroupId,
CcdtQueueManagerName,
CipherSpec,
MultiEndpointServer,
HeartBeatInterval,
BindingVersion
) ++ ServerBindingModel.fields

override val `type`: List[ValueType] = ApiBinding + "IBMMQServerBinding" :: ServerBindingModel.`type`

override val key: Field = Type

override val doc: ModelDoc = ModelDoc(ModelVocabularies.ApiBinding, "IBMMQServerBinding")
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@ import org.mulesoft.common.client.lexical.Position
import amf.core.internal.render.BaseEmitters.{ValueEmitter, pos, traverse}
import amf.core.internal.render.SpecOrdering
import amf.core.internal.render.emitters.EntryEmitter
import amf.apicontract.internal.metamodel.domain.bindings.{MqttServerBindingModel, MqttServerLastWillModel}
import amf.apicontract.internal.metamodel.domain.bindings.{
IBMMQServerBindingModel,
MqttServerBindingModel,
MqttServerLastWillModel
}
import amf.apicontract.client.scala.model.domain.bindings.ServerBinding
import amf.apicontract.client.scala.model.domain.bindings.ibmmq.IBMMQServerBinding
import amf.apicontract.client.scala.model.domain.bindings.mqtt.{MqttServerBinding, MqttServerLastWill}
import amf.apicontract.internal.spec.async.parser.bindings.Bindings._
import amf.apicontract.internal.spec.oas.emitter.context.OasLikeSpecEmitterContext
import org.yaml.model.{YDocument, YNode}

Expand All @@ -21,8 +27,9 @@ class AsyncApiServerBindingsEmitter(binding: ServerBinding, ordering: SpecOrderi
}

private def emitterFor(binding: ServerBinding): Option[EntryEmitter] = binding match {
case binding: MqttServerBinding => Some(new MqttServerBindingEmitter(binding, ordering))
case _ => None
case binding: MqttServerBinding => Some(new MqttServerBindingEmitter(binding, ordering))
case binding: IBMMQServerBinding => Some(new IBMMQServerBindingEmitter(binding, ordering))
case _ => None
}

override def position(): Position = pos(binding.annotations)
Expand All @@ -33,7 +40,7 @@ class MqttServerBindingEmitter(binding: MqttServerBinding, ordering: SpecOrderin

override def emit(b: YDocument.EntryBuilder): Unit = {
b.entry(
YNode("mqtt"),
YNode(Mqtt),
_.obj { emitter =>
val result = ListBuffer[EntryEmitter]()
val fs = binding.fields
Expand Down Expand Up @@ -73,3 +80,31 @@ class MqttServerBindingEmitter(binding: MqttServerBinding, ordering: SpecOrderin
override def position(): Position = pos(lastWill.annotations)
}
}

class IBMMQServerBindingEmitter(binding: IBMMQServerBinding, ordering: SpecOrdering)
extends AsyncApiCommonBindingEmitter {

override def emit(b: YDocument.EntryBuilder): Unit = {
b.entry(
YNode(IBMMQ),
_.obj { emitter =>
val result = ListBuffer[EntryEmitter]()
val fs = binding.fields

fs.entry(IBMMQServerBindingModel.GroupId).foreach(f => result += ValueEmitter("groupId", f))
fs.entry(IBMMQServerBindingModel.CcdtQueueManagerName)
.foreach(f => result += ValueEmitter("ccdtQueueManagerName", f))
fs.entry(IBMMQServerBindingModel.CipherSpec).foreach(f => result += ValueEmitter("cipherSpec", f))
fs.entry(IBMMQServerBindingModel.MultiEndpointServer)
.foreach(f => result += ValueEmitter("multiEndpointServer", f))
fs.entry(IBMMQServerBindingModel.HeartBeatInterval).foreach(f => result += ValueEmitter("heartBeatInterval", f))

emitBindingVersion(fs, result)

traverse(ordering.sorted(result), emitter)
}
)
}

override def position(): Position = pos(binding.annotations)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package amf.apicontract.internal.spec.async.parser.bindings

import amf.apicontract.client.scala.model.domain.bindings.{ServerBinding, ServerBindings}
import amf.apicontract.internal.metamodel.domain.bindings.ServerBindingsModel
import amf.apicontract.internal.spec.async.parser.bindings.Bindings.Mqtt
import amf.apicontract.internal.spec.async.parser.bindings.server.MqttServerBindingParser
import amf.apicontract.internal.spec.async.parser.bindings.Bindings.{IBMMQ, Mqtt}
import amf.apicontract.internal.spec.async.parser.bindings.server._
import amf.apicontract.internal.spec.async.parser.context.AsyncWebApiContext
import amf.apicontract.internal.spec.common.WebApiDeclarations.ErrorServerBindings
import amf.apicontract.internal.spec.spec.OasDefinitions
Expand All @@ -14,7 +14,8 @@ import amf.shapes.internal.spec.common.parser.YMapEntryLike

object AsyncServerBindingsParser {
private val parserMap: Map[String, BindingParser[ServerBinding]] = Map(
Mqtt -> MqttServerBindingParser
Mqtt -> MqttServerBindingParser,
IBMMQ -> IBMMQServerBindingParser
)
}
case class AsyncServerBindingsParser(entryLike: YMapEntryLike)(implicit ctx: AsyncWebApiContext)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package amf.apicontract.internal.spec.async.parser.bindings.server

import amf.apicontract.client.scala.model.domain.bindings.ibmmq.IBMMQServerBinding
import amf.apicontract.internal.metamodel.domain.bindings.IBMMQServerBindingModel
import amf.apicontract.internal.spec.async.parser.bindings.BindingParser
import amf.apicontract.internal.spec.async.parser.context.AsyncWebApiContext
import amf.core.internal.parser.YMapOps
import amf.core.internal.parser.domain.Annotations
import org.yaml.model.{YMap, YMapEntry}

object IBMMQServerBindingParser extends BindingParser[IBMMQServerBinding] {
override def parse(entry: YMapEntry, parent: String)(implicit ctx: AsyncWebApiContext): IBMMQServerBinding = {
val binding = IBMMQServerBinding(Annotations(entry))
val map = entry.value.as[YMap]

map.key("groupId", IBMMQServerBindingModel.GroupId in binding)
map.key("ccdtQueueManagerName", IBMMQServerBindingModel.CcdtQueueManagerName in binding)
map.key("cipherSpec", IBMMQServerBindingModel.CipherSpec in binding)
map.key("multiEndpointServer", IBMMQServerBindingModel.MultiEndpointServer in binding)
map.key("heartBeatInterval", IBMMQServerBindingModel.HeartBeatInterval in binding)

parseBindingVersion(binding, IBMMQServerBindingModel.BindingVersion, map)

ctx.closedShape(binding, map, "IBMMQServerBinding")

binding
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ object Async21Syntax extends SpecSyntax {
"description",
"expiry",
"bindingVersion"
),
"IBMMQServerBinding" -> Set(
"groupId",
"ccdtQueueManagerName",
"cipherSpec",
"multiEndpointServer",
"heartBeatInterval",
"bindingVersion"
)
)
}
Loading

0 comments on commit 8c5df8d

Please sign in to comment.