Communications
This section gives details around client to server and server to server communications. This includes message formats and defining message metadata in the Genesis Application Platform, how to set up encrypted process communication, and using the network API.
GenesisSet
GenesisSet
is a generic message format used to send data between Genesis processes. The information in the messages must be stored as key-value pairs. A GenesisSet can store integers, booleans, text, etc. Importantly, it can also contain other GenesisSets.
In this section, we give you some examples that illustrate usage and structure.
Send message to Event Handler service
- Kotlin
- Java
genesisSet {
MESSAGE_TYPE with "EVENT_LOGIN_AUTH"
SERVICE_NAME with "GENESIS_AUTH_MANAGER"
SOURCE_REF with "sourceRef"
DETAILS with genesisSet {
USER_NAME with "User"
PASSWORD with "Password"
}
}
GenesisSet.builder()
.setString(MESSAGE_TYPE, "EVENT_LOGIN_AUTH")
.setString(SERVICE_NAME, "GENESIS_AUTH_MANAGER")
.setString(SOURCE_REF, "sourceRef")
.setGenesisSet("DETAILS", GenesisSet.builder()
.setString("USER_NAME", "User")
.setString("PASSWORD", "Password")
.build()
).build();
Send message to Request Server
- Kotlin
- Java
genesisSet {
MESSAGE_TYPE with "REQ_INSTRUMENT"
SERVICE_NAME with "GCOM_REQUEST_SERVER"
SOURCE_REF with "sourceRef"
REQUEST with genesisSet {
"INSTRUMENT_ID" with "*"
}
}
GenesisSet.builder()
.setString(MESSAGE_TYPE, "REQ_INSTRUMENT")
.setString(SERVICE_NAME, "GCOM_REQUEST_SERVER")
.setString(SOURCE_REF, "sourceRef")
.setGenesisSet("REQUEST", GenesisSet.builder()
.setString("INSTRUMENT_ID", "*")
.build()
).build();
Using constructor
- Kotlin
- Java
val genesisSet = GenesisSet()
genesisSet.setInteger("PRICE", 10)
genesisSet.setString("MESSAGE_TYPE", "EVENT_LOGIN_AUTH")
GenesisSet genesisSet = new GenesisSet();
genesisSet.setInteger("PRICE", 10)
genesisSet.setString("MESSAGE_TYPE", "EVENT_LOGIN_AUTH")
Constructors
Signature | Description |
---|---|
GenesisSet(expectedSize: Int = 32) | Creates a GenesisSet object with a predetermined expected number of key-value pairs. |
GenesisSet(fields: MutableMap<String, Any?>) | Creates a GenesisSet object using an already existing Map object containing key-value pairs. |
Functions
Name | Signature | Description |
---|---|---|
containsField | fun containsField(fieldName: String): Boolean | Checks whether provided field name exists in GenesisSet |
equals | override fun equals(other: Any?): Boolean | Checks equality of two GenesisSets |
getArray | open operator override fun equals(other: Any?): Boolean | Get an array value, or default value if property not present. |
getBigDecimal | fun getBigDecimal(property: String, defaultValue: BigDecimal) | Get a BigDecimal value, or default value if property not present. |
getBoolean | fun getBoolean(property: String, defaultValue: Boolean) | Get a boolean value, or the 'defaultValue' parameter if field not found. |
getByteArray | fun getByteArray(property: String): ByteArray? | Get a byte array value (assume a Base64 string if a string is found). You can use a full stop to denote an embedded Genesis set, or retrieve the set directly. |
getDate | fun getDate(key: String, defaultValue: DateTime) | Get a DateTime value, or default value if property not present. |
getDouble | fun getDouble(property: String, defaultValue: Double) | Get a double value, or default value if property not present. |
getGenesisSet | fun getGenesisSet(property: String, defaultValue: GenesisSet) | Get a Genesis set, or default value if property not present. |
getInteger | fun getInteger(property: String, defaultValue: Int) | Get an integer value, or default value if property not present. |
getLong | fun getLong(property: String, defaultValue: Long) | Get a long value, or default value if property not present. |
getObject | tailrec fun getObject(property: String, genesisSet: GenesisSet = this): Any? | Recursively get an object. |
getShort | fun getShort(property: String, defaultValue: Short) | Get a short value, or default value if property not present. |
getString | fun getString(property: String, defaultValue: String) | Get a string value, or the default value if property not found. You can use a full stop to denote an embedded Genesis set, or retrieve the set directly. |
setArray | fun setArray(key: String, value: Any?) | Set an array value. Method can be called repeatedly with the same key to build up a list of values. |
setBigDecimal | fun setBigDecimal(key: String, value: BigDecimal?) | Set BigDecimal value. If the value exists in the set it is overwritten. |
setBoolean | fun setBoolean(key: String, value: Boolean?) | Set integer value. If the value exists in the set it is overwritten. |
setByteArray | fun setByteArray(key: String, value: ByteArray?) | Set byte array value. If the value exists in the set it is overwritten. |
setDate | fun setDate(key: String, date: DateTime?) | Set date value. If the value exists in the set it is overwritten. |
setDirect | fun setDirect(property: String, value: Any?) | Shorthand method to set a field that may be multiple sets deep. |
setDirectNull | fun setDirectNull(property: String, value: Any?, defaultValue: Any) | Shorthand method to set a field that may be multiple sets deep, and accepts a default value for null parameters. |
setDouble | fun setDouble(key: String, value: Double?) | Set integer value. If the value exists in the set it is overwritten. |
setFullArray | fun setFullArray(key: String, array: Iterable<*>) | Set a full list of values. |
setGenesisSet | setGenesisSet(key: String, set: GenesisSet?) | Embed a set inside this set. If the value exists in the set it is overwritten. |
setInteger | fun setInteger(key: String, value: Int?) | Set integer value. If the value exists in the set it is overwritten. |
setLong | fun setLong(key: String, value: Long?) | Set long value. If the value exists in the set it is overwritten. |
setString | fun setString(key: String, value: String? | Set string value. If the value exists in the set it is overwritten. |
toString | override fun toString(): String | Returns a pretty-print string. |
unSet | fun unSet(field: String) | Shorthand method to unset a single field. |
unSetDirect | tailrec fun unSetDirect(property: String, genesisSet: GenesisSet = this) | Shorthand method to unset a field that may be multiple sets deep |
unSetGenesisSet | fun unSetGenesisSet(key: String) | Shorthand method to unset a GenesisSet. |
with | infix fun String.with(any: Any?) | Sets key-value in GenesisSet Ex: MESSAGE_TYPE with EVENT_INSERT |
Companion object
Functions
fun genesisSet(init: GenesisSet.() -> Unit): GenesisSet
: This function enables the Kotlin DSL builder used in these examples.
fun builder(): GenesisSetBuilder
: This method is commonly used as an alternative to the Kotlin DSL builder when creating GenesisSet objects in Java. GenesisSetBuilder allows you to create new instances of GenesisSet in a fluent way, as shown in the above examples.
Type-safe messages
The Genesis Application Platform uses type-safe messages to perform message serialization and deserialization. In addition, it automatically extracts relevant metadata to expose this to the front end in the form of a Json Schema definition that is compliant with the 2019-09 specification. These messages will be validated automatically in the back end, based on their definition.
These type-safe messages are most commonly used in Request Servers, GPAL Event Handlers and Event Handlers that have been implemented as a set of classes.
Input messages
The input message type I
is defined as a Kotlin data class, which specifies all the necessary information to parse the incoming message and to expose it as metadata. Take a look at this example, which we shall discuss below:
enum class LogLevel {
TRACE, DEBUG, INFO, WARN, ERROR
}
data class SetLogLevel(
@Title("Process name")
val processName: String,
@Description("Represents the target logging level")
val logLevel: LogLevel? = null,
val datadump: Boolean = false,
val expiration: Int = 0
)
In this example, the SetLogLevel
data class has a single constructor that also defines the properties of the data class. Also note:
- Mandatory metadata field.
processName
does not have a default value associated with it; therefore, a value is mandatory to construct this message. So, it will be exposed as a mandatory metadata field. - Optional metadata fields.
logLevel
,datadump
andexpiration
all have default values; they will therefore be exposed as optional metadata fields.
You are free to use all the following types, as long as they are composed using the same elements:
- Genesis metadata field basic types (Boolean, Short, Int, Long, Double, String, BigDecimal or Joda DateTime)
- enumerated types (as you can see defined in
LogLevel
above) - basic collection types (List, Set and Map)
- other Kotlin data classes
All these different types will be understood by the metadata system and exposed accordingly. Kotlin also has nullable and non-nullable types, and the metadata system will expose this information too.
Annotations such as @Title
and @Description
can be used to provide extra information to the front end.
For example:
@Title
could be used to provide a human-readable name for a metadata field to be displayed in a grid column.@Description
could be used to provide tooltip information when hovering over that column header.
You can find more information in our page about metadata annotations.
Read-only values
Read-only values can be exposed inside a Kotlin companion object and can be as complex as any other metadata field definition. In the example below, the enhanced SetLogLevel
class provides information about the default LogLevel:
data class SetLogLevel(
@Title("Process name")
val processName: String,
@Description("Represents the target logging level")
val logLevel: LogLevel? = null,
val datadump: Boolean = false,
val expiration: Int = 0
) {
companion object ReadOnly {
val defaultLogLevel: LogLevel = LogLevel.INFO
}
}
Deserialized fields
There is a significant disadvantage in using type-safe messages with support for default values; once the message has been deserialized, you don't know what the original payload contained.
Following the previous example with the SetLogLevel
data class, it is possible to receive a message with just a processName
value; you will still have default values for all the other fields because of the automatic defaults. This causes problems where you have business logic where those fields were part of the original payload.
For example, if you receive a value for the field expiration
set as 0, you might want to define a different business logic than if the value was never sent in the first place - even though 0 is the same value as the default value.
In order to solve this problem, there is a class called DeserializedFieldsSupport
. This class can be extended by any type-safe data class. It is available for both Event Handler definitions and Request Server definitions. The SetLogLevel
data class in the previous example would now look like this:
data class SetLogLevel(
@Title("Process name")
val processName: String,
@Description("Represents the target logging level")
val logLevel: LogLevel? = null,
val datadump: Boolean = false,
val expiration: Int = 0
) : DeserializedFieldsSupport() {
companion object ReadOnly {
val defaultLogLevel: LogLevel = LogLevel.INFO
}
}
Any message extending this class will have access to a property called deserializedFields
of type Map<String, DeserializedField>
This property provides enough information to reconstruct the values that were part of the original payload.
The DeserializedField
sealed class definition looks like this:
sealed class DeserializedField {
object Simple : DeserializedField()
data class Array(val fields: List<DeserializedField>) : DeserializedField()
data class Object(val fields: Map<String, DeserializedField>) : DeserializedField()
}
So, if we revisit a real-life example for SetLogLevel
in which we only receive field values for processName
and datadump
, the content of deserializedFields
will be a Map
with the following key values:
{
"PROCESS_NAME" : DeserializedField.Simple
"DATADUMP" : DeserializedField.Simple
}
If your message has nested arrays or objects, the deserializedFields
property will also contain nested structures in the shape of DeserializedField.Array
and DeserializedField.Object
types.
Output messages
The output message type O
can be defined as a single Kotlin data class or sealed class with multiple Kotlin data classes defined as subtypes. For multiple subtypes, the Genesis Application Platform is able to extract information for all the possible messages and expose it as metadata.
As an example, we shall look at EventReply
and how Event Handlers work with output types in real life.
Event Handler examples
The default output message type to use in Event Handlers is EventReply
. This is a Kotlin sealed class, which is most commonly represented by two subtypes: EventAck
and EventNack
. The Kotlin definitions of these are:
data class EventAck(val generated: List<Map<String, Any>> = emptyList()) : EventReply()
data class EventNack(
val warning: List<GenesisError> = emptyList(),
val error: List<GenesisError> = emptyList()
) : EventReply()
Alternatively, you can create your own reply type using a normal Kotlin data class or sealed class. The example below defines EventSetLogLevelReply
:
sealed class EventSetLogLevelReply : Outbound() {
class EventSetLogLevelAck : EventSetLogLevelReply()
data class EventSetLogLevelNack(val error: String) : EventSetLogLevelReply()
}
These custom reply types allow a predetermined number of customized replies for a single eventHandler
codeblock, with their type information exposed in the metadata system. They need to be handled carefully, as the internal error-handling mechanism for the Event Handler is only able to handle EventReply
messages. Therefore, non-captured exceptions and errors will break the type-safety guarantees of the reply.
IMPORTANT! The success message should always end in Ack
in order for the internal eventHandler
logic to handle validation correctly.
Error messages
There is a common format for error or warning messages sent between server and client. The message format is the same for all HTTP and WebSocket messages that we support:
MESSAGE_TYPE = ...
SOURCE_REF = ...
ERROR = [
{
CODE (String) = -- predefined error code,
TEXT (String) = -- human readable message,
STATUS_CODE (ENUM: HttpStatusCode) = -- http status code
// Optional: Additional custom fields
}
]
WARNING = [
{
CODE = -- predefined error code,
TEXT = -- human readable message,
STATUS_CODE (ENUM: HttpStatusCode) = -- http status code
// Optional: Additional custom fields
}
]
All errors and warnings are represented as implementations of the GenesisError interface. This is defined as follows:
interface GenesisError {
val code: String
val text: String
val statusCode: HttpStatusCode
get() = HttpStatusCode.InternalServerError
}
So by default, all error/warning messages have the following properties, along with any extra properties that are needed to represent the error:
-
CODE is the error code, which can be of two types:
- ErrorCode is the ENUM class that contains a list of different error codes coming from the server, as shown below
- String is used to pass any code that is not part of ErrorCode enum
-
TEXT is of type String and contains more detailed information about the error code that is being sent.
-
STATUS_CODE is of type ENUM, represented by HttpStatusCode enum class, which corresponds to netty
HttpResponseStatus
and will be used to represent HTTP status of all error/warning messages.
There is also the common interface GenesisNackReply
, for NACK messages:
interface GenesisNackReply {
val warning: List<GenesisError>
val error: List<GenesisError>
}
The interface GenesisNackReply
with MESSAGE_TYPE and SOURCE_REF fields represents the whole error or warning message that is sent to the API client.
Types of Nack message
These are the main types of Nack (error or warning) message. Most of them are sent either as EVENT_NACK or MSG_NACK:
Nack message type | Details |
---|---|
EVENT_NACK | used as response for unsuccessful event |
MSG_NACK | used when something unexpected happens and on anything that is not an event |
LOGOUT_NACK | used when there is an issue with Logout Request |
LOGIN_AUTH_NACK | used when there is an issue with Login Request |
LOGON_NACK | used when there is an issue with Data Server subscription |
EVENT_LOGIN_DETAILS_NACK | used when there is an issue with provided login details: USER_NAME or SESSION_AUTH_TOKEN |
CREATE_MFA_SECRET_NACK | used when there is an issue with creation of MFA secret |
Error codes
Below is the list of standard error codes, along with their HTTP Status code. The framework implementation is standardized to provide error code CODE
as Enum represented by ErrorCode
class, but it also provides the flexibility to include any error code.
ErrorCode class definition
enum class ErrorCode(private val readableString: String, val statusCode: HttpStatusCode)
Error Code | HTTP status code |
---|---|
GENERIC_ERROR | 500 Internal Server Error |
MISSING_FIELD | 400 Bad Request |
VALIDATION_ERROR | 400 Bad Request |
INVALID_MESSAGE | 400 Bad Request |
NOT_SUPPORTED_ENUM_VALUE | 400 Bad Request |
NOT_AUTHORISED | 403 Forbidden |
DUPLICATE_KEY | 500 Internal Server Error |
INVALID_MESSAGE_TYPE | 400 Bad Request |
INVALID_DATASOURCE | 400 Bad Request |
INVALID_PARAMETER | 400 Bad Request |
LOGIN_ERROR | 401 Unauthorized |
MULTIPLE_TABLES | 500 Internal Server Error |
MISSING_KEY | 400 Bad Request |
UNKNOWN_TABLE | 400 Bad Request |
UNKNOWN_FIELD | 400 Bad Request |
UNKNOWN | 500 Internal Server Error |
NO_MESSAGE_TYPE | 400 Bad Request |
NO_SOURCE_REF | 400 Bad Request |
NO_USER_NAME | 400 Bad Request |
UNAVAILABLE | 503 Service Unavailable |
UNKNOWN_MESSAGE_TYPE | 400 Bad Request |
FEATURE_NOT_PROVIDED | 400 Bad Request |
FEATURE_NOT_FOUND | 404 Not Found |
JSON_SCHEMA_NOT_FOUND | 404 Not Found |
REJECT_RULE_DOES_NOT_EXIST | 400 Bad Request |
ERROR_CHECKING_EXISTING_RULE | 400 Bad Request |
NO_DS_NAME | 400 Bad Request |
INVALID_DS_NAME | 404 Not Found |
INVALID_INDEX | 400 Bad Request |
REJECT_RULE_MISSING | 404 Not Found |
ERROR_MODIFYING_RULE | 500 Internal Server Error |
INVALID_CRITERIA | 400 Bad Request |
MAX_LOGON_LIMIT | 429 Too Many Requests |
RECORD_NOT_FOUND | 404 Not Found |
SERVICE_NOT_FOUND | 404 Not Found |
DATABASE_FAILURE | 500 Internal Server Error |
DATABASE_ERROR | 500 Internal Server Error |
OPERATION_TIMEOUT | 408 Request Timeout |
DEPENDENT_RECORD_FOUND | 500 Internal Server Error |
REQUIRES_APPROVAL | 403 Forbidden |
APPROVAL_MESSAGE_MISSING | 400 Bad Request |
INTERNAL_ERROR | 500 Internal Server Error |
GATEWAY_ERROR | 400 Bad Request |
REQUEST_FAILED | 400 Bad Request |
UNABLE_TO_UPDATE_APPROVAL | 500 Internal Server Error |
APPROVAL_SAME_USER_CANNOT_ACCEPT | 400 Bad Request |
APPROVAL_RECORD_NOT_FOUND | 404 Not Found |
REJECTED_BY_SERVICE | 500 Internal Server Error |
APPROVAL_DIFF_USER_CANNOT_CANCEL | 400 Bad Request |
APPROVAL_WRONG_STATUS_CANNOT_CANCEL | 400 Bad Request |
APPROVAL_WRONG_STATUS_CANNOT_ACCEPT | 400 Bad Request |
APPROVAL_SAME_USER_CANNOT_REJECT | 400 Bad Request |
APPROVAL_WRONG_STATUS_CANNOT_REJECT | 400 Bad Request |
MISSING_HOSTNAME | 400 Bad Request |
NUMBER_OF_RECORDS_DOES_NOT_MATCH | 400 Bad Request |
HTTP status code
We use standard HTTP status codes to represent the response status. This is a well-known standard that is easy to understand. It is internally represented by the HttpStatusCode
enum class, which corresponds to netty HttpResponseStatus.
To get the appropriate status code for an error message, you need to enable this at router-level. You do this using the property strictHttpStatusCode
.
For example, strictHttpStatusCode
is set to false
by default. Because of this, you will get 200 OK
for some error messages, and you cannot guarantee that you will always receive the appropriate status code. So, we set strictHttpStatusCode
to true
in the genesis-router.kts file:
router {
webPort = 9064
socketPort = 9065
strictHttpStatusCode = true
nettyLoggingEnabled = true
}
A single message can contain multiple errors and warnings. Here is how the response status code for the message is allocated:
Messages with only errors
- If the message contains a single error, then its code is used as the response status code for the message
- If the message contains multiple errors with the same code, then this is used as the response status code for the message
- If the message contains multiple errors with different status codes, then:
- for multiple 5xx errors, the response status code is set to 500
- for multiple 4xx errors, the response status code is set to the status code of first error
- for a mix of 5xx and 4xx errors, the response status code is set to 500
Messages with only warnings
- If there are only warning messages, the response status is set to 400.
Messages with errors and warnings
- If there are both error messages and warning messages, the response status code is based on the error message or messages:
- for a single error message or multiple error messages of the same type, this error code is used as the response status code for the message
- for multiple 5xx errors, the response status code is set to 500
- for multiple 4xx errors, the response status code is set to the status code of first error
- for a mix of 5xx and 4xx errors, the response status code is set to 500
Metadata annotations
The following annotations are found in the package global.genesis.message.core.annotation
and can be applied when defining Kotlin data classes to be used as input I
message types.
As an example, these input types can be used in Event Handlers and custom Request Servers (see type-safe messages).
It is important to note that these annotations will influence the automatic generation of relevant Json schema definitions within the backend metadata system, as well as enforcing transparent validation checks.
The UniqueItems
annotation will generate a Json schema uniqueItems
definition. Unfortunately, the current specification of uniqueItems
means that only primitive values will be checked for uniqueness (i.e. string, integer, etc), as opposed to fully fledged object definitions. One of the consequences is that it is currently impossible to use Json Schema and allow for advanced uniqueItems
checks, including unique id
checks. See discussions around key-based uniqueness in here.
Annotation name | Targets | Parameters | Description |
---|---|---|---|
Title | Property and class | title: String | Suggests a human readable name for the annotated class or property |
Description | Property and class | description: String | Suggests a human description for the annotated class or property |
StringConstant | Property | constant: String | Defines a constant value, which is always expected for a property |
MinItems | Property | minItems: Int | Defines a minimum number of items for a list type property |
MaxItems | Property | maxItems: Int | Defines a maximum number of items for a list type property |
UniqueItems | Property | none | Marks a list type property as unique items only |
MinLength | Property | minLength: Int | Defines a minimum number of characters in a String property |
MaxLength | Property | maxLength: Int | Defines a maximum number of characters in a String property |
Pattern | Property | pattern: String | Defines an expected regular expression pattern for a String property |
ShortMin | Property | min: Short | Defines the minimum value expected for a Short property |
ShortMax | Property | max: Short | Defines the maximum value expected for a Short property |
IntMin | Property | min: Int | Defines the minimum value expected for an Int property |
IntMax | Property | max: Int | Defines the maximum value expected for an Int property |
LongMin | Property | min: Long | Defines the minimum value expected for a Long property |
LongMax | Property | max: Long | Defines the maximum value expected for a Long property |
DoubleMin | Property | min: Double | Defines the minimum value expected for a Double property |
DoubleMax | Property | max: Double | Defines the maximum value expected for a Double property |
BigDecimalMin | Property | min: String | Defines the minimum value expected for a BigDecimal property |
BigDecimalMax | Property | max: String | Defines the maximum value expected for a BigDecimal property |
Network API
Use these APIs to send and receive messages between micro-services.
ClientConnectionsManager
Use @Inject
to create ClientConnectionsManager
.
See the example below:
class TestService(@Inject val clientConnectionManager: ClientConnectionsManager) {}
GenesisMessageClient
GenesisMessageClient
is a messaging client that can be obtained using ClientConnectionManager
. Here is an example:
If you connect successfully to the POSITION_APP_EVENT_HANDLER service, you will get GenesisMessageClient. Otherwise, you will get null.
class TestAuthManagerService(@Inject val clientConnectionManager: ClientConnectionsManager) {
private val genesisMessageClient = clientConnectionManager.getGenesisMessageClient("POSITION_APP_EVENT_HANDLER")
// custom code here
}
Constructor
GenesisMessageClient(address: String, port: Int, secure: Boolean, configuration: NetworkConfiguration)
Functions
Name | Signature |
---|---|
addConnectionEventHandler | fun addConnectionEventHandler(handler: ConnectionEventHandler) |
removeConnectionEventHandler | fun removeConnectionEventHandler(handler: ConnectionEventHandler) |
request | fun <I : Inbound, O : Outbound> request(messageWorkflow: DataWorkflow<I, O>, timeout: Int = configuration.reqRepTimeout,): Single<O> |
request | suspend fun <I : Any, O : Any> request(messageWorkflow: RequestReplyDataWorkflow<I, O>,timeout: Int = configuration.reqRepTimeout,): Reply<O> |
request | fun <I : Inbound, O : Outbound> request(message: I, output: Class<O>, timeout: Int = configuration.reqRepTimeout,): Single<O> |
request | suspend inline fun <reified O : Outbound> request(message: Inbound, messageType: String, timeout: Int = configuration.reqRepTimeout,): O |
requestParametric | suspend inline fun <reified O, reified P : Any> requestParametric(message: Inbound, messageType: String, timeout: Int = configuration.reqRepTimeout,): |
sendMessage | fun sendMessage(set: GenesisSet): Boolean |
sendMessage | fun sendMessage(set: GenesisMessage): Boolean |
sendMessages | fun sendMessages(sets: List<GenesisSet>) |
sendReqRep | fun sendReqRep(set: GenesisSet, consumer: Consumer<GenesisSet>) |
sendReqRep | fun sendReqRep(set: GenesisSet, consumer: Consumer<GenesisSet>, reqRepTimeout: Int,) |
sendReqRep | fun sendReqRep(set: GenesisSet): ListenableFuture<GenesisSet> |
sendReqRep | fun sendReqRep(set: GenesisSet, reqRepTimeout: Int,): ListenableFuture<GenesisSet> |
shutdown | @Throws(InterruptedException::class) fun shutdown() |
suspendRequest | suspend inline fun <reified I : Inbound, reified O : Outbound> suspendRequest(message: I, timeout: Int = configuration.reqRepTimeout,): O? |
suspendRequest | suspend inline fun <reified I : Inbound, reified O : Outbound> suspendRequest(messageWorkflow: DataWorkflow<I, O>, timeout: Int = configuration.reqRepTimeout,): O? |
Properties
Name | Summary |
---|---|
handler | Gives GenesisMessageHandler, which allows us to attach listeners to servers and clients |
isActive | Checks whether netty connector is open for new connection |
isConnected | Checks whether netty connector is open for new connection |
Example:
class TestAuthManagerService(@Inject val clientConnectionManager: ClientConnectionsManager) {
private val genesisMessageClient = clientConnectionManager.getGenesisMessageClient("GENESIS_AUTH_MANAGER")
fun sendMessageToEventHandler() {
genesisMessageClient?.waitForConnection()
genesisMessageClient?.sendReqRep(
genesisSet {
MESSAGE_TYPE with "EVENT_LOGIN_AUTH"
SERVICE_NAME with "GENESIS_AUTH_MANAGER"
SOURCE_REF with "sourceRef"
DETAILS with genesisSet {
USER_NAME with "User"
PASSWORD with "Password"
}
}
)?.get()
genesisMessageClient?.shutdown()
}
}
GenesisMessageHandler
GenesisMessageHandler enables you to attach listeners to servers and clients.
Functions
Name | Signature |
---|---|
addListener | fun addListener(listener: GenesisMessageListener<V>) |
removeListener | fun removeListener(listener: GenesisMessageListener<V>) |
GenesisMessageListener
GenesisMessageListener
is a functional interface with method onNewMessage
, which listens for any new messages. @FunctionalInterface public interface GenesisMessageListener<V extends GenesisMessage>
onNewMessage
This method is called when a new message is received.
Example:
class CreateListener(@Inject val clientConnectionManager: ClientConnectionsManager) {
private val genesisMessageClient = clientConnectionManager.getGenesisMessageClient("GENESIS_AUTH_MANAGER")
fun listener(args: Array<String>) {
// Add listener which prints GenesisSet
genesisMessageClient?.handler?.addListener {
set: GenesisSet?, channel: GenesisChannel? -> println(set)
}
// Listener gets called when new message is received
genesisMessageClient?.sendMessage(genesisSet {
MESSAGE_TYPE with "EVENT_LOGIN_AUTH"
SERVICE_NAME with "GENESIS_AUTH_MANAGER"
SOURCE_REF with "sourceRef"
DETAILS with genesisSet {
USER_NAME with "User"
PASSWORD with "Password"
}
})
}
}