diff options
Diffstat (limited to 'src/main/scala/com/drivergrp/core/app.scala')
-rw-r--r-- | src/main/scala/com/drivergrp/core/app.scala | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/src/main/scala/com/drivergrp/core/app.scala b/src/main/scala/com/drivergrp/core/app.scala new file mode 100644 index 0000000..34a92e3 --- /dev/null +++ b/src/main/scala/com/drivergrp/core/app.scala @@ -0,0 +1,115 @@ +package com.drivergrp.core + +import akka.actor.ActorSystem +import akka.http.scaladsl.Http +import akka.http.scaladsl.server.Directives._ +import akka.http.scaladsl.server.RouteResult._ +import akka.stream.ActorMaterializer +import com.drivergrp.core.logging.{Logger, TypesafeScalaLogger} +import akka.http.scaladsl.server.{Route, RouteConcatenation} +import com.drivergrp.core.rest.Swagger +import com.typesafe.config.Config +import org.slf4j.LoggerFactory + + +object app { + + class DriverApp(modules: Seq[Module], + log: Logger = new TypesafeScalaLogger( + com.typesafe.scalalogging.Logger(LoggerFactory.getLogger(classOf[DriverApp]))), + config: Config = com.drivergrp.core.config.loadDefaultConfig, + interface: String = "localhost", port: Int = 8080) { + + def run() = { + activateServices(modules) + scheduleServicesDeactivation(modules) + bindHttp(modules) + } + + protected def bindHttp(modules: Seq[Module]) { + implicit val actorSystem = ActorSystem("spray-routing", config) + implicit val executionContext = actorSystem.dispatcher + implicit val materializer = ActorMaterializer()(actorSystem) + + val serviceTypes = modules.flatMap(_.routeTypes) + val swaggerService = new Swagger(actorSystem, serviceTypes, config) + val swaggerRoutes = swaggerService.routes ~ swaggerService.swaggerUI + + Http()(actorSystem).bindAndHandle( + route2HandlerFlow(logRequestResult("log")(modules.map(_.route).foldLeft(swaggerRoutes) { _ ~ _ })), + interface, port)(materializer) + } + + /** + * Initializes services + */ + protected def activateServices(services: Seq[Module]) = { + services.foreach { service => + Console.print(s"Service ${service.name} starts ...") + try { + service.activate() + } catch { + case t: Throwable => + log.fatal(s"Service ${service.name} failed to activate", t) + Console.print(" Failed! (check log)") + } + Console.println(" Done") + } + } + + /** + * Schedules services to be deactivated on the app shutdown + */ + protected def scheduleServicesDeactivation(services: Seq[Module]) = { + Runtime.getRuntime.addShutdownHook(new Thread() { + override def run(): Unit = { + services.foreach { service => + Console.print(s"Service ${service.name} shutting down ...") + try { + service.deactivate() + } catch { + case t: Throwable => + log.fatal(s"Service ${service.name} failed to deactivate", t) + Console.print(" Failed! (check log)") + } + Console.println(" Done") + } + } + }) + } + } + + + import scala.reflect.runtime.universe._ + + trait Module { + val name: String + def route: Route + def routeTypes: Seq[Type] + + def activate(): Unit = {} + def deactivate(): Unit = {} + } + + class SimpleModule(val name: String, val route: Route, routeType: Type) extends Module { + def routeTypes: Seq[Type] = Seq(routeType) + } + + /** + * Module implementation which may be used to composed a few + * + * @param name more general name of the composite module, + * must be provided as there is no good way to automatically + * generalize the name from the composed modules' names + * @param modules modules to compose into a single one + */ + class CompositeModule(val name: String, modules: Seq[Module]) + extends Module with RouteConcatenation { + + def route: Route = modules.map(_.route).reduce(_ ~ _) + def routeTypes = modules.flatMap(_.routeTypes) + + override def activate() = modules.foreach(_.activate()) + override def deactivate() = modules.reverse.foreach(_.deactivate()) + } +} |