From 482459a63433c281b7a576236111e6a86e4521c9 Mon Sep 17 00:00:00 2001 From: vlad Date: Sat, 16 Jul 2016 04:09:40 -0400 Subject: Default implementations for easier testing + Database implicits reorganized --- src/main/scala/com/drivergrp/core/DriverApp.scala | 19 +++++------ src/main/scala/com/drivergrp/core/Service.scala | 34 -------------------- src/main/scala/com/drivergrp/core/database.scala | 30 +++++++++++------ src/main/scala/com/drivergrp/core/logging.scala | 2 +- src/main/scala/com/drivergrp/core/module.scala | 39 +++++++++++++++++++++++ src/main/scala/com/drivergrp/core/rest.scala | 22 +++++++++---- src/main/scala/com/drivergrp/core/time.scala | 1 + 7 files changed, 87 insertions(+), 60 deletions(-) delete mode 100644 src/main/scala/com/drivergrp/core/Service.scala create mode 100644 src/main/scala/com/drivergrp/core/module.scala (limited to 'src/main') diff --git a/src/main/scala/com/drivergrp/core/DriverApp.scala b/src/main/scala/com/drivergrp/core/DriverApp.scala index 7b991d1..b361c15 100644 --- a/src/main/scala/com/drivergrp/core/DriverApp.scala +++ b/src/main/scala/com/drivergrp/core/DriverApp.scala @@ -6,40 +6,41 @@ import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.server.RouteResult._ import akka.stream.ActorMaterializer import com.drivergrp.core.logging.{Logger, TypesafeScalaLogger} +import com.drivergrp.core.module.Module import com.typesafe.config.Config import org.slf4j.LoggerFactory -class DriverApp(services: Seq[Service], +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(services) - scheduleServicesDeactivation(services) - bindHttp(services) + activateServices(modules) + scheduleServicesDeactivation(modules) + bindHttp(modules) } - protected def bindHttp(services: Seq[Service]) { + 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 = services.flatMap(_.serviceTypes) + val serviceTypes = modules.flatMap(_.routeTypes) val swaggerService = new Swagger(actorSystem, serviceTypes, config) val swaggerRoutes = swaggerService.routes ~ swaggerService.swaggerUI Http()(actorSystem).bindAndHandle( - route2HandlerFlow(logRequestResult("log")(services.map(_.route).foldLeft(swaggerRoutes) { _ ~ _ })), + route2HandlerFlow(logRequestResult("log")(modules.map(_.route).foldLeft(swaggerRoutes) { _ ~ _ })), interface, port)(materializer) } /** * Initializes services */ - protected def activateServices(services: Seq[Service]) = { + protected def activateServices(services: Seq[Module]) = { services.foreach { service => Console.print(s"Service ${service.name} starts ...") try { @@ -56,7 +57,7 @@ class DriverApp(services: Seq[Service], /** * Schedules services to be deactivated on the app shutdown */ - protected def scheduleServicesDeactivation(services: Seq[Service]) = { + protected def scheduleServicesDeactivation(services: Seq[Module]) = { Runtime.getRuntime.addShutdownHook(new Thread() { override def run(): Unit = { services.foreach { service => diff --git a/src/main/scala/com/drivergrp/core/Service.scala b/src/main/scala/com/drivergrp/core/Service.scala deleted file mode 100644 index 4404c9c..0000000 --- a/src/main/scala/com/drivergrp/core/Service.scala +++ /dev/null @@ -1,34 +0,0 @@ -package com.drivergrp.core - -import akka.http.scaladsl.server.{Route, RouteConcatenation} - - -trait Service { - import scala.reflect.runtime.universe._ - - val name: String - def route: Route - def serviceTypes: Seq[Type] - - def activate(): Unit = {} - def deactivate(): Unit = {} -} - -/** - * Service implementation which may be used to composed a few - * - * @param name more general name of the composite service, - * must be provided as there is no good way to automatically - * generalize the name from the composed services' names - * @param services services to compose into a single one - */ -class CompositeService(val name: String, services: Seq[Service]) - extends Service with RouteConcatenation { - - def route: Route = services.map(_.route).reduce(_ ~ _) - - def serviceTypes = services.flatMap(_.serviceTypes) - - override def activate() = services.foreach(_.activate()) - override def deactivate() = services.reverse.foreach(_.deactivate()) -} \ No newline at end of file diff --git a/src/main/scala/com/drivergrp/core/database.scala b/src/main/scala/com/drivergrp/core/database.scala index f39512c..89cfac1 100644 --- a/src/main/scala/com/drivergrp/core/database.scala +++ b/src/main/scala/com/drivergrp/core/database.scala @@ -11,14 +11,6 @@ object database { trait Database { val profile: JdbcProfile val database: JdbcProfile#Backend#Database - - import profile.api._ - - implicit def idColumnType[T] = - MappedColumnType.base[Id[T], Long]({ id => id: Long }, { id => Id[T](id) }) - - implicit def nameColumnType[T] = - MappedColumnType.base[Name[T], String]({ name => name: String }, { name => Name[T](name) }) } object Database { @@ -33,8 +25,28 @@ object database { } } - trait DatabaseObject { + + trait IdColumnTypes { + val database: Database + + import database.profile.api._ + + implicit def idColumnType[T] = + MappedColumnType.base[Id[T], Long]({ id => id: Long }, { id => Id[T](id) }) + + implicit def nameColumnType[T] = + MappedColumnType.base[Name[T], String]({ name => name: String }, { name => Name[T](name) }) + } + + + trait DatabaseObject extends IdColumnTypes { + def createTables(): Future[Unit] def disconnect(): Unit } + + abstract class DatabaseObjectAdapter extends DatabaseObject { + def createTables(): Future[Unit] = Future.successful(()) + def disconnect(): Unit = {} + } } diff --git a/src/main/scala/com/drivergrp/core/logging.scala b/src/main/scala/com/drivergrp/core/logging.scala index 4729c09..67a852b 100644 --- a/src/main/scala/com/drivergrp/core/logging.scala +++ b/src/main/scala/com/drivergrp/core/logging.scala @@ -67,7 +67,7 @@ object logging { def debug(marker: Marker, message: String, args: AnyRef*): Unit = scalaLogging.debug(marker, message, args) } - class NopLogger() extends Logger { + class NoLogger() extends Logger { def fatal(message: String): Unit = {} def fatal(message: String, cause: Throwable): Unit = {} diff --git a/src/main/scala/com/drivergrp/core/module.scala b/src/main/scala/com/drivergrp/core/module.scala new file mode 100644 index 0000000..94dd6a3 --- /dev/null +++ b/src/main/scala/com/drivergrp/core/module.scala @@ -0,0 +1,39 @@ +package com.drivergrp.core + +import akka.http.scaladsl.server.{Route, RouteConcatenation} + + +object module { + 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()) + } +} \ No newline at end of file diff --git a/src/main/scala/com/drivergrp/core/rest.scala b/src/main/scala/com/drivergrp/core/rest.scala index b772a2e..51823da 100644 --- a/src/main/scala/com/drivergrp/core/rest.scala +++ b/src/main/scala/com/drivergrp/core/rest.scala @@ -23,20 +23,29 @@ import scalaz.{Failure => _, Success => _, _} object rest { - class RestService(actorSystem: ActorSystem, log: Logger, stats: Stats, - time: TimeProvider, executionContext: ExecutionContext) { + trait RestService { + def sendRequest(request: HttpRequest): Future[HttpResponse] + } - protected implicit val timeout = Timeout(5 seconds) + class AkkaHttpRestService(actorSystem: ActorSystem) extends RestService { + protected implicit val materializer = ActorMaterializer()(actorSystem) + + def sendRequest(request: HttpRequest): Future[HttpResponse] = + Http()(actorSystem).singleRequest(request)(materializer) + } - implicit val materializer = ActorMaterializer()(actorSystem) + class ProxyRestService(actorSystem: ActorSystem, log: Logger, stats: Stats, + time: TimeProvider, executionContext: ExecutionContext) + extends AkkaHttpRestService(actorSystem) { + protected implicit val timeout = Timeout(5 seconds) - def sendRequest(request: HttpRequest): Future[HttpResponse] = { + override def sendRequest(request: HttpRequest): Future[HttpResponse] = { log.audit(s"Sending to ${request.uri} request $request") val requestTime = time.currentTime() - val response = Http()(actorSystem).singleRequest(request)(materializer) + val response = super.sendRequest(request) response.onComplete { case Success(_) => @@ -55,7 +64,6 @@ object rest { } } - object basicFormats { implicit def idFormat[T] = new RootJsonFormat[Id[T]] { diff --git a/src/main/scala/com/drivergrp/core/time.scala b/src/main/scala/com/drivergrp/core/time.scala index cce479f..2502a70 100644 --- a/src/main/scala/com/drivergrp/core/time.scala +++ b/src/main/scala/com/drivergrp/core/time.scala @@ -5,6 +5,7 @@ import java.util.{Calendar, Date, GregorianCalendar} import scala.concurrent.duration.Duration + object time { // The most useful time units -- cgit v1.2.3