diff --git a/atlas-akka/src/main/scala/com/netflix/atlas/akka/ActorService.scala b/atlas-akka/src/main/scala/com/netflix/atlas/akka/ActorService.scala index bdbeb7faa..eba2994ef 100644 --- a/atlas-akka/src/main/scala/com/netflix/atlas/akka/ActorService.scala +++ b/atlas-akka/src/main/scala/com/netflix/atlas/akka/ActorService.scala @@ -16,6 +16,7 @@ package com.netflix.atlas.akka import javax.inject.Inject +import javax.inject.Singleton import akka.actor.Actor import akka.actor.ActorSystem @@ -32,6 +33,7 @@ import scala.concurrent.duration.Duration * Exposes actor system as service for healthcheck and proper shutdown. Additional * actors to start up can be specified using the `atlas.akka.actors` property. */ +@Singleton class ActorService @Inject() (system: ActorSystem, config: Config, classFactory: ClassFactory) extends AbstractService with StrictLogging { diff --git a/atlas-akka/src/main/scala/com/netflix/atlas/akka/WebServer.scala b/atlas-akka/src/main/scala/com/netflix/atlas/akka/WebServer.scala index c872a8c0c..28a517ea2 100644 --- a/atlas-akka/src/main/scala/com/netflix/atlas/akka/WebServer.scala +++ b/atlas-akka/src/main/scala/com/netflix/atlas/akka/WebServer.scala @@ -17,6 +17,7 @@ package com.netflix.atlas.akka import java.util.concurrent.TimeUnit import javax.inject.Inject +import javax.inject.Singleton import akka.actor.Actor import akka.actor.ActorSystem @@ -50,6 +51,7 @@ import scala.util.Success * @param system * Instance of the actor system. */ +@Singleton class WebServer @Inject() ( config: Config, classFactory: ClassFactory, diff --git a/atlas-module-akka/src/main/resources/META-INF/services/com.google.inject.Module b/atlas-module-akka/src/main/resources/META-INF/services/com.google.inject.Module new file mode 100644 index 000000000..44c8e91d5 --- /dev/null +++ b/atlas-module-akka/src/main/resources/META-INF/services/com.google.inject.Module @@ -0,0 +1 @@ +com.netflix.atlas.akka.AkkaModule \ No newline at end of file diff --git a/atlas-module-akka/src/main/scala/com/netflix/atlas/akka/AkkaModule.scala b/atlas-module-akka/src/main/scala/com/netflix/atlas/akka/AkkaModule.scala new file mode 100644 index 000000000..76d6d3124 --- /dev/null +++ b/atlas-module-akka/src/main/scala/com/netflix/atlas/akka/AkkaModule.scala @@ -0,0 +1,46 @@ +/* + * Copyright 2014-2016 Netflix, Inc. + * + * 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 com.netflix.atlas.akka + +import javax.inject.Singleton + +import akka.actor.ActorSystem +import com.google.inject.AbstractModule +import com.google.inject.Provides +import com.google.inject.multibindings.Multibinder +import com.netflix.iep.guice.LifecycleModule +import com.netflix.iep.service.Service +import com.typesafe.config.Config + +/** + * Configures the actor system and web server. This module expects that bindings + * are available for [[com.typesafe.config.Config]] and [[com.netflix.spectator.api.Registry]]. + */ +class AkkaModule extends AbstractModule { + override def configure(): Unit = { + install(new LifecycleModule) + val serviceBinder = Multibinder.newSetBinder(binder, classOf[Service]) + serviceBinder.addBinding().to(classOf[ActorService]) + serviceBinder.addBinding().to(classOf[WebServer]) + } + + @Provides @Singleton + private def providesActorSystem(config: Config): ActorSystem = { + val name = config.getString("atlas.akka.name") + ActorSystem(name, config) + } +} + diff --git a/atlas-module-akka/src/test/scala/com/netflix/atlas/akka/AkkaModuleSuite.scala b/atlas-module-akka/src/test/scala/com/netflix/atlas/akka/AkkaModuleSuite.scala new file mode 100644 index 000000000..71195af2e --- /dev/null +++ b/atlas-module-akka/src/test/scala/com/netflix/atlas/akka/AkkaModuleSuite.scala @@ -0,0 +1,50 @@ +/* + * Copyright 2014-2016 Netflix, Inc. + * + * 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 com.netflix.atlas.akka + +import akka.actor.ActorSystem +import com.google.inject.AbstractModule +import com.google.inject.Guice +import com.netflix.iep.guice.PreDestroyList +import com.netflix.iep.service.ServiceManager +import com.netflix.spectator.api.NoopRegistry +import com.netflix.spectator.api.Registry +import com.typesafe.config.Config +import com.typesafe.config.ConfigFactory +import org.scalatest.FunSuite + +class AkkaModuleSuite extends FunSuite { + + private val testCfg = ConfigFactory.parseString( + """ + |atlas.akka.name = test + |atlas.akka.port = 0 + |atlas.akka.actors = [] + """.stripMargin) + + test("load module") { + val deps = new AbstractModule { + override def configure(): Unit = { + bind(classOf[Config]).toInstance(testCfg.withFallback(ConfigFactory.load())) + bind(classOf[Registry]).toInstance(new NoopRegistry) + } + } + val injector = Guice.createInjector(deps, new AkkaModule) + assert(injector.getInstance(classOf[ActorSystem]) != null) + assert(injector.getInstance(classOf[ServiceManager]).services().size === 2) + injector.getInstance(classOf[PreDestroyList]).invokeAll() + } +} diff --git a/atlas-module-webapi/src/main/resources/META-INF/services/com.google.inject.Module b/atlas-module-webapi/src/main/resources/META-INF/services/com.google.inject.Module new file mode 100644 index 000000000..55ca9df32 --- /dev/null +++ b/atlas-module-webapi/src/main/resources/META-INF/services/com.google.inject.Module @@ -0,0 +1 @@ +com.netflix.atlas.guice.WebApiModule \ No newline at end of file diff --git a/atlas-akka/src/main/scala/com/netflix/atlas/akka/ActorSystemProvider.scala b/atlas-module-webapi/src/main/scala/com/netflix/atlas/guice/WebApiModule.scala similarity index 52% rename from atlas-akka/src/main/scala/com/netflix/atlas/akka/ActorSystemProvider.scala rename to atlas-module-webapi/src/main/scala/com/netflix/atlas/guice/WebApiModule.scala index c68a96f05..b1e60d308 100644 --- a/atlas-akka/src/main/scala/com/netflix/atlas/akka/ActorSystemProvider.scala +++ b/atlas-module-webapi/src/main/scala/com/netflix/atlas/guice/WebApiModule.scala @@ -13,23 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.netflix.atlas.akka +package com.netflix.atlas.guice -import javax.inject.Inject -import javax.inject.Provider -import javax.inject.Singleton +import com.google.inject.AbstractModule +import com.netflix.atlas.core.db.Database +import com.netflix.atlas.webapi.DatabaseProvider +import com.netflix.iep.guice.LifecycleModule -import akka.actor.ActorSystem -import com.netflix.spectator.api.Registry -import com.typesafe.config.Config - -/** Provider for getting an instance of the actor system. */ -@Singleton -class ActorSystemProvider @Inject() (config: Config, registry: Registry) - extends Provider[ActorSystem] { - - private val name = config.getString("atlas.akka.name") - private val system = ActorSystem(name, config) - - override def get(): ActorSystem = system +/** + * Configures the database needed for the webapi. + */ +class WebApiModule extends AbstractModule { + override def configure(): Unit = { + install(new LifecycleModule) + bind(classOf[Database]).toProvider(classOf[DatabaseProvider]) + } } diff --git a/atlas-module-webapi/src/test/scala/com/netflix/atlas/guice/WebApiModuleSuite.scala b/atlas-module-webapi/src/test/scala/com/netflix/atlas/guice/WebApiModuleSuite.scala new file mode 100644 index 000000000..088cb928e --- /dev/null +++ b/atlas-module-webapi/src/test/scala/com/netflix/atlas/guice/WebApiModuleSuite.scala @@ -0,0 +1,38 @@ +/* + * Copyright 2014-2016 Netflix, Inc. + * + * 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 com.netflix.atlas.guice + +import com.google.inject.AbstractModule +import com.google.inject.Guice +import com.netflix.atlas.core.db.Database +import com.netflix.iep.guice.PreDestroyList +import com.typesafe.config.Config +import com.typesafe.config.ConfigFactory +import org.scalatest.FunSuite + +class WebApiModuleSuite extends FunSuite { + + test("load module") { + val deps = new AbstractModule { + override def configure(): Unit = { + bind(classOf[Config]).toInstance(ConfigFactory.load()) + } + } + val injector = Guice.createInjector(deps, new WebApiModule) + assert(injector.getInstance(classOf[Database]) != null) + injector.getInstance(classOf[PreDestroyList]).invokeAll() + } +} diff --git a/atlas-standalone/src/main/scala/com/netflix/atlas/standalone/Main.scala b/atlas-standalone/src/main/scala/com/netflix/atlas/standalone/Main.scala index f2c9446fb..d6dd0f942 100644 --- a/atlas-standalone/src/main/scala/com/netflix/atlas/standalone/Main.scala +++ b/atlas-standalone/src/main/scala/com/netflix/atlas/standalone/Main.scala @@ -24,7 +24,6 @@ import com.google.inject.multibindings.Multibinder import com.google.inject.multibindings.OptionalBinder import com.google.inject.util.Modules import com.netflix.atlas.akka.ActorService -import com.netflix.atlas.akka.ActorSystemProvider import com.netflix.atlas.akka.WebServer import com.netflix.atlas.config.ConfigManager import com.netflix.atlas.core.db.Database @@ -73,30 +72,16 @@ object Main extends StrictLogging { } def start(): Unit = { - val serviceModule = new AbstractModule { - override def configure(): Unit = { - GuiceHelper.getModulesUsingServiceLoader.forEach(install) - - OptionalBinder.newOptionalBinder(binder(), classOf[Registry]) - .setBinding().toInstance(Spectator.globalRegistry()) - bind(classOf[ActorSystem]).toProvider(classOf[ActorSystemProvider]) - bind(classOf[Database]).toProvider(classOf[DatabaseProvider]) - - val serviceBinder = Multibinder.newSetBinder(binder, classOf[Service]) - serviceBinder.addBinding().to(classOf[ActorService]) - serviceBinder.addBinding().to(classOf[WebServer]) - } - } - - val overrides = Modules.`override`(serviceModule).`with`(new AbstractModule { + val configModule = new AbstractModule { override def configure(): Unit = { bind(classOf[Config]).toInstance(ConfigManager.current) + bind(classOf[Registry]).toInstance(Spectator.globalRegistry()) } - }) + } - val modules = new java.util.ArrayList[Module]() - modules.add(overrides) + val modules = GuiceHelper.getModulesUsingServiceLoader + modules.add(configModule) guice = new GuiceHelper guice.start(modules) diff --git a/project/Build.scala b/project/Build.scala index acc8fa4e9..23c3cdd9a 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -29,6 +29,8 @@ object MainBuild extends Build { `atlas-core`, `atlas-jmh`, `atlas-json`, + `atlas-module-akka`, + `atlas-module-webapi`, `atlas-standalone`, `atlas-test`, `atlas-webapi`, @@ -89,12 +91,31 @@ object MainBuild extends Build { Dependencies.jodaConvert )) - lazy val `atlas-standalone` = project + lazy val `atlas-module-akka` = project + .dependsOn(`atlas-akka`) + .settings(buildSettings: _*) + .settings(libraryDependencies ++= commonDeps) + .settings(libraryDependencies ++= Seq( + Dependencies.guiceCore, + Dependencies.guiceMulti, + Dependencies.iepGuice + )) + + lazy val `atlas-module-webapi` = project .dependsOn(`atlas-webapi`) .settings(buildSettings: _*) .settings(libraryDependencies ++= commonDeps) .settings(libraryDependencies ++= Seq( - Dependencies.iepGovernator, + Dependencies.guiceCore, + Dependencies.iepGuice + )) + + lazy val `atlas-standalone` = project + .dependsOn(`atlas-module-akka`, `atlas-module-webapi`) + .settings(buildSettings: _*) + .settings(libraryDependencies ++= commonDeps) + .settings(libraryDependencies ++= Seq( + Dependencies.iepGuice, Dependencies.guiceCore, Dependencies.guiceMulti, Dependencies.log4jApi, diff --git a/project/Dependencies.scala b/project/Dependencies.scala index c57ad252c..837426a3b 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -27,7 +27,7 @@ object Dependencies { val equalsVerifier = "nl.jqno.equalsverifier" % "equalsverifier" % "2.1.3" val guiceCore = "com.google.inject" % "guice" % guice val guiceMulti = "com.google.inject.extensions" % "guice-multibindings" % guice - val iepGovernator = "com.netflix.iep" % "iep-guice" % iep + val iepGuice = "com.netflix.iep" % "iep-guice" % iep val iepService = "com.netflix.iep" % "iep-service" % iep val jacksonAnno2 = "com.fasterxml.jackson.core" % "jackson-annotations" % jackson val jacksonCore2 = "com.fasterxml.jackson.core" % "jackson-core" % jackson