Skip to main content

Genesis Router

Genesis Router is responsible for all communication between the front end and back end. On the Genesis Platform, the front end connects to the back end through HTTPS or secure Websockets via a reverse proxy. This must run on the same instance as the back end.

The GENESIS_ROUTER service on the server acts as the endpoint for all API calls and listens (by default) to port 9064. It proxies all requests to the relevant process based on the MESSAGE_TYPE

It can be configured genesis-router.kts, which should be placed in the cfg folder to override the default platform provided configuration file for an application.

Here is an example:

router {
webPort = 9064
socketPort = 9065

httpServerCodec {
maxInitialLineLength = 4096
maxHeaderSize = 8192
maxChunkSize = 8192
validateHeaders = true
initialBufferSize = 128
}
httpObjectAggregator {
maxContentLength = 262144
closeOnExpectationFailed = false
}

routes {
route(messageType = "ALL_ORDERS", process = "OEMS_DATASERVER")
route(messageType = "ALL_TRADES", process = "OEMS_DATASERVER")
route(messageType = "ALL_ORDER_AUDITS", process = "OEMS_DATASERVER")
}

allowList {
entry("ALL_ORDERS")
entry("ALL_TRADES")
entry("ALL_ORDER_AUDITS")
}

cookieAuthentication {
enabled = false
httpOnly = false
secure = false
wrap = false
path = "/"
domain = null
sameSite = SameSite.Lax
}

clientHandler {
channelCapacity = 20
onChannelFull = CLOSE
}
}

Router configuration

Let's have a look at the different options for configuring this file. You have seen some, but not all of these in the example above.

webPort This port is used for tcp/ip socket. You must declare a port, and it cannot be below 1024.

socketPort This port is used for http/websockets. You must declare a port, and it cannot be below 1024.

dataserverPollingTimeout This setting contains the timeout (in seconds) to expire inactive dataserver subscriptions. Subscription inactivity is determined by the lack of HTTP requests from the client targeting a specific Data Server subscription. Default value is 60 seconds.

authDisabled This is a dangerous setting! If set to true, it disables all authentication on the router. Typically, it is used for development mode. If you need to use this for another reason, see our section on non-authenticated Genesis Routers. Default value is false.

nettyLoggingEnabled If set to true, this setting enables internal netty logging. Default value false.

Netty configuration

`httpServerCodecDefinition: A combination of HttpRequestDecoder and HttpResponseEncoder, which enables easier server-side HTTP implementation. You can find more information in the netty documentation.

Different decoder options

  • maxInitialLineLength default value: 4096
  • maxHeaderSize default value: 8192
  • maxChunkSize default value: 8192
  • validateHeaders default value: true
  • initialBufferSize default value: 128

httpObjectAggregatorDefinition A ChannelHandler that aggregates an HttpMessage and its following HttpContents into a single FullHttpRequest or FullHttpResponse (depending on if it used to handle requests or responses) with no following HttpContents.

There is more information in the netty documentation.

  • maxContentLength The maximum length of the aggregated content in bytes. Default value: 262144
  • closeOnExpectationFailed If a 100-continue response is detected but the content length is too large, then true means close the connection. Otherwise, the connection will remain open and data will be consumed and discarded until the next request is received. Default value: false

Message routes

routes You can redirect some microservice messages to particular processes by declaring new route blocks within this one.

route Is the defined route taking both a messageType and a specific process.

Blocked and allowed resources

You can control which resources are exposed to the front end by the Genesis Router using either allowList or blockList.

  • If you specify one or more resources as allowList, then only these resources (and the Genesis defaults) are accessible.
  • If you specify one or more resources as blockList, then these resources are not exposed. All other resources (including the Genesis defaults) are accessible.
  • If you don't specify any resources as either allowList or blockList, then all resources (including the Genesis defaults) are accessible.

The allowList and blockList tags are mutually exclusive. If you specify both, it will generate an error.

The default resources that are always exposed are:

  • EVENT_LOGIN_AUTH
  • EVENT_LOGOUT
  • MORE_ROWS
  • MORE_COLUMNS
  • DATA_LOGOFF
  • DATA_GET

entry Is the additional accepted messageType.

Cookie authentication

From GSF version 6.7 onwards, you can configure the HTTP authentication flow to use a cookie-based approach. When the cookie authentication mechanism is enabled:

  • The Genesis Platform expects all login and logout events to be called via HTTP.
  • Information related to the session itself (e.g. session id, session token, refresh token) is handled transparently using cookies.

Given these expectations, login and logout operations via Websocket are not allowed. A Websocket connection to GENESIS_ROUTER is only possible after a successful HTTP login.

The configuration options are:

  • enabled defines whether the cookie authentication mechanism will be enabled or disabled at the Router level. Default: false
  • httpOnly sets the generated cookies to be 'HttpOnly' (more information here). Default: false
  • secure sets the generated cookies to be 'Secure' (more information here). Default: false
  • wrap wraps the value of the cookie itself in double quotes (i.e. ") Default: false
  • path sets the specific path attributed to the cookie values. Default: "/"
  • domain sets the expected domain for the generated cookie. Default: null
  • sameSite configures the behaviour of the cookie when used as part of cross-site requests. Cookies with undefined (i.e. null) sameSite configuration will default to SameSite.Lax . Available values: SameSite.None, SameSite.Lax, SameSite.Strict. Default: null (i.e. therefore SameSite.Lax)

For more information about all the different cookie configuration options and the impact they have in terms of security, refer to the OWASP cookie testing guide.

Configuring client handling

For each client connection, the Router maintains its own message buffer (channel) for sending messages to a client. You can configure:

  • the size of the channel buffer
  • the behaviour if the buffer becomes full

To configure client handling, open a clientHandler block. There is an example of this in the main example at the top of the page. The configuration options are:

  • channelSize sets the size of the channel buffer. Defaults to 32.

  • onChannelFullsets the behavior when the buffer is full:

    • SUSPEND is the default behaviour. This utilises Kotlin coroutines and they will wait (suspend) for the buffer to have space before adding any further messages to the buffer.
    • CLOSE causes the client connection to be closed if the channel buffer becomes full. This could happen with slow consumers, and can help protect the ROUTER process rather than causing a large backlog of messages, which consumes memory. In the worst case, this could cause an Out Of Memory error on the ROUTER process.

Configuring runtime

There are two important files in your application that contain configuration information; make sure that your Genesis Router is configured correctly in both of them:

  • application-name-processes.xml
  • application-name-service-definitions.xml

Configuring in processes.xml

Here is an example of the Genesis Router's configuration in an application's processes.xml file:

<process name="GENESIS_ROUTER">
<start>true</start>
<scheduleRestart>true</scheduleRestart>
<groupId>GENESIS</groupId>
<options>-Xmx512m -DXSD_VALIDATE=false</options>
<module>router</module>
<package>global.genesis.router,global.genesis.console</package>
<config>router-process-config.kts</config>
<script>genesis-router.kts</script>
<language>pal</language>
<classpath>genesis-console-*.jar</classpath>
<description>Socket, Websocket and HTTP proxy which routes incoming messages to GENESIS microservices</description>
</process>

For more information on the tags that can be set within the configuration for your application in this file, go to our page on processes.xml.

Configuring in service-definitions.xml

The service definition is designed to make sure that each module (service) has a unique port number for inter-process messaging. Here is an example:

  <service host="localhost" name="GENESIS_ROUTER" port="9017"/>

For more information on the attributes that can be set here, go to our page on service definitions.

Custom endpoints

To create a custom endpoint using the Genesis Router, simply implement the WebEndpoint interface provided by Genesis Router. Call upon the registerEndpoint method of an injected WebEndpointRegistry object.

In the following examples, a FileEndpointCommon class has also been created to hold utility methods that may be needed across multiple endpoints:

FileEndpointCommon

public class FileEndpointCommon {
companion object {
const val ENDPOINT_NAME = "file-handler"
}
}

FileProcessor

@Module
class FileProcessorKotlin @Inject constructor(
private val registry: WebEndpointRegistry
) : WebEndpoint {
@PostConstruct
fun init() {
registry.registerEndpoint(FileEndpointCommon.ENDPOINT_NAME, this)
}

override fun allowedMethods(): Set<RequestType> {
return ALLOWED_HTTP_METHODS
}

override fun name(): String {
return "upload"
}

override fun process(s: String, fullHttpRequest: FullHttpRequest, channel: Channel): Any {
LOG.debug("Hit {}/{} endpoint", FileEndpointCommon.ENDPOINT_NAME, name())
//This is where you would make calls to other services and libraries with the newly uploaded file.
val responseJson = "{ \"Result\": \"Successful upload\"}".toByteArray(StandardCharsets.UTF_8)
val responseBuffer = Unpooled.wrappedBuffer(responseJson)
val response = DefaultFullHttpResponse(
HttpVersion.HTTP_1_1,
HttpResponseStatus.OK,
responseBuffer
)
response.headers().add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON)
HttpUtil.setContentLength(response, responseJson.size.toLong())
return response
}

override fun requiresAuth(): Boolean {
return if (System.getProperty("TEST_MODE") != null) {
false
} else {
super.requiresAuth()
}
}

companion object {
private val LOG = LoggerFactory.getLogger(FileProcessorKotlin::class.java)
private val ALLOWED_HTTP_METHODS: Set<RequestType> = ImmutableSet.of(RequestType.POST)
}
}

Non-authenticated routers

As we have noted, the authDisabled setting is dangerous. One way or another, it is essential that you make your Genesis Router secure. If you want to disable authentication for any other reason than local testing (for example, heavy interaction with legacy systems that can be secured at a legacy level), you still need to take the greatest care to ensure security:

  • Use unique ports, and make sure there is no clash with other modules. By default, Genesis Router uses 9064/9065. Make sure this is correctly entered in your application-service-definitions.xml file.
  • Make sure that the firewall settings for these ports are limited, so that unwanted external traffic cannot reach it.
  • It is useful to rename your Genesis Router's genesis-router.kts file to genesis-router-no-auth.kts. In this file, you must list the event/dataserver/reqrep resource names in an allowList block (one entry per item) to specify the resources that can be hit. These are the only resources that can be hit. This is critical to ensuring security.

Once you have defined a non-authenticated Genesis Router and arranged its security, you need to make sure it has a correct entry in your application-processes file; this must point at your .kts file. For best practice, clearly name the process as non-authenticated. For example:

<process name="GENESIS_ROUTER_NO_AUTH">
<start>true</start>
<groupId>GENESIS</groupId>
<opKons>-Xmx512m -DXSD_VALIDATE=false</opKons>
<module>router</module>
<package>global.genesis.router </package>
<config>genesis-router-no-auth.kts</config>
<classpath>genesis-console-4*.jar,ppt-pdjandler-*.jar</classpath>
<descripKon>Socket, Websocket and HTTP proxy which routes incoming messages to GENESIS
microservices</descripKon>
</process>

Testing the Genesis Router

To create unit tests for Genesis Router, you can extend the AbstractGenesisTestSupport class and specify the genesis-router.kts as the Script file name. Examples of how you would initialise a test extending this class are provided below.

More information about how testing works is in our section on Integration testing.

class TestEndpoint : AbstractGenesisTestSupport<GenesisSet>(
GenesisTestConfig {
packageNames = mutableListOf("global.genesis.router", "org.file.processor")
genesisHome = "/genesisHome"
scriptFileName = "genesis-router.kts"
parser = { it }
}
) {
override fun createDictionary(): GenesisDictionary = testDictionary()}

@Test
fun testRouterEndPoint() {
val client = HttpClient.newHttpClient()
val request = HttpRequest
.newBuilder(URI("http://localhost:9064/file-handler/upload"))
.version(HttpClient.Version.HTTP_1_1)
.POST(HttpRequest.BodyPublishers.ofString("TEXT"))
.build()
val response = client.send(request, HttpResponse.BodyHandlers.ofString())
Assert.assertEquals("{ \"Result\": \"Successful upload\"}", response.body())
}

Metrics

info

Ensure you have enabled metrics in your environment to view them.

The metrics for Genesis Router measure the number of connections and the processing latency.

MetricExplanation
active_connectionsThe number of client connections
message_processing_latencyThe latency for processing messages