From 980deaf70e4e0ba906d0af534aebc839015f0581 Mon Sep 17 00:00:00 2001 From: vlad Date: Sat, 16 Jul 2016 02:43:54 -0400 Subject: Dependency injection through constructor parameters + bug fixes --- src/main/scala/com/drivergrp/core/DriverApp.scala | 55 ++++++++++++----------- src/main/scala/com/drivergrp/core/config.scala | 36 +++------------ src/main/scala/com/drivergrp/core/database.scala | 43 ++++++++---------- src/main/scala/com/drivergrp/core/execution.scala | 28 ------------ src/main/scala/com/drivergrp/core/logging.scala | 32 ------------- src/main/scala/com/drivergrp/core/messages.scala | 26 +++-------- src/main/scala/com/drivergrp/core/rest.scala | 16 +++---- src/main/scala/com/drivergrp/core/stats.scala | 11 +---- src/main/scala/com/drivergrp/core/time.scala | 5 --- 9 files changed, 70 insertions(+), 182 deletions(-) delete mode 100644 src/main/scala/com/drivergrp/core/execution.scala (limited to 'src/main/scala/com/drivergrp/core') diff --git a/src/main/scala/com/drivergrp/core/DriverApp.scala b/src/main/scala/com/drivergrp/core/DriverApp.scala index 01fee03..7b991d1 100644 --- a/src/main/scala/com/drivergrp/core/DriverApp.scala +++ b/src/main/scala/com/drivergrp/core/DriverApp.scala @@ -5,41 +5,42 @@ 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.config.ConfigModule -import com.drivergrp.core.logging.LoggerModule +import com.drivergrp.core.logging.{Logger, TypesafeScalaLogger} +import com.typesafe.config.Config +import org.slf4j.LoggerFactory -trait DriverApp { - this: ConfigModule with LoggerModule => +class DriverApp(services: Seq[Service], + 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 interface: String = "localhost" - def port: Int = 8080 - - def services: Seq[Service] - - - val servicesInstances = services - activateServices(servicesInstances) - scheduleServicesDeactivation(servicesInstances) - - implicit val actorSystem = ActorSystem("spray-routing", config) - implicit val executionContext = actorSystem.dispatcher - implicit val materializer = ActorMaterializer()(actorSystem) + def run() = { + activateServices(services) + scheduleServicesDeactivation(services) + bindHttp(services) + } - val serviceTypes = servicesInstances.flatMap(_.serviceTypes) - val swaggerService = new Swagger(actorSystem, serviceTypes, config) - val swaggerRoutes = swaggerService.routes ~ swaggerService.swaggerUI + protected def bindHttp(services: Seq[Service]) { + implicit val actorSystem = ActorSystem("spray-routing", config) + implicit val executionContext = actorSystem.dispatcher + implicit val materializer = ActorMaterializer()(actorSystem) - Http()(actorSystem).bindAndHandle( - route2HandlerFlow(logRequestResult("log")(servicesInstances.map(_.route).foldLeft(swaggerRoutes) { _ ~ _ })), - interface, port)(materializer) + val serviceTypes = services.flatMap(_.serviceTypes) + val swaggerService = new Swagger(actorSystem, serviceTypes, config) + val swaggerRoutes = swaggerService.routes ~ swaggerService.swaggerUI + Http()(actorSystem).bindAndHandle( + route2HandlerFlow(logRequestResult("log")(services.map(_.route).foldLeft(swaggerRoutes) { _ ~ _ })), + interface, port)(materializer) + } /** * Initializes services */ - protected def activateServices(servicesInstances: Seq[Service]) = { - servicesInstances.foreach { service => + protected def activateServices(services: Seq[Service]) = { + services.foreach { service => Console.print(s"Service ${service.name} starts ...") try { service.activate() @@ -55,10 +56,10 @@ trait DriverApp { /** * Schedules services to be deactivated on the app shutdown */ - protected def scheduleServicesDeactivation(servicesInstances: Seq[Service]) = { + protected def scheduleServicesDeactivation(services: Seq[Service]) = { Runtime.getRuntime.addShutdownHook(new Thread() { override def run(): Unit = { - servicesInstances.foreach { service => + services.foreach { service => Console.print(s"Service ${service.name} shutting down ...") try { service.deactivate() diff --git a/src/main/scala/com/drivergrp/core/config.scala b/src/main/scala/com/drivergrp/core/config.scala index 5a89752..bc17d6b 100644 --- a/src/main/scala/com/drivergrp/core/config.scala +++ b/src/main/scala/com/drivergrp/core/config.scala @@ -6,38 +6,16 @@ import com.typesafe.config.{Config, ConfigFactory} object config { - trait ConfigModule { - def config: Config - } - - /** - * Configuration implementation providing config which is specified as the parameter - * which might be used for testing purposes - * - * @param config fixed config to provide - */ - class DefaultConfigModule(val config: Config) extends ConfigModule - - /** - * Configuration implementation reading default typesafe config - */ - trait TypesafeConfigModule extends ConfigModule { + def loadDefaultConfig: Config = { + val configDefaults = + ConfigFactory.load(this.getClass.getClassLoader, "application.conf") - private val internalConfig: Config = { - val configDefaults = - ConfigFactory.load(this.getClass.getClassLoader, "application.conf") + scala.sys.props.get("application.config") match { - scala.sys.props.get("application.config") match { + case Some(filename) => + ConfigFactory.parseFile(new File(filename)).withFallback(configDefaults) - case Some(filename) => - ConfigFactory.parseFile(new File(filename)).withFallback(configDefaults) - - case None => configDefaults - } + case None => configDefaults } - - protected val rootConfig = internalConfig - - val config = rootConfig } } diff --git a/src/main/scala/com/drivergrp/core/database.scala b/src/main/scala/com/drivergrp/core/database.scala index 5eb9d28..f39512c 100644 --- a/src/main/scala/com/drivergrp/core/database.scala +++ b/src/main/scala/com/drivergrp/core/database.scala @@ -1,45 +1,40 @@ package com.drivergrp.core import com.drivergrp.core.id.{Id, Name} - import scala.concurrent.Future +import slick.backend.DatabaseConfig +import slick.driver.JdbcProfile object database { - import slick.backend.DatabaseConfig - import slick.driver.JdbcProfile - - - trait DatabaseModule { + trait Database { val profile: JdbcProfile val database: JdbcProfile#Backend#Database - } - trait ConfigDatabaseModule extends DatabaseModule { + 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) }) + } - protected def databaseConfigKey: String + object Database { - private val dbConfig: DatabaseConfig[JdbcProfile] = DatabaseConfig.forConfig(databaseConfigKey) + def fromConfig(databaseName: String): Database = { + val dbConfig: DatabaseConfig[JdbcProfile] = DatabaseConfig.forConfig(databaseName) - val profile: JdbcProfile = dbConfig.driver - val database: JdbcProfile#Backend#Database = dbConfig.db + new Database { + val profile: JdbcProfile = dbConfig.driver + val database: JdbcProfile#Backend#Database = dbConfig.db + } + } } trait DatabaseObject { def createTables(): Future[Unit] def disconnect(): Unit } - - trait IdColumnTypes { - this: DatabaseModule => - - 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) }) - } } diff --git a/src/main/scala/com/drivergrp/core/execution.scala b/src/main/scala/com/drivergrp/core/execution.scala deleted file mode 100644 index 7274f00..0000000 --- a/src/main/scala/com/drivergrp/core/execution.scala +++ /dev/null @@ -1,28 +0,0 @@ -package com.drivergrp.core - - -object execution { - - import scala.concurrent.ExecutionContext - import java.util.concurrent.Executors - import akka.actor.ActorSystem - - - trait ExecutionContextModule { - - def executionContext: ExecutionContext - } - - trait FixedThreadsExecutionContext extends ExecutionContextModule { - - def threadsNumber: Int - - val executionContext: ExecutionContext = - ExecutionContext.fromExecutor(Executors.newFixedThreadPool(threadsNumber)) - } - - trait ActorSystemModule { - - def actorSystem: ActorSystem - } -} diff --git a/src/main/scala/com/drivergrp/core/logging.scala b/src/main/scala/com/drivergrp/core/logging.scala index 35f3a1b..4729c09 100644 --- a/src/main/scala/com/drivergrp/core/logging.scala +++ b/src/main/scala/com/drivergrp/core/logging.scala @@ -1,42 +1,10 @@ package com.drivergrp.core -import com.typesafe.scalalogging.{LazyLogging, StrictLogging} import org.slf4j.Marker object logging { - trait LoggerModule { - - def log: Logger - } - - trait NopLoggerModule extends LoggerModule { - - def log: Logger = new NopLogger() - } - - /** - * Defines `logger` as a lazy value initialized with an underlying `org.slf4j.Logger` - * named according to the class into which this trait is mixed. - */ - trait LazyLoggerModule extends LoggerModule { - this: LazyLogging => - - override val log: Logger = new TypesafeScalaLogger(logger) - } - - /** - * Defines `logger` as a value initialized with an underlying `org.slf4j.Logger` - * named according to the class into which this trait is mixed. - */ - trait StrictLoggerModule extends LoggerModule { - this: StrictLogging => - - override val log: Logger = new TypesafeScalaLogger(logger) - } - - trait Logger { def fatal(message: String): Unit diff --git a/src/main/scala/com/drivergrp/core/messages.scala b/src/main/scala/com/drivergrp/core/messages.scala index cf0bb6c..105d1e3 100644 --- a/src/main/scala/com/drivergrp/core/messages.scala +++ b/src/main/scala/com/drivergrp/core/messages.scala @@ -3,37 +3,23 @@ package com.drivergrp.core import java.util.Locale -import com.drivergrp.core.config.ConfigModule -import com.drivergrp.core.logging.{Logger, LoggerModule} +import com.drivergrp.core.logging.Logger +import com.typesafe.config.Config import scala.collection.JavaConverters._ -import scala.collection.concurrent.TrieMap /** * Scala internationalization (i18n) support */ object messages { - trait MessagesModule { - - def messages: Messages - } - - trait ConfigMessagesModule extends MessagesModule { - this: ConfigModule with LoggerModule => - - private val loadedFromConfig = new TrieMap[Locale, Messages]() - val locale: Locale = Locale.US - - val messages: Messages = { - loadedFromConfig.getOrElseUpdate(locale, { - val map = config.getConfig(locale.getISO3Language).root().unwrapped().asScala.mapValues(_.toString).toMap - Messages(map, locale, log) - }) + object Messages { + def messages(config: Config, log: Logger, locale: Locale = Locale.US): Messages = { + val map = config.getConfig(locale.getLanguage).root().unwrapped().asScala.mapValues(_.toString).toMap + Messages(map, locale, log) } } - case class Messages(map: Map[String, String], locale: Locale, log: Logger) { /** diff --git a/src/main/scala/com/drivergrp/core/rest.scala b/src/main/scala/com/drivergrp/core/rest.scala index e121640..b772a2e 100644 --- a/src/main/scala/com/drivergrp/core/rest.scala +++ b/src/main/scala/com/drivergrp/core/rest.scala @@ -1,21 +1,21 @@ package com.drivergrp.core +import akka.actor.ActorSystem import akka.http.scaladsl.Http import akka.http.scaladsl.model.{HttpRequest, HttpResponse} import akka.http.scaladsl.server.{Directive, _} import akka.http.scaladsl.util.FastFuture._ import akka.stream.ActorMaterializer import akka.util.Timeout -import com.drivergrp.core.execution.{ActorSystemModule, ExecutionContextModule} import com.drivergrp.core.id.{Id, Name} -import com.drivergrp.core.logging.LoggerModule -import com.drivergrp.core.stats.StatsModule +import com.drivergrp.core.logging.Logger +import com.drivergrp.core.stats.Stats import com.drivergrp.core.time.TimeRange -import com.drivergrp.core.time.provider.TimeModule +import com.drivergrp.core.time.provider.TimeProvider import spray.json.{DeserializationException, JsNumber, JsString, JsValue, RootJsonFormat} -import scala.concurrent.Future import scala.concurrent.duration._ +import scala.concurrent.{ExecutionContext, Future} import scala.language.postfixOps import scala.util.{Failure, Success, Try} import scalaz.{Failure => _, Success => _, _} @@ -23,8 +23,8 @@ import scalaz.{Failure => _, Success => _, _} object rest { - trait RestService { - this: ActorSystemModule with LoggerModule with StatsModule with TimeModule with ExecutionContextModule => + class RestService(actorSystem: ActorSystem, log: Logger, stats: Stats, + time: TimeProvider, executionContext: ExecutionContext) { protected implicit val timeout = Timeout(5 seconds) @@ -68,7 +68,7 @@ object rest { } implicit def nameFormat[T] = new RootJsonFormat[Name[T]] { - def write(name: Name[T]) = JsNumber(name) + def write(name: Name[T]) = JsString(name) def read(value: JsValue): Name[T] = value match { case JsString(name) => Name[T](name) diff --git a/src/main/scala/com/drivergrp/core/stats.scala b/src/main/scala/com/drivergrp/core/stats.scala index 2a173df..152d4c6 100644 --- a/src/main/scala/com/drivergrp/core/stats.scala +++ b/src/main/scala/com/drivergrp/core/stats.scala @@ -1,6 +1,6 @@ package com.drivergrp.core -import com.drivergrp.core.logging.LoggerModule +import com.drivergrp.core.logging.Logger import com.drivergrp.core.time.{Time, TimeRange} object stats { @@ -9,11 +9,6 @@ object stats { type StatsKeys = Seq[StatsKey] - trait StatsModule { - - def stats: Stats - } - trait Stats { def recordStats(keys: StatsKeys, interval: TimeRange, value: BigDecimal): Unit @@ -40,9 +35,7 @@ object stats { recordStats(Vector(key), TimeRange(time, time), BigDecimal(value)) } - trait LogStats extends Stats { - this: LoggerModule => - + class LogStats(log: Logger) extends Stats { def recordStats(keys: StatsKeys, interval: TimeRange, value: BigDecimal): Unit = { log.audit(s"${keys.mkString(".")}(${interval.start.millis}-${interval.end.millis})=${value.toString}") } diff --git a/src/main/scala/com/drivergrp/core/time.scala b/src/main/scala/com/drivergrp/core/time.scala index 645c991..cce479f 100644 --- a/src/main/scala/com/drivergrp/core/time.scala +++ b/src/main/scala/com/drivergrp/core/time.scala @@ -59,11 +59,6 @@ object time { * All the calls to receive current time must be made using time * provider injected to the caller. */ - - trait TimeModule { - def time: TimeProvider - } - trait TimeProvider { def currentTime(): Time } -- cgit v1.2.3