All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.bluebank.braid.corda.BraidVerticle.kt Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2018 Royal Bank of Scotland
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.bluebank.braid.corda

import io.bluebank.braid.corda.rest.RestMounter
import io.bluebank.braid.corda.router.Routers
import io.bluebank.braid.core.http.setupAllowAnyCORS
import io.bluebank.braid.core.http.setupOptionsMethod
import io.bluebank.braid.core.http.withCompatibleWebsockets
import io.bluebank.braid.core.logging.loggerFor
import io.vertx.core.AbstractVerticle
import io.vertx.core.Future
import io.vertx.core.WorkerExecutor
import io.vertx.ext.web.Router
import io.vertx.ext.web.handler.BodyHandler
import io.vertx.ext.web.handler.LoggerFormat
import io.vertx.ext.web.handler.LoggerHandler
import net.corda.core.node.AppServiceHub
import java.net.URL
import java.util.concurrent.TimeUnit

class BraidVerticle(
  private val services: AppServiceHub?,
  private val config: BraidConfig
) : AbstractVerticle() {

  companion object {
    private val log = loggerFor()
  }

  override fun start(startFuture: Future) {
    // setupRouter takes 3500 msec to run on my machine, even for a simple test
    // (though it's only slow when running Braid in a separate server and using the class path scanner,
    // because when using braid within a cordapp it's reasonably fast).

    // The vertx blocked thread checker would warn, if we used vertx.executeBlocking and that took more than 10 seconds,
    // so instead let's use a WorkerExecutor here, which *can* run for longer than 10 seconds.
    // CordappScanner supports an unbounded number of cordapps -- so what's a safe/optimum timeout value?
    // Let's arbitrarily choose "2 minutes" for now and maybe make it infinite or configurable later.

    val poolSize = 1
    val maxExecuteTime: Long = 60
    val executor = super.vertx.createSharedWorkerExecutor(
      "braid-startup-threadpool",
      poolSize,
      maxExecuteTime,
      TimeUnit.SECONDS
    )

    fun log(start: Long, method: String) {
      log.info("BraidVerticle.$method complete -- ${System.currentTimeMillis() - start} msec")
    }

    executor.executeBlocking(
      {
        val start = System.currentTimeMillis()
        it.complete(setupRouter())
        log(start, "setupRouter")
      },
      {
        if (it.failed()) {
          throw it.cause();
        }
        val start = System.currentTimeMillis()
        setupWebserver(it.result(), startFuture)
        log(start, "setupWebserver")

        executor.close()

        log.info(
          "Braid server started on",
          "${config.protocol}://localhost:${config.port}${config.rootPath}"
        )
      }
    )
  }

  private fun setupWebserver(router: Router, startFuture: Future) {
    vertx.createHttpServer(config.httpServerOptions.withCompatibleWebsockets())
      .requestHandler(router)
      .listen(config.port) {
        if (it.succeeded()) {
          log.info("Braid service mounted on ${config.protocol}://localhost:${config.port}${config.rootPath}")
        } else {
          log.error("failed to start server: ${it.cause().message}")
        }
        startFuture.handle(it.mapEmpty())
      }
  }

  private fun setupRouter(): Router {
    val router = Routers.create(vertx, config.port)
    log.info("BraidVerticle.setupRouter starting...")
    router.route().handler(LoggerHandler.create(LoggerFormat.SHORT))
    router.route().handler(BodyHandler.create())
    router.setupAllowAnyCORS()
    router.setupOptionsMethod()
    services?.let {
      router.setupSockJSHandler(vertx, services, config)
    }
    config.restConfig?.let { restConfig ->
      val host = URL(restConfig.hostAndPortUri).host
      val updatedHostAndPort = "${config.protocol}://$host:${config.port}"
      val moddedConfig = restConfig.withHostAndPortUri(updatedHostAndPort)
        .withAuth(config.authConstructor?.invoke(vertx))

      RestMounter.mount(moddedConfig, router, vertx)
    }
    return router
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy